summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:08:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:08:37 +0000
commit971e619d8602fa52b1bfcb3ea65b7ab96be85318 (patch)
tree26feb2498c72b796e07b86349d17f544046de279
parentInitial commit. (diff)
downloadnftables-971e619d8602fa52b1bfcb3ea65b7ab96be85318.tar.xz
nftables-971e619d8602fa52b1bfcb3ea65b7ab96be85318.zip
Adding upstream version 1.0.9.upstream/1.0.9upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--COPYING349
-rw-r--r--INSTALL108
-rw-r--r--Make_global.am21
-rw-r--r--Makefile.am14
-rw-r--r--Makefile.in913
-rw-r--r--aclocal.m41474
-rwxr-xr-xbuild-aux/ar-lib271
-rwxr-xr-xbuild-aux/compile348
-rwxr-xr-xbuild-aux/config.guess1480
-rwxr-xr-xbuild-aux/config.sub1801
-rwxr-xr-xbuild-aux/depcomp791
-rwxr-xr-xbuild-aux/install-sh541
-rwxr-xr-xbuild-aux/ltmain.sh11251
-rwxr-xr-xbuild-aux/missing215
-rwxr-xr-xbuild-aux/ylwrap247
-rw-r--r--config.h.in133
-rwxr-xr-xconfigure15963
-rw-r--r--configure.ac146
-rw-r--r--doc/Makefile.am30
-rw-r--r--doc/Makefile.in652
-rw-r--r--doc/data-types.txt537
-rw-r--r--doc/libnftables-json.52422
-rw-r--r--doc/libnftables-json.adoc1416
-rw-r--r--doc/libnftables.3393
-rw-r--r--doc/libnftables.adoc319
-rw-r--r--doc/nft.89717
-rw-r--r--doc/nft.txt1009
-rw-r--r--doc/payload-expression.txt973
-rw-r--r--doc/primary-expression.txt488
-rw-r--r--doc/stateful-objects.txt243
-rw-r--r--doc/statements.txt875
-rw-r--r--examples/Makefile.am6
-rw-r--r--examples/Makefile.in625
-rw-r--r--examples/nft-buffer.c34
-rw-r--r--examples/nft-json-file.c30
-rw-r--r--files/Makefile638
-rw-r--r--files/Makefile.am3
-rw-r--r--files/Makefile.in638
-rw-r--r--files/examples/Makefile530
-rw-r--r--files/examples/Makefile.am5
-rw-r--r--files/examples/Makefile.in530
-rwxr-xr-xfiles/examples/ct_helpers.nft43
-rwxr-xr-xfiles/examples/load_balancing.nft54
-rwxr-xr-xfiles/examples/secmark.nft87
-rwxr-xr-xfiles/examples/sets_and_maps.nft54
-rw-r--r--files/nftables/Makefile525
-rw-r--r--files/nftables/Makefile.am14
-rw-r--r--files/nftables/Makefile.in525
-rw-r--r--files/nftables/all-in-one.nft35
-rw-r--r--files/nftables/arp-filter.nft4
-rw-r--r--files/nftables/bridge-filter.nft5
-rw-r--r--files/nftables/inet-filter.nft5
-rw-r--r--files/nftables/inet-nat.nft6
-rw-r--r--files/nftables/ipv4-filter.nft5
-rw-r--r--files/nftables/ipv4-mangle.nft3
-rw-r--r--files/nftables/ipv4-nat.nft6
-rw-r--r--files/nftables/ipv4-raw.nft4
-rw-r--r--files/nftables/ipv6-filter.nft5
-rw-r--r--files/nftables/ipv6-mangle.nft3
-rw-r--r--files/nftables/ipv6-nat.nft6
-rw-r--r--files/nftables/ipv6-raw.nft4
-rw-r--r--files/nftables/netdev-ingress.nft5
-rw-r--r--files/osf/Makefile512
-rw-r--r--files/osf/Makefile.am2
-rw-r--r--files/osf/Makefile.in512
-rw-r--r--files/osf/pf.os703
-rw-r--r--include/Makefile.am43
-rw-r--r--include/Makefile.in681
-rw-r--r--include/cache.h155
-rw-r--r--include/cli.h16
-rw-r--r--include/cmd.h13
-rw-r--r--include/ct.h45
-rw-r--r--include/datatype.h323
-rw-r--r--include/dccpopt.h41
-rw-r--r--include/erec.h84
-rw-r--r--include/expression.h530
-rw-r--r--include/exthdr.h120
-rw-r--r--include/fib.h12
-rw-r--r--include/gmputil.h80
-rw-r--r--include/hash.h10
-rw-r--r--include/headers.h159
-rw-r--r--include/iface.h18
-rw-r--r--include/intervals.h12
-rw-r--r--include/ipopt.h29
-rw-r--r--include/json.h281
-rw-r--r--include/linux/Makefile.am12
-rw-r--r--include/linux/Makefile.in650
-rw-r--r--include/linux/netfilter.h81
-rw-r--r--include/linux/netfilter/Makefile.am10
-rw-r--r--include/linux/netfilter/Makefile.in533
-rw-r--r--include/linux/netfilter/nf_conntrack_common.h104
-rw-r--r--include/linux/netfilter/nf_conntrack_tuple_common.h41
-rw-r--r--include/linux/netfilter/nf_log.h15
-rw-r--r--include/linux/netfilter/nf_nat.h55
-rw-r--r--include/linux/netfilter/nf_synproxy.h23
-rw-r--r--include/linux/netfilter/nf_tables.h1983
-rw-r--r--include/linux/netfilter/nf_tables_compat.h38
-rw-r--r--include/linux/netfilter/nfnetlink.h69
-rw-r--r--include/linux/netfilter/nfnetlink_hook.h82
-rw-r--r--include/linux/netfilter/nfnetlink_osf.h119
-rw-r--r--include/linux/netfilter_arp.h19
-rw-r--r--include/linux/netfilter_arp/Makefile.am1
-rw-r--r--include/linux/netfilter_arp/Makefile.in523
-rw-r--r--include/linux/netfilter_arp/arp_tables.h204
-rw-r--r--include/linux/netfilter_bridge.h40
-rw-r--r--include/linux/netfilter_bridge/Makefile.am1
-rw-r--r--include/linux/netfilter_bridge/Makefile.in523
-rw-r--r--include/linux/netfilter_bridge/ebtables.h266
-rw-r--r--include/linux/netfilter_decnet.h72
-rw-r--r--include/linux/netfilter_ipv4.h81
-rw-r--r--include/linux/netfilter_ipv4/Makefile.am1
-rw-r--r--include/linux/netfilter_ipv4/Makefile.in523
-rw-r--r--include/linux/netfilter_ipv4/ip_tables.h227
-rw-r--r--include/linux/netfilter_ipv6.h72
-rw-r--r--include/linux/netfilter_ipv6/Makefile.am1
-rw-r--r--include/linux/netfilter_ipv6/Makefile.in523
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h265
-rw-r--r--include/list.h643
-rw-r--r--include/meta.h48
-rw-r--r--include/mini-gmp.h300
-rw-r--r--include/misspell.h13
-rw-r--r--include/mnl.h105
-rw-r--r--include/netlink.h263
-rw-r--r--include/nft.h12
-rw-r--r--include/nftables.h244
-rw-r--r--include/nftables/Makefile.am1
-rw-r--r--include/nftables/Makefile.in576
-rw-r--r--include/nftables/libnftables.h106
-rw-r--r--include/numgen.h8
-rw-r--r--include/osf.h9
-rw-r--r--include/owner.h6
-rw-r--r--include/parser.h115
-rw-r--r--include/payload.h74
-rw-r--r--include/proto.h474
-rw-r--r--include/rt.h37
-rw-r--r--include/rule.h791
-rw-r--r--include/sctp_chunk.h87
-rw-r--r--include/socket.h24
-rw-r--r--include/statement.h426
-rw-r--r--include/tcpopt.h85
-rw-r--r--include/utils.h155
-rw-r--r--include/xfrm.h16
-rw-r--r--include/xt.h29
-rw-r--r--libnftables.pc.in15
-rw-r--r--m4/gcc4_visibility.m421
-rw-r--r--m4/libtool.m48394
-rw-r--r--m4/ltoptions.m4437
-rw-r--r--m4/ltsugar.m4124
-rw-r--r--m4/ltversion.m423
-rw-r--r--m4/lt~obsolete.m499
-rw-r--r--py/Makefile.am1
-rw-r--r--py/Makefile.in455
-rw-r--r--py/pyproject.toml3
-rw-r--r--py/setup.cfg24
-rwxr-xr-xpy/setup.py5
-rw-r--r--py/src/__init__.py1
-rw-r--r--py/src/nftables.py604
-rw-r--r--py/src/schema.json16
-rw-r--r--src/Makefile.am123
-rw-r--r--src/Makefile.in1097
-rw-r--r--src/cache.c1295
-rw-r--r--src/cli.c275
-rw-r--r--src/cmd.c495
-rw-r--r--src/ct.c593
-rw-r--r--src/datatype.c1553
-rw-r--r--src/dccpopt.c277
-rw-r--r--src/erec.c238
-rw-r--r--src/evaluate.c5857
-rw-r--r--src/expression.c1563
-rw-r--r--src/exthdr.c610
-rw-r--r--src/fib.c202
-rw-r--r--src/gmputil.c198
-rw-r--r--src/hash.c165
-rw-r--r--src/iface.c173
-rw-r--r--src/intervals.c750
-rw-r--r--src/ipopt.c145
-rw-r--r--src/json.c2090
-rw-r--r--src/libnftables.c810
-rw-r--r--src/libnftables.map40
-rw-r--r--src/main.c554
-rw-r--r--src/mergesort.c122
-rw-r--r--src/meta.c1043
-rw-r--r--src/mini-gmp.c4412
-rw-r--r--src/misspell.c114
-rw-r--r--src/mnl.c2669
-rw-r--r--src/monitor.c1014
-rw-r--r--src/netlink.c2240
-rw-r--r--src/netlink_delinearize.c3512
-rw-r--r--src/netlink_linearize.c1789
-rw-r--r--src/nfnl_osf.c396
-rw-r--r--src/nftutils.c100
-rw-r--r--src/nftutils.h20
-rw-r--r--src/numgen.c140
-rw-r--r--src/optimize.c1406
-rw-r--r--src/osf.c84
-rw-r--r--src/owner.c182
-rw-r--r--src/parser_bison.c17491
-rw-r--r--src/parser_bison.h845
-rw-r--r--src/parser_bison.y6290
-rw-r--r--src/parser_json.c4415
-rw-r--r--src/payload.c1494
-rw-r--r--src/print.c39
-rw-r--r--src/proto.c1320
-rw-r--r--src/rt.c211
-rw-r--r--src/rule.c2799
-rw-r--r--src/scanner.c8546
-rw-r--r--src/scanner.l1326
-rw-r--r--src/sctp_chunk.c262
-rw-r--r--src/segtree.c637
-rw-r--r--src/socket.c136
-rw-r--r--src/statement.c1085
-rw-r--r--src/tcpopt.c266
-rw-r--r--src/utils.c107
-rw-r--r--src/xfrm.c184
-rw-r--r--src/xt.c377
-rw-r--r--tests/build/README12
-rwxr-xr-xtests/build/run-tests.sh59
-rw-r--r--tests/build/tests.log3597
-rwxr-xr-xtests/json_echo/run-test.py309
-rw-r--r--tests/monitor/README59
-rwxr-xr-xtests/monitor/run-tests.sh211
-rw-r--r--tests/monitor/testcases/map-expr.t6
-rw-r--r--tests/monitor/testcases/object.t46
-rw-r--r--tests/monitor/testcases/set-interval.t30
-rw-r--r--tests/monitor/testcases/set-maps.t14
-rw-r--r--tests/monitor/testcases/set-mixed.t22
-rw-r--r--tests/monitor/testcases/set-multiple.t15
-rw-r--r--tests/monitor/testcases/set-simple.t61
-rw-r--r--tests/monitor/testcases/simple.t28
-rw-r--r--tests/py/README197
-rw-r--r--tests/py/any/counter.t14
-rw-r--r--tests/py/any/counter.t.json39
-rw-r--r--tests/py/any/counter.t.json.output28
-rw-r--r--tests/py/any/counter.t.payload15
-rw-r--r--tests/py/any/ct.t149
-rw-r--r--tests/py/any/ct.t.json1523
-rw-r--r--tests/py/any/ct.t.json.output666
-rw-r--r--tests/py/any/ct.t.payload518
-rw-r--r--tests/py/any/icmpX.t.netdev9
-rw-r--r--tests/py/any/icmpX.t.netdev.payload36
-rw-r--r--tests/py/any/last.t13
-rw-r--r--tests/py/any/last.t.json16
-rw-r--r--tests/py/any/last.t.json.output14
-rw-r--r--tests/py/any/last.t.payload8
-rw-r--r--tests/py/any/limit.t55
-rw-r--r--tests/py/any/limit.t.json413
-rw-r--r--tests/py/any/limit.t.json.output277
-rw-r--r--tests/py/any/limit.t.payload141
-rw-r--r--tests/py/any/log.t41
-rw-r--r--tests/py/any/log.t.json178
-rw-r--r--tests/py/any/log.t.json.output16
-rw-r--r--tests/py/any/log.t.payload71
-rw-r--r--tests/py/any/meta.t226
-rw-r--r--tests/py/any/meta.t.json2760
-rw-r--r--tests/py/any/meta.t.json.output828
-rw-r--r--tests/py/any/meta.t.payload1074
-rw-r--r--tests/py/any/objects.t16
-rw-r--r--tests/py/any/queue.t33
-rw-r--r--tests/py/any/queue.t.json251
-rw-r--r--tests/py/any/queue.t.json.output9
-rw-r--r--tests/py/any/queue.t.payload81
-rw-r--r--tests/py/any/quota.t25
-rw-r--r--tests/py/any/quota.t.json136
-rw-r--r--tests/py/any/quota.t.payload52
-rw-r--r--tests/py/any/rawpayload.t24
-rw-r--r--tests/py/any/rawpayload.t.json206
-rw-r--r--tests/py/any/rawpayload.t.json.output119
-rw-r--r--tests/py/any/rawpayload.t.payload63
-rw-r--r--tests/py/any/rt.t9
-rw-r--r--tests/py/any/rt.t.json45
-rw-r--r--tests/py/any/rt.t.payload15
-rw-r--r--tests/py/any/tcpopt.t62
-rw-r--r--tests/py/any/tcpopt.t.json622
-rw-r--r--tests/py/any/tcpopt.t.json.output32
-rw-r--r--tests/py/any/tcpopt.t.payload202
-rw-r--r--tests/py/arp/arp.t60
-rw-r--r--tests/py/arp/arp.t.json893
-rw-r--r--tests/py/arp/arp.t.json.output180
-rw-r--r--tests/py/arp/arp.t.payload261
-rw-r--r--tests/py/arp/arp.t.payload.netdev351
-rw-r--r--tests/py/arp/chains.t5
-rw-r--r--tests/py/arp/chains.t.payload0
-rw-r--r--tests/py/bridge/chains.t8
-rw-r--r--tests/py/bridge/chains.t.payload0
-rw-r--r--tests/py/bridge/ether.t12
-rw-r--r--tests/py/bridge/ether.t.json193
-rw-r--r--tests/py/bridge/ether.t.json.output43
-rw-r--r--tests/py/bridge/ether.t.payload60
-rw-r--r--tests/py/bridge/icmpX.t8
-rw-r--r--tests/py/bridge/icmpX.t.json88
-rw-r--r--tests/py/bridge/icmpX.t.json.output56
-rw-r--r--tests/py/bridge/icmpX.t.payload36
-rw-r--r--tests/py/bridge/meta.t13
-rw-r--r--tests/py/bridge/meta.t.json105
-rw-r--r--tests/py/bridge/meta.t.payload37
-rw-r--r--tests/py/bridge/redirect.t5
-rw-r--r--tests/py/bridge/redirect.t.json12
-rw-r--r--tests/py/bridge/redirect.t.payload4
-rw-r--r--tests/py/bridge/reject.t42
-rw-r--r--tests/py/bridge/reject.t.json341
-rw-r--r--tests/py/bridge/reject.t.json.output83
-rw-r--r--tests/py/bridge/reject.t.payload140
-rw-r--r--tests/py/bridge/vlan.t56
-rw-r--r--tests/py/bridge/vlan.t.json894
-rw-r--r--tests/py/bridge/vlan.t.json.output204
-rw-r--r--tests/py/bridge/vlan.t.payload314
-rw-r--r--tests/py/bridge/vlan.t.payload.netdev368
-rw-r--r--tests/py/inet/ah.t47
-rw-r--r--tests/py/inet/ah.t.json412
-rw-r--r--tests/py/inet/ah.t.payload182
-rw-r--r--tests/py/inet/comp.t30
-rw-r--r--tests/py/inet/comp.t.json244
-rw-r--r--tests/py/inet/comp.t.json.output170
-rw-r--r--tests/py/inet/comp.t.payload105
-rw-r--r--tests/py/inet/ct.t15
-rw-r--r--tests/py/inet/ct.t.json60
-rw-r--r--tests/py/inet/ct.t.json.output16
-rw-r--r--tests/py/inet/ct.t.payload17
-rw-r--r--tests/py/inet/dccp.t30
-rw-r--r--tests/py/inet/dccp.t.json276
-rw-r--r--tests/py/inet/dccp.t.json.output18
-rw-r--r--tests/py/inet/dccp.t.payload115
-rw-r--r--tests/py/inet/dnat.t22
-rw-r--r--tests/py/inet/dnat.t.json241
-rw-r--r--tests/py/inet/dnat.t.payload86
-rw-r--r--tests/py/inet/esp.t21
-rw-r--r--tests/py/inet/esp.t.json204
-rw-r--r--tests/py/inet/esp.t.payload91
-rw-r--r--tests/py/inet/ether-ip.t9
-rw-r--r--tests/py/inet/ether-ip.t.json92
-rw-r--r--tests/py/inet/ether-ip.t.json.output43
-rw-r--r--tests/py/inet/ether-ip.t.payload28
-rw-r--r--tests/py/inet/ether-ip.t.payload.netdev29
-rw-r--r--tests/py/inet/ether.t20
-rw-r--r--tests/py/inet/ether.t.json122
-rw-r--r--tests/py/inet/ether.t.json.output31
-rw-r--r--tests/py/inet/ether.t.payload52
-rw-r--r--tests/py/inet/ether.t.payload.bridge44
-rw-r--r--tests/py/inet/ether.t.payload.ip52
-rw-r--r--tests/py/inet/fib.t17
-rw-r--r--tests/py/inet/fib.t.json132
-rw-r--r--tests/py/inet/fib.t.json.output39
-rw-r--r--tests/py/inet/fib.t.payload32
-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/icmp.t18
-rw-r--r--tests/py/inet/icmp.t.json124
-rw-r--r--tests/py/inet/icmp.t.json.output32
-rw-r--r--tests/py/inet/icmp.t.payload54
-rw-r--r--tests/py/inet/icmpX.t10
-rw-r--r--tests/py/inet/icmpX.t.json125
-rw-r--r--tests/py/inet/icmpX.t.json.output84
-rw-r--r--tests/py/inet/icmpX.t.payload46
-rw-r--r--tests/py/inet/ip.t12
-rw-r--r--tests/py/inet/ip.t.json42
-rw-r--r--tests/py/inet/ip.t.payload11
-rw-r--r--tests/py/inet/ip.t.payload.bridge11
-rw-r--r--tests/py/inet/ip.t.payload.inet14
-rw-r--r--tests/py/inet/ip.t.payload.netdev14
-rw-r--r--tests/py/inet/ip_tcp.t21
-rw-r--r--tests/py/inet/ip_tcp.t.json170
-rw-r--r--tests/py/inet/ip_tcp.t.json.output142
-rw-r--r--tests/py/inet/ip_tcp.t.payload52
-rw-r--r--tests/py/inet/ip_tcp.t.payload.bridge51
-rw-r--r--tests/py/inet/ip_tcp.t.payload.netdev53
-rw-r--r--tests/py/inet/ipsec.t23
-rw-r--r--tests/py/inet/ipsec.t.json157
-rw-r--r--tests/py/inet/ipsec.t.payload45
-rw-r--r--tests/py/inet/map.t10
-rw-r--r--tests/py/inet/map.t.json66
-rw-r--r--tests/py/inet/map.t.json.output66
-rw-r--r--tests/py/inet/map.t.payload23
-rw-r--r--tests/py/inet/map.t.payload.ip19
-rw-r--r--tests/py/inet/map.t.payload.netdev23
-rw-r--r--tests/py/inet/meta.t32
-rw-r--r--tests/py/inet/meta.t.json528
-rw-r--r--tests/py/inet/meta.t.json.got86
-rw-r--r--tests/py/inet/meta.t.json.output53
-rw-r--r--tests/py/inet/meta.t.payload175
-rw-r--r--tests/py/inet/meta.t.payload.got40
-rw-r--r--tests/py/inet/osf.t18
-rw-r--r--tests/py/inet/osf.t.json170
-rw-r--r--tests/py/inet/osf.t.payload53
-rw-r--r--tests/py/inet/reject.t41
-rw-r--r--tests/py/inet/reject.t.json331
-rw-r--r--tests/py/inet/reject.t.json.output77
-rw-r--r--tests/py/inet/reject.t.payload.inet144
-rw-r--r--tests/py/inet/rt.t15
-rw-r--r--tests/py/inet/rt.t.json59
-rw-r--r--tests/py/inet/rt.t.json.output25
-rw-r--r--tests/py/inet/rt.t.payload18
-rw-r--r--tests/py/inet/sctp.t73
-rw-r--r--tests/py/inet/sctp.t.json928
-rw-r--r--tests/py/inet/sctp.t.payload351
-rw-r--r--tests/py/inet/sets.t25
-rw-r--r--tests/py/inet/sets.t.json136
-rw-r--r--tests/py/inet/sets.t.payload.bridge42
-rw-r--r--tests/py/inet/sets.t.payload.inet41
-rw-r--r--tests/py/inet/sets.t.payload.netdev41
-rw-r--r--tests/py/inet/snat.t21
-rw-r--r--tests/py/inet/snat.t.json131
-rw-r--r--tests/py/inet/snat.t.payload42
-rw-r--r--tests/py/inet/socket.t15
-rw-r--r--tests/py/inet/socket.t.json74
-rw-r--r--tests/py/inet/socket.t.payload24
-rw-r--r--tests/py/inet/synproxy.t13
-rw-r--r--tests/py/inet/synproxy.t.json64
-rw-r--r--tests/py/inet/synproxy.t.payload24
-rw-r--r--tests/py/inet/tcp.t115
-rw-r--r--tests/py/inet/tcp.t.json1799
-rw-r--r--tests/py/inet/tcp.t.json.output210
-rw-r--r--tests/py/inet/tcp.t.payload674
-rw-r--r--tests/py/inet/tproxy.t21
-rw-r--r--tests/py/inet/tproxy.t.json185
-rw-r--r--tests/py/inet/tproxy.t.payload63
-rw-r--r--tests/py/inet/udp.t45
-rw-r--r--tests/py/inet/udp.t.json583
-rw-r--r--tests/py/inet/udp.t.payload248
-rw-r--r--tests/py/inet/udplite.t38
-rw-r--r--tests/py/inet/udplite.t.json413
-rw-r--r--tests/py/inet/udplite.t.payload178
-rw-r--r--tests/py/inet/vmap.t10
-rw-r--r--tests/py/inet/vmap.t.json144
-rw-r--r--tests/py/inet/vmap.t.payload34
-rw-r--r--tests/py/inet/vmap.t.payload.netdev34
-rw-r--r--tests/py/inet/vxlan.t23
-rw-r--r--tests/py/inet/vxlan.t.json344
-rw-r--r--tests/py/inet/vxlan.t.payload114
-rw-r--r--tests/py/ip/chains.t15
-rw-r--r--tests/py/ip/ct.t36
-rw-r--r--tests/py/ip/ct.t.json481
-rw-r--r--tests/py/ip/ct.t.json.output27
-rw-r--r--tests/py/ip/ct.t.payload136
-rw-r--r--tests/py/ip/dnat.t23
-rw-r--r--tests/py/ip/dnat.t.json743
-rw-r--r--tests/py/ip/dnat.t.json.output65
-rw-r--r--tests/py/ip/dnat.t.payload.ip204
-rw-r--r--tests/py/ip/dup.t7
-rw-r--r--tests/py/ip/dup.t.json46
-rw-r--r--tests/py/ip/dup.t.payload21
-rw-r--r--tests/py/ip/ether.t8
-rw-r--r--tests/py/ip/ether.t.json163
-rw-r--r--tests/py/ip/ether.t.json.output43
-rw-r--r--tests/py/ip/ether.t.payload50
-rw-r--r--tests/py/ip/flowtable.t5
-rw-r--r--tests/py/ip/flowtable.t.json24
-rw-r--r--tests/py/ip/flowtable.t.payload7
-rw-r--r--tests/py/ip/hash.t10
-rw-r--r--tests/py/ip/hash.t.json230
-rw-r--r--tests/py/ip/hash.t.payload49
-rw-r--r--tests/py/ip/icmp.t77
-rw-r--r--tests/py/ip/icmp.t.json1494
-rw-r--r--tests/py/ip/icmp.t.json.output169
-rw-r--r--tests/py/ip/icmp.t.payload.ip619
-rw-r--r--tests/py/ip/igmp.t23
-rw-r--r--tests/py/ip/igmp.t.json273
-rw-r--r--tests/py/ip/igmp.t.payload118
-rw-r--r--tests/py/ip/ip.t135
-rw-r--r--tests/py/ip/ip.t.json1811
-rw-r--r--tests/py/ip/ip.t.json.got62
-rw-r--r--tests/py/ip/ip.t.json.output232
-rw-r--r--tests/py/ip/ip.t.payload558
-rw-r--r--tests/py/ip/ip.t.payload.bridge728
-rw-r--r--tests/py/ip/ip.t.payload.bridge.got24
-rw-r--r--tests/py/ip/ip.t.payload.got18
-rw-r--r--tests/py/ip/ip.t.payload.inet728
-rw-r--r--tests/py/ip/ip.t.payload.inet.got24
-rw-r--r--tests/py/ip/ip.t.payload.netdev728
-rw-r--r--tests/py/ip/ip.t.payload.netdev.got24
-rw-r--r--tests/py/ip/ip_tcp.t9
-rw-r--r--tests/py/ip/ip_tcp.t.json64
-rw-r--r--tests/py/ip/ip_tcp.t.json.output52
-rw-r--r--tests/py/ip/ip_tcp.t.payload16
-rw-r--r--tests/py/ip/masquerade.t30
-rw-r--r--tests/py/ip/masquerade.t.json429
-rw-r--r--tests/py/ip/masquerade.t.json.output123
-rw-r--r--tests/py/ip/masquerade.t.payload142
-rw-r--r--tests/py/ip/meta.t22
-rw-r--r--tests/py/ip/meta.t.json236
-rw-r--r--tests/py/ip/meta.t.json.output48
-rw-r--r--tests/py/ip/meta.t.payload78
-rw-r--r--tests/py/ip/numgen.t9
-rw-r--r--tests/py/ip/numgen.t.json129
-rw-r--r--tests/py/ip/numgen.t.json.output112
-rw-r--r--tests/py/ip/numgen.t.payload40
-rw-r--r--tests/py/ip/objects.t58
-rw-r--r--tests/py/ip/objects.t.json229
-rw-r--r--tests/py/ip/objects.t.json.output64
-rw-r--r--tests/py/ip/objects.t.payload79
-rw-r--r--tests/py/ip/redirect.t51
-rw-r--r--tests/py/ip/redirect.t.json625
-rw-r--r--tests/py/ip/redirect.t.json.output146
-rw-r--r--tests/py/ip/redirect.t.payload220
-rw-r--r--tests/py/ip/reject.t17
-rw-r--r--tests/py/ip/reject.t.json105
-rw-r--r--tests/py/ip/reject.t.json.output28
-rw-r--r--tests/py/ip/reject.t.payload44
-rw-r--r--tests/py/ip/rt.t7
-rw-r--r--tests/py/ip/rt.t.json16
-rw-r--r--tests/py/ip/rt.t.payload5
-rw-r--r--tests/py/ip/sets.t68
-rw-r--r--tests/py/ip/sets.t.json305
-rw-r--r--tests/py/ip/sets.t.json.got62
-rw-r--r--tests/py/ip/sets.t.json.payload.got157
-rw-r--r--tests/py/ip/sets.t.payload.inet106
-rw-r--r--tests/py/ip/sets.t.payload.ip83
-rw-r--r--tests/py/ip/sets.t.payload.ip.got14
-rw-r--r--tests/py/ip/sets.t.payload.netdev107
-rw-r--r--tests/py/ip/sets.t.payload.netdev.got18
-rw-r--r--tests/py/ip/snat.t21
-rw-r--r--tests/py/ip/snat.t.json530
-rw-r--r--tests/py/ip/snat.t.json.output249
-rw-r--r--tests/py/ip/snat.t.payload154
-rw-r--r--tests/py/ip/tcp.t6
-rw-r--r--tests/py/ip/tcp.t.json62
-rw-r--r--tests/py/ip/tcp.t.json.output50
-rw-r--r--tests/py/ip/tcp.t.payload18
-rw-r--r--tests/py/ip/tproxy.t14
-rw-r--r--tests/py/ip/tproxy.t.json126
-rw-r--r--tests/py/ip/tproxy.t.json.output61
-rw-r--r--tests/py/ip/tproxy.t.payload44
-rw-r--r--tests/py/ip6/chains.t17
-rw-r--r--tests/py/ip6/ct.t9
-rw-r--r--tests/py/ip6/ct.t.json293
-rw-r--r--tests/py/ip6/ct.t.payload46
-rw-r--r--tests/py/ip6/dnat.t9
-rw-r--r--tests/py/ip6/dnat.t.json106
-rw-r--r--tests/py/ip6/dnat.t.payload.ip647
-rw-r--r--tests/py/ip6/dst.t21
-rw-r--r--tests/py/ip6/dst.t.json315
-rw-r--r--tests/py/ip6/dst.t.json.output88
-rw-r--r--tests/py/ip6/dst.t.payload.inet131
-rw-r--r--tests/py/ip6/dst.t.payload.ip699
-rw-r--r--tests/py/ip6/dup.t7
-rw-r--r--tests/py/ip6/dup.t.json46
-rw-r--r--tests/py/ip6/dup.t.payload21
-rw-r--r--tests/py/ip6/ether.t8
-rw-r--r--tests/py/ip6/ether.t.json163
-rw-r--r--tests/py/ip6/ether.t.json.output43
-rw-r--r--tests/py/ip6/ether.t.payload49
-rw-r--r--tests/py/ip6/exthdr.t19
-rw-r--r--tests/py/ip6/exthdr.t.json180
-rw-r--r--tests/py/ip6/exthdr.t.json.output60
-rw-r--r--tests/py/ip6/exthdr.t.payload.ip660
-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.t40
-rw-r--r--tests/py/ip6/frag.t.json644
-rw-r--r--tests/py/ip6/frag.t.json.output118
-rw-r--r--tests/py/ip6/frag.t.payload.inet232
-rw-r--r--tests/py/ip6/frag.t.payload.ip6176
-rw-r--r--tests/py/ip6/frag.t.payload.ip6.got43
-rw-r--r--tests/py/ip6/frag.t.payload.netdev232
-rw-r--r--tests/py/ip6/frag.t.payload.netdev.got232
-rw-r--r--tests/py/ip6/hbh.t22
-rw-r--r--tests/py/ip6/hbh.t.json316
-rw-r--r--tests/py/ip6/hbh.t.json.output68
-rw-r--r--tests/py/ip6/hbh.t.payload.inet132
-rw-r--r--tests/py/ip6/hbh.t.payload.ip6100
-rw-r--r--tests/py/ip6/icmpv6.t99
-rw-r--r--tests/py/ip6/icmpv6.t.json1425
-rw-r--r--tests/py/ip6/icmpv6.t.json.output760
-rw-r--r--tests/py/ip6/icmpv6.t.payload.ip6643
-rw-r--r--tests/py/ip6/ip6.t153
-rw-r--r--tests/py/ip6/ip6.t.json1559
-rw-r--r--tests/py/ip6/ip6.t.json.output374
-rw-r--r--tests/py/ip6/ip6.t.payload.inet641
-rw-r--r--tests/py/ip6/ip6.t.payload.ip6481
-rw-r--r--tests/py/ip6/map.t5
-rw-r--r--tests/py/ip6/map.t.json38
-rw-r--r--tests/py/ip6/map.t.json.output38
-rw-r--r--tests/py/ip6/map.t.payload10
-rw-r--r--tests/py/ip6/masquerade.t30
-rw-r--r--tests/py/ip6/masquerade.t.json423
-rw-r--r--tests/py/ip6/masquerade.t.json.output98
-rw-r--r--tests/py/ip6/masquerade.t.payload.ip6142
-rw-r--r--tests/py/ip6/meta.t19
-rw-r--r--tests/py/ip6/meta.t.json313
-rw-r--r--tests/py/ip6/meta.t.json.output64
-rw-r--r--tests/py/ip6/meta.t.payload82
-rw-r--r--tests/py/ip6/mh.t42
-rw-r--r--tests/py/ip6/mh.t.json640
-rw-r--r--tests/py/ip6/mh.t.json.output88
-rw-r--r--tests/py/ip6/mh.t.payload.inet267
-rw-r--r--tests/py/ip6/mh.t.payload.ip6201
-rw-r--r--tests/py/ip6/redirect.t49
-rw-r--r--tests/py/ip6/redirect.t.json589
-rw-r--r--tests/py/ip6/redirect.t.json.output146
-rw-r--r--tests/py/ip6/redirect.t.payload.ip6204
-rw-r--r--tests/py/ip6/reject.t16
-rw-r--r--tests/py/ip6/reject.t.json95
-rw-r--r--tests/py/ip6/reject.t.json.output28
-rw-r--r--tests/py/ip6/reject.t.payload.ip640
-rw-r--r--tests/py/ip6/rt.t38
-rw-r--r--tests/py/ip6/rt.t.json576
-rw-r--r--tests/py/ip6/rt.t.json.output88
-rw-r--r--tests/py/ip6/rt.t.payload.inet244
-rw-r--r--tests/py/ip6/rt.t.payload.ip6184
-rw-r--r--tests/py/ip6/rt0.t6
-rw-r--r--tests/py/ip6/rt0.t.json16
-rw-r--r--tests/py/ip6/rt0.t.payload5
-rw-r--r--tests/py/ip6/sets.t48
-rw-r--r--tests/py/ip6/sets.t.json150
-rw-r--r--tests/py/ip6/sets.t.json.got31
-rw-r--r--tests/py/ip6/sets.t.json.payload.got107
-rw-r--r--tests/py/ip6/sets.t.payload0
-rw-r--r--tests/py/ip6/sets.t.payload.inet49
-rw-r--r--tests/py/ip6/sets.t.payload.inet.got9
-rw-r--r--tests/py/ip6/sets.t.payload.ip638
-rw-r--r--tests/py/ip6/sets.t.payload.ip6.got7
-rw-r--r--tests/py/ip6/sets.t.payload.netdev50
-rw-r--r--tests/py/ip6/sets.t.payload.netdev.got9
-rw-r--r--tests/py/ip6/snat.t6
-rw-r--r--tests/py/ip6/snat.t.json54
-rw-r--r--tests/py/ip6/snat.t.payload.ip625
-rw-r--r--tests/py/ip6/srh.t22
-rw-r--r--tests/py/ip6/srh.t.json194
-rw-r--r--tests/py/ip6/srh.t.json.output22
-rw-r--r--tests/py/ip6/srh.t.payload64
-rw-r--r--tests/py/ip6/tproxy.t14
-rw-r--r--tests/py/ip6/tproxy.t.json125
-rw-r--r--tests/py/ip6/tproxy.t.json.output60
-rw-r--r--tests/py/ip6/tproxy.t.payload44
-rw-r--r--tests/py/ip6/vmap.t58
-rw-r--r--tests/py/ip6/vmap.t.json1037
-rw-r--r--tests/py/ip6/vmap.t.json.output336
-rw-r--r--tests/py/ip6/vmap.t.payload.inet420
-rw-r--r--tests/py/ip6/vmap.t.payload.ip6336
-rw-r--r--tests/py/ip6/vmap.t.payload.netdev420
-rw-r--r--tests/py/log1004
-rw-r--r--tests/py/netdev/dup.t8
-rw-r--r--tests/py/netdev/dup.t.json30
-rw-r--r--tests/py/netdev/dup.t.payload14
-rw-r--r--tests/py/netdev/fwd.t9
-rw-r--r--tests/py/netdev/fwd.t.json47
-rw-r--r--tests/py/netdev/fwd.t.json.output27
-rw-r--r--tests/py/netdev/fwd.t.payload20
-rw-r--r--tests/py/netdev/reject.t40
-rw-r--r--tests/py/netdev/reject.t.json293
-rw-r--r--tests/py/netdev/reject.t.payload142
-rwxr-xr-xtests/py/nft-test.py1586
-rwxr-xr-xtests/py/tools/test-sanitizer.sh78
-rw-r--r--tests/py/y14
-rw-r--r--tests/shell/README35
-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
-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/inet_ingress.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/netdev_chain_without_device.nft7
-rw-r--r--tests/shell/features/netdev_egress.nft7
-rw-r--r--tests/shell/features/osf.nft7
-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/set_with_two_expressions.nft9
-rw-r--r--tests/shell/features/table_flag_owner.nft5
-rwxr-xr-xtests/shell/helpers/nft-valgrind-wrapper.sh31
-rwxr-xr-xtests/shell/helpers/random-source.sh40
-rwxr-xr-xtests/shell/helpers/test-wrapper.sh223
-rw-r--r--tests/shell/log41
-rw-r--r--tests/shell/log-0393
-rw-r--r--tests/shell/log-1395
-rw-r--r--tests/shell/log-10393
-rw-r--r--tests/shell/log-11394
-rw-r--r--tests/shell/log-12394
-rw-r--r--tests/shell/log-13393
-rw-r--r--tests/shell/log-14393
-rw-r--r--tests/shell/log-15393
-rw-r--r--tests/shell/log-16395
-rw-r--r--tests/shell/log-17396
-rw-r--r--tests/shell/log-18394
-rw-r--r--tests/shell/log-19395
-rw-r--r--tests/shell/log-2393
-rw-r--r--tests/shell/log-3393
-rw-r--r--tests/shell/log-4394
-rw-r--r--tests/shell/log-5393
-rw-r--r--tests/shell/log-6393
-rw-r--r--tests/shell/log-7393
-rw-r--r--tests/shell/log-8397
-rw-r--r--tests/shell/log-9393
-rw-r--r--tests/shell/overlap-interval.txt430
-rw-r--r--tests/shell/run-tests-kmemleak.sh19
-rwxr-xr-xtests/shell/run-tests.sh945
-rw-r--r--tests/shell/stable-log/log-4.14750
-rw-r--r--tests/shell/stable-log/log-4.19750
-rw-r--r--tests/shell/stable-log/log-5.10754
-rw-r--r--tests/shell/stable-log/log-5.15751
-rw-r--r--tests/shell/stable-log/log-5.4751
-rw-r--r--tests/shell/stable-log/log-6.1751
-rw-r--r--tests/shell/test-list.txt367
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_013
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_113
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_213
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_313
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_413
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_513
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_613
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_713
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_813
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_913
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_2.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_3.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_4.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_5.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_6.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_7.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_8.nft6
-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.nft0
-rw-r--r--tests/shell/testcases/bogons/nft-f/include-device1
-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/scope_underflow_assert6
-rw-r--r--tests/shell/testcases/bogons/nft-f/zero_length_devicename_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/zero_length_devicename_flowtable_assert5
-rwxr-xr-xtests/shell/testcases/cache/0001_cache_handling_026
-rwxr-xr-xtests/shell/testcases/cache/0002_interval_018
-rwxr-xr-xtests/shell/testcases/cache/0003_cache_update_050
-rwxr-xr-xtests/shell/testcases/cache/0004_cache_update_015
-rwxr-xr-xtests/shell/testcases/cache/0005_cache_chain_flush16
-rwxr-xr-xtests/shell/testcases/cache/0006_cache_table_flush16
-rwxr-xr-xtests/shell/testcases/cache/0007_echo_cache_init_014
-rwxr-xr-xtests/shell/testcases/cache/0008_delete_by_handle_025
-rwxr-xr-xtests/shell/testcases/cache/0009_delete_by_handle_incorrect_08
-rwxr-xr-xtests/shell/testcases/cache/0010_implicit_chain_021
-rwxr-xr-xtests/shell/testcases/cache/0011_index_012
-rw-r--r--tests/shell/testcases/cache/dumps/0001_cache_handling_0.nft12
-rw-r--r--tests/shell/testcases/cache/dumps/0002_interval_0.nft7
-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.nft5
-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.nft14
-rw-r--r--tests/shell/testcases/cache/dumps/0007_echo_cache_init_0.nft7
-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.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.nft8
-rwxr-xr-xtests/shell/testcases/chains/0001jumps_017
-rwxr-xr-xtests/shell/testcases/chains/0002jumps_126
-rwxr-xr-xtests/shell/testcases/chains/0003jump_loop_122
-rwxr-xr-xtests/shell/testcases/chains/0004busy_113
-rwxr-xr-xtests/shell/testcases/chains/0005busy_map_113
-rwxr-xr-xtests/shell/testcases/chains/0006masquerade_07
-rwxr-xr-xtests/shell/testcases/chains/0007masquerade_111
-rwxr-xr-xtests/shell/testcases/chains/0008masquerade_jump_113
-rwxr-xr-xtests/shell/testcases/chains/0009masquerade_jump_113
-rwxr-xr-xtests/shell/testcases/chains/0010endless_jump_loop_111
-rwxr-xr-xtests/shell/testcases/chains/0011endless_jump_loop_115
-rwxr-xr-xtests/shell/testcases/chains/0013rename_08
-rwxr-xr-xtests/shell/testcases/chains/0014rename_019
-rwxr-xr-xtests/shell/testcases/chains/0015check_jump_loop_113
-rwxr-xr-xtests/shell/testcases/chains/0016delete_handle_017
-rwxr-xr-xtests/shell/testcases/chains/0017masquerade_jump_114
-rwxr-xr-xtests/shell/testcases/chains/0018check_jump_loop_113
-rwxr-xr-xtests/shell/testcases/chains/0019masquerade_jump_113
-rwxr-xr-xtests/shell/testcases/chains/0020depth_123
-rwxr-xr-xtests/shell/testcases/chains/0021prio_090
-rwxr-xr-xtests/shell/testcases/chains/0022prio_dummy_19
-rwxr-xr-xtests/shell/testcases/chains/0023prio_inet_srcnat_116
-rwxr-xr-xtests/shell/testcases/chains/0024prio_inet_dstnat_116
-rwxr-xr-xtests/shell/testcases/chains/0025prio_arp_117
-rwxr-xr-xtests/shell/testcases/chains/0026prio_netdev_117
-rwxr-xr-xtests/shell/testcases/chains/0027prio_bridge_dstnat_115
-rwxr-xr-xtests/shell/testcases/chains/0028prio_bridge_out_115
-rwxr-xr-xtests/shell/testcases/chains/0029prio_bridge_srcnat_115
-rwxr-xr-xtests/shell/testcases/chains/0030create_06
-rwxr-xr-xtests/shell/testcases/chains/0031priority_variable_017
-rwxr-xr-xtests/shell/testcases/chains/0032priority_variable_027
-rwxr-xr-xtests/shell/testcases/chains/0033priority_variable_118
-rwxr-xr-xtests/shell/testcases/chains/0034priority_variable_118
-rwxr-xr-xtests/shell/testcases/chains/0035policy_variable_017
-rwxr-xr-xtests/shell/testcases/chains/0036policy_variable_017
-rwxr-xr-xtests/shell/testcases/chains/0037policy_variable_118
-rwxr-xr-xtests/shell/testcases/chains/0038policy_variable_118
-rwxr-xr-xtests/shell/testcases/chains/0039negative_priority_08
-rwxr-xr-xtests/shell/testcases/chains/0041chain_binding_029
-rwxr-xr-xtests/shell/testcases/chains/0042chain_variable_046
-rwxr-xr-xtests/shell/testcases/chains/0043chain_ingress_019
-rwxr-xr-xtests/shell/testcases/chains/0044chain_destroy_012
-rw-r--r--tests/shell/testcases/chains/dumps/0001jumps_0.nft64
-rw-r--r--tests/shell/testcases/chains/dumps/0002jumps_1.nft68
-rw-r--r--tests/shell/testcases/chains/dumps/0003jump_loop_1.nft64
-rw-r--r--tests/shell/testcases/chains/dumps/0004busy_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0005busy_map_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0006masquerade_0.nft6
-rw-r--r--tests/shell/testcases/chains/dumps/0007masquerade_1.nft5
-rw-r--r--tests/shell/testcases/chains/dumps/0008masquerade_jump_1.nft9
-rw-r--r--tests/shell/testcases/chains/dumps/0009masquerade_jump_1.nft9
-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.nft13
-rw-r--r--tests/shell/testcases/chains/dumps/0013rename_0.nft4
-rw-r--r--tests/shell/testcases/chains/dumps/0014rename_0.nft7
-rw-r--r--tests/shell/testcases/chains/dumps/0015check_jump_loop_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0016delete_handle_0.nft14
-rw-r--r--tests/shell/testcases/chains/dumps/0017masquerade_jump_1.nft9
-rw-r--r--tests/shell/testcases/chains/dumps/0018check_jump_loop_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0019masquerade_jump_1.nft9
-rw-r--r--tests/shell/testcases/chains/dumps/0020depth_1.nft84
-rw-r--r--tests/shell/testcases/chains/dumps/0021prio_0.nft1566
-rw-r--r--tests/shell/testcases/chains/dumps/0022prio_dummy_1.nft2
-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.nft6
-rw-r--r--tests/shell/testcases/chains/dumps/0025prio_arp_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0026prio_netdev_1.nft2
-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.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0030create_0.nft4
-rw-r--r--tests/shell/testcases/chains/dumps/0031priority_variable_0.nft5
-rw-r--r--tests/shell/testcases/chains/dumps/0032priority_variable_0.nft13
-rw-r--r--tests/shell/testcases/chains/dumps/0033priority_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0034priority_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0035policy_variable_0.nft5
-rw-r--r--tests/shell/testcases/chains/dumps/0036policy_variable_0.nft5
-rw-r--r--tests/shell/testcases/chains/dumps/0037policy_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0038policy_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0039negative_priority_0.nft5
-rw-r--r--tests/shell/testcases/chains/dumps/0041chain_binding_0.nft12
-rw-r--r--tests/shell/testcases/chains/dumps/0042chain_variable_0.nft19
-rw-r--r--tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft13
-rw-r--r--tests/shell/testcases/chains/dumps/0044chain_destroy_0.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_0.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_autoremove.nft0
-rwxr-xr-xtests/shell/testcases/chains/netdev_chain_029
-rwxr-xr-xtests/shell/testcases/chains/netdev_chain_autoremove9
-rwxr-xr-xtests/shell/testcases/comments/comments_044
-rw-r--r--tests/shell/testcases/comments/dumps/comments_0.nft12
-rwxr-xr-xtests/shell/testcases/flowtable/0001flowtable_015
-rwxr-xr-xtests/shell/testcases/flowtable/0002create_flowtable_012
-rwxr-xr-xtests/shell/testcases/flowtable/0003add_after_flush_08
-rwxr-xr-xtests/shell/testcases/flowtable/0004delete_after_add_06
-rwxr-xr-xtests/shell/testcases/flowtable/0005delete_in_use_111
-rwxr-xr-xtests/shell/testcases/flowtable/0006segfault_011
-rwxr-xr-xtests/shell/testcases/flowtable/0007prio_024
-rwxr-xr-xtests/shell/testcases/flowtable/0008prio_114
-rwxr-xr-xtests/shell/testcases/flowtable/0009deleteafterflush_09
-rwxr-xr-xtests/shell/testcases/flowtable/0010delete_handle_021
-rwxr-xr-xtests/shell/testcases/flowtable/0011deleteafterflush_010
-rwxr-xr-xtests/shell/testcases/flowtable/0012flowtable_variable_035
-rwxr-xr-xtests/shell/testcases/flowtable/0013addafterdelete_027
-rwxr-xr-xtests/shell/testcases/flowtable/0014addafterdelete_036
-rwxr-xr-xtests/shell/testcases/flowtable/0015destroy_012
-rw-r--r--tests/shell/testcases/flowtable/dumps/0001flowtable_0.nft10
-rw-r--r--tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.nft6
-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.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.nft10
-rw-r--r--tests/shell/testcases/flowtable/dumps/0006segfault_0.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0007prio_0.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0008prio_1.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.nft4
-rw-r--r--tests/shell/testcases/flowtable/dumps/0010delete_handle_0.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.nft4
-rw-r--r--tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft14
-rw-r--r--tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft7
-rw-r--r--tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.nft12
-rw-r--r--tests/shell/testcases/flowtable/dumps/0015destroy_0.nft2
-rwxr-xr-xtests/shell/testcases/include/0001absolute_029
-rwxr-xr-xtests/shell/testcases/include/0002relative_029
-rwxr-xr-xtests/shell/testcases/include/0003includepath_031
-rwxr-xr-xtests/shell/testcases/include/0004endlessloop_119
-rwxr-xr-xtests/shell/testcases/include/0005glob_empty_031
-rwxr-xr-xtests/shell/testcases/include/0006glob_single_036
-rwxr-xr-xtests/shell/testcases/include/0007glob_double_033
-rwxr-xr-xtests/shell/testcases/include/0008glob_nofile_wildcard_033
-rwxr-xr-xtests/shell/testcases/include/0009glob_nofile_131
-rwxr-xr-xtests/shell/testcases/include/0010glob_broken_file_146
-rwxr-xr-xtests/shell/testcases/include/0011glob_dependency_050
-rwxr-xr-xtests/shell/testcases/include/0012glob_dependency_149
-rwxr-xr-xtests/shell/testcases/include/0013glob_dotfile_049
-rwxr-xr-xtests/shell/testcases/include/0013input_descriptors_included_files_052
-rwxr-xr-xtests/shell/testcases/include/0014glob_directory_043
-rwxr-xr-xtests/shell/testcases/include/0015doubleincludepath_052
-rwxr-xr-xtests/shell/testcases/include/0016maxdepth_08
-rwxr-xr-xtests/shell/testcases/include/0017glob_more_than_maxdepth_139
-rwxr-xr-xtests/shell/testcases/include/0018include_error_034
-rwxr-xr-xtests/shell/testcases/include/0019include_error_063
-rwxr-xr-xtests/shell/testcases/include/0020include_chain_023
-rw-r--r--tests/shell/testcases/include/dumps/0001absolute_0.nft2
-rw-r--r--tests/shell/testcases/include/dumps/0002relative_0.nft2
-rw-r--r--tests/shell/testcases/include/dumps/0003includepath_0.nft2
-rw-r--r--tests/shell/testcases/include/dumps/0004endlessloop_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0005glob_empty_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0006glob_single_0.nft2
-rw-r--r--tests/shell/testcases/include/dumps/0007glob_double_0.nft4
-rw-r--r--tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0009glob_nofile_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0010glob_broken_file_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0011glob_dependency_0.nft4
-rw-r--r--tests/shell/testcases/include/dumps/0012glob_dependency_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0013glob_dotfile_0.nft2
-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.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0015doubleincludepath_0.nft4
-rw-r--r--tests/shell/testcases/include/dumps/0016maxdepth_0.nft0
-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.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0019include_error_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0020include_chain_0.nft6
-rwxr-xr-xtests/shell/testcases/json/0001set_statements_011
-rwxr-xr-xtests/shell/testcases/json/0002table_map_011
-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_011
-rwxr-xr-xtests/shell/testcases/json/0006obj_comment_011
-rw-r--r--tests/shell/testcases/json/dumps/0001set_statements_0.nft12
-rw-r--r--tests/shell/testcases/json/dumps/0002table_map_0.nft6
-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.nft0
-rw-r--r--tests/shell/testcases/json/dumps/0005secmark_objref_0.nft18
-rw-r--r--tests/shell/testcases/json/dumps/0006obj_comment_0.nft6
-rw-r--r--tests/shell/testcases/json/dumps/netdev.nft2
-rwxr-xr-xtests/shell/testcases/json/netdev28
-rwxr-xr-xtests/shell/testcases/listing/0001ruleset_07
-rwxr-xr-xtests/shell/testcases/listing/0002ruleset_07
-rwxr-xr-xtests/shell/testcases/listing/0003table_023
-rwxr-xr-xtests/shell/testcases/listing/0004table_018
-rwxr-xr-xtests/shell/testcases/listing/0005ruleset_ip_020
-rwxr-xr-xtests/shell/testcases/listing/0006ruleset_ip6_020
-rwxr-xr-xtests/shell/testcases/listing/0007ruleset_inet_020
-rwxr-xr-xtests/shell/testcases/listing/0008ruleset_arp_020
-rwxr-xr-xtests/shell/testcases/listing/0009ruleset_bridge_020
-rwxr-xr-xtests/shell/testcases/listing/0010sets_062
-rwxr-xr-xtests/shell/testcases/listing/0011sets_043
-rwxr-xr-xtests/shell/testcases/listing/0012sets_038
-rwxr-xr-xtests/shell/testcases/listing/0013objects_023
-rwxr-xr-xtests/shell/testcases/listing/0014objects_029
-rwxr-xr-xtests/shell/testcases/listing/0015dynamic_023
-rwxr-xr-xtests/shell/testcases/listing/0016anonymous_033
-rwxr-xr-xtests/shell/testcases/listing/0017objects_018
-rwxr-xr-xtests/shell/testcases/listing/0018data_018
-rwxr-xr-xtests/shell/testcases/listing/0019set_018
-rwxr-xr-xtests/shell/testcases/listing/0020flowtable_063
-rwxr-xr-xtests/shell/testcases/listing/0021ruleset_json_terse_019
-rwxr-xr-xtests/shell/testcases/listing/0022terse_069
-rw-r--r--tests/shell/testcases/listing/dumps/0001ruleset_0.nft2
-rw-r--r--tests/shell/testcases/listing/dumps/0002ruleset_0.nft0
-rw-r--r--tests/shell/testcases/listing/dumps/0003table_0.nft2
-rw-r--r--tests/shell/testcases/listing/dumps/0004table_0.nft4
-rw-r--r--tests/shell/testcases/listing/dumps/0005ruleset_ip_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0007ruleset_inet_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0008ruleset_arp_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0010sets_0.nft39
-rw-r--r--tests/shell/testcases/listing/dumps/0011sets_0.nft25
-rw-r--r--tests/shell/testcases/listing/dumps/0012sets_0.nft39
-rw-r--r--tests/shell/testcases/listing/dumps/0013objects_0.nft27
-rw-r--r--tests/shell/testcases/listing/dumps/0014objects_0.nft12
-rw-r--r--tests/shell/testcases/listing/dumps/0015dynamic_0.nft7
-rw-r--r--tests/shell/testcases/listing/dumps/0016anonymous_0.nft6
-rw-r--r--tests/shell/testcases/listing/dumps/0017objects_0.nft5
-rw-r--r--tests/shell/testcases/listing/dumps/0018data_0.nft5
-rw-r--r--tests/shell/testcases/listing/dumps/0019set_0.nft5
-rw-r--r--tests/shell/testcases/listing/dumps/0020flowtable_0.nft20
-rw-r--r--tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.nft9
-rw-r--r--tests/shell/testcases/listing/dumps/0022terse_0.nft12
-rwxr-xr-xtests/shell/testcases/maps/0003map_add_many_elements_067
-rwxr-xr-xtests/shell/testcases/maps/0004interval_map_create_once_074
-rwxr-xr-xtests/shell/testcases/maps/0005interval_map_add_many_elements_058
-rwxr-xr-xtests/shell/testcases/maps/0006interval_map_overlap_016
-rwxr-xr-xtests/shell/testcases/maps/0007named_ifname_dtype_018
-rwxr-xr-xtests/shell/testcases/maps/0008interval_map_delete_031
-rwxr-xr-xtests/shell/testcases/maps/0009vmap_019
-rwxr-xr-xtests/shell/testcases/maps/0010concat_map_019
-rwxr-xr-xtests/shell/testcases/maps/0011vmap_033
-rwxr-xr-xtests/shell/testcases/maps/0012map_036
-rwxr-xr-xtests/shell/testcases/maps/0013map_014
-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/anon_objmap_concat6
-rwxr-xr-xtests/shell/testcases/maps/anonymous_snat_map_08
-rwxr-xr-xtests/shell/testcases/maps/different_map_types_113
-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.nft8
-rw-r--r--tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.nft7
-rw-r--r--tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.nft11
-rw-r--r--tests/shell/testcases/maps/dumps/0008interval_map_delete_0.nft15
-rw-r--r--tests/shell/testcases/maps/dumps/0009vmap_0.nft13
-rw-r--r--tests/shell/testcases/maps/dumps/0010concat_map_0.nft11
-rw-r--r--tests/shell/testcases/maps/dumps/0011vmap_0.nft19
-rw-r--r--tests/shell/testcases/maps/dumps/0012map_0.nft25
-rw-r--r--tests/shell/testcases/maps/dumps/0013map_0.nft13
-rw-r--r--tests/shell/testcases/maps/dumps/0014destroy_0.nft2
-rw-r--r--tests/shell/testcases/maps/dumps/0016map_leak_0.nft0
-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.nft0
-rw-r--r--tests/shell/testcases/maps/dumps/anon_objmap_concat.nft16
-rw-r--r--tests/shell/testcases/maps/dumps/anonymous_snat_map_0.nft5
-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.nft4
-rw-r--r--tests/shell/testcases/maps/dumps/map_with_flags_0.nft6
-rw-r--r--tests/shell/testcases/maps/dumps/named_snat_map_0.nft10
-rw-r--r--tests/shell/testcases/maps/dumps/nat_addr_port.nft129
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_integer_0.nft20
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_0.nft36
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_add_delete.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.nft21
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_raw_0.nft13
-rw-r--r--tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.nft26
-rw-r--r--tests/shell/testcases/maps/dumps/vmap_timeout.nft36
-rwxr-xr-xtests/shell/testcases/maps/map_catchall_double_deactivate13
-rwxr-xr-xtests/shell/testcases/maps/map_with_flags_06
-rwxr-xr-xtests/shell/testcases/maps/named_snat_map_010
-rwxr-xr-xtests/shell/testcases/maps/nat_addr_port207
-rwxr-xr-xtests/shell/testcases/maps/typeof_integer_027
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_0101
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_add_delete54
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_concat6
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_concat_update_019
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_update_028
-rwxr-xr-xtests/shell/testcases/maps/typeof_raw_018
-rwxr-xr-xtests/shell/testcases/maps/vmap_mark_bitwise_038
-rwxr-xr-xtests/shell/testcases/maps/vmap_timeout53
-rwxr-xr-xtests/shell/testcases/netns/0001nft-f_099
-rwxr-xr-xtests/shell/testcases/netns/0002loosecommands_061
-rwxr-xr-xtests/shell/testcases/netns/0003many_0113
-rw-r--r--tests/shell/testcases/netns/dumps/0001nft-f_0.nft0
-rw-r--r--tests/shell/testcases/netns/dumps/0002loosecommands_0.nft0
-rw-r--r--tests/shell/testcases/netns/dumps/0003many_0.nft0
-rwxr-xr-xtests/shell/testcases/nft-f/0001define_slash_011
-rwxr-xr-xtests/shell/testcases/nft-f/0002rollback_rule_040
-rwxr-xr-xtests/shell/testcases/nft-f/0003rollback_jump_040
-rwxr-xr-xtests/shell/testcases/nft-f/0004rollback_set_040
-rwxr-xr-xtests/shell/testcases/nft-f/0005rollback_map_043
-rwxr-xr-xtests/shell/testcases/nft-f/0006action_object_059
-rwxr-xr-xtests/shell/testcases/nft-f/0007action_object_set_segfault_114
-rwxr-xr-xtests/shell/testcases/nft-f/0008split_tables_022
-rwxr-xr-xtests/shell/testcases/nft-f/0009variable_014
-rwxr-xr-xtests/shell/testcases/nft-f/0010variable_013
-rwxr-xr-xtests/shell/testcases/nft-f/0011manydefines_053
-rwxr-xr-xtests/shell/testcases/nft-f/0012different_defines_043
-rwxr-xr-xtests/shell/testcases/nft-f/0013defines_118
-rwxr-xr-xtests/shell/testcases/nft-f/0014defines_118
-rwxr-xr-xtests/shell/testcases/nft-f/0015defines_117
-rwxr-xr-xtests/shell/testcases/nft-f/0016redefines_133
-rwxr-xr-xtests/shell/testcases/nft-f/0017ct_timeout_obj_018
-rwxr-xr-xtests/shell/testcases/nft-f/0018ct_expectation_obj_018
-rwxr-xr-xtests/shell/testcases/nft-f/0018jump_variable_019
-rwxr-xr-xtests/shell/testcases/nft-f/0019jump_variable_120
-rwxr-xr-xtests/shell/testcases/nft-f/0020jump_variable_120
-rwxr-xr-xtests/shell/testcases/nft-f/0021list_ruleset_015
-rwxr-xr-xtests/shell/testcases/nft-f/0022variables_021
-rwxr-xr-xtests/shell/testcases/nft-f/0023check_112
-rwxr-xr-xtests/shell/testcases/nft-f/0024priority_014
-rwxr-xr-xtests/shell/testcases/nft-f/0025empty_dynset_030
-rwxr-xr-xtests/shell/testcases/nft-f/0026listing_014
-rwxr-xr-xtests/shell/testcases/nft-f/0027split_chains_017
-rwxr-xr-xtests/shell/testcases/nft-f/0028variable_cmdline_017
-rwxr-xr-xtests/shell/testcases/nft-f/0029split_file_025
-rwxr-xr-xtests/shell/testcases/nft-f/0030variable_reuse_019
-rwxr-xr-xtests/shell/testcases/nft-f/0031vmap_string_021
-rwxr-xr-xtests/shell/testcases/nft-f/0032pknock_034
-rw-r--r--tests/shell/testcases/nft-f/dumps/0001define_slash_0.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0002rollback_rule_0.nft16
-rw-r--r--tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.nft16
-rw-r--r--tests/shell/testcases/nft-f/dumps/0004rollback_set_0.nft16
-rw-r--r--tests/shell/testcases/nft-f/dumps/0005rollback_map_0.nft16
-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.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0008split_tables_0.nft10
-rw-r--r--tests/shell/testcases/nft-f/dumps/0009variable_0.nft7
-rw-r--r--tests/shell/testcases/nft-f/dumps/0010variable_0.nft6
-rw-r--r--tests/shell/testcases/nft-f/dumps/0011manydefines_0.nodump0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft21
-rw-r--r--tests/shell/testcases/nft-f/dumps/0013defines_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0014defines_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0015defines_1.nft0
-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.nft11
-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.nft8
-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.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0021list_ruleset_0.nft5
-rw-r--r--tests/shell/testcases/nft-f/dumps/0022variables_0.nft14
-rw-r--r--tests/shell/testcases/nft-f/dumps/0023check_1.nft5
-rw-r--r--tests/shell/testcases/nft-f/dumps/0024priority_0.nft10
-rw-r--r--tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft18
-rw-r--r--tests/shell/testcases/nft-f/dumps/0026listing_0.nft5
-rw-r--r--tests/shell/testcases/nft-f/dumps/0027split_chains_0.nft9
-rw-r--r--tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft8
-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.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.nft25
-rw-r--r--tests/shell/testcases/nft-f/dumps/sample-ruleset.nft239
-rwxr-xr-xtests/shell/testcases/nft-f/sample-ruleset262
-rwxr-xr-xtests/shell/testcases/nft-i/0001define_022
-rw-r--r--tests/shell/testcases/nft-i/dumps/0001define_0.nft0
-rwxr-xr-xtests/shell/testcases/optimizations/dependency_kill48
-rw-r--r--tests/shell/testcases/optimizations/dumps/dependency_kill.nft42
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat.nft40
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_reject.nft13
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts.nft5
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft18
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft9
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft13
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft31
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmaps.nft20
-rw-r--r--tests/shell/testcases/optimizations/dumps/not_mergeable.nft19
-rw-r--r--tests/shell/testcases/optimizations/dumps/ruleset.nft0
-rw-r--r--tests/shell/testcases/optimizations/dumps/single_anon_set.nft16
-rw-r--r--tests/shell/testcases/optimizations/dumps/single_anon_set.nft.input38
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_merge.nft23
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_non_eq.nft6
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_unsupported.nft18
-rw-r--r--tests/shell/testcases/optimizations/dumps/variables.nft0
-rwxr-xr-xtests/shell/testcases/optimizations/merge_nat67
-rwxr-xr-xtests/shell/testcases/optimizations/merge_reject26
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts13
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_concat35
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_concat_vmap17
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_vmap21
-rwxr-xr-xtests/shell/testcases/optimizations/merge_vmap_raw32
-rwxr-xr-xtests/shell/testcases/optimizations/merge_vmaps31
-rwxr-xr-xtests/shell/testcases/optimizations/not_mergeable22
-rwxr-xr-xtests/shell/testcases/optimizations/ruleset168
-rwxr-xr-xtests/shell/testcases/optimizations/single_anon_set13
-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_08
-rwxr-xr-xtests/shell/testcases/optionals/comments_chain_012
-rwxr-xr-xtests/shell/testcases/optionals/comments_handles_010
-rwxr-xr-xtests/shell/testcases/optionals/comments_objects_044
-rwxr-xr-xtests/shell/testcases/optionals/comments_objects_dup_097
-rwxr-xr-xtests/shell/testcases/optionals/comments_table_05
-rwxr-xr-xtests/shell/testcases/optionals/delete_object_handles_042
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_0.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_chain_0.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_handles_0.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_objects_0.nft37
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft0
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_table_0.nft3
-rw-r--r--tests/shell/testcases/optionals/dumps/delete_object_handles_0.nft18
-rw-r--r--tests/shell/testcases/optionals/dumps/handles_0.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/handles_1.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/log_prefix_0.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/update_object_handles_0.nft9
-rwxr-xr-xtests/shell/testcases/optionals/handles_08
-rwxr-xr-xtests/shell/testcases/optionals/handles_110
-rwxr-xr-xtests/shell/testcases/optionals/log_prefix_016
-rwxr-xr-xtests/shell/testcases/optionals/update_object_handles_024
-rwxr-xr-xtests/shell/testcases/owner/0001-flowtable-uaf26
-rw-r--r--tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft0
-rw-r--r--tests/shell/testcases/packetpath/dumps/vlan_8021ad_tag.nodump0
-rwxr-xr-xtests/shell/testcases/packetpath/vlan_8021ad_tag50
-rwxr-xr-xtests/shell/testcases/parsing/describe7
-rw-r--r--tests/shell/testcases/parsing/dumps/describe.nft0
-rw-r--r--tests/shell/testcases/parsing/dumps/large_rule_pipe.nft561
-rw-r--r--tests/shell/testcases/parsing/dumps/log.nft0
-rw-r--r--tests/shell/testcases/parsing/dumps/octal.nft0
-rwxr-xr-xtests/shell/testcases/parsing/large_rule_pipe571
-rwxr-xr-xtests/shell/testcases/parsing/log10
-rwxr-xr-xtests/shell/testcases/parsing/octal13
-rwxr-xr-xtests/shell/testcases/rule_management/0001addinsertposition_085
-rwxr-xr-xtests/shell/testcases/rule_management/0002addinsertlocation_123
-rwxr-xr-xtests/shell/testcases/rule_management/0003insert_015
-rwxr-xr-xtests/shell/testcases/rule_management/0004replace_010
-rwxr-xr-xtests/shell/testcases/rule_management/0005replace_113
-rwxr-xr-xtests/shell/testcases/rule_management/0006replace_113
-rwxr-xr-xtests/shell/testcases/rule_management/0007delete_011
-rwxr-xr-xtests/shell/testcases/rule_management/0008delete_113
-rwxr-xr-xtests/shell/testcases/rule_management/0009delete_113
-rwxr-xr-xtests/shell/testcases/rule_management/0010replace_012
-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.nft7
-rw-r--r--tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.nft6
-rw-r--r--tests/shell/testcases/rule_management/dumps/0003insert_0.nft8
-rw-r--r--tests/shell/testcases/rule_management/dumps/0004replace_0.nft5
-rw-r--r--tests/shell/testcases/rule_management/dumps/0005replace_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0006replace_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0007delete_0.nft5
-rw-r--r--tests/shell/testcases/rule_management/dumps/0008delete_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0009delete_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0010replace_0.nft0
-rw-r--r--tests/shell/testcases/rule_management/dumps/0011reset_0.nft31
-rw-r--r--tests/shell/testcases/rule_management/dumps/0012destroy_0.nft4
-rwxr-xr-xtests/shell/testcases/sets/0001named_interval_039
-rwxr-xr-xtests/shell/testcases/sets/0002named_interval_automerging_012
-rwxr-xr-xtests/shell/testcases/sets/0003named_interval_missing_flag_012
-rwxr-xr-xtests/shell/testcases/sets/0004named_interval_shadow_013
-rwxr-xr-xtests/shell/testcases/sets/0005named_interval_shadow_013
-rwxr-xr-xtests/shell/testcases/sets/0006create_set_014
-rwxr-xr-xtests/shell/testcases/sets/0007create_element_015
-rwxr-xr-xtests/shell/testcases/sets/0008comments_interval_012
-rwxr-xr-xtests/shell/testcases/sets/0008create_verdict_map_017
-rwxr-xr-xtests/shell/testcases/sets/0009comments_timeout_012
-rwxr-xr-xtests/shell/testcases/sets/0010comments_011
-rwxr-xr-xtests/shell/testcases/sets/0011add_many_elements_047
-rwxr-xr-xtests/shell/testcases/sets/0012add_delete_many_elements_047
-rwxr-xr-xtests/shell/testcases/sets/0013add_delete_many_elements_048
-rwxr-xr-xtests/shell/testcases/sets/0014malformed_set_is_not_defined_025
-rwxr-xr-xtests/shell/testcases/sets/0015rulesetflush_018
-rwxr-xr-xtests/shell/testcases/sets/0016element_leak_011
-rwxr-xr-xtests/shell/testcases/sets/0017add_after_flush_012
-rwxr-xr-xtests/shell/testcases/sets/0018set_check_size_111
-rwxr-xr-xtests/shell/testcases/sets/0019set_check_size_020
-rwxr-xr-xtests/shell/testcases/sets/0020comments_012
-rwxr-xr-xtests/shell/testcases/sets/0021nesting_024
-rwxr-xr-xtests/shell/testcases/sets/0022type_selective_flush_032
-rwxr-xr-xtests/shell/testcases/sets/0023incomplete_add_set_command_016
-rwxr-xr-xtests/shell/testcases/sets/0024named_objects_063
-rwxr-xr-xtests/shell/testcases/sets/0025anonymous_set_017
-rwxr-xr-xtests/shell/testcases/sets/0026named_limit_019
-rwxr-xr-xtests/shell/testcases/sets/0027ipv6_maps_ipv4_017
-rwxr-xr-xtests/shell/testcases/sets/0028autoselect_017
-rwxr-xr-xtests/shell/testcases/sets/0028delete_handle_034
-rwxr-xr-xtests/shell/testcases/sets/0029named_ifname_dtype_065
-rwxr-xr-xtests/shell/testcases/sets/0030add_many_elements_interval_044
-rwxr-xr-xtests/shell/testcases/sets/0031set_timeout_size_012
-rwxr-xr-xtests/shell/testcases/sets/0032restore_set_simple_06
-rwxr-xr-xtests/shell/testcases/sets/0033add_set_simple_flat_09
-rwxr-xr-xtests/shell/testcases/sets/0034get_element_070
-rwxr-xr-xtests/shell/testcases/sets/0035add_set_elements_flat_010
-rwxr-xr-xtests/shell/testcases/sets/0036add_set_element_expiration_024
-rwxr-xr-xtests/shell/testcases/sets/0037_set_with_inet_service_06
-rwxr-xr-xtests/shell/testcases/sets/0038meter_list_029
-rwxr-xr-xtests/shell/testcases/sets/0039delete_interval_017
-rwxr-xr-xtests/shell/testcases/sets/0040get_host_endian_elements_043
-rwxr-xr-xtests/shell/testcases/sets/0041interval_025
-rwxr-xr-xtests/shell/testcases/sets/0042update_set_021
-rwxr-xr-xtests/shell/testcases/sets/0043concatenated_ranges_0194
-rwxr-xr-xtests/shell/testcases/sets/0043concatenated_ranges_123
-rwxr-xr-xtests/shell/testcases/sets/0044interval_overlap_0166
-rwxr-xr-xtests/shell/testcases/sets/0044interval_overlap_138
-rwxr-xr-xtests/shell/testcases/sets/0045concat_ipv4_service16
-rwxr-xr-xtests/shell/testcases/sets/0046netmap_020
-rwxr-xr-xtests/shell/testcases/sets/0047nat_040
-rwxr-xr-xtests/shell/testcases/sets/0048set_counters_018
-rwxr-xr-xtests/shell/testcases/sets/0049set_define_016
-rwxr-xr-xtests/shell/testcases/sets/0050set_define_117
-rwxr-xr-xtests/shell/testcases/sets/0051set_interval_counter_019
-rwxr-xr-xtests/shell/testcases/sets/0052overlap_016
-rwxr-xr-xtests/shell/testcases/sets/0053echo_016
-rwxr-xr-xtests/shell/testcases/sets/0054comments_set_09
-rwxr-xr-xtests/shell/testcases/sets/0055tcpflags_027
-rwxr-xr-xtests/shell/testcases/sets/0056dynamic_limit_019
-rwxr-xr-xtests/shell/testcases/sets/0057set_create_fails_018
-rwxr-xr-xtests/shell/testcases/sets/0058_setupdate_timeout_017
-rwxr-xr-xtests/shell/testcases/sets/0059set_update_multistmt_019
-rwxr-xr-xtests/shell/testcases/sets/0060set_multistmt_052
-rwxr-xr-xtests/shell/testcases/sets/0060set_multistmt_140
-rwxr-xr-xtests/shell/testcases/sets/0061anonymous_automerge_011
-rwxr-xr-xtests/shell/testcases/sets/0062set_connlimit_026
-rwxr-xr-xtests/shell/testcases/sets/0063set_catchall_023
-rwxr-xr-xtests/shell/testcases/sets/0064map_catchall_026
-rwxr-xr-xtests/shell/testcases/sets/0065_icmp_postprocessing13
-rwxr-xr-xtests/shell/testcases/sets/0067nat_concat_interval_071
-rwxr-xr-xtests/shell/testcases/sets/0068interval_stack_overflow_045
-rwxr-xr-xtests/shell/testcases/sets/0069interval_merge_028
-rwxr-xr-xtests/shell/testcases/sets/0070stacked_l2_headers6
-rwxr-xr-xtests/shell/testcases/sets/0071unclosed_prefix_interval_023
-rwxr-xr-xtests/shell/testcases/sets/0072destroy_012
-rwxr-xr-xtests/shell/testcases/sets/0073flat_interval_set11
-rwxr-xr-xtests/shell/testcases/sets/0074nested_interval_set6
-rwxr-xr-xtests/shell/testcases/sets/automerge_0131
-rwxr-xr-xtests/shell/testcases/sets/collapse_elem_019
-rwxr-xr-xtests/shell/testcases/sets/concat_interval_024
-rw-r--r--tests/shell/testcases/sets/dumps/0001named_interval_0.nft34
-rw-r--r--tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.nft5
-rw-r--r--tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0006create_set_0.nft5
-rw-r--r--tests/shell/testcases/sets/dumps/0007create_element_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0008comments_interval_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0008create_verdict_map_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0009comments_timeout_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0010comments_0.nft6
-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.nft5
-rw-r--r--tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.nft5
-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.nft11
-rw-r--r--tests/shell/testcases/sets/dumps/0016element_leak_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0017add_after_flush_0.nft7
-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.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0020comments_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0021nesting_0.nft5
-rw-r--r--tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.nft2
-rw-r--r--tests/shell/testcases/sets/dumps/0024named_objects_0.nft50
-rw-r--r--tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0026named_limit_0.nft10
-rw-r--r--tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0028autoselect_0.nft26
-rw-r--r--tests/shell/testcases/sets/dumps/0028delete_handle_0.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft57
-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.nft11
-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.nft23
-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.nft16
-rw-r--r--tests/shell/testcases/sets/dumps/0038meter_list_0.nft11
-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.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0041interval_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0042update_set_0.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.nft11
-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.nft106
-rw-r--r--tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/0046netmap_0.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/0047nat_0.nft30
-rw-r--r--tests/shell/testcases/sets/dumps/0048set_counters_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0049set_define_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0050set_define_1.nft0
-rw-r--r--tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0052overlap_0.nft8
-rw-r--r--tests/shell/testcases/sets/dumps/0053echo_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0054comments_set_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0055tcpflags_0.nft10
-rw-r--r--tests/shell/testcases/sets/dumps/0056dynamic_limit_0.nft0
-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.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_1.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.nft5
-rw-r--r--tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft16
-rw-r--r--tests/shell/testcases/sets/dumps/0063set_catchall_0.nft14
-rw-r--r--tests/shell/testcases/sets/dumps/0064map_catchall_0.nft18
-rw-r--r--tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft42
-rw-r--r--tests/shell/testcases/sets/dumps/0068interval_stack_overflow_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/0069interval_merge_0.nft9
-rw-r--r--tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft28
-rw-r--r--tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft19
-rw-r--r--tests/shell/testcases/sets/dumps/0072destroy_0.nft2
-rw-r--r--tests/shell/testcases/sets/dumps/0073flat_interval_set.nft11
-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.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/concat_interval_0.nft14
-rw-r--r--tests/shell/testcases/sets/dumps/dynset_missing.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/errors_0.nft0
-rw-r--r--tests/shell/testcases/sets/dumps/exact_overlap_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/inner_0.nft18
-rw-r--r--tests/shell/testcases/sets/dumps/reset_command_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/set_eval_0.nft11
-rw-r--r--tests/shell/testcases/sets/dumps/sets_with_ifnames.nft62
-rw-r--r--tests/shell/testcases/sets/dumps/type_set_symbol.nft16
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_raw_0.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_0.nft97
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_1.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_concat.nft12
-rwxr-xr-xtests/shell/testcases/sets/dynset_missing32
-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/reset_command_093
-rwxr-xr-xtests/shell/testcases/sets/set_eval_017
-rwxr-xr-xtests/shell/testcases/sets/sets_with_ifnames150
-rwxr-xr-xtests/shell/testcases/sets/type_set_symbol6
-rwxr-xr-xtests/shell/testcases/sets/typeof_raw_017
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_0226
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_122
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_concat6
-rwxr-xr-xtests/shell/testcases/transactions/0001table_014
-rwxr-xr-xtests/shell/testcases/transactions/0002table_015
-rwxr-xr-xtests/shell/testcases/transactions/0003table_046
-rwxr-xr-xtests/shell/testcases/transactions/0010chain_015
-rwxr-xr-xtests/shell/testcases/transactions/0011chain_015
-rwxr-xr-xtests/shell/testcases/transactions/0012chain_019
-rwxr-xr-xtests/shell/testcases/transactions/0013chain_020
-rwxr-xr-xtests/shell/testcases/transactions/0014chain_110
-rwxr-xr-xtests/shell/testcases/transactions/0015chain_025
-rwxr-xr-xtests/shell/testcases/transactions/0020rule_014
-rwxr-xr-xtests/shell/testcases/transactions/0021rule_017
-rwxr-xr-xtests/shell/testcases/transactions/0022rule_111
-rwxr-xr-xtests/shell/testcases/transactions/0023rule_110
-rwxr-xr-xtests/shell/testcases/transactions/0024rule_017
-rwxr-xr-xtests/shell/testcases/transactions/0025rule_021
-rwxr-xr-xtests/shell/testcases/transactions/0030set_014
-rwxr-xr-xtests/shell/testcases/transactions/0031set_014
-rwxr-xr-xtests/shell/testcases/transactions/0032set_015
-rwxr-xr-xtests/shell/testcases/transactions/0033set_013
-rwxr-xr-xtests/shell/testcases/transactions/0034set_014
-rwxr-xr-xtests/shell/testcases/transactions/0035set_016
-rwxr-xr-xtests/shell/testcases/transactions/0036set_112
-rwxr-xr-xtests/shell/testcases/transactions/0037set_014
-rwxr-xr-xtests/shell/testcases/transactions/0038set_016
-rwxr-xr-xtests/shell/testcases/transactions/0039set_016
-rwxr-xr-xtests/shell/testcases/transactions/0040set_042
-rwxr-xr-xtests/shell/testcases/transactions/0041nat_restore_017
-rwxr-xr-xtests/shell/testcases/transactions/0042_stateful_expr_014
-rwxr-xr-xtests/shell/testcases/transactions/0043set_114
-rwxr-xr-xtests/shell/testcases/transactions/0044rule_022
-rwxr-xr-xtests/shell/testcases/transactions/0045anon-unbind_010
-rwxr-xr-xtests/shell/testcases/transactions/0046set_018
-rwxr-xr-xtests/shell/testcases/transactions/0047set_026
-rwxr-xr-xtests/shell/testcases/transactions/0048helpers_015
-rwxr-xr-xtests/shell/testcases/transactions/0049huge_067
-rwxr-xr-xtests/shell/testcases/transactions/0050rule_119
-rwxr-xr-xtests/shell/testcases/transactions/0051map_0122
-rwxr-xr-xtests/shell/testcases/transactions/30s-stress637
-rwxr-xr-xtests/shell/testcases/transactions/anon_chain_loop19
-rwxr-xr-xtests/shell/testcases/transactions/bad_expression38
-rw-r--r--tests/shell/testcases/transactions/dumps/0001table_0.nft4
-rw-r--r--tests/shell/testcases/transactions/dumps/0002table_0.nft7
-rw-r--r--tests/shell/testcases/transactions/dumps/0003table_0.nft4
-rw-r--r--tests/shell/testcases/transactions/dumps/0010chain_0.nft4
-rw-r--r--tests/shell/testcases/transactions/dumps/0011chain_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0012chain_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0013chain_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0014chain_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0015chain_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0020rule_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0021rule_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0022rule_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0023rule_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0024rule_0.nft8
-rw-r--r--tests/shell/testcases/transactions/dumps/0025rule_0.nft6
-rw-r--r--tests/shell/testcases/transactions/dumps/0030set_0.nft2
-rw-r--r--tests/shell/testcases/transactions/dumps/0031set_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0032set_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0033set_0.nft2
-rw-r--r--tests/shell/testcases/transactions/dumps/0034set_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0035set_0.nft6
-rw-r--r--tests/shell/testcases/transactions/dumps/0036set_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0037set_0.nft6
-rw-r--r--tests/shell/testcases/transactions/dumps/0038set_0.nft7
-rw-r--r--tests/shell/testcases/transactions/dumps/0039set_0.nft7
-rw-r--r--tests/shell/testcases/transactions/dumps/0040set_0.nft14
-rw-r--r--tests/shell/testcases/transactions/dumps/0041nat_restore_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0043set_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0044rule_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0045anon-unbind_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0046set_0.nft2
-rw-r--r--tests/shell/testcases/transactions/dumps/0047set_0.nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0048helpers_0.nft2
-rw-r--r--tests/shell/testcases/transactions/dumps/0049huge_0.nft749
-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.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/anon_chain_loop.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/bad_expression.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/table_onoff.nft8
-rwxr-xr-xtests/shell/testcases/transactions/table_onoff44
-rw-r--r--tests/shell/x5
1472 files changed, 279853 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..a0dd81b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,349 @@
+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.
+
+Pablo Neira Ayuso <pablo@netfilter.org>
+
+-------------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..5d45ec9
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,108 @@
+Installation instructions for nftables
+======================================
+
+ Prerequisites
+ =============
+
+ - build tooling: glibc headers, gcc, autotools, automake, libtool, pkg-config.
+
+ - libmnl: git://git.netfilter.org/libmnl.git
+
+ - libnftnl: git://git.netfilter.org/libnftnl.git
+
+ - flex
+
+ - bison
+
+ - libgmp: alternatively, see mini-gmp support below.
+
+ - libreadline or libedit or linenoise: required by interactive command line
+
+ - optional: libxtables: required to interact with iptables-compat
+
+ - optional: libjansson: required to build JSON support
+
+ - optional: asciidoc: required for building man-page
+
+ Configuring and compiling
+ =========================
+
+ Run "sh autogen.sh" to generate the configure script, then:
+
+ sh configure [options]
+
+ --prefix=
+
+ The prefix to put all installed files under. It defaults to
+ /usr/local, so the binaries will go into /usr/local/bin, sbin,
+ manpages into /usr/local/share/man, etc.
+
+ --datarootdir=
+
+ The base directory for arch-independent files. Defaults to
+ $prefix/share.
+
+ --disable-debug
+
+ Disable debugging
+
+ --with-mini-gmp
+
+ Use builtin mini-gmp instead of linking with a shared libgmp.
+ This is useful for embedded platforms optimizing for size and
+ having no other use for libgmp.
+ Note: This decreases the debugging verbosity in some files.
+
+ --with-xtables
+
+ For libxtables support to interact with the iptables-compat
+ utility.
+
+ --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.
+
+ 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
+ ===========
+
+ Netfilter's Linux kernel tree can be found at:
+
+ 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:
+
+ git://git.netfilter.org/nftables.git
diff --git a/Make_global.am b/Make_global.am
new file mode 100644
index 0000000..5bb541f
--- /dev/null
+++ b/Make_global.am
@@ -0,0 +1,21 @@
+# 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
new file mode 100644
index 0000000..84c3c36
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,14 @@
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = src \
+ include \
+ files \
+ doc \
+ examples\
+ py
+
+EXTRA_DIST = tests \
+ files
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libnftables.pc
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..a8e2fe4
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,913 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+ $(am__configure_deps) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = libnftables.pc
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgconfigdir)"
+DATA = $(pkgconfig_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ cscope distdir distdir-am dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \
+ config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(srcdir)/libnftables.pc.in $(top_srcdir)/build-aux/ar-lib \
+ $(top_srcdir)/build-aux/compile \
+ $(top_srcdir)/build-aux/config.guess \
+ $(top_srcdir)/build-aux/config.sub \
+ $(top_srcdir)/build-aux/install-sh \
+ $(top_srcdir)/build-aux/ltmain.sh \
+ $(top_srcdir)/build-aux/missing COPYING INSTALL \
+ build-aux/ar-lib build-aux/compile build-aux/config.guess \
+ build-aux/config.sub build-aux/install-sh build-aux/ltmain.sh \
+ build-aux/missing build-aux/ylwrap
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ if test -d "$(distdir)"; then \
+ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -rf "$(distdir)" \
+ || { sleep 5 && rm -rf "$(distdir)"; }; \
+ else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+GZIP_ENV = --best
+DIST_ARCHIVES = $(distdir).tar.xz
+DIST_TARGETS = dist-xz
+# Exists only to be overridden by the user if desired.
+AM_DISTCHECK_DVI_TARGET = dvi
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I m4
+SUBDIRS = src \
+ include \
+ files \
+ doc \
+ examples\
+ py
+
+EXTRA_DIST = tests \
+ files
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libnftables.pc
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+libnftables.pc: $(top_builddir)/config.status $(srcdir)/libnftables.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+ $(am__post_remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ $(am__post_remove_distdir)
+
+dist-lzip: distdir
+ tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+ $(am__post_remove_distdir)
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__post_remove_distdir)
+
+dist-zstd: distdir
+ tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst
+ $(am__post_remove_distdir)
+
+dist-tarZ: distdir
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__post_remove_distdir)
+
+dist-shar: distdir
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+ $(am__post_remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__post_remove_distdir)
+
+dist dist-all:
+ $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+ $(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lz*) \
+ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ *.tar.zst*) \
+ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\
+ esac
+ chmod -R a-w $(distdir)
+ chmod u+w $(distdir)
+ mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build/sub \
+ && ../../configure \
+ $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ --srcdir=../.. --prefix="$$dc_install_base" \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__post_remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @test -n '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: trying to run $@ with an empty' \
+ '$$(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ $(am__cd) '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA) config.h
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(pkgconfigdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-pkgconfigDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-pkgconfigDATA
+
+.MAKE: $(am__recursive_targets) all install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--refresh check check-am clean clean-cscope clean-generic \
+ clean-libtool cscope cscopelist-am ctags ctags-am dist \
+ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \
+ dist-xz dist-zip dist-zstd distcheck distclean \
+ distclean-generic distclean-hdr distclean-libtool \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkgconfigDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..c77083a
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1474 @@
+# generated automatically by aclocal 1.16.3 -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+# serial 12 (pkg-config-0.29.2)
+
+dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29.2])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+ [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])dnl PKG_PROG_PKG_CONFIG
+
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])dnl _PKG_CONFIG
+
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
+
+
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $2])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
+
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+ [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+ [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+ [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+ [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
+
+# Copyright (C) 2002-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.16'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.16.3], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.16.3])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed. If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+ [AC_LANG_PUSH([C])
+ am_cv_ar_interface=ar
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+ [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([am_ar_try])
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=ar
+ else
+ am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([am_ar_try])
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=lib
+ else
+ am_cv_ar_interface=unknown
+ fi
+ fi
+ rm -f conftest.lib libconftest.a
+ ])
+ AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+ ;;
+lib)
+ # Microsoft lib, so override with the ar-lib wrapper script.
+ # FIXME: It is wrong to rewrite AR.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__AR in this case,
+ # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+ # similar.
+ AR="$am_aux_dir/ar-lib $AR"
+ ;;
+unknown)
+ m4_default([$1],
+ [AC_MSG_ERROR([could not determine $AR interface])])
+ ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ # TODO: see whether this extra hack can be removed once we start
+ # requiring Autoconf 2.70 or later.
+ AS_CASE([$CONFIG_FILES],
+ [*\'*], [eval set x "$CONFIG_FILES"],
+ [*], [set x $CONFIG_FILES])
+ shift
+ # Used to flag and report bootstrapping failures.
+ am_rc=0
+ for am_mf
+ do
+ # Strip MF so we end up with the name of the file.
+ am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile which includes
+ # dependency-tracking related rules and includes.
+ # Grep'ing the whole file directly is not great: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
+ || continue
+ am_dirpart=`AS_DIRNAME(["$am_mf"])`
+ am_filepart=`AS_BASENAME(["$am_mf"])`
+ AM_RUN_LOG([cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles]) || am_rc=$?
+ done
+ if test $am_rc -ne 0; then
+ AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments
+ for automatic dependency tracking. If GNU make was not used, consider
+ re-running the configure script with MAKE="gmake" (or whatever is
+ necessary). You can also try re-running configure with the
+ '--disable-dependency-tracking' option to at least be able to build
+ the package (albeit without support for automatic dependency tracking).])
+ fi
+ AS_UNSET([am_dirpart])
+ AS_UNSET([am_filepart])
+ AS_UNSET([am_mf])
+ AS_UNSET([am_rc])
+ rm -f conftest-deps.mk
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking is enabled.
+# This creates each '.Po' and '.Plo' makefile fragment that we'll need in
+# order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <https://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+ fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check whether make has an 'include' directive that can support all
+# the idioms we need for our automatic dependency tracking code.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive])
+cat > confinc.mk << 'END'
+am__doit:
+ @echo this is the am__doit target >confinc.out
+.PHONY: am__doit
+END
+am__include="#"
+am__quote=
+# BSD make does it like this.
+echo '.include "confinc.mk" # ignored' > confmf.BSD
+# Other make implementations (GNU, Solaris 10, AIX) do it like this.
+echo 'include confinc.mk # ignored' > confmf.GNU
+_am_result=no
+for s in GNU BSD; do
+ AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out])
+ AS_CASE([$?:`cat confinc.out 2>/dev/null`],
+ ['0:this is the am__doit target'],
+ [AS_CASE([$s],
+ [BSD], [am__include='.include' am__quote='"'],
+ [am__include='include' am__quote=''])])
+ if test "$am__include" != "#"; then
+ _am_result="yes ($s style)"
+ break
+ fi
+done
+rm -f confinc.* confmf.*
+AC_MSG_RESULT([${_am_result}])
+AC_SUBST([am__include])])
+AC_SUBST([am__quote])])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ MISSING="\${SHELL} '$am_aux_dir/missing'"
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+ [whether $CC understands -c and -o together],
+ [am_cv_prog_cc_c_o],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2020 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/gcc4_visibility.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/build-aux/ar-lib b/build-aux/ar-lib
new file mode 100755
index 0000000..1e9388e
--- /dev/null
+++ b/build-aux/ar-lib
@@ -0,0 +1,271 @@
+#! /bin/sh
+# Wrapper for Microsoft lib.exe
+
+me=ar-lib
+scriptversion=2019-07-04.01; # UTC
+
+# Copyright (C) 2010-2020 Free Software Foundation, Inc.
+# Written by Peter Rosin <peda@lysator.liu.se>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+
+# func_error message
+func_error ()
+{
+ echo "$me: $1" 1>&2
+ exit 1
+}
+
+file_conv=
+
+# func_file_conv build_file
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN* | MSYS*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv in
+ mingw)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin | msys)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_at_file at_file operation archive
+# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
+# for each of them.
+# When interpreting the content of the @FILE, do NOT use func_file_conv,
+# since the user would need to supply preconverted file names to
+# binutils ar, at least for MinGW.
+func_at_file ()
+{
+ operation=$2
+ archive=$3
+ at_file_contents=`cat "$1"`
+ eval set x "$at_file_contents"
+ shift
+
+ for member
+ do
+ $AR -NOLOGO $operation:"$member" "$archive" || exit $?
+ done
+}
+
+case $1 in
+ '')
+ func_error "no command. Try '$0 --help' for more information."
+ ;;
+ -h | --h*)
+ cat <<EOF
+Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
+
+Members may be specified in a file named with @FILE.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "$me, version $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test $# -lt 3; then
+ func_error "you must specify a program, an action and an archive"
+fi
+
+AR=$1
+shift
+while :
+do
+ if test $# -lt 2; then
+ func_error "you must specify a program, an action and an archive"
+ fi
+ case $1 in
+ -lib | -LIB \
+ | -ltcg | -LTCG \
+ | -machine* | -MACHINE* \
+ | -subsystem* | -SUBSYSTEM* \
+ | -verbose | -VERBOSE \
+ | -wx* | -WX* )
+ AR="$AR $1"
+ shift
+ ;;
+ *)
+ action=$1
+ shift
+ break
+ ;;
+ esac
+done
+orig_archive=$1
+shift
+func_file_conv "$orig_archive"
+archive=$file
+
+# strip leading dash in $action
+action=${action#-}
+
+delete=
+extract=
+list=
+quick=
+replace=
+index=
+create=
+
+while test -n "$action"
+do
+ case $action in
+ d*) delete=yes ;;
+ x*) extract=yes ;;
+ t*) list=yes ;;
+ q*) quick=yes ;;
+ r*) replace=yes ;;
+ s*) index=yes ;;
+ S*) ;; # the index is always updated implicitly
+ c*) create=yes ;;
+ u*) ;; # TODO: don't ignore the update modifier
+ v*) ;; # TODO: don't ignore the verbose modifier
+ *)
+ func_error "unknown action specified"
+ ;;
+ esac
+ action=${action#?}
+done
+
+case $delete$extract$list$quick$replace,$index in
+ yes,* | ,yes)
+ ;;
+ yesyes*)
+ func_error "more than one action specified"
+ ;;
+ *)
+ func_error "no action specified"
+ ;;
+esac
+
+if test -n "$delete"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ for member
+ do
+ case $1 in
+ @*)
+ func_at_file "${1#@}" -REMOVE "$archive"
+ ;;
+ *)
+ func_file_conv "$1"
+ $AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
+ ;;
+ esac
+ done
+
+elif test -n "$extract"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ if test $# -gt 0; then
+ for member
+ do
+ case $1 in
+ @*)
+ func_at_file "${1#@}" -EXTRACT "$archive"
+ ;;
+ *)
+ func_file_conv "$1"
+ $AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
+ ;;
+ esac
+ done
+ else
+ $AR -NOLOGO -LIST "$archive" | tr -d '\r' | sed -e 's/\\/\\\\/g' \
+ | while read member
+ do
+ $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
+ done
+ fi
+
+elif test -n "$quick$replace"; then
+ if test ! -f "$orig_archive"; then
+ if test -z "$create"; then
+ echo "$me: creating $orig_archive"
+ fi
+ orig_archive=
+ else
+ orig_archive=$archive
+ fi
+
+ for member
+ do
+ case $1 in
+ @*)
+ func_file_conv "${1#@}"
+ set x "$@" "@$file"
+ ;;
+ *)
+ func_file_conv "$1"
+ set x "$@" "$file"
+ ;;
+ esac
+ shift
+ shift
+ done
+
+ if test -n "$orig_archive"; then
+ $AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
+ else
+ $AR -NOLOGO -OUT:"$archive" "$@" || exit $?
+ fi
+
+elif test -n "$list"; then
+ if test ! -f "$orig_archive"; then
+ func_error "archive not found"
+ fi
+ $AR -NOLOGO -LIST "$archive" || exit $?
+fi
diff --git a/build-aux/compile b/build-aux/compile
new file mode 100755
index 0000000..23fcba0
--- /dev/null
+++ b/build-aux/compile
@@ -0,0 +1,348 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN* | MSYS*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/* | msys/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
+ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/build-aux/config.guess b/build-aux/config.guess
new file mode 100755
index 0000000..f50dcdb
--- /dev/null
+++ b/build-aux/config.guess
@@ -0,0 +1,1480 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2018 Free Software Foundation, Inc.
+
+timestamp='2018-02-24'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2018 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > "$dummy.c" ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "$UNAME_SYSTEM" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval "$set_cc_for_build"
+ cat <<-EOF > "$dummy.c"
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+
+ # If ldd exists, use it to detect musl libc.
+ if command -v ldd >/dev/null && \
+ ldd --version 2>&1 | grep -q ^musl
+ then
+ LIBC=musl
+ fi
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+ "/sbin/$sysctl" 2>/dev/null || \
+ "/usr/sbin/$sysctl" 2>/dev/null || \
+ echo unknown)`
+ case "$UNAME_MACHINE_ARCH" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ earmv*)
+ arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+ endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
+ machine="${arch}${endian}"-unknown
+ ;;
+ *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently (or will in the future) and ABI.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ os=netbsdelf
+ ;;
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval "$set_cc_for_build"
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # Determine ABI tags.
+ case "$UNAME_MACHINE_ARCH" in
+ earm*)
+ expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+ abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "$UNAME_VERSION" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "$machine-${os}${release}${abi}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
+ exit ;;
+ *:LibertyBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+ echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
+ exit ;;
+ *:MidnightBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
+ exit ;;
+ *:SolidBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:MirBSD:*:*)
+ echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
+ exit ;;
+ *:Sortix:*:*)
+ echo "$UNAME_MACHINE"-unknown-sortix
+ exit ;;
+ *:Redox:*:*)
+ echo "$UNAME_MACHINE"-unknown-redox
+ exit ;;
+ mips:OSF1:*.*)
+ echo mips-dec-osf1
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE=alpha ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE=alpha ;;
+ "EV5 (21164)")
+ UNAME_MACHINE=alphaev5 ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE=alphaev56 ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE=alphapca56 ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE=alphapca57 ;;
+ "EV6 (21264)")
+ UNAME_MACHINE=alphaev6 ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE=alphaev67 ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE=alphaev68 ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE=alphaev69 ;;
+ "EV7 (21364)")
+ UNAME_MACHINE=alphaev7 ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE=alphaev79 ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo "$UNAME_MACHINE"-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix"$UNAME_RELEASE"
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux"$UNAME_RELEASE"
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval "$set_cc_for_build"
+ SUN_ARCH=i386
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH=x86_64
+ fi
+ fi
+ echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos"$UNAME_RELEASE"
+ ;;
+ sun4)
+ echo sparc-sun-sunos"$UNAME_RELEASE"
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos"$UNAME_RELEASE"
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint"$UNAME_RELEASE"
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint"$UNAME_RELEASE"
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint"$UNAME_RELEASE"
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint"$UNAME_RELEASE"
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten"$UNAME_RELEASE"
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix"$UNAME_RELEASE"
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix"$UNAME_RELEASE"
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" &&
+ dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos"$UNAME_RELEASE"
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+ then
+ if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
+ [ "$TARGET_BINARY_INTERFACE"x = x ]
+ then
+ echo m88k-dg-dgux"$UNAME_RELEASE"
+ else
+ echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+ fi
+ else
+ echo i586-dg-dgux"$UNAME_RELEASE"
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/lslpp ] ; then
+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+ else
+ IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+ fi
+ echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ case "$UNAME_MACHINE" in
+ 9000/31?) HP_ARCH=m68000 ;;
+ 9000/[34]??) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "$sc_cpu_version" in
+ 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "$sc_kernel_bits" in
+ 32) HP_ARCH=hppa2.0n ;;
+ 64) HP_ARCH=hppa2.0w ;;
+ '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "$HP_ARCH" = "" ]; then
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ "$HP_ARCH" = hppa2.0w ]
+ then
+ eval "$set_cc_for_build"
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH=hppa2.0w
+ else
+ HP_ARCH=hppa64
+ fi
+ fi
+ echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux"$HPUX_REV"
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo "$UNAME_MACHINE"-unknown-osf1mk
+ else
+ echo "$UNAME_MACHINE"-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+ FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ *:BSD/OS:*:*)
+ echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case "$UNAME_PROCESSOR" in
+ amd64)
+ UNAME_PROCESSOR=x86_64 ;;
+ i386)
+ UNAME_PROCESSOR=i586 ;;
+ esac
+ echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ exit ;;
+ i*:CYGWIN*:*)
+ echo "$UNAME_MACHINE"-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo "$UNAME_MACHINE"-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo "$UNAME_MACHINE"-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo "$UNAME_MACHINE"-pc-msys
+ exit ;;
+ i*:PW*:*)
+ echo "$UNAME_MACHINE"-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case "$UNAME_MACHINE" in
+ x86)
+ echo i586-pc-interix"$UNAME_RELEASE"
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix"$UNAME_RELEASE"
+ exit ;;
+ esac ;;
+ i*:UWIN*:*)
+ echo "$UNAME_MACHINE"-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
+ exit ;;
+ i*86:Minix:*:*)
+ echo "$UNAME_MACHINE"-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ arm*:Linux:*:*)
+ eval "$set_cc_for_build"
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+ else
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ cris:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ crisv32:Linux:*:*)
+ echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
+ exit ;;
+ e2k:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ frv:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ hexagon:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:Linux:*:*)
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ exit ;;
+ ia64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ k1om:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m32r*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ m68*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval "$set_cc_for_build"
+ sed 's/^ //' << EOF > "$dummy.c"
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`"
+ test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; }
+ ;;
+ mips64el:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-"$LIBC"
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-"$LIBC"
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-"$LIBC"
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
+ PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
+ *) echo hppa-unknown-linux-"$LIBC" ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-"$LIBC"
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-"$LIBC"
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-"$LIBC"
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-"$LIBC"
+ exit ;;
+ riscv32:Linux:*:* | riscv64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
+ exit ;;
+ sh64*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sh*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ tile*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ vax:Linux:*:*)
+ echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
+ exit ;;
+ x86_64:Linux:*:*)
+ if objdump -f /bin/sh | grep -q elf32-x86-64; then
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32
+ else
+ echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+ fi
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo "$UNAME_MACHINE"-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo "$UNAME_MACHINE"-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo "$UNAME_MACHINE"-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo "$UNAME_MACHINE"-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ i*86:*DOS:*:*)
+ echo "$UNAME_MACHINE"-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:*)
+ UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}"
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+ else
+ echo "$UNAME_MACHINE"-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configure will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos"$UNAME_RELEASE"
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv"$UNAME_RELEASE"
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo "$UNAME_MACHINE"-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo "$UNAME_MACHINE"-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux"$UNAME_RELEASE"
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv"$UNAME_RELEASE"
+ else
+ echo mips-unknown-sysv"$UNAME_RELEASE"
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ SX-ACE:SUPER-UX:*:*)
+ echo sxace-nec-superux"$UNAME_RELEASE"
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ *:Rhapsody:*:*)
+ echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval "$set_cc_for_build"
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
+ if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+ if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_PPC >/dev/null
+ then
+ UNAME_PROCESSOR=powerpc
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = x86; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-*:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSR-*:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSV-*:NONSTOP_KERNEL:*:*)
+ echo nsv-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ NSX-*:NONSTOP_KERNEL:*:*)
+ echo nsx-tandem-nsk"$UNAME_RELEASE"
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = 386; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo "$UNAME_MACHINE"-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux"$UNAME_RELEASE"
+ exit ;;
+ *:DragonFly:*:*)
+ echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "$UNAME_MACHINE" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
+ exit ;;
+ i*86:rdos:*:*)
+ echo "$UNAME_MACHINE"-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo "$UNAME_MACHINE"-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo "$UNAME_MACHINE"-unknown-esx
+ exit ;;
+ amd64:Isilon\ OneFS:*:*)
+ echo x86_64-unknown-onefs
+ exit ;;
+esac
+
+echo "$0: unable to guess system type" >&2
+
+case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+ mips:Linux | mips64:Linux)
+ # If we got here on MIPS GNU/Linux, output extra information.
+ cat >&2 <<EOF
+
+NOTE: MIPS GNU/Linux systems require a C compiler to fully recognize
+the system type. Please install a C compiler and try again.
+EOF
+ ;;
+esac
+
+cat >&2 <<EOF
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite *all*
+copies of config.guess and config.sub with the latest versions from:
+
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+ https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = "$UNAME_MACHINE"
+UNAME_RELEASE = "$UNAME_RELEASE"
+UNAME_SYSTEM = "$UNAME_SYSTEM"
+UNAME_VERSION = "$UNAME_VERSION"
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-functions 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build-aux/config.sub b/build-aux/config.sub
new file mode 100755
index 0000000..1d8e98b
--- /dev/null
+++ b/build-aux/config.sub
@@ -0,0 +1,1801 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2018 Free Software Foundation, Inc.
+
+timestamp='2018-02-22'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
+
+Canonicalize a configuration name.
+
+Options:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2018 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo "$1"
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+ kopensolaris*-gnu* | cloudabi*-eabi* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo "$1" | sed 's/-[^-]*$//'`
+ if [ "$basic_machine" != "$1" ]
+ then os=`echo "$1" | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | ba \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | epiphany \
+ | fido | fr30 | frv | ft32 \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pru \
+ | pyramid \
+ | riscv32 | riscv64 \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | visium \
+ | wasm32 \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ leon|leon[3-9])
+ basic_machine=sparc-$basic_machine
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | ba-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | e2k-* | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | k1om-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pru-* \
+ | pyramid-* \
+ | riscv32-* | riscv64-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | visium-* \
+ | wasm32-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-pc
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ asmjs)
+ basic_machine=asmjs-unknown
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2*)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ e500v[12])
+ basic_machine=powerpc-unknown
+ os=$os"spe"
+ ;;
+ e500v[12]-*)
+ basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=$os"spe"
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ leon-*|leon[3-9]-*)
+ basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'`
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=-moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next)
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ nsv-tandem)
+ basic_machine=nsv-tandem
+ ;;
+ nsx-tandem)
+ basic_machine=nsx-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ x64)
+ basic_machine=x86_64-pc
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases that might get confused
+ # with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # es1800 is here to avoid being matched by es* (a different OS)
+ -es1800*)
+ os=-ose
+ ;;
+ # Now accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST end in a * to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* | -cloudabi* | -sortix* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \
+ | -midnightbsd*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -xray | -os68k* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo "$os" | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2)
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -pikeos*)
+ # Until real need of OS specific support for
+ # particular features comes up, bare metal
+ # configurations are quite functional.
+ case $basic_machine in
+ arm*)
+ os=-eabi
+ ;;
+ *)
+ os=-elf
+ ;;
+ esac
+ ;;
+ -nacl*)
+ ;;
+ -ios)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ pru-*)
+ os=-elf
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next)
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo "$basic_machine$os"
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-functions 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/build-aux/depcomp b/build-aux/depcomp
new file mode 100755
index 0000000..6b39162
--- /dev/null
+++ b/build-aux/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/build-aux/install-sh b/build-aux/install-sh
new file mode 100755
index 0000000..ec298b5
--- /dev/null
+++ b/build-aux/install-sh
@@ -0,0 +1,541 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2020-11-14.01; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+tab=' '
+nl='
+'
+IFS=" $tab$nl"
+
+# Set DOITPROG to "echo" to test this script.
+
+doit=${DOITPROG-}
+doit_exec=${doit:-exec}
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+# Create dirs (including intermediate dirs) using mode 755.
+# This is like GNU 'install' as of coreutils 8.32 (2020).
+mkdir_umask=22
+
+backupsuffix=
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+is_target_a_directory=possibly
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -p pass -p to $cpprog.
+ -s $stripprog installed files.
+ -S SUFFIX attempt to back up existing files, with suffix SUFFIX.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+
+By default, rm is invoked with -f; when overridden with RMPROG,
+it's up to you to specify -f if you want it.
+
+If -S is not specified, no backups are attempted.
+
+Email bug reports to bug-automake@gnu.org.
+Automake home page: https://www.gnu.org/software/automake/
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -p) cpprog="$cpprog -p";;
+
+ -s) stripcmd=$stripprog;;
+
+ -S) backupsuffix="$2"
+ shift;;
+
+ -t)
+ is_target_a_directory=always
+ dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) is_target_a_directory=never;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+# We allow the use of options -d and -T together, by making -d
+# take the precedence; this is for compatibility with GNU install.
+
+if test -n "$dir_arg"; then
+ if test -n "$dst_arg"; then
+ echo "$0: target directory not allowed when installing a directory." >&2
+ exit 1
+ fi
+fi
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ if test $# -gt 1 || test "$is_target_a_directory" = always; then
+ if test ! -d "$dst_arg"; then
+ echo "$0: $dst_arg: Is not a directory." >&2
+ exit 1
+ fi
+ fi
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ # Don't chown directories that already exist.
+ if test $dstdir_status = 0; then
+ chowncmd=""
+ fi
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename.
+ if test -d "$dst"; then
+ if test "$is_target_a_directory" = never; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dstbase=`basename "$src"`
+ case $dst in
+ */) dst=$dst$dstbase;;
+ *) dst=$dst/$dstbase;;
+ esac
+ dstdir_status=0
+ else
+ dstdir=`dirname "$dst"`
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ case $dstdir in
+ */) dstdirslash=$dstdir;;
+ *) dstdirslash=$dstdir/;;
+ esac
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ # The $RANDOM variable is not portable (e.g., dash). Use it
+ # here however when possible just to lower collision chance.
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+ trap '
+ ret=$?
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
+ exit $ret
+ ' 0
+
+ # Because "mkdir -p" follows existing symlinks and we likely work
+ # directly in world-writeable /tmp, make sure that the '$tmpdir'
+ # directory is successfully created first before we actually test
+ # 'mkdir -p'.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ set -f
+ set fnord $dstdir
+ shift
+ set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=${dstdirslash}_inst.$$_
+ rmtmp=${dstdirslash}_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask &&
+ { test -z "$stripcmd" || {
+ # Create $dsttmp read-write so that cp doesn't create it read-only,
+ # which would cause strip to fail.
+ if test -z "$doit"; then
+ : >"$dsttmp" # No need to fork-exec 'touch'.
+ else
+ $doit touch "$dsttmp"
+ fi
+ }
+ } &&
+ $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+ set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ set +f &&
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # If $backupsuffix is set, and the file being installed
+ # already exists, attempt a backup. Don't worry if it fails,
+ # e.g., if mv doesn't support -f.
+ if test -n "$backupsuffix" && test -f "$dst"; then
+ $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
+ fi
+
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/build-aux/ltmain.sh b/build-aux/ltmain.sh
new file mode 100755
index 0000000..21e5e07
--- /dev/null
+++ b/build-aux/ltmain.sh
@@ -0,0 +1,11251 @@
+#! /bin/sh
+## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
+## by inline-source v2014-01-03.01
+
+# libtool (GNU libtool) 2.4.6
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.6 Debian-2.4.6-15"
+package_revision=2.4.6
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Run './libtool --help' for help with using this script from the
+# command line.
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# After configure completes, it has a better idea of some of the
+# shell tools we need than the defaults used by the functions shared
+# with bootstrap, so set those here where they can still be over-
+# ridden by the user, but otherwise take precedence.
+
+: ${AUTOCONF="autoconf"}
+: ${AUTOMAKE="automake"}
+
+
+## -------------------------- ##
+## Source external libraries. ##
+## -------------------------- ##
+
+# Much of our low-level functionality needs to be sourced from external
+# libraries, which are installed to $pkgauxdir.
+
+# Set a version string for this script.
+scriptversion=2015-01-20.17; # UTC
+
+# General shell script boiler plate, and helper functions.
+# Written by Gary V. Vaughan, 2004
+
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# Evaluate this file near the top of your script to gain access to
+# the functions and variables defined here:
+#
+# . `echo "$0" | ${SED-sed} 's|[^/]*$||'`/build-aux/funclib.sh
+#
+# If you need to override any of the default environment variable
+# settings, do that before evaluating this file.
+
+
+## -------------------- ##
+## Shell normalisation. ##
+## -------------------- ##
+
+# Some shells need a little help to be as Bourne compatible as possible.
+# Before doing anything else, make sure all that help has been provided!
+
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac
+fi
+
+# NLS nuisances: We save the old values in case they are required later.
+_G_user_locale=
+_G_safe_locale=
+for _G_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test set = \"\${$_G_var+set}\"; then
+ save_$_G_var=\$$_G_var
+ $_G_var=C
+ export $_G_var
+ _G_user_locale=\"$_G_var=\\\$save_\$_G_var; \$_G_user_locale\"
+ _G_safe_locale=\"$_G_var=C; \$_G_safe_locale\"
+ fi"
+done
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Make sure IFS has a sensible default
+sp=' '
+nl='
+'
+IFS="$sp $nl"
+
+# There are apparently some retarded systems that use ';' as a PATH separator!
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+
+## ------------------------- ##
+## Locate command utilities. ##
+## ------------------------- ##
+
+
+# func_executable_p FILE
+# ----------------------
+# Check that FILE is an executable regular file.
+func_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+}
+
+
+# func_path_progs PROGS_LIST CHECK_FUNC [PATH]
+# --------------------------------------------
+# Search for either a program that responds to --version with output
+# containing "GNU", or else returned by CHECK_FUNC otherwise, by
+# trying all the directories in PATH with each of the elements of
+# PROGS_LIST.
+#
+# CHECK_FUNC should accept the path to a candidate program, and
+# set $func_check_prog_result if it truncates its output less than
+# $_G_path_prog_max characters.
+func_path_progs ()
+{
+ _G_progs_list=$1
+ _G_check_func=$2
+ _G_PATH=${3-"$PATH"}
+
+ _G_path_prog_max=0
+ _G_path_prog_found=false
+ _G_save_IFS=$IFS; IFS=${PATH_SEPARATOR-:}
+ for _G_dir in $_G_PATH; do
+ IFS=$_G_save_IFS
+ test -z "$_G_dir" && _G_dir=.
+ for _G_prog_name in $_G_progs_list; do
+ for _exeext in '' .EXE; do
+ _G_path_prog=$_G_dir/$_G_prog_name$_exeext
+ func_executable_p "$_G_path_prog" || continue
+ case `"$_G_path_prog" --version 2>&1` in
+ *GNU*) func_path_progs_result=$_G_path_prog _G_path_prog_found=: ;;
+ *) $_G_check_func $_G_path_prog
+ func_path_progs_result=$func_check_prog_result
+ ;;
+ esac
+ $_G_path_prog_found && break 3
+ done
+ done
+ done
+ IFS=$_G_save_IFS
+ test -z "$func_path_progs_result" && {
+ echo "no acceptable sed could be found in \$PATH" >&2
+ exit 1
+ }
+}
+
+
+# We want to be able to use the functions in this file before configure
+# has figured out where the best binaries are kept, which means we have
+# to search for them ourselves - except when the results are already set
+# where we skip the searches.
+
+# Unless the user overrides by setting SED, search the path for either GNU
+# sed, or the sed that truncates its output the least.
+test -z "$SED" && {
+ _G_sed_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for _G_i in 1 2 3 4 5 6 7; do
+ _G_sed_script=$_G_sed_script$nl$_G_sed_script
+ done
+ echo "$_G_sed_script" 2>/dev/null | sed 99q >conftest.sed
+ _G_sed_script=
+
+ func_check_prog_sed ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo '' >> conftest.nl
+ "$_G_path_prog" -f conftest.sed <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
+ rm -f conftest.sed
+ SED=$func_path_progs_result
+}
+
+
+# Unless the user overrides by setting GREP, search the path for either GNU
+# grep, or the grep that truncates its output the least.
+test -z "$GREP" && {
+ func_check_prog_grep ()
+ {
+ _G_path_prog=$1
+
+ _G_count=0
+ _G_path_prog_max=0
+ printf 0123456789 >conftest.in
+ while :
+ do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo 'GREP' >> conftest.nl
+ "$_G_path_prog" -e 'GREP$' -e '-(cannot match)-' <conftest.nl >conftest.out 2>/dev/null || break
+ diff conftest.out conftest.nl >/dev/null 2>&1 || break
+ _G_count=`expr $_G_count + 1`
+ if test "$_G_count" -gt "$_G_path_prog_max"; then
+ # Best one so far, save it but keep looking for a better one
+ func_check_prog_result=$_G_path_prog
+ _G_path_prog_max=$_G_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test 10 -lt "$_G_count" && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out
+ }
+
+ func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
+ GREP=$func_path_progs_result
+}
+
+
+## ------------------------------- ##
+## User overridable command paths. ##
+## ------------------------------- ##
+
+# All uppercase variable names are used for environment variables. These
+# variables can be overridden by the user before calling a script that
+# uses them if a suitable command of that name is not already available
+# in the command search PATH.
+
+: ${CP="cp -f"}
+: ${ECHO="printf %s\n"}
+: ${EGREP="$GREP -E"}
+: ${FGREP="$GREP -F"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+
+
+## -------------------- ##
+## Useful sed snippets. ##
+## -------------------- ##
+
+sed_dirname='s|/[^/]*$||'
+sed_basename='s|^.*/||'
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
+
+# Same as above, but do not quote variable references.
+sed_double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s|[].[^$\\*\/]|\\&|g'
+
+# Sed substitution that converts a w32 file name or path
+# that contains forward slashes, into one that contains
+# (escaped) backslashes. A very naive implementation.
+sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-'\' parameter expansions in output of sed_double_quote_subst that
+# were '\'-ed in input to the same. If an odd number of '\' preceded a
+# '$' in input to sed_double_quote_subst, that '$' was protected from
+# expansion. Since each input '\' is now two '\'s, look for any number
+# of runs of four '\'s followed by two '\'s and then a '$'. '\' that '$'.
+_G_bs='\\'
+_G_bs2='\\\\'
+_G_bs4='\\\\\\\\'
+_G_dollar='\$'
+sed_double_backslash="\
+ s/$_G_bs4/&\\
+/g
+ s/^$_G_bs2$_G_dollar/$_G_bs&/
+ s/\\([^$_G_bs]\\)$_G_bs2$_G_dollar/\\1$_G_bs2$_G_bs$_G_dollar/g
+ s/\n//g"
+
+
+## ----------------- ##
+## Global variables. ##
+## ----------------- ##
+
+# Except for the global variables explicitly listed below, the following
+# functions in the '^func_' namespace, and the '^require_' namespace
+# variables initialised in the 'Resource management' section, sourcing
+# this file will not pollute your global namespace with anything
+# else. There's no portable way to scope variables in Bourne shell
+# though, so actually running these functions will sometimes place
+# results into a variable named after the function, and often use
+# temporary variables in the '^_G_' namespace. If you are careful to
+# avoid using those namespaces casually in your sourcing script, things
+# should continue to work as you expect. And, of course, you can freely
+# overwrite any of the functions or variables defined here before
+# calling anything to customize them.
+
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+# Allow overriding, eg assuming that you follow the convention of
+# putting '$debug_cmd' at the start of all your functions, you can get
+# bash to show function call trace with:
+#
+# debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+debug_cmd=${debug_cmd-":"}
+exit_cmd=:
+
+# By convention, finish your script with:
+#
+# exit $exit_status
+#
+# so that you can set exit_status to non-zero if you want to indicate
+# something went wrong during execution without actually bailing out at
+# the point of failure.
+exit_status=$EXIT_SUCCESS
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath=$0
+
+# The name of this program.
+progname=`$ECHO "$progpath" |$SED "$sed_basename"`
+
+# Make sure we have an absolute progpath for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=`$ECHO "$progpath" |$SED "$sed_dirname"`
+ progdir=`cd "$progdir" && pwd`
+ progpath=$progdir/$progname
+ ;;
+ *)
+ _G_IFS=$IFS
+ IFS=${PATH_SEPARATOR-:}
+ for progdir in $PATH; do
+ IFS=$_G_IFS
+ test -x "$progdir/$progname" && break
+ done
+ IFS=$_G_IFS
+ test -n "$progdir" || progdir=`pwd`
+ progpath=$progdir/$progname
+ ;;
+esac
+
+
+## ----------------- ##
+## Standard options. ##
+## ----------------- ##
+
+# The following options affect the operation of the functions defined
+# below, and should be set appropriately depending on run-time para-
+# meters passed on the command line.
+
+opt_dry_run=false
+opt_quiet=false
+opt_verbose=false
+
+# Categories 'all' and 'none' are always available. Append any others
+# you will pass as the first argument to func_warning from your own
+# code.
+warning_categories=
+
+# By default, display warnings according to 'opt_warning_types'. Set
+# 'warning_func' to ':' to elide all warnings, or func_fatal_error to
+# treat the next displayed warning as a fatal error.
+warning_func=func_warn_and_continue
+
+# Set to 'all' to display all warnings, 'none' to suppress all
+# warnings, or a space delimited list of some subset of
+# 'warning_categories' to display only the listed warnings.
+opt_warning_types=all
+
+
+## -------------------- ##
+## Resource management. ##
+## -------------------- ##
+
+# This section contains definitions for functions that each ensure a
+# particular resource (a file, or a non-empty configuration variable for
+# example) is available, and if appropriate to extract default values
+# from pertinent package files. Call them using their associated
+# 'require_*' variable to ensure that they are executed, at most, once.
+#
+# It's entirely deliberate that calling these functions can set
+# variables that don't obey the namespace limitations obeyed by the rest
+# of this file, in order that that they be as useful as possible to
+# callers.
+
+
+# require_term_colors
+# -------------------
+# Allow display of bold text on terminals that support it.
+require_term_colors=func_require_term_colors
+func_require_term_colors ()
+{
+ $debug_cmd
+
+ test -t 1 && {
+ # COLORTERM and USE_ANSI_COLORS environment variables take
+ # precedence, because most terminfo databases neglect to describe
+ # whether color sequences are supported.
+ test -n "${COLORTERM+set}" && : ${USE_ANSI_COLORS="1"}
+
+ if test 1 = "$USE_ANSI_COLORS"; then
+ # Standard ANSI escape sequences
+ tc_reset=''
+ tc_bold=''; tc_standout=''
+ tc_red=''; tc_green=''
+ tc_blue=''; tc_cyan=''
+ else
+ # Otherwise trust the terminfo database after all.
+ test -n "`tput sgr0 2>/dev/null`" && {
+ tc_reset=`tput sgr0`
+ test -n "`tput bold 2>/dev/null`" && tc_bold=`tput bold`
+ tc_standout=$tc_bold
+ test -n "`tput smso 2>/dev/null`" && tc_standout=`tput smso`
+ test -n "`tput setaf 1 2>/dev/null`" && tc_red=`tput setaf 1`
+ test -n "`tput setaf 2 2>/dev/null`" && tc_green=`tput setaf 2`
+ test -n "`tput setaf 4 2>/dev/null`" && tc_blue=`tput setaf 4`
+ test -n "`tput setaf 5 2>/dev/null`" && tc_cyan=`tput setaf 5`
+ }
+ fi
+ }
+
+ require_term_colors=:
+}
+
+
+## ----------------- ##
+## Function library. ##
+## ----------------- ##
+
+# This section contains a variety of useful functions to call in your
+# scripts. Take note of the portable wrappers for features provided by
+# some modern shells, which will fall back to slower equivalents on
+# less featureful shells.
+
+
+# func_append VAR VALUE
+# ---------------------
+# Append VALUE onto the existing contents of VAR.
+
+ # We should try to minimise forks, especially on Windows where they are
+ # unreasonably slow, so skip the feature probes when bash or zsh are
+ # being used:
+ if test set = "${BASH_VERSION+set}${ZSH_VERSION+set}"; then
+ : ${_G_HAVE_ARITH_OP="yes"}
+ : ${_G_HAVE_XSI_OPS="yes"}
+ # The += operator was introduced in bash 3.1
+ case $BASH_VERSION in
+ [12].* | 3.0 | 3.0*) ;;
+ *)
+ : ${_G_HAVE_PLUSEQ_OP="yes"}
+ ;;
+ esac
+ fi
+
+ # _G_HAVE_PLUSEQ_OP
+ # Can be empty, in which case the shell is probed, "yes" if += is
+ # useable or anything else if it does not work.
+ test -z "$_G_HAVE_PLUSEQ_OP" \
+ && (eval 'x=a; x+=" b"; test "a b" = "$x"') 2>/dev/null \
+ && _G_HAVE_PLUSEQ_OP=yes
+
+if test yes = "$_G_HAVE_PLUSEQ_OP"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_append ()
+ {
+ $debug_cmd
+
+ eval "$1+=\$2"
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_append ()
+ {
+ $debug_cmd
+
+ eval "$1=\$$1\$2"
+ }
+fi
+
+
+# func_append_quoted VAR VALUE
+# ----------------------------
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+if test yes = "$_G_HAVE_PLUSEQ_OP"; then
+ eval 'func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1+=\\ \$func_quote_for_eval_result"
+ }'
+else
+ func_append_quoted ()
+ {
+ $debug_cmd
+
+ func_quote_for_eval "$2"
+ eval "$1=\$$1\\ \$func_quote_for_eval_result"
+ }
+fi
+
+
+# func_append_uniq VAR VALUE
+# --------------------------
+# Append unique VALUE onto the existing contents of VAR, assuming
+# entries are delimited by the first character of VALUE. For example:
+#
+# func_append_uniq options " --another-option option-argument"
+#
+# will only append to $options if " --another-option option-argument "
+# is not already present somewhere in $options already (note spaces at
+# each end implied by leading space in second argument).
+func_append_uniq ()
+{
+ $debug_cmd
+
+ eval _G_current_value='`$ECHO $'$1'`'
+ _G_delim=`expr "$2" : '\(.\)'`
+
+ case $_G_delim$_G_current_value$_G_delim in
+ *"$2$_G_delim"*) ;;
+ *) func_append "$@" ;;
+ esac
+}
+
+
+# func_arith TERM...
+# ------------------
+# Set func_arith_result to the result of evaluating TERMs.
+ test -z "$_G_HAVE_ARITH_OP" \
+ && (eval 'test 2 = $(( 1 + 1 ))') 2>/dev/null \
+ && _G_HAVE_ARITH_OP=yes
+
+if test yes = "$_G_HAVE_ARITH_OP"; then
+ eval 'func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=$(( $* ))
+ }'
+else
+ func_arith ()
+ {
+ $debug_cmd
+
+ func_arith_result=`expr "$@"`
+ }
+fi
+
+
+# func_basename FILE
+# ------------------
+# Set func_basename_result to FILE with everything up to and including
+# the last / stripped.
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ # If this shell supports suffix pattern removal, then use it to avoid
+ # forking. Hide the definitions single quotes in case the shell chokes
+ # on unsupported syntax...
+ _b='func_basename_result=${1##*/}'
+ _d='case $1 in
+ */*) func_dirname_result=${1%/*}$2 ;;
+ * ) func_dirname_result=$3 ;;
+ esac'
+
+else
+ # ...otherwise fall back to using sed.
+ _b='func_basename_result=`$ECHO "$1" |$SED "$sed_basename"`'
+ _d='func_dirname_result=`$ECHO "$1" |$SED "$sed_dirname"`
+ if test "X$func_dirname_result" = "X$1"; then
+ func_dirname_result=$3
+ else
+ func_append func_dirname_result "$2"
+ fi'
+fi
+
+eval 'func_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+}'
+
+
+# func_dirname FILE APPEND NONDIR_REPLACEMENT
+# -------------------------------------------
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+eval 'func_dirname ()
+{
+ $debug_cmd
+
+ '"$_d"'
+}'
+
+
+# func_dirname_and_basename FILE APPEND NONDIR_REPLACEMENT
+# --------------------------------------------------------
+# Perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# For efficiency, we do not delegate to the functions above but instead
+# duplicate the functionality here.
+eval 'func_dirname_and_basename ()
+{
+ $debug_cmd
+
+ '"$_b"'
+ '"$_d"'
+}'
+
+
+# func_echo ARG...
+# ----------------
+# Echo program name prefixed message.
+func_echo ()
+{
+ $debug_cmd
+
+ _G_message=$*
+
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
+
+
+# func_echo_all ARG...
+# --------------------
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+
+# func_echo_infix_1 INFIX ARG...
+# ------------------------------
+# Echo program name, followed by INFIX on the first line, with any
+# additional lines not showing INFIX.
+func_echo_infix_1 ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ _G_infix=$1; shift
+ _G_indent=$_G_infix
+ _G_prefix="$progname: $_G_infix: "
+ _G_message=$*
+
+ # Strip color escape sequences before counting printable length
+ for _G_tc in "$tc_reset" "$tc_bold" "$tc_standout" "$tc_red" "$tc_green" "$tc_blue" "$tc_cyan"
+ do
+ test -n "$_G_tc" && {
+ _G_esc_tc=`$ECHO "$_G_tc" | $SED "$sed_make_literal_regex"`
+ _G_indent=`$ECHO "$_G_indent" | $SED "s|$_G_esc_tc||g"`
+ }
+ done
+ _G_indent="$progname: "`echo "$_G_indent" | $SED 's|.| |g'`" " ## exclude from sc_prohibit_nested_quotes
+
+ func_echo_infix_1_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_infix_1_IFS
+ $ECHO "$_G_prefix$tc_bold$_G_line$tc_reset" >&2
+ _G_prefix=$_G_indent
+ done
+ IFS=$func_echo_infix_1_IFS
+}
+
+
+# func_error ARG...
+# -----------------
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ func_echo_infix_1 " $tc_standout${tc_red}error$tc_reset" "$*" >&2
+}
+
+
+# func_fatal_error ARG...
+# -----------------------
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ $debug_cmd
+
+ func_error "$*"
+ exit $EXIT_FAILURE
+}
+
+
+# func_grep EXPRESSION FILENAME
+# -----------------------------
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $debug_cmd
+
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_len STRING
+# ---------------
+# Set func_len_result to the length of STRING. STRING may not
+# start with a hyphen.
+ test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=${#1}
+ }'
+else
+ func_len ()
+ {
+ $debug_cmd
+
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+ }
+fi
+
+
+# func_mkdir_p DIRECTORY-PATH
+# ---------------------------
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ $debug_cmd
+
+ _G_directory_path=$1
+ _G_dir_list=
+
+ if test -n "$_G_directory_path" && test : != "$opt_dry_run"; then
+
+ # Protect directory names starting with '-'
+ case $_G_directory_path in
+ -*) _G_directory_path=./$_G_directory_path ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$_G_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ _G_dir_list=$_G_directory_path:$_G_dir_list
+
+ # If the last portion added has no slash in it, the list is done
+ case $_G_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ _G_directory_path=`$ECHO "$_G_directory_path" | $SED -e "$sed_dirname"`
+ done
+ _G_dir_list=`$ECHO "$_G_dir_list" | $SED 's|:*$||'`
+
+ func_mkdir_p_IFS=$IFS; IFS=:
+ for _G_dir in $_G_dir_list; do
+ IFS=$func_mkdir_p_IFS
+ # mkdir can fail with a 'File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$_G_dir" 2>/dev/null || :
+ done
+ IFS=$func_mkdir_p_IFS
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$_G_directory_path" || \
+ func_fatal_error "Failed to create '$1'"
+ fi
+}
+
+
+# func_mktempdir [BASENAME]
+# -------------------------
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, BASENAME is the basename for that directory.
+func_mktempdir ()
+{
+ $debug_cmd
+
+ _G_template=${TMPDIR-/tmp}/${1-$progname}
+
+ if test : = "$opt_dry_run"; then
+ # Return a directory name, but don't create it in dry-run mode
+ _G_tmpdir=$_G_template-$$
+ else
+
+ # If mktemp works, use that first and foremost
+ _G_tmpdir=`mktemp -d "$_G_template-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$_G_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ _G_tmpdir=$_G_template-${RANDOM-0}$$
+
+ func_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$_G_tmpdir"
+ umask $func_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$_G_tmpdir" || \
+ func_fatal_error "cannot create temporary directory '$_G_tmpdir'"
+ fi
+
+ $ECHO "$_G_tmpdir"
+}
+
+
+# func_normal_abspath PATH
+# ------------------------
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+func_normal_abspath ()
+{
+ $debug_cmd
+
+ # These SED scripts presuppose an absolute path with a trailing slash.
+ _G_pathcar='s|^/\([^/]*\).*$|\1|'
+ _G_pathcdr='s|^/[^/]*||'
+ _G_removedotparts=':dotsl
+ s|/\./|/|g
+ t dotsl
+ s|/\.$|/|'
+ _G_collapseslashes='s|/\{1,\}|/|g'
+ _G_finalslash='s|/*$|/|'
+
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
+ *)
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
+ esac
+
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_removedotparts" -e "$_G_collapseslashes" -e "$_G_finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test / = "$func_normal_abspath_tpath"; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result"; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$_G_pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_append func_normal_abspath_result "/$func_normal_abspath_tcomponent"
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+
+# func_notquiet ARG...
+# --------------------
+# Echo program name prefixed message only when not in quiet mode.
+func_notquiet ()
+{
+ $debug_cmd
+
+ $opt_quiet || func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+
+# func_relative_path SRCDIR DSTDIR
+# --------------------------------
+# Set func_relative_path_result to the relative path from SRCDIR to DSTDIR.
+func_relative_path ()
+{
+ $debug_cmd
+
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=$func_dirname_result
+ if test -z "$func_relative_path_tlibdir"; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test -n "$func_stripname_result"; then
+ func_append func_relative_path_result "/$func_stripname_result"
+ fi
+
+ # Normalisation. If bindir is libdir, return '.' else relative path.
+ if test -n "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ fi
+
+ test -n "$func_relative_path_result" || func_relative_path_result=.
+
+ :
+}
+
+
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+# i) func_quote_for_eval_result
+# double-quoted, suitable for a subsequent eval
+# ii) func_quote_for_eval_unquoted_result
+# has all characters that are still active within double
+# quotes backslashified.
+func_quote_for_eval ()
+{
+ $debug_cmd
+
+ func_quote_for_eval_unquoted_result=
+ func_quote_for_eval_result=
+ while test 0 -lt $#; do
+ case $1 in
+ *[\\\`\"\$]*)
+ _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+ *)
+ _G_unquoted_arg=$1 ;;
+ esac
+ if test -n "$func_quote_for_eval_unquoted_result"; then
+ func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+ else
+ func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+ fi
+
+ case $_G_unquoted_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and variable expansion
+ # for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ _G_quoted_arg=\"$_G_unquoted_arg\"
+ ;;
+ *)
+ _G_quoted_arg=$_G_unquoted_arg
+ ;;
+ esac
+
+ if test -n "$func_quote_for_eval_result"; then
+ func_append func_quote_for_eval_result " $_G_quoted_arg"
+ else
+ func_append func_quote_for_eval_result "$_G_quoted_arg"
+ fi
+ shift
+ done
+}
+
+
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ $debug_cmd
+
+ case $1 in
+ *[\\\`\"]*)
+ _G_arg=`$ECHO "$1" | $SED \
+ -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ _G_arg=$1 ;;
+ esac
+
+ case $_G_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ _G_arg=\"$_G_arg\"
+ ;;
+ esac
+
+ func_quote_for_expand_result=$_G_arg
+}
+
+
+# func_stripname PREFIX SUFFIX NAME
+# ---------------------------------
+# strip PREFIX and SUFFIX from NAME, and store in func_stripname_result.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_stripname ()
+ {
+ $debug_cmd
+
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary variable first.
+ func_stripname_result=$3
+ func_stripname_result=${func_stripname_result#"$1"}
+ func_stripname_result=${func_stripname_result%"$2"}
+ }'
+else
+ func_stripname ()
+ {
+ $debug_cmd
+
+ case $2 in
+ .*) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%\\\\$2\$%%"`;;
+ *) func_stripname_result=`$ECHO "$3" | $SED -e "s%^$1%%" -e "s%$2\$%%"`;;
+ esac
+ }
+fi
+
+
+# func_show_eval CMD [FAIL_EXP]
+# -----------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ $debug_cmd
+
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
+
+ func_quote_for_expand "$_G_cmd"
+ eval "func_notquiet $func_quote_for_expand_result"
+
+ $opt_dry_run || {
+ eval "$_G_cmd"
+ _G_status=$?
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
+ fi
+ }
+}
+
+
+# func_show_eval_locale CMD [FAIL_EXP]
+# ------------------------------------
+# Unless opt_quiet is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ $debug_cmd
+
+ _G_cmd=$1
+ _G_fail_exp=${2-':'}
+
+ $opt_quiet || {
+ func_quote_for_expand "$_G_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ $opt_dry_run || {
+ eval "$_G_user_locale
+ $_G_cmd"
+ _G_status=$?
+ eval "$_G_safe_locale"
+ if test 0 -ne "$_G_status"; then
+ eval "(exit $_G_status); $_G_fail_exp"
+ fi
+ }
+}
+
+
+# func_tr_sh
+# ----------
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result. All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+ $debug_cmd
+
+ case $1 in
+ [0-9]* | *[!a-zA-Z0-9_]*)
+ func_tr_sh_result=`$ECHO "$1" | $SED -e 's/^\([0-9]\)/_\1/' -e 's/[^a-zA-Z0-9_]/_/g'`
+ ;;
+ * )
+ func_tr_sh_result=$1
+ ;;
+ esac
+}
+
+
+# func_verbose ARG...
+# -------------------
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $debug_cmd
+
+ $opt_verbose && func_echo "$*"
+
+ :
+}
+
+
+# func_warn_and_continue ARG...
+# -----------------------------
+# Echo program name prefixed warning message to standard error.
+func_warn_and_continue ()
+{
+ $debug_cmd
+
+ $require_term_colors
+
+ func_echo_infix_1 "${tc_red}warning$tc_reset" "$*" >&2
+}
+
+
+# func_warning CATEGORY ARG...
+# ----------------------------
+# Echo program name prefixed warning message to standard error. Warning
+# messages can be filtered according to CATEGORY, where this function
+# elides messages where CATEGORY is not listed in the global variable
+# 'opt_warning_types'.
+func_warning ()
+{
+ $debug_cmd
+
+ # CATEGORY must be in the warning_categories list!
+ case " $warning_categories " in
+ *" $1 "*) ;;
+ *) func_internal_error "invalid warning category '$1'" ;;
+ esac
+
+ _G_category=$1
+ shift
+
+ case " $opt_warning_types " in
+ *" $_G_category "*) $warning_func ${1+"$@"} ;;
+ esac
+}
+
+
+# func_sort_ver VER1 VER2
+# -----------------------
+# 'sort -V' is not generally available.
+# Note this deviates from the version comparison in automake
+# in that it treats 1.5 < 1.5.0, and treats 1.4.4a < 1.4-p3a
+# but this should suffice as we won't be specifying old
+# version formats or redundant trailing .0 in bootstrap.conf.
+# If we did want full compatibility then we should probably
+# use m4_version_compare from autoconf.
+func_sort_ver ()
+{
+ $debug_cmd
+
+ printf '%s\n%s\n' "$1" "$2" \
+ | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n
+}
+
+# func_lt_ver PREV CURR
+# ---------------------
+# Return true if PREV and CURR are in the correct order according to
+# func_sort_ver, otherwise false. Use it like this:
+#
+# func_lt_ver "$prev_ver" "$proposed_ver" || func_fatal_error "..."
+func_lt_ver ()
+{
+ $debug_cmd
+
+ test "x$1" = x`func_sort_ver "$1" "$2" | $SED 1q`
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+#! /bin/sh
+
+# Set a version string for this script.
+scriptversion=2015-10-07.11; # UTC
+
+# A portable, pluggable option parser for Bourne shell.
+# Written by Gary V. Vaughan, 2010
+
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary@gnu.org.
+
+
+## ------ ##
+## Usage. ##
+## ------ ##
+
+# This file is a library for parsing options in your shell scripts along
+# with assorted other useful supporting features that you can make use
+# of too.
+#
+# For the simplest scripts you might need only:
+#
+# #!/bin/sh
+# . relative/path/to/funclib.sh
+# . relative/path/to/options-parser
+# scriptversion=1.0
+# func_options ${1+"$@"}
+# eval set dummy "$func_options_result"; shift
+# ...rest of your script...
+#
+# In order for the '--version' option to work, you will need to have a
+# suitably formatted comment like the one at the top of this file
+# starting with '# Written by ' and ending with '# warranty; '.
+#
+# For '-h' and '--help' to work, you will also need a one line
+# description of your script's purpose in a comment directly above the
+# '# Written by ' line, like the one at the top of this file.
+#
+# The default options also support '--debug', which will turn on shell
+# execution tracing (see the comment above debug_cmd below for another
+# use), and '--verbose' and the func_verbose function to allow your script
+# to display verbose messages only when your user has specified
+# '--verbose'.
+#
+# After sourcing this file, you can plug processing for additional
+# options by amending the variables from the 'Configuration' section
+# below, and following the instructions in the 'Option parsing'
+# section further down.
+
+## -------------- ##
+## Configuration. ##
+## -------------- ##
+
+# You should override these variables in your script after sourcing this
+# file so that they reflect the customisations you have added to the
+# option parser.
+
+# The usage line for option parsing errors and the start of '-h' and
+# '--help' output messages. You can embed shell variables for delayed
+# expansion at the time the message is displayed, but you will need to
+# quote other shell meta-characters carefully to prevent them being
+# expanded when the contents are evaled.
+usage='$progpath [OPTION]...'
+
+# Short help message in response to '-h' and '--help'. Add to this or
+# override it after sourcing this library to reflect the full set of
+# options your script accepts.
+usage_message="\
+ --debug enable verbose shell tracing
+ -W, --warnings=CATEGORY
+ report the warnings falling in CATEGORY [all]
+ -v, --verbose verbosely report processing
+ --version print version information and exit
+ -h, --help print short or long help message and exit
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+long_help_message="
+Warning categories include:
+ 'all' show all warnings
+ 'none' turn off all the warnings
+ 'error' warnings are treated as fatal errors"
+
+# Help message printed before fatal option parsing errors.
+fatal_help="Try '\$progname --help' for more information."
+
+
+
+## ------------------------- ##
+## Hook function management. ##
+## ------------------------- ##
+
+# This section contains functions for adding, removing, and running hooks
+# to the main code. A hook is just a named list of of function, that can
+# be run in order later on.
+
+# func_hookable FUNC_NAME
+# -----------------------
+# Declare that FUNC_NAME will run hooks added with
+# 'func_add_hook FUNC_NAME ...'.
+func_hookable ()
+{
+ $debug_cmd
+
+ func_append hookable_fns " $1"
+}
+
+
+# func_add_hook FUNC_NAME HOOK_FUNC
+# ---------------------------------
+# Request that FUNC_NAME call HOOK_FUNC before it returns. FUNC_NAME must
+# first have been declared "hookable" by a call to 'func_hookable'.
+func_add_hook ()
+{
+ $debug_cmd
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not accept hook functions." ;;
+ esac
+
+ eval func_append ${1}_hooks '" $2"'
+}
+
+
+# func_remove_hook FUNC_NAME HOOK_FUNC
+# ------------------------------------
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
+func_remove_hook ()
+{
+ $debug_cmd
+
+ eval ${1}_hooks='`$ECHO "\$'$1'_hooks" |$SED "s| '$2'||"`'
+}
+
+
+# func_run_hooks FUNC_NAME [ARG]...
+# ---------------------------------
+# Run all hook functions registered to FUNC_NAME.
+# It is assumed that the list of hook functions contains nothing more
+# than a whitespace-delimited list of legal shell function names, and
+# no effort is wasted trying to catch shell meta-characters or preserve
+# whitespace.
+func_run_hooks ()
+{
+ $debug_cmd
+
+ _G_rc_run_hooks=false
+
+ case " $hookable_fns " in
+ *" $1 "*) ;;
+ *) func_fatal_error "'$1' does not support hook funcions.n" ;;
+ esac
+
+ eval _G_hook_fns=\$$1_hooks; shift
+
+ for _G_hook in $_G_hook_fns; do
+ if eval $_G_hook '"$@"'; then
+ # store returned options list back into positional
+ # parameters for next 'cmd' execution.
+ eval _G_hook_result=\$${_G_hook}_result
+ eval set dummy "$_G_hook_result"; shift
+ _G_rc_run_hooks=:
+ fi
+ done
+
+ $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result
+}
+
+
+
+## --------------- ##
+## Option parsing. ##
+## --------------- ##
+
+# In order to add your own option parsing hooks, you must accept the
+# full positional parameter list in your hook function, you may remove/edit
+# any options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'. In this case you also must return $EXIT_SUCCESS to let the
+# hook's caller know that it should pay attention to
+# '<hooked_function_name>_result'. Returning $EXIT_FAILURE signalizes that
+# arguments are left untouched by the hook and therefore caller will ignore the
+# result variable.
+#
+# Like this:
+#
+# my_options_prep ()
+# {
+# $debug_cmd
+#
+# # Extend the existing usage message.
+# usage_message=$usage_message'
+# -s, --silent don'\''t print informational messages
+# '
+# # No change in '$@' (ignored completely by this hook). There is
+# # no need to do the equivalent (but slower) action:
+# # func_quote_for_eval ${1+"$@"}
+# # my_options_prep_result=$func_quote_for_eval_result
+# false
+# }
+# func_add_hook func_options_prep my_options_prep
+#
+#
+# my_silent_option ()
+# {
+# $debug_cmd
+#
+# args_changed=false
+#
+# # Note that for efficiency, we parse as many options as we can
+# # recognise in a loop before passing the remainder back to the
+# # caller on the first unrecognised argument we encounter.
+# while test $# -gt 0; do
+# opt=$1; shift
+# case $opt in
+# --silent|-s) opt_silent=:
+# args_changed=:
+# ;;
+# # Separate non-argument short options:
+# -s*) func_split_short_opt "$_G_opt"
+# set dummy "$func_split_short_opt_name" \
+# "-$func_split_short_opt_arg" ${1+"$@"}
+# shift
+# args_changed=:
+# ;;
+# *) # Make sure the first unrecognised option "$_G_opt"
+# # is added back to "$@", we could need that later
+# # if $args_changed is true.
+# set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
+# esac
+# done
+#
+# if $args_changed; then
+# func_quote_for_eval ${1+"$@"}
+# my_silent_option_result=$func_quote_for_eval_result
+# fi
+#
+# $args_changed
+# }
+# func_add_hook func_parse_options my_silent_option
+#
+#
+# my_option_validation ()
+# {
+# $debug_cmd
+#
+# $opt_silent && $opt_verbose && func_fatal_help "\
+# '--silent' and '--verbose' options are mutually exclusive."
+#
+# false
+# }
+# func_add_hook func_validate_options my_option_validation
+#
+# You'll also need to manually amend $usage_message to reflect the extra
+# options you parse. It's preferable to append if you can, so that
+# multiple option parsing hooks can be added safely.
+
+
+# func_options_finish [ARG]...
+# ----------------------------
+# Finishing the option parse loop (call 'func_options' hooks ATM).
+func_options_finish ()
+{
+ $debug_cmd
+
+ _G_func_options_finish_exit=false
+ if func_run_hooks func_options ${1+"$@"}; then
+ func_options_finish_result=$func_run_hooks_result
+ _G_func_options_finish_exit=:
+ fi
+
+ $_G_func_options_finish_exit
+}
+
+
+# func_options [ARG]...
+# ---------------------
+# All the functions called inside func_options are hookable. See the
+# individual implementations for details.
+func_hookable func_options
+func_options ()
+{
+ $debug_cmd
+
+ _G_rc_options=false
+
+ for my_func in options_prep parse_options validate_options options_finish
+ do
+ if eval func_$my_func '${1+"$@"}'; then
+ eval _G_res_var='$'"func_${my_func}_result"
+ eval set dummy "$_G_res_var" ; shift
+ _G_rc_options=:
+ fi
+ done
+
+ # Save modified positional parameters for caller. As a top-level
+ # options-parser function we always need to set the 'func_options_result'
+ # variable (regardless the $_G_rc_options value).
+ if $_G_rc_options; then
+ func_options_result=$_G_res_var
+ else
+ func_quote_for_eval ${1+"$@"}
+ func_options_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_options
+}
+
+
+# func_options_prep [ARG]...
+# --------------------------
+# All initialisations required before starting the option parse loop.
+# Note that when calling hook functions, we pass through the list of
+# positional parameters. If a hook function modifies that list, and
+# needs to propagate that back to rest of this script, then the complete
+# modified list must be put in 'func_run_hooks_result' before
+# returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned).
+func_hookable func_options_prep
+func_options_prep ()
+{
+ $debug_cmd
+
+ # Option defaults:
+ opt_verbose=false
+ opt_warning_types=
+
+ _G_rc_options_prep=false
+ if func_run_hooks func_options_prep ${1+"$@"}; then
+ _G_rc_options_prep=:
+ # save modified positional parameters for caller
+ func_options_prep_result=$func_run_hooks_result
+ fi
+
+ $_G_rc_options_prep
+}
+
+
+# func_parse_options [ARG]...
+# ---------------------------
+# The main option parsing loop.
+func_hookable func_parse_options
+func_parse_options ()
+{
+ $debug_cmd
+
+ func_parse_options_result=
+
+ _G_rc_parse_options=false
+ # this just eases exit handling
+ while test $# -gt 0; do
+ # Defer to hook functions for initial option parsing, so they
+ # get priority in the event of reusing an option name.
+ if func_run_hooks func_parse_options ${1+"$@"}; then
+ eval set dummy "$func_run_hooks_result"; shift
+ _G_rc_parse_options=:
+ fi
+
+ # Break out of the loop if we already parsed every option.
+ test $# -gt 0 || break
+
+ _G_match_parse_options=:
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --debug|-x) debug_cmd='set -x'
+ func_echo "enabling shell trace mode"
+ $debug_cmd
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ set dummy --warnings none ${1+"$@"}
+ shift
+ ;;
+
+ --warnings|--warning|-W)
+ if test $# = 0 && func_missing_arg $_G_opt; then
+ _G_rc_parse_options=:
+ break
+ fi
+ case " $warning_categories $1" in
+ *" $1 "*)
+ # trailing space prevents matching last $1 above
+ func_append_uniq opt_warning_types " $1"
+ ;;
+ *all)
+ opt_warning_types=$warning_categories
+ ;;
+ *none)
+ opt_warning_types=none
+ warning_func=:
+ ;;
+ *error)
+ opt_warning_types=$warning_categories
+ warning_func=func_fatal_error
+ ;;
+ *)
+ func_fatal_error \
+ "unsupported warning category: '$1'"
+ ;;
+ esac
+ shift
+ ;;
+
+ --verbose|-v) opt_verbose=: ;;
+ --version) func_version ;;
+ -\?|-h) func_usage ;;
+ --help) func_help ;;
+
+ # Separate optargs to long options (plugins may need this):
+ --*=*) func_split_equals "$_G_opt"
+ set dummy "$func_split_equals_lhs" \
+ "$func_split_equals_rhs" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate optargs to short options:
+ -W*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate non-argument short options:
+ -\?*|-h*|-v*|-x*)
+ func_split_short_opt "$_G_opt"
+ set dummy "$func_split_short_opt_name" \
+ "-$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ --) _G_rc_parse_options=: ; break ;;
+ -*) func_fatal_help "unrecognised option: '$_G_opt'" ;;
+ *) set dummy "$_G_opt" ${1+"$@"}; shift
+ _G_match_parse_options=false
+ break
+ ;;
+ esac
+
+ $_G_match_parse_options && _G_rc_parse_options=:
+ done
+
+
+ if $_G_rc_parse_options; then
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ func_parse_options_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_parse_options
+}
+
+
+# func_validate_options [ARG]...
+# ------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+func_hookable func_validate_options
+func_validate_options ()
+{
+ $debug_cmd
+
+ _G_rc_validate_options=false
+
+ # Display all warnings if -W was not given.
+ test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
+
+ if func_run_hooks func_validate_options ${1+"$@"}; then
+ # save modified positional parameters for caller
+ func_validate_options_result=$func_run_hooks_result
+ _G_rc_validate_options=:
+ fi
+
+ # Bail if the options were screwed!
+ $exit_cmd $EXIT_FAILURE
+
+ $_G_rc_validate_options
+}
+
+
+
+## ----------------- ##
+## Helper functions. ##
+## ----------------- ##
+
+# This section contains the helper functions used by the rest of the
+# hookable option parser framework in ascii-betical order.
+
+
+# func_fatal_help ARG...
+# ----------------------
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ $debug_cmd
+
+ eval \$ECHO \""Usage: $usage"\"
+ eval \$ECHO \""$fatal_help"\"
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+
+# func_help
+# ---------
+# Echo long help message to standard output and exit.
+func_help ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message"
+ exit 0
+}
+
+
+# func_missing_arg ARGNAME
+# ------------------------
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ $debug_cmd
+
+ func_error "Missing argument for '$1'."
+ exit_cmd=exit
+}
+
+
+# func_split_equals STRING
+# ------------------------
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
+test -z "$_G_HAVE_XSI_OPS" \
+ && (eval 'x=a/b/c;
+ test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
+ && _G_HAVE_XSI_OPS=yes
+
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=${1%%=*}
+ func_split_equals_rhs=${1#*=}
+ test "x$func_split_equals_lhs" = "x$1" \
+ && func_split_equals_rhs=
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_equals ()
+ {
+ $debug_cmd
+
+ func_split_equals_lhs=`expr "x$1" : 'x\([^=]*\)'`
+ func_split_equals_rhs=
+ test "x$func_split_equals_lhs" = "x$1" \
+ || func_split_equals_rhs=`expr "x$1" : 'x[^=]*=\(.*\)$'`
+ }
+fi #func_split_equals
+
+
+# func_split_short_opt SHORTOPT
+# -----------------------------
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+if test yes = "$_G_HAVE_XSI_OPS"
+then
+ # This is an XSI compatible shell, allowing a faster implementation...
+ eval 'func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_arg=${1#??}
+ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}
+ }'
+else
+ # ...otherwise fall back to using expr, which is often a shell builtin.
+ func_split_short_opt ()
+ {
+ $debug_cmd
+
+ func_split_short_opt_name=`expr "x$1" : 'x-\(.\)'`
+ func_split_short_opt_arg=`expr "x$1" : 'x-.\(.*\)$'`
+ }
+fi #func_split_short_opt
+
+
+# func_usage
+# ----------
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "Run '$progname --help |${PAGER-more}' for full usage"
+ exit 0
+}
+
+
+# func_usage_message
+# ------------------
+# Echo short help message to standard output.
+func_usage_message ()
+{
+ $debug_cmd
+
+ eval \$ECHO \""Usage: $usage"\"
+ echo
+ $SED -n 's|^# ||
+ /^Written by/{
+ x;p;x
+ }
+ h
+ /^Written by/q' < "$progpath"
+ echo
+ eval \$ECHO \""$usage_message"\"
+}
+
+
+# func_version
+# ------------
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $debug_cmd
+
+ printf '%s\n' "$progname $scriptversion"
+ $SED -n '
+ /(C)/!b go
+ :more
+ /\./!{
+ N
+ s|\n# | |
+ b more
+ }
+ :go
+ /^# Written by /,/# warranty; / {
+ s|^# ||
+ s|^# *$||
+ s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+ p
+ }
+ /^# Written by / {
+ s|^# ||
+ p
+ }
+ /^warranty; /q' < "$progpath"
+
+ exit $?
+}
+
+
+# Local variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-time-zone: "UTC"
+# End:
+
+# Set a version string.
+scriptversion='(GNU libtool) 2.4.6'
+
+
+# func_echo ARG...
+# ----------------
+# Libtool also displays the current mode in messages, so override
+# funclib.sh func_echo with this custom definition.
+func_echo ()
+{
+ $debug_cmd
+
+ _G_message=$*
+
+ func_echo_IFS=$IFS
+ IFS=$nl
+ for _G_line in $_G_message; do
+ IFS=$func_echo_IFS
+ $ECHO "$progname${opt_mode+: $opt_mode}: $_G_line"
+ done
+ IFS=$func_echo_IFS
+}
+
+
+# func_warning ARG...
+# -------------------
+# Libtool warnings are not categorized, so override funclib.sh
+# func_warning with this simpler definition.
+func_warning ()
+{
+ $debug_cmd
+
+ $warning_func ${1+"$@"}
+}
+
+
+## ---------------- ##
+## Options parsing. ##
+## ---------------- ##
+
+# Hook in the functions to make sure our own options are parsed during
+# the option parsing loop.
+
+usage='$progpath [OPTION]... [MODE-ARG]...'
+
+# Short help message in response to '-h'.
+usage_message="Options:
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+ -n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --mode=MODE use operation mode MODE
+ --no-warnings equivalent to '-Wnone'
+ --preserve-dup-deps don't remove duplicate dependency libraries
+ --quiet, --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ -v, --verbose print more informational messages than default
+ --version print version information
+ -W, --warnings=CATEGORY report the warnings falling in CATEGORY [all]
+ -h, --help, --help-all print short, long, or detailed help message
+"
+
+# Additional text appended to 'usage_message' in response to '--help'.
+func_help ()
+{
+ $debug_cmd
+
+ func_usage_message
+ $ECHO "$long_help_message
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. When passed as first option,
+'--mode=MODE' may be abbreviated as 'MODE' or a unique abbreviation of that.
+Try '$progname --help --mode=MODE' for a more detailed description of MODE.
+
+When reporting a bug, please describe a test case to reproduce it and
+include the following information:
+
+ host-triplet: $host
+ shell: $SHELL
+ compiler: $LTCC
+ compiler flags: $LTCFLAGS
+ linker: $LD (gnu? $with_gnu_ld)
+ version: $progname $scriptversion Debian-2.4.6-15
+ automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
+ autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q`
+
+Report bugs to <bug-libtool@gnu.org>.
+GNU libtool home page: <http://www.gnu.org/s/libtool/>.
+General help using GNU software: <http://www.gnu.org/gethelp/>."
+ exit 0
+}
+
+
+# func_lo2o OBJECT-NAME
+# ---------------------
+# Transform OBJECT-NAME from a '.lo' suffix to the platform specific
+# object suffix.
+
+lo2o=s/\\.lo\$/.$objext/
+o2lo=s/\\.$objext\$/.lo/
+
+if test yes = "$_G_HAVE_XSI_OPS"; then
+ eval 'func_lo2o ()
+ {
+ case $1 in
+ *.lo) func_lo2o_result=${1%.lo}.$objext ;;
+ * ) func_lo2o_result=$1 ;;
+ esac
+ }'
+
+ # func_xform LIBOBJ-OR-SOURCE
+ # ---------------------------
+ # Transform LIBOBJ-OR-SOURCE from a '.o' or '.c' (or otherwise)
+ # suffix to a '.lo' libtool-object suffix.
+ eval 'func_xform ()
+ {
+ func_xform_result=${1%.*}.lo
+ }'
+else
+ # ...otherwise fall back to using sed.
+ func_lo2o ()
+ {
+ func_lo2o_result=`$ECHO "$1" | $SED "$lo2o"`
+ }
+
+ func_xform ()
+ {
+ func_xform_result=`$ECHO "$1" | $SED 's|\.[^.]*$|.lo|'`
+ }
+fi
+
+
+# func_fatal_configuration ARG...
+# -------------------------------
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func__fatal_error ${1+"$@"} \
+ "See the $PACKAGE documentation for more information." \
+ "Fatal configuration error."
+}
+
+
+# func_config
+# -----------
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+
+# func_features
+# -------------
+# Display the features supported by this script.
+func_features ()
+{
+ echo "host: $host"
+ if test yes = "$build_libtool_libs"; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test yes = "$build_old_libs"; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+
+ exit $?
+}
+
+
+# func_enable_tag TAGNAME
+# -----------------------
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname=$1
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf=/$re_begincf/,/$re_endcf/p
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+
+# func_check_version_match
+# ------------------------
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+# libtool_options_prep [ARG]...
+# -----------------------------
+# Preparation for options parsed by libtool.
+libtool_options_prep ()
+{
+ $debug_mode
+
+ # Option defaults:
+ opt_config=false
+ opt_dlopen=
+ opt_dry_run=false
+ opt_help=false
+ opt_mode=
+ opt_preserve_dup_deps=false
+ opt_quiet=false
+
+ nonopt=
+ preserve_args=
+
+ _G_rc_lt_options_prep=:
+
+ # Shorthand for --mode=foo, only valid as the first argument
+ case $1 in
+ clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+ compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+ execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+ finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+ link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+ *)
+ _G_rc_lt_options_prep=false
+ ;;
+ esac
+
+ if $_G_rc_lt_options_prep; then
+ # Pass back the list of options.
+ func_quote_for_eval ${1+"$@"}
+ libtool_options_prep_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_lt_options_prep
+}
+func_add_hook func_options_prep libtool_options_prep
+
+
+# libtool_parse_options [ARG]...
+# ---------------------------------
+# Provide handling for libtool specific options.
+libtool_parse_options ()
+{
+ $debug_cmd
+
+ _G_rc_lt_parse_options=false
+
+ # Perform our own loop to consume as many options as possible in
+ # each iteration.
+ while test $# -gt 0; do
+ _G_match_lt_parse_options=:
+ _G_opt=$1
+ shift
+ case $_G_opt in
+ --dry-run|--dryrun|-n)
+ opt_dry_run=:
+ ;;
+
+ --config) func_config ;;
+
+ --dlopen|-dlopen)
+ opt_dlopen="${opt_dlopen+$opt_dlopen
+}$1"
+ shift
+ ;;
+
+ --preserve-dup-deps)
+ opt_preserve_dup_deps=: ;;
+
+ --features) func_features ;;
+
+ --finish) set dummy --mode finish ${1+"$@"}; shift ;;
+
+ --help) opt_help=: ;;
+
+ --help-all) opt_help=': help-all' ;;
+
+ --mode) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_mode=$1
+ case $1 in
+ # Valid mode arguments:
+ clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $_G_opt"
+ exit_cmd=exit
+ break
+ ;;
+ esac
+ shift
+ ;;
+
+ --no-silent|--no-quiet)
+ opt_quiet=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-warnings|--no-warning|--no-warn)
+ opt_warning=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --no-verbose)
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --silent|--quiet)
+ opt_quiet=:
+ opt_verbose=false
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ --tag) test $# = 0 && func_missing_arg $_G_opt && break
+ opt_tag=$1
+ func_append preserve_args " $_G_opt $1"
+ func_enable_tag "$1"
+ shift
+ ;;
+
+ --verbose|-v) opt_quiet=false
+ opt_verbose=:
+ func_append preserve_args " $_G_opt"
+ ;;
+
+ # An option not handled by this hook function:
+ *) set dummy "$_G_opt" ${1+"$@"} ; shift
+ _G_match_lt_parse_options=false
+ break
+ ;;
+ esac
+ $_G_match_lt_parse_options && _G_rc_lt_parse_options=:
+ done
+
+ if $_G_rc_lt_parse_options; then
+ # save modified positional parameters for caller
+ func_quote_for_eval ${1+"$@"}
+ libtool_parse_options_result=$func_quote_for_eval_result
+ fi
+
+ $_G_rc_lt_parse_options
+}
+func_add_hook func_parse_options libtool_parse_options
+
+
+
+# libtool_validate_options [ARG]...
+# ---------------------------------
+# Perform any sanity checks on option settings and/or unconsumed
+# arguments.
+libtool_validate_options ()
+{
+ # save first non-option argument
+ if test 0 -lt $#; then
+ nonopt=$1
+ shift
+ fi
+
+ # preserve --debug
+ test : = "$debug_cmd" || func_append preserve_args " --debug"
+
+ case $host in
+ # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
+ # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
+ *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+ ;;
+ esac
+
+ $opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ test yes != "$build_libtool_libs" \
+ && test yes != "$build_old_libs" \
+ && func_fatal_configuration "not configured to build any kind of library"
+
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$opt_dlopen" && test execute != "$opt_mode"; then
+ func_error "unrecognized option '-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help=$help
+ help="Try '$progname --help --mode=$opt_mode' for more information."
+ }
+
+ # Pass back the unparsed argument list
+ func_quote_for_eval ${1+"$@"}
+ libtool_validate_options_result=$func_quote_for_eval_result
+}
+func_add_hook func_validate_options libtool_validate_options
+
+
+# Process options as early as possible so that --help and --version
+# can return quickly.
+func_options ${1+"$@"}
+eval set dummy "$func_options_result"; shift
+
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+magic='%%%MAGIC variable%%%'
+magic_exe='%%%MAGIC EXE variable%%%'
+
+# Global variables.
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# func_generated_by_libtool
+# True iff stdin has been generated by Libtool. This function is only
+# a basic sanity check; it will hardly flush out determined imposters.
+func_generated_by_libtool_p ()
+{
+ $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool '.la' library or '.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if 'file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case $lalib_p_line in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test yes = "$lalib_p"
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ test -f "$1" &&
+ $lt_truncate_bin < "$1" 2>/dev/null | func_generated_by_libtool_p
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result=$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $debug_cmd
+
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$sp$nl
+ eval cmd=\"$cmd\"
+ IFS=$save_ifs
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# 'FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $debug_cmd
+
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot. Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+ func_resolve_sysroot_result=$1
+ case $func_resolve_sysroot_result in
+ =*)
+ func_stripname '=' '' "$func_resolve_sysroot_result"
+ func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+ ;;
+ esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+ case $lt_sysroot:$1 in
+ ?*:"$lt_sysroot"*)
+ func_stripname "$lt_sysroot" '' "$1"
+ func_replace_sysroot_result='='$func_stripname_result
+ ;;
+ *)
+ # Including no sysroot.
+ func_replace_sysroot_result=$1
+ ;;
+ esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $debug_cmd
+
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`$SED -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case "$@ " in
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with '--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=$1
+ if test yes = "$build_libtool_libs"; then
+ write_lobj=\'$2\'
+ else
+ write_lobj=none
+ fi
+
+ if test yes = "$build_old_libs"; then
+ write_oldobj=\'$3\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "$write_libobj"
+ }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+ $debug_cmd
+
+ func_convert_core_file_wine_to_w32_result=$1
+ if test -n "$1"; then
+ # Unfortunately, winepath does not exit with a non-zero error code, so we
+ # are forced to check the contents of stdout. On the other hand, if the
+ # command is not found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both error code of
+ # zero AND non-empty stdout, which explains the odd construction:
+ func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "$func_convert_core_file_wine_to_w32_tmp"; then
+ func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+ $SED -e "$sed_naive_backslashify"`
+ else
+ func_convert_core_file_wine_to_w32_result=
+ fi
+ fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+ $debug_cmd
+
+ # unfortunately, winepath doesn't convert paths, only file names
+ func_convert_core_path_wine_to_w32_result=
+ if test -n "$1"; then
+ oldIFS=$IFS
+ IFS=:
+ for func_convert_core_path_wine_to_w32_f in $1; do
+ IFS=$oldIFS
+ func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+ if test -n "$func_convert_core_file_wine_to_w32_result"; then
+ if test -z "$func_convert_core_path_wine_to_w32_result"; then
+ func_convert_core_path_wine_to_w32_result=$func_convert_core_file_wine_to_w32_result
+ else
+ func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+ fi
+ fi
+ done
+ IFS=$oldIFS
+ fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+ $debug_cmd
+
+ if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+ func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+ if test "$?" -ne 0; then
+ # on failure, ensure result is empty
+ func_cygpath_result=
+ fi
+ else
+ func_cygpath_result=
+ func_error "LT_CYGPATH is empty or specifies non-existent file: '$LT_CYGPATH'"
+ fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format. Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+ $debug_cmd
+
+ # awkward: cmd appends spaces to result
+ func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+ $debug_cmd
+
+ if test -z "$2" && test -n "$1"; then
+ func_error "Could not determine host file name corresponding to"
+ func_error " '$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_file_result=$1
+ fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+ $debug_cmd
+
+ if test -z "$4" && test -n "$3"; then
+ func_error "Could not determine the host path corresponding to"
+ func_error " '$3'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This is a deliberately simplistic "conversion" and
+ # should not be "improved". See libtool.info.
+ if test "x$1" != "x$2"; then
+ lt_replace_pathsep_chars="s|$1|$2|g"
+ func_to_host_path_result=`echo "$3" |
+ $SED -e "$lt_replace_pathsep_chars"`
+ else
+ func_to_host_path_result=$3
+ fi
+ fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+ $debug_cmd
+
+ case $4 in
+ $1 ) func_to_host_path_result=$3$func_to_host_path_result
+ ;;
+ esac
+ case $4 in
+ $2 ) func_append func_to_host_path_result "$3"
+ ;;
+ esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via '$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+ $debug_cmd
+
+ $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result. If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+ $debug_cmd
+
+ case ,$2, in
+ *,"$to_tool_file_cmd",*)
+ func_to_tool_file_result=$1
+ ;;
+ *)
+ $to_tool_file_cmd "$1"
+ func_to_tool_file_result=$func_to_host_file_result
+ ;;
+ esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+ func_to_host_file_result=$1
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_to_host_file_result=$func_convert_core_msys_to_w32_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+ # LT_CYGPATH in this case.
+ func_to_host_file_result=`cygpath -m "$1"`
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format. Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_file_wine_to_w32 "$1"
+ func_to_host_file_result=$func_convert_core_file_wine_to_w32_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_msys_to_w32_result"
+ func_to_host_file_result=$func_cygpath_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set. Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_file_result=$1
+ if test -n "$1"; then
+ # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+ func_convert_core_file_wine_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+ func_to_host_file_result=$func_cygpath_result
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via '$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format. If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+# file name conversion function : func_convert_file_X_to_Y ()
+# path conversion function : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same. If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+ $debug_cmd
+
+ if test -z "$to_host_path_cmd"; then
+ func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+ to_host_path_cmd=func_convert_path_$func_stripname_result
+ fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+ $debug_cmd
+
+ func_init_to_host_path_cmd
+ $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+ func_to_host_path_result=$1
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from ARG. MSYS
+ # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+ # and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result=$func_convert_core_msys_to_w32_result
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format. Requires a wine environment and
+# a working winepath. Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result=$func_convert_core_path_wine_to_w32_result
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+ func_to_host_path_result=$func_cygpath_result
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set. Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+ $debug_cmd
+
+ func_to_host_path_result=$1
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+ func_to_host_path_result=$func_cygpath_result
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_dll_def_p FILE
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with _LT_DLL_DEF_P in libtool.m4
+func_dll_def_p ()
+{
+ $debug_cmd
+
+ func_dll_def_p_tmp=`$SED -n \
+ -e 's/^[ ]*//' \
+ -e '/^\(;.*\)*$/d' \
+ -e 's/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p' \
+ -e q \
+ "$1"`
+ test DEF = "$func_dll_def_p_tmp"
+}
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $debug_cmd
+
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile=$nonopt # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg=$arg
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj=$arg
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify '-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ func_append pie_flag " $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ func_append later " $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs=$IFS; IFS=,
+ for arg in $args; do
+ IFS=$save_ifs
+ func_append_quoted lastarg "$arg"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ func_append base_compile " $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg=$srcfile
+ srcfile=$arg
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_append_quoted base_compile "$lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with '-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj=$func_basename_result
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from '$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test yes = "$build_libtool_libs" \
+ || func_fatal_configuration "cannot build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name '$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname=$func_basename_result
+ xdir=$func_dirname_result
+ lobj=$xdir$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test yes = "$build_old_libs"; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test no = "$pic_mode" && test pass_all != "$deplibs_check_method"; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test no = "$compiler_c_o"; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.$objext
+ lockfile=$output_obj.lock
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test yes = "$need_locks"; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test warn = "$need_locks"; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ func_append removelist " $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ func_append removelist " $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+ srcfile=$func_to_tool_file_result
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test yes = "$build_libtool_libs"; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test no != "$pic_mode"; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ func_append command " -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test warn = "$need_locks" &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test yes = "$suppress_opt"; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test yes = "$build_old_libs"; then
+ if test yes != "$pic_mode"; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test yes = "$compiler_c_o"; then
+ func_append command " -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ func_append command "$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test warn = "$need_locks" &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support '-c' and '-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test no != "$need_locks"; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+ test compile = "$opt_mode" && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $opt_mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to build PIC objects only
+ -prefer-non-pic try to build non-PIC objects only
+ -shared do not build a '.o' file suitable for static linking
+ -static only build a '.o' file suitable for static linking
+ -Wc,FLAG pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a 'standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix '.c' with the
+library object suffix, '.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to '-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the '--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the 'install' or 'cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -bindir BINDIR specify path to binaries directory (for systems where
+ libraries must be found in the PATH setting at runtime)
+ -dlopen FILE '-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE use a list of object files found in FILE to specify objects
+ -os2dllname NAME force a short DLL name on OS/2 (no effect on other OSes)
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+ -Wc,FLAG
+ -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wl,FLAG
+ -Xlinker FLAG pass linker-specific FLAG directly to the linker
+ -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with '-') are ignored.
+
+Every other argument is treated as a filename. Files ending in '.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in '.la', then a libtool library is created,
+only library objects ('.lo' files) may be specified, and '-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in '.a' or '.lib', then a standard library is created
+using 'ar' and 'ranlib', or on Windows using 'lib'.
+
+If OUTPUT-FILE ends in '.lo' or '.$objext', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically '/bin/rm'). RM-OPTIONS are options (such as '-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode '$opt_mode'"
+ ;;
+ esac
+
+ echo
+ $ECHO "Try '$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+ if test : = "$opt_help"; then
+ func_mode_help
+ else
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ func_mode_help
+ done
+ } | $SED -n '1p; 2,$s/^Usage:/ or: /p'
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ echo
+ func_mode_help
+ done
+ } |
+ $SED '1d
+ /^When reporting/,/^Report/{
+ H
+ d
+ }
+ $x
+ /information about other modes/d
+ /more detailed .*MODE/d
+ s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+ fi
+ exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $debug_cmd
+
+ # The first argument is the command name.
+ cmd=$nonopt
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $opt_dlopen; do
+ test -f "$file" \
+ || func_fatal_help "'$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "'$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "'$file' was not linked with '-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+
+ if test -f "$dir/$objdir/$dlname"; then
+ func_append dir "/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find '$dlname' in '$dir' or '$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+ ;;
+
+ *)
+ func_warning "'-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir=$absdir
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic=$magic
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -* | *.la | *.lo ) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file=$progdir/$program
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file=$progdir/$program
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_append_quoted args "$file"
+ done
+
+ if $opt_dry_run; then
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ else
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd=\$cmd$args
+ fi
+}
+
+test execute = "$opt_mode" && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $debug_cmd
+
+ libs=
+ libdirs=
+ admincmds=
+
+ for opt in "$nonopt" ${1+"$@"}
+ do
+ if test -d "$opt"; then
+ func_append libdirs " $opt"
+
+ elif test -f "$opt"; then
+ if func_lalib_unsafe_p "$opt"; then
+ func_append libs " $opt"
+ else
+ func_warning "'$opt' is not a valid libtool archive"
+ fi
+
+ else
+ func_fatal_error "invalid argument '$opt'"
+ fi
+ done
+
+ if test -n "$libs"; then
+ if test -n "$lt_sysroot"; then
+ sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+ sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+ else
+ sysroot_cmd=
+ fi
+
+ # Remove sysroot references
+ if $opt_dry_run; then
+ for lib in $libs; do
+ echo "removing references to $lt_sysroot and '=' prefixes from $lib"
+ done
+ else
+ tmpdir=`func_mktempdir`
+ for lib in $libs; do
+ $SED -e "$sysroot_cmd s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+ > $tmpdir/tmp-la
+ mv -f $tmpdir/tmp-la $lib
+ done
+ ${RM}r "$tmpdir"
+ fi
+ fi
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || func_append admincmds "
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_quiet && exit $EXIT_SUCCESS
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the '-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the '$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the '$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $ECHO " - use the '$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to '/etc/ld.so.conf'"
+ fi
+ echo
+
+ echo "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ echo "pages."
+ ;;
+ *)
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ echo "----------------------------------------------------------------------"
+ fi
+ exit $EXIT_SUCCESS
+}
+
+test finish = "$opt_mode" && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $debug_cmd
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$SHELL" = "$nonopt" || test /bin/sh = "$nonopt" ||
+ # Allow the use of GNU shtool's install command.
+ case $nonopt in *shtool*) :;; *) false;; esac
+ then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ func_append install_prog "$func_quote_for_eval_result"
+ install_shared_prog=$install_prog
+ case " $install_prog " in
+ *[\\\ /]cp\ *) install_cp=: ;;
+ *) install_cp=false ;;
+ esac
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=false
+ stripme=
+ no_mode=:
+ for arg
+ do
+ arg2=
+ if test -n "$dest"; then
+ func_append files " $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=: ;;
+ -f)
+ if $install_cp; then :; else
+ prev=$arg
+ fi
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ if test X-m = "X$prev" && test -n "$install_override_mode"; then
+ arg2=$install_override_mode
+ no_mode=false
+ fi
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ func_append install_prog " $func_quote_for_eval_result"
+ if test -n "$arg2"; then
+ func_quote_for_eval "$arg2"
+ fi
+ func_append install_shared_prog " $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the '$prev' option requires an argument"
+
+ if test -n "$install_override_mode" && $no_mode; then
+ if $install_cp; then :; else
+ func_quote_for_eval "$install_override_mode"
+ func_append install_shared_prog " -m $func_quote_for_eval_result"
+ fi
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=:
+ if $isdir; then
+ destdir=$dest
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir=$func_dirname_result
+ destname=$func_basename_result
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "'$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "'$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic=$magic
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ func_append staticlibs " $file"
+ ;;
+
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "'$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append current_libdirs " $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append future_libdirs " $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir=$func_dirname_result
+ func_append dir "$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install '$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking '$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink '\''$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname=$1
+ shift
+
+ srcname=$realname
+ test -n "$relink_command" && srcname=${realname}T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme=$stripme
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=
+ ;;
+ esac
+ ;;
+ os2*)
+ case $realname in
+ *_dll.a)
+ tstripme=
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try 'ln -sf' first, because the 'ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib=$destdir/$realname
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name=$func_basename_result
+ instname=$dir/${name}i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile=$destdir/$destname
+ else
+ func_basename "$file"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest=$destfile
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to '$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test yes = "$build_old_libs"; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile=$destdir/$destname
+ else
+ func_basename "$file"
+ destfile=$func_basename_result
+ destfile=$destdir/$destfile
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=.exe
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script '$wrapper'"
+
+ finalize=:
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile=$libdir/`$ECHO "$lib" | $SED 's%^.*/%%g'`
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "'$lib' has not been installed in '$libdir'"
+ finalize=false
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test no = "$fast_install" && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if $finalize; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file=$func_basename_result
+ outputname=$tmpdir/$file
+ # Replace the output file specification.
+ relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_quiet || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink '$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file=$outputname
+ else
+ func_warning "cannot relink '$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name=$func_basename_result
+
+ # Set up the ranlib parameters.
+ oldlib=$destdir/$name
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run '$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL "$progpath" $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test install = "$opt_mode" && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $debug_cmd
+
+ my_outputname=$1
+ my_originator=$2
+ my_pic_p=${3-false}
+ my_prefix=`$ECHO "$my_originator" | $SED 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms=${my_outputname}S.c
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist=$output_objdir/$my_outputname.nm
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for '$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined __GNUC__ && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test yes = "$dlself"; then
+ func_verbose "generating symbol list for '$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+ func_verbose "extracting global C symbols from '$func_to_tool_file_result'"
+ $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols=$output_objdir/$outputname.exp
+ $opt_dry_run || {
+ $RM $export_symbols
+ eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ eval "$SED -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from '$dlprefile'"
+ func_basename "$dlprefile"
+ name=$func_basename_result
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ # if an import library, we need to obtain dlname
+ if func_win32_import_lib_p "$dlprefile"; then
+ func_tr_sh "$dlprefile"
+ eval "curr_lafile=\$libfile_$func_tr_sh_result"
+ dlprefile_dlbasename=
+ if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+ # Use subshell, to avoid clobbering current variable values
+ dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+ if test -n "$dlprefile_dlname"; then
+ func_basename "$dlprefile_dlname"
+ dlprefile_dlbasename=$func_basename_result
+ else
+ # no lafile. user explicitly requested -dlpreopen <import library>.
+ $sharedlib_from_linklib_cmd "$dlprefile"
+ dlprefile_dlbasename=$sharedlib_from_linklib_result
+ fi
+ fi
+ $opt_dry_run || {
+ if test -n "$dlprefile_dlbasename"; then
+ eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+ else
+ func_warning "Could not compute DLL name from $name"
+ eval '$ECHO ": $name " >> "$nlist"'
+ fi
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+ $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+ }
+ else # not an import lib
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ fi
+ ;;
+ *)
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ ;;
+ esac
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ func_show_eval '$RM "${nlist}I"'
+ if test -n "$global_symbol_to_import"; then
+ eval "$global_symbol_to_import"' < "$nlist"S > "$nlist"I'
+ fi
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];\
+"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+static void lt_syminit(void)
+{
+ LT_DLSYM_CONST lt_dlsymlist *symbol = lt_${my_prefix}_LTX_preloaded_symbols;
+ for (; symbol->name; ++symbol)
+ {"
+ $SED 's/.*/ if (STREQ (symbol->name, \"&\")) symbol->address = (void *) \&&;/' < "$nlist"I >> "$output_objdir/$my_dlsyms"
+ echo >> "$output_objdir/$my_dlsyms" "\
+ }
+}"
+ fi
+ echo >> "$output_objdir/$my_dlsyms" "\
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{ {\"$my_originator\", (void *) 0},"
+
+ if test -s "$nlist"I; then
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {\"@INIT@\", (void *) &lt_syminit},"
+ fi
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ $my_pic_p && pic_flag_for_symtable=" $pic_flag"
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) func_append symtab_cflags " $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T" "${nlist}I"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj=$output_objdir/${my_outputname}S.$objext
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for '$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+ test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+ $debug_cmd
+
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+ test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+ $debug_cmd
+
+ win32_libid_type=unknown
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+ case $nm_interface in
+ "MS dumpbin")
+ if func_cygming_ms_implib_p "$1" ||
+ func_cygming_gnu_implib_p "$1"
+ then
+ win32_nmres=import
+ else
+ win32_nmres=
+ fi
+ ;;
+ *)
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s|.*|import|
+ p
+ q
+ }
+ }'`
+ ;;
+ esac
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+ $debug_cmd
+
+ sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+ $debug_cmd
+
+ match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+ $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+ $SED '/^Contents of section '"$match_literal"':/{
+ # Place marker at beginning of archive member dllname section
+ s/.*/====MARK====/
+ p
+ d
+ }
+ # These lines can sometimes be longer than 43 characters, but
+ # are always uninteresting
+ /:[ ]*file format pe[i]\{,1\}-/d
+ /^In archive [^:]*:/d
+ # Ensure marker is printed
+ /^====MARK====/p
+ # Remove all lines with less than 43 characters
+ /^.\{43\}/!d
+ # From remaining lines, remove first 43 characters
+ s/^.\{43\}//' |
+ $SED -n '
+ # Join marker and all lines until next marker into a single line
+ /^====MARK====/ b para
+ H
+ $ b para
+ b
+ :para
+ x
+ s/\n//g
+ # Remove the marker
+ s/^====MARK====//
+ # Remove trailing dots and whitespace
+ s/[\. \t]*$//
+ # Print
+ /./p' |
+ # we now have a list, one entry per line, of the stringified
+ # contents of the appropriate section of all members of the
+ # archive that possess that section. Heuristic: eliminate
+ # all those that have a first or second character that is
+ # a '.' (that is, objdump's representation of an unprintable
+ # character.) This should work for all archives with less than
+ # 0x302f exports -- but will fail for DLLs whose name actually
+ # begins with a literal '.' or a single character followed by
+ # a '.'.
+ #
+ # Of those that remain, print the first one.
+ $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+ $debug_cmd
+
+ if func_cygming_gnu_implib_p "$1"; then
+ # binutils import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+ elif func_cygming_ms_implib_p "$1"; then
+ # ms-generated import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+ else
+ # unknown
+ sharedlib_from_linklib_result=
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $debug_cmd
+
+ f_ex_an_ar_dir=$1; shift
+ f_ex_an_ar_oldlib=$1
+ if test yes = "$lock_old_archive_extraction"; then
+ lockfile=$f_ex_an_ar_oldlib.lock
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ fi
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+ 'stat=$?; rm -f "$lockfile"; exit $stat'
+ if test yes = "$lock_old_archive_extraction"; then
+ $opt_dry_run || rm -f "$lockfile"
+ fi
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $debug_cmd
+
+ my_gentop=$1; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=
+ my_xlib=
+ my_xabs=
+ my_xdir=
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs=$my_xlib ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib=$func_basename_result
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir=$my_gentop/$my_xlib_u
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ func_basename "$darwin_archive"
+ darwin_base_archive=$func_basename_result
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches; do
+ func_mkdir_p "unfat-$$/$darwin_base_archive-$darwin_arch"
+ $LIPO -thin $darwin_arch -output "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive" "$darwin_archive"
+ cd "unfat-$$/$darwin_base_archive-$darwin_arch"
+ func_extract_an_archive "`pwd`" "$darwin_base_archive"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/$darwin_base_archive-$darwin_arch/$darwin_base_archive"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$sed_basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result=$my_oldobjs
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory where it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=${1-no}
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ file=\"\$0\""
+
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+ ECHO=\"$qECHO\"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ that is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options that match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=\$0
+ shift
+ for lt_opt
+ do
+ case \"\$lt_opt\" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+ test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+ lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+ cat \"\$lt_dump_D/\$lt_dump_F\"
+ exit 0
+ ;;
+ --lt-*)
+ \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n \"\$lt_option_debug\"; then
+ echo \"$outputname:$output:\$LINENO: libtool wrapper (GNU $PACKAGE) $VERSION\" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[\$lt_dump_args_N]: \$lt_arg\"
+ lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir/\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case \" \$* \" in
+ *\\ --lt-*)
+ for lt_wr_arg
+ do
+ case \$lt_wr_arg in
+ --lt-*) ;;
+ *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core \${1+\"\$@\"}
+}
+
+ # Parse options
+ func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test yes = "$fast_install"; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | $SED 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ \$ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # fixup the dll searchpath if we need to.
+ #
+ # Fix the DLL searchpath if we need to. Do this before prepending
+ # to shlibpath, because on Windows, both are PATH and uninstalled
+ # libraries must come first.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ # Export our shlibpath_var if we have one.
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+ func_exec_program \${1+\"\$@\"}
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: '\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+*/
+EOF
+ cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define STREQ(s1, s2) (strcmp ((s1), (s2)) == 0)
+
+/* declarations of non-ANSI functions */
+#if defined __MINGW32__
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined __CYGWIN__
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined other_platform || defined ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined _MSC_VER
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+# define S_IXUSR _S_IEXEC
+#elif defined __MINGW32__
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+#elif defined __CYGWIN__
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined other platforms ... */
+#endif
+
+#if defined PATH_MAX
+# define LT_PATHMAX PATH_MAX
+#elif defined MAXPATHLEN
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined _WIN32 || defined __MSDOS__ || defined __DJGPP__ || \
+ defined __OS2__
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free (stale); stale = 0; } \
+} while (0)
+
+#if defined LT_DEBUGWRAPPER
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+ cat <<EOF
+#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5)
+# define externally_visible volatile
+#else
+# define externally_visible __attribute__((externally_visible)) volatile
+#endif
+externally_visible const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test yes = "$shlibpath_overrides_runpath" && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_path "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_path "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test yes = "$fast_install"; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ int rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ newargz = XMALLOC (char *, (size_t) argc + 1);
+
+ /* very simple arg parsing; don't want to rely on getopt
+ * also, copy all non cwrapper options to newargz, except
+ * argz[0], which is handled differently
+ */
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (STREQ (argv[i], dumpscript_opt))
+ {
+EOF
+ case $host in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ lt_dump_script (stdout);
+ return 0;
+ }
+ if (STREQ (argv[i], debug_opt))
+ {
+ lt_debug = 1;
+ continue;
+ }
+ if (STREQ (argv[i], ltwrapper_option_prefix))
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal (__FILE__, __LINE__,
+ "unrecognized %s option: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+EOF
+ cat <<EOF
+ /* The GNU banner must be the first non-error debug message */
+ lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE) $VERSION\n");
+EOF
+ cat <<"EOF"
+ lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (before symlink chase) at: %s\n",
+ tmp_pathspec);
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (after symlink chase) at: %s\n",
+ actual_cwrapper_path);
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) libtool target name: %s\n",
+ target_name);
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must
+ be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+ because on Windows, both *_VARNAMEs are PATH but uninstalled
+ libraries must come first. */
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+ lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+ nonnull (lt_argv_zero));
+ for (i = 0; i < newargc; i++)
+ {
+ lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+ i, nonnull (newargz[i]));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ newargz = prepare_spawn (newargz);
+ rval = (int) _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) failed to launch target \"%s\": %s\n",
+ lt_argv_zero, nonnull (strerror (errno)));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ size_t tmp_len;
+ char *concat_name;
+
+ lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+ nonempty (wrapper));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined HAVE_DOS_BASED_FILE_SYSTEM
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = (size_t) (q - p);
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ lt_debugprintf (__FILE__, __LINE__,
+ "checking path component for symlinks: %s\n",
+ tmp_pathspec);
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "error accessing file \"%s\": %s",
+ tmp_pathspec, nonnull (strerror (errno)));
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (STREQ (str, pat))
+ *str = '\0';
+ }
+ return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+ if (lt_debug)
+ {
+ (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+ }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+ int line, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+ va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+ return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+ return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_setenv) setting '%s' to '%s'\n",
+ nonnull (name), nonnull (value));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ size_t len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ size_t orig_value_len = strlen (orig_value);
+ size_t add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ size_t len = strlen (new_value);
+ while ((len > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[--len] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+EOF
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+ Note that spawn() does not by itself call the command interpreter
+ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&v);
+ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+ }) ? "cmd.exe" : "command.com").
+ Instead it simply concatenates the arguments, separated by ' ', and calls
+ CreateProcess(). We must quote the arguments since Win32 CreateProcess()
+ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+ special way:
+ - Space and tab are interpreted as delimiters. They are not treated as
+ delimiters if they are surrounded by double quotes: "...".
+ - Unescaped double quotes are removed from the input. Their only effect is
+ that within double quotes, space and tab are treated like normal
+ characters.
+ - Backslashes not followed by double quotes are not special.
+ - But 2*n+1 backslashes followed by a double quote become
+ n backslashes followed by a double quote (n >= 0):
+ \" -> "
+ \\\" -> \"
+ \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+ size_t argc;
+ char **new_argv;
+ size_t i;
+
+ /* Count number of arguments. */
+ for (argc = 0; argv[argc] != NULL; argc++)
+ ;
+
+ /* Allocate new argument vector. */
+ new_argv = XMALLOC (char *, argc + 1);
+
+ /* Put quoted arguments into the new argument vector. */
+ for (i = 0; i < argc; i++)
+ {
+ const char *string = argv[i];
+
+ if (string[0] == '\0')
+ new_argv[i] = xstrdup ("\"\"");
+ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+ {
+ int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+ size_t length;
+ unsigned int backslashes;
+ const char *s;
+ char *quoted_string;
+ char *p;
+
+ length = 0;
+ backslashes = 0;
+ if (quote_around)
+ length++;
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ length += backslashes + 1;
+ length++;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ length += backslashes + 1;
+
+ quoted_string = XMALLOC (char, length + 1);
+
+ p = quoted_string;
+ backslashes = 0;
+ if (quote_around)
+ *p++ = '"';
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ {
+ unsigned int j;
+ for (j = backslashes + 1; j > 0; j--)
+ *p++ = '\\';
+ }
+ *p++ = c;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ {
+ unsigned int j;
+ for (j = backslashes; j > 0; j--)
+ *p++ = '\\';
+ *p++ = '"';
+ }
+ *p = '\0';
+
+ new_argv[i] = quoted_string;
+ }
+ else
+ new_argv[i] = (char *) string;
+ }
+ new_argv[argc] = NULL;
+
+ return new_argv;
+}
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+ func_emit_wrapper yes |
+ $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/ fputs ("\1", f);/p
+g
+D'
+ cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+ $debug_cmd
+
+ case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+ *import*) : ;;
+ *) false ;;
+ esac
+}
+
+# func_suncc_cstd_abi
+# !!ONLY CALL THIS FOR SUN CC AFTER $compile_command IS FULLY EXPANDED!!
+# Several compiler flags select an ABI that is incompatible with the
+# Cstd library. Avoid specifying it if any are in CXXFLAGS.
+func_suncc_cstd_abi ()
+{
+ $debug_cmd
+
+ case " $compile_command " in
+ *" -compat=g "*|*\ -std=c++[0-9][0-9]\ *|*" -library=stdcxx4 "*|*" -library=stlport4 "*)
+ suncc_use_cstd_abi=no
+ ;;
+ *)
+ suncc_use_cstd_abi=yes
+ ;;
+ esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $debug_cmd
+
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # what system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll that has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ bindir=
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ os2dllname=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=false
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module=$wl-single_module
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test yes != "$build_libtool_libs" \
+ && func_fatal_configuration "cannot build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test yes = "$build_libtool_libs" && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg=$1
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ bindir)
+ bindir=$arg
+ prev=
+ continue
+ ;;
+ dlfiles|dlprefiles)
+ $preload || {
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=:
+ }
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test no = "$dlself"; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test dlprefiles = "$prev"; then
+ dlself=yes
+ elif test dlfiles = "$prev" && test yes != "$dlopen_self"; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test dlfiles = "$prev"; then
+ func_append dlfiles " $arg"
+ else
+ func_append dlprefiles " $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols=$arg
+ test -f "$arg" \
+ || func_fatal_error "symbol file '$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex=$arg
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) func_append deplibs " $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir=$arg
+ prev=
+ continue
+ ;;
+ mllvm)
+ # Clang does not use LLVM to link, so we can simply discard any
+ # '-mllvm $arg' options when doing the link step.
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# func_append moreargs " $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ if test none != "$pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ pic_object=$xdir$pic_object
+
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test dlprefiles = "$prev"; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg=$pic_object
+ fi
+
+ # Non-PIC object.
+ if test none != "$non_pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object=$xdir$non_pic_object
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object=$pic_object
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "'$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file '$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ os2dllname)
+ os2dllname=$arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex=$arg
+ prev=
+ continue
+ ;;
+ release)
+ release=-$arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test rpath = "$prev"; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) func_append rpath " $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) func_append xrpath " $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds=$arg
+ prev=
+ continue
+ ;;
+ weak)
+ func_append weak_libs " $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg=$arg
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "'-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -bindir)
+ prev=bindir
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test X-export-symbols = "X$arg"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname "-L" '' "$arg"
+ if test -z "$func_stripname_result"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between '-L' and '$1'"
+ else
+ func_fatal_error "need path for '-L' option"
+ fi
+ fi
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of '$dir'"
+ dir=$absdir
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "* | *" $arg "*)
+ # Will only happen for absolute or sysroot arguments
+ ;;
+ *)
+ # Preserve sysroot, but never include relative directories
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+ *) func_append deplibs " -L$dir" ;;
+ esac
+ func_append lib_search_path " $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) func_append dllsearchpath ":$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test X-lc = "X$arg" || test X-lm = "X$arg"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ # Do not include libc due to us having libc/libc_r.
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ func_append deplibs " System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test X-lc = "X$arg" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test X-lc = "X$arg" && continue
+ ;;
+ esac
+ elif test X-lc_r = "X$arg"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ func_append deplibs " $arg"
+ continue
+ ;;
+
+ -mllvm)
+ prev=mllvm
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot|--sysroot)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) func_append new_inherited_linker_flags " $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module=$wl-multi_module
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "'-no-install' is ignored for $host"
+ func_warning "assuming '-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -os2dllname)
+ prev=os2dllname
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ =*)
+ func_stripname '=' '' "$dir"
+ dir=$lt_sysroot$func_stripname_result
+ ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs=$IFS; IFS=,
+ for flag in $args; do
+ IFS=$save_ifs
+ func_quote_for_eval "$flag"
+ func_append arg " $func_quote_for_eval_result"
+ func_append compiler_flags " $func_quote_for_eval_result"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs=$IFS; IFS=,
+ for flag in $args; do
+ IFS=$save_ifs
+ func_quote_for_eval "$flag"
+ func_append arg " $wl$func_quote_for_eval_result"
+ func_append compiler_flags " $wl$func_quote_for_eval_result"
+ func_append linker_flags " $func_quote_for_eval_result"
+ done
+ IFS=$save_ifs
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+
+ # Flags to be passed through unchanged, with rationale:
+ # -64, -mips[0-9] enable 64-bit mode for the SGI compiler
+ # -r[0-9][0-9]* specify processor for the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+ # +DA*, +DD* enable 64-bit mode for the HP compiler
+ # -q* compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+ # -F/path path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* profiling flags for GCC
+ # -fstack-protector* stack protector flags for GCC
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ # --sysroot=* for sysroot support
+ # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ # -specs=* GCC specs files
+ # -stdlib=* select c++ std lib with clang
+ # -fsanitize=* Clang/GCC memory and address sanitizer
+ # -fuse-ld=* Linker select flags for GCC
+ # -static-* direct GCC to link specific libraries statically
+ # -fcilkplus Cilk Plus language extension features for C/C++
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+ -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
+ -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ func_append compiler_flags " $arg"
+ continue
+ ;;
+
+ -Z*)
+ if test os2 = "`expr $host : '.*\(os2\)'`"; then
+ # OS/2 uses -Zxxx to specify OS/2-specific options
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case $arg in
+ -Zlinker | -Zstack)
+ prev=xcompiler
+ ;;
+ esac
+ continue
+ else
+ # Otherwise treat like 'Some other compiler flag' below
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ fi
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+
+ *.$objext)
+ # A standard object.
+ func_append objs " $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test none = "$pic_object" &&
+ test none = "$non_pic_object"; then
+ func_fatal_error "cannot find name of object for '$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ test none = "$pic_object" || {
+ # Prepend the subdirectory the object is found in.
+ pic_object=$xdir$pic_object
+
+ if test dlfiles = "$prev"; then
+ if test yes = "$build_libtool_libs" && test yes = "$dlopen_support"; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test dlprefiles = "$prev"; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg=$pic_object
+ }
+
+ # Non-PIC object.
+ if test none != "$non_pic_object"; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object=$xdir$non_pic_object
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test none = "$pic_object"; then
+ arg=$non_pic_object
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object=$pic_object
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir=$func_dirname_result
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "'$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ func_append deplibs " $arg"
+ func_append old_deplibs " $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ func_resolve_sysroot "$arg"
+ if test dlfiles = "$prev"; then
+ # This library was specified with -dlopen.
+ func_append dlfiles " $func_resolve_sysroot_result"
+ prev=
+ elif test dlprefiles = "$prev"; then
+ # The library was specified with -dlpreopen.
+ func_append dlprefiles " $func_resolve_sysroot_result"
+ prev=
+ else
+ func_append deplibs " $func_resolve_sysroot_result"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg=$func_quote_for_eval_result
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the '$prevarg' option requires an argument"
+
+ if test yes = "$export_dynamic" && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname=$func_basename_result
+ libobjs_save=$libobjs
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"\$$shlibpath_var\" \| \$SED \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ # Definition is injected by LT_CONFIG during libtool generation.
+ func_munge_path_list sys_lib_dlsearch_path "$LT_SYS_LIBRARY_PATH"
+
+ func_dirname "$output" "/" ""
+ output_objdir=$func_dirname_result$objdir
+ func_to_tool_file "$output_objdir/"
+ tool_output_objdir=$func_to_tool_file_result
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_preserve_dup_deps; then
+ case "$libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append libs " $deplib"
+ done
+
+ if test lib = "$linkmode"; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+ esac
+ func_append pre_post_deps " $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can '-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=false
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test lib,link = "$linkmode,$pass"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs=$tmp_deplibs
+ fi
+
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass"; then
+ libs=$deplibs
+ deplibs=
+ fi
+ if test prog = "$linkmode"; then
+ case $pass in
+ dlopen) libs=$dlfiles ;;
+ dlpreopen) libs=$dlprefiles ;;
+ link)
+ libs="$deplibs %DEPLIBS%"
+ test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+ ;;
+ esac
+ fi
+ if test lib,dlpreopen = "$linkmode,$pass"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ func_resolve_sysroot "$lib"
+ case $lib in
+ *.la) func_source "$func_resolve_sysroot_result" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ func_basename "$deplib"
+ deplib_base=$func_basename_result
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) func_append deplibs " $deplib" ;;
+ esac
+ done
+ done
+ libs=$dlprefiles
+ fi
+ if test dlopen = "$pass"; then
+ # Collect dlpreopened libraries
+ save_deplibs=$deplibs
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=false
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append compiler_flags " $deplib"
+ if test lib = "$linkmode"; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test lib != "$linkmode" && test prog != "$linkmode"; then
+ func_warning "'-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test lib = "$linkmode"; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib=$searchdir/lib$name$search_ext
+ if test -f "$lib"; then
+ if test .la = "$search_ext"; then
+ found=:
+ else
+ found=false
+ fi
+ break 2
+ fi
+ done
+ done
+ if $found; then
+ # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll=$l
+ done
+ if test "X$ll" = "X$old_library"; then # only static version available
+ found=false
+ func_dirname "$lib" "" "."
+ ladir=$func_dirname_result
+ lib=$ladir/$old_library
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ else
+ # deplib doesn't seem to be a libtool library
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test lib = "$linkmode" && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ ;; # -l
+ *.ltframework)
+ if test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test lib = "$linkmode"; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test conv = "$pass" && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ prog)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test scan = "$pass"; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ *)
+ func_warning "'-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test link = "$pass"; then
+ func_stripname '-R' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ lib=$func_resolve_sysroot_result
+ ;;
+ *.$libext)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=false
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=:
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=:
+ ;;
+ esac
+ if $valid_a_lib; then
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ else
+ echo
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because the file extensions .$libext of this argument makes me believe"
+ echo "*** that it is just a static archive that I should not use here."
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test link != "$pass"; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test conv = "$pass"; then
+ deplibs="$deplib $deplibs"
+ elif test prog = "$linkmode"; then
+ if test dlpreopen = "$pass" || test yes != "$dlopen_support" || test no = "$build_libtool_libs"; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ func_append newdlprefiles " $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append newdlfiles " $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=:
+ continue
+ ;;
+ esac # case $deplib
+
+ $found || test -f "$lib" \
+ || func_fatal_error "cannot find the library '$lib' or unhandled argument '$deplib'"
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "'$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir=$func_dirname_result
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test lib,link = "$linkmode,$pass" ||
+ test prog,scan = "$linkmode,$pass" ||
+ { test prog != "$linkmode" && test lib != "$linkmode"; }; then
+ test -n "$dlopen" && func_append dlfiles " $dlopen"
+ test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+ fi
+
+ if test conv = "$pass"; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for '$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ func_append convenience " $ladir/$objdir/$old_library"
+ func_append old_convenience " $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done
+ elif test prog != "$linkmode" && test lib != "$linkmode"; then
+ func_fatal_error "'$lib' is not a convenience library"
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ if test -n "$old_library" &&
+ { test yes = "$prefer_static_libs" ||
+ test built,no = "$prefer_static_libs,$installed"; }; then
+ linklib=$old_library
+ else
+ for l in $old_library $library_names; do
+ linklib=$l
+ done
+ fi
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for '$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test dlopen = "$pass"; then
+ test -z "$libdir" \
+ && func_fatal_error "cannot -dlopen a convenience library: '$lib'"
+ if test -z "$dlname" ||
+ test yes != "$dlopen_support" ||
+ test no = "$build_libtool_libs"
+ then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ func_append dlprefiles " $lib $dependency_libs"
+ else
+ func_append newdlfiles " $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir=$ladir ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of '$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir=$ladir
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname=$func_basename_result
+
+ # Find the relevant object directory and library name.
+ if test yes = "$installed"; then
+ if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library '$lib' was moved."
+ dir=$ladir
+ absdir=$abs_ladir
+ libdir=$abs_ladir
+ else
+ dir=$lt_sysroot$libdir
+ absdir=$lt_sysroot$libdir
+ fi
+ test yes = "$hardcode_automatic" && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir=$ladir
+ absdir=$abs_ladir
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ else
+ dir=$ladir/$objdir
+ absdir=$abs_ladir/$objdir
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test dlpreopen = "$pass"; then
+ if test -z "$libdir" && test prog = "$linkmode"; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: '$lib'"
+ fi
+ case $host in
+ # special handling for platforms with PE-DLLs.
+ *cygwin* | *mingw* | *cegcc* )
+ # Linker will automatically link against shared library if both
+ # static and shared are present. Therefore, ensure we extract
+ # symbols from the import library if a shared library is present
+ # (otherwise, the dlopen module name will be incorrect). We do
+ # this by putting the import library name into $newdlprefiles.
+ # We recover the dlopen module name by 'saving' the la file
+ # name in a special purpose variable, and (later) extracting the
+ # dlname from the la file.
+ if test -n "$dlname"; then
+ func_tr_sh "$dir/$linklib"
+ eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+ func_append newdlprefiles " $dir/$linklib"
+ else
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ fi
+ ;;
+ * )
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ func_append newdlprefiles " $dir/$dlname"
+ else
+ func_append newdlprefiles " $dir/$linklib"
+ fi
+ ;;
+ esac
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test lib = "$linkmode"; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test prog,link = "$linkmode,$pass"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test prog = "$linkmode" && test link != "$pass"; then
+ func_append newlib_search_path " $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=false
+ if test no != "$link_all_deplibs" || test -z "$library_names" ||
+ test no = "$build_libtool_libs"; then
+ linkalldeplibs=:
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if $linkalldeplibs; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test prog,link = "$linkmode,$pass"; then
+ if test -n "$library_names" &&
+ { { test no = "$prefer_static_libs" ||
+ test built,yes = "$prefer_static_libs,$installed"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath"; then
+ # Make sure the rpath contains only unique directories.
+ case $temp_rpath: in
+ *"$absdir:"*) ;;
+ *) func_append temp_rpath "$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if $alldeplibs &&
+ { test pass_all = "$deplibs_check_method" ||
+ { test yes = "$build_libtool_libs" &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test built = "$use_static_libs" && test yes = "$installed"; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test no = "$use_static_libs" || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc* | *os2*)
+ # No point in relinking DLLs because paths are not encoded
+ func_append notinst_deplibs " $lib"
+ need_relink=no
+ ;;
+ *)
+ if test no = "$installed"; then
+ func_append notinst_deplibs " $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule=$dlpremoduletest
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test yes = "$shouldnotlink" && test link = "$pass"; then
+ echo
+ if test prog = "$linkmode"; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test lib = "$linkmode" &&
+ test yes = "$hardcode_into_libs"; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname=$1
+ shift
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname=$dlname
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc* | *os2*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix=-$major
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname=$realname
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot=$soname
+ func_basename "$soroot"
+ soname=$func_basename_result
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from '$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for '$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test prog = "$linkmode" || test relink != "$opt_mode"; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test no = "$hardcode_direct"; then
+ add=$dir/$linklib
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir=-L$dir ;;
+ *-*-sysv4*uw2*) add_dir=-L$dir ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir=-L$dir ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we cannot
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library"; then
+ echo
+ echo "*** And there doesn't seem to be a static archive available"
+ echo "*** The link will probably fail, sorry"
+ else
+ add=$dir/$old_library
+ fi
+ elif test -n "$old_library"; then
+ add=$dir/$old_library
+ fi
+ fi
+ esac
+ elif test no = "$hardcode_minus_L"; then
+ case $host in
+ *-*-sunos*) add_shlibpath=$dir ;;
+ esac
+ add_dir=-L$dir
+ add=-l$name
+ elif test no = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$dir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$absdir
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
+ add_shlibpath=$dir
+ add=-l$name
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test yes != "$lib_linked"; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) func_append compile_shlibpath "$add_shlibpath:" ;;
+ esac
+ fi
+ if test prog = "$linkmode"; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test yes != "$hardcode_direct" &&
+ test yes != "$hardcode_minus_L" &&
+ test yes = "$hardcode_shlibpath_var"; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test prog = "$linkmode" || test relink = "$opt_mode"; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test yes = "$hardcode_direct" &&
+ test no = "$hardcode_direct_absolute"; then
+ add=$libdir/$linklib
+ elif test yes = "$hardcode_minus_L"; then
+ add_dir=-L$libdir
+ add=-l$name
+ elif test yes = "$hardcode_shlibpath_var"; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ add=-l$name
+ elif test yes = "$hardcode_automatic"; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib"; then
+ add=$inst_prefix_dir$libdir/$linklib
+ else
+ add=$libdir/$linklib
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir=-L$libdir
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add=-l$name
+ fi
+
+ if test prog = "$linkmode"; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test prog = "$linkmode"; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test unsupported != "$hardcode_direct"; then
+ test -n "$old_library" && linklib=$old_library
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test yes = "$build_libtool_libs"; then
+ # Not a shared library
+ if test pass_all != "$deplibs_check_method"; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ $ECHO "*** Warning: This system cannot link to static lib archive $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test yes = "$module"; then
+ echo "*** But as you try to build a module library, libtool will still create "
+ echo "*** a static module, that should work as long as the dlopening application"
+ echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test no = "$build_old_libs"; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test lib = "$linkmode"; then
+ if test -n "$dependency_libs" &&
+ { test yes != "$hardcode_into_libs" ||
+ test yes = "$build_old_libs" ||
+ test yes = "$link_static"; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) func_append xrpath " $temp_xrpath";;
+ esac;;
+ *) func_append temp_deplibs " $libdir";;
+ esac
+ done
+ dependency_libs=$temp_deplibs
+ fi
+
+ func_append newlib_search_path " $absdir"
+ # Link against this library
+ test no = "$link_static" && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result";;
+ *) func_resolve_sysroot "$deplib" ;;
+ esac
+ if $opt_preserve_dup_deps; then
+ case "$tmp_libs " in
+ *" $func_resolve_sysroot_result "*)
+ func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+ esac
+ fi
+ func_append tmp_libs " $func_resolve_sysroot_result"
+ done
+
+ if test no != "$link_all_deplibs"; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path=$deplib ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ deplib=$func_resolve_sysroot_result
+ func_dirname "$deplib" "" "."
+ dir=$func_dirname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir=$dir ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of '$dir'"
+ absdir=$dir
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ eval deplibrary_names=`$SED -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names"; then
+ for tmp in $deplibrary_names; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl"; then
+ depdepl=$absdir/$objdir/$depdepl
+ darwin_install_name=`$OTOOL -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`$OTOOL64 -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ func_append compiler_flags " $wl-dylib_file $wl$darwin_install_name:$depdepl"
+ func_append linker_flags " -dylib_file $darwin_install_name:$depdepl"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path=-L$absdir/$objdir
+ ;;
+ esac
+ else
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "'$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "'$deplib' seems to be moved"
+
+ path=-L$absdir
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test link = "$pass"; then
+ if test prog = "$linkmode"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs=$newdependency_libs
+ if test dlpreopen = "$pass"; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test dlopen != "$pass"; then
+ test conv = "$pass" || {
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) func_append lib_search_path " $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ }
+
+ if test prog,link = "$linkmode,$pass"; then
+ vars="compile_deplibs finalize_deplibs"
+ else
+ vars=deplibs
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+
+ # Add Sun CC postdeps if required:
+ test CXX = "$tagname" && {
+ case $host_os in
+ linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C++ 5.9
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ func_cc_basename "$CC"
+ case $func_cc_basename_result in
+ CC* | sunCC*)
+ func_suncc_cstd_abi
+
+ if test no != "$suncc_use_cstd_abi"; then
+ func_append postdeps ' -library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ }
+
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=
+ ;;
+ esac
+ if test -n "$i"; then
+ func_append tmp_libs " $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test prog = "$linkmode"; then
+ dlfiles=$newdlfiles
+ fi
+ if test prog = "$linkmode" || test lib = "$linkmode"; then
+ dlprefiles=$newdlprefiles
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "'-l' and '-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "'-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "'-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "'-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs=$output
+ func_append objs "$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form 'libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ test no = "$module" \
+ && func_fatal_help "libtool library '$output' must begin with 'lib'"
+
+ if test no != "$need_lib_prefix"; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test pass_all != "$deplibs_check_method"; then
+ func_fatal_error "cannot build libtool library '$output' from non-libtool objects on this host:$objs"
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ func_append libobjs " $objs"
+ fi
+ fi
+
+ test no = "$dlself" \
+ || func_warning "'-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test 1 -lt "$#" \
+ && func_warning "ignoring multiple '-rpath's for a libtool library"
+
+ install_libdir=$1
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test yes = "$build_libtool_libs"; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a '.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs=$IFS; IFS=:
+ set dummy $vinfo 0 0 0
+ shift
+ IFS=$save_ifs
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to '-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major=$1
+ number_minor=$2
+ number_revision=$3
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # that has an extra 1 added just for fun
+ #
+ case $version_type in
+ # correct linux to gnu/linux during the next big refactor
+ darwin|freebsd-elf|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age=$number_minor
+ revision=$number_revision
+ ;;
+ freebsd-aout|qnx|sunos)
+ current=$number_major
+ revision=$number_minor
+ age=0
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age=$number_minor
+ revision=$number_minor
+ lt_irix_increment=no
+ ;;
+ *)
+ func_fatal_configuration "$modename: unknown library version type '$version_type'"
+ ;;
+ esac
+ ;;
+ no)
+ current=$1
+ revision=$2
+ age=$3
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT '$current' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION '$revision' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE '$age' must be a nonnegative integer"
+ func_fatal_error "'$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE '$age' is greater than the current interface number '$current'"
+ func_fatal_error "'$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ # On Darwin other compilers
+ case $CC in
+ nagfor*)
+ verstring="$wl-compatibility_version $wl$minor_current $wl-current_version $wl$minor_current.$revision"
+ ;;
+ *)
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+ esac
+ ;;
+
+ freebsd-aout)
+ major=.$current
+ versuffix=.$current.$revision
+ ;;
+
+ freebsd-elf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ ;;
+
+ irix | nonstopux)
+ if test no = "$lt_irix_increment"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring=$verstring_prefix$major.$revision
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test 0 -ne "$loop"; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring=$verstring_prefix$major.$iface:$verstring
+ done
+
+ # Before this point, $major must not contain '.'.
+ major=.$major
+ versuffix=$major.$revision
+ ;;
+
+ linux) # correct to gnu/linux during the next big refactor
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=$major.$age.$revision
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=.$current.$age.$revision
+ verstring=$current.$age.$revision
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test 0 -ne "$loop"; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring=$verstring:$iface.0
+ done
+
+ # Make executables depend on our current version.
+ func_append verstring ":$current.0"
+ ;;
+
+ qnx)
+ major=.$current
+ versuffix=.$current
+ ;;
+
+ sco)
+ major=.$current
+ versuffix=.$current
+ ;;
+
+ sunos)
+ major=.$current
+ versuffix=.$current.$revision
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 file systems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix=-$major
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type '$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring=0.0
+ ;;
+ esac
+ if test no = "$need_version"; then
+ versuffix=
+ else
+ versuffix=.0.0
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test yes,no = "$avoid_version,$need_version"; then
+ major=
+ versuffix=
+ verstring=
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test yes = "$allow_undefined"; then
+ if test unsupported = "$allow_undefined_flag"; then
+ if test yes = "$build_old_libs"; then
+ func_warning "undefined symbols not allowed in $host shared libraries; building static only"
+ build_libtool_libs=no
+ else
+ func_fatal_error "can't build $host shared library unless -no-undefined is specified"
+ fi
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag=$no_undefined_flag
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" :
+ func_append libobjs " $symfileobj"
+ test " " = "$libobjs" && libobjs=
+
+ if test relink != "$opt_mode"; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/$libname$release.*)
+ if test -n "$precious_files_regex"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ func_append removelist " $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test yes = "$build_old_libs" && test convenience != "$build_libtool_libs"; then
+ func_append oldlibs " $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; $lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+ # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ func_replace_sysroot "$libdir"
+ func_append temp_xrpath " -R$func_replace_sysroot_result"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ if test yes != "$hardcode_into_libs" || test yes = "$build_old_libs"; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles=$dlfiles
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) func_append dlfiles " $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles=$dlprefiles
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) func_append dlprefiles " $lib" ;;
+ esac
+ done
+
+ if test yes = "$build_libtool_libs"; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ func_append deplibs " System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test yes = "$build_libtool_need_lc"; then
+ func_append deplibs " -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=
+ versuffix=
+ major=
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=
+ ;;
+ esac
+ fi
+ if test -n "$i"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which I believe you do not have"
+ echo "*** because a test_compile did reveal that the linker did not use it for"
+ echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=
+ ;;
+ esac
+ fi
+ if test -n "$i"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because a test_compile did reveal that the linker did not use this one"
+ echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ if test -n "$file_magic_glob"; then
+ libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+ else
+ libnameglob=$libname
+ fi
+ test yes = "$want_nocaseglob" && nocaseglob=`shopt -p nocaseglob`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ if test yes = "$want_nocaseglob"; then
+ shopt -s nocaseglob
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ $nocaseglob
+ else
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ fi
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib=$potent_lib
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | $SED 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib=$potliblink;;
+ *) potlib=`$ECHO "$potlib" | $SED 's|[^/]*$||'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib"; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib"; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib"; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib=$potent_lib # see symlink-check above in file_magic test
+ if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib"; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib"; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=
+ tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+ if test yes = "$allow_libtool_libs_with_static_runtimes"; then
+ for i in $predeps $postdeps; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s|$i||"`
+ done
+ fi
+ case $tmp_deplibs in
+ *[!\ \ ]*)
+ echo
+ if test none = "$deplibs_check_method"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ ;;
+ esac
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test yes = "$droppeddeps"; then
+ if test yes = "$module"; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using 'nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** 'nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test no = "$allow_undefined"; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test no = "$build_old_libs"; then
+ oldlibs=$output_objdir/$libname.$libext
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ deplibs=$new_libs
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test yes = "$build_libtool_libs"; then
+ # Remove $wl instances when linking with ld.
+ # FIXME: should test the right _cmds variable.
+ case $archive_cmds in
+ *\$LD\ *) wl= ;;
+ esac
+ if test yes = "$hardcode_into_libs"; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath=$finalize_rpath
+ test relink = "$opt_mode" || rpath=$compile_rpath$rpath
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ func_replace_sysroot "$libdir"
+ libdir=$func_replace_sysroot_result
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append dep_rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath=$finalize_shlibpath
+ test relink = "$opt_mode" || shlibpath=$compile_shlibpath$shlibpath
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ shift
+ realname=$1
+ shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname=$realname
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib=$output_objdir/$realname
+ linknames=
+ for link
+ do
+ func_append linknames " $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols=$output_objdir/$libname.uexp
+ func_append delfiles " $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ func_dll_def_p "$export_symbols" || {
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols=$export_symbols
+ export_symbols=
+ always_export_symbols=yes
+ }
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test yes = "$always_export_symbols" || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs=$IFS; IFS='~'
+ for cmd1 in $cmds; do
+ IFS=$save_ifs
+ # Take the normal branch if the nm_file_list_spec branch
+ # doesn't work or if tool conversion is not needed.
+ case $nm_file_list_spec~$to_tool_file_cmd in
+ *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+ try_normal_branch=yes
+ eval cmd=\"$cmd1\"
+ func_len " $cmd"
+ len=$func_len_result
+ ;;
+ *)
+ try_normal_branch=no
+ ;;
+ esac
+ if test yes = "$try_normal_branch" \
+ && { test "$len" -lt "$max_cmd_len" \
+ || test "$max_cmd_len" -le -1; }
+ then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ elif test -n "$nm_file_list_spec"; then
+ func_basename "$output"
+ output_la=$func_basename_result
+ save_libobjs=$libobjs
+ save_output=$output
+ output=$output_objdir/$output_la.nm
+ func_to_tool_file "$output"
+ libobjs=$nm_file_list_spec$func_to_tool_file_result
+ func_append delfiles " $output"
+ func_verbose "creating $NM input file list: $output"
+ for obj in $save_libobjs; do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > "$output"
+ eval cmd=\"$cmd1\"
+ func_show_eval "$cmd" 'exit $?'
+ output=$save_output
+ libobjs=$save_libobjs
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS=$save_ifs
+ if test -n "$export_symbols_regex" && test : != "$skipped_export"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test : != "$skipped_export" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands, which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ func_append tmp_deplibs " $test_deplib"
+ ;;
+ esac
+ done
+ deplibs=$tmp_deplibs
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test yes = "$compiler_needs_object" &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test yes = "$thread_safe" && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ func_append linker_flags " $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test relink = "$opt_mode"; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test yes = "$module" && test -n "$module_cmds"; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test : != "$skipped_export" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ func_basename "$output"
+ output_la=$func_basename_result
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test : != "$skipped_export" && test yes = "$with_gnu_ld"; then
+ output=$output_objdir/$output_la.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ echo 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ echo ')' >> $output
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$func_to_tool_file_result
+ elif test -n "$save_libobjs" && test : != "$skipped_export" && test -n "$file_list_spec"; then
+ output=$output_objdir/$output_la.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test yes = "$compiler_needs_object"; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-$k.$objext
+ eval test_cmds=\"$reload_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test -z "$objlist" ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test 1 -eq "$k"; then
+ # The first file doesn't have a previous command to add.
+ reload_objs=$objlist
+ eval concat_cmds=\"$reload_cmds\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-$k.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-$k.$objext
+ objlist=" $obj"
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds$reload_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ func_append delfiles " $output"
+
+ else
+ output=
+ fi
+
+ ${skipped_export-false} && {
+ func_verbose "generating symbol list for '$libname.la'"
+ export_symbols=$output_objdir/$libname.exp
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ }
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs=$IFS; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS=$save_ifs
+ $opt_quiet || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS=$save_ifs
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ ${skipped_export-false} && {
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols=$export_symbols
+ test -n "$orig_export_symbols" && tmp_export_symbols=$orig_export_symbols
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for '$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands, which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ }
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test yes = "$module" && test -n "$module_cmds"; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval cmds=\"\$cmds~\$RM $delfiles\"
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs=$IFS; IFS='~'
+ for cmd in $cmds; do
+ IFS=$sp$nl
+ eval cmd=\"$cmd\"
+ IFS=$save_ifs
+ $opt_quiet || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS=$save_ifs
+
+ # Restore the uninstalled library and exit
+ if test relink = "$opt_mode"; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test yes = "$module" || test yes = "$export_dynamic"; then
+ # On all known operating systems, these are identical.
+ dlname=$soname
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test no != "$dlself"; then
+ func_warning "'-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "'-l' and '-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "'-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "'-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "'-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object '$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj=$output
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # if reload_cmds runs $LD directly, get rid of -Wl from
+ # whole_archive_flag_spec and hope we can get by with turning comma
+ # into space.
+ case $reload_cmds in
+ *\$LD[\ \$]*) wl= ;;
+ esac
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ test -n "$wl" || tmp_whole_archive_flags=`$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ reload_conv_objs=$reload_objs\ $tmp_whole_archive_flags
+ else
+ gentop=$output_objdir/${obj}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # If we're not building shared, we need to use non_pic_objs
+ test yes = "$build_libtool_libs" || libobjs=$non_pic_objects
+
+ # Create the old-style object.
+ reload_objs=$objs$old_deplibs' '`$ECHO "$libobjs" | $SP2NL | $SED "/\.$libext$/d; /\.lib$/d; $lo2o" | $NL2SP`' '$reload_conv_objs
+
+ output=$obj
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ test yes = "$build_libtool_libs" || {
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ }
+
+ if test -n "$pic_flag" || test default != "$pic_mode"; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output=$libobj
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "'-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "'-release' is ignored for programs"
+
+ $preload \
+ && test unknown,unknown,unknown = "$dlopen_support,$dlopen_self,$dlopen_self_static" \
+ && func_warning "'LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test CXX = "$tagname"; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ func_append compile_command " $wl-bind_at_load"
+ func_append finalize_command " $wl-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ compile_deplibs=$new_libs
+
+
+ func_append compile_command " $compile_deplibs"
+ func_append finalize_command " $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) func_append dllsearchpath ":$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath=$rpath
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs=$libdir
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir=$hardcode_libdirs
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath=$rpath
+
+ if test -n "$libobjs" && test yes = "$build_old_libs"; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" false
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=:
+ case $host in
+ *cegcc* | *mingw32ce*)
+ # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+ wrappers_required=false
+ ;;
+ *cygwin* | *mingw* )
+ test yes = "$build_libtool_libs" || wrappers_required=false
+ ;;
+ *)
+ if test no = "$need_relink" || test yes != "$build_libtool_libs"; then
+ wrappers_required=false
+ fi
+ ;;
+ esac
+ $wrappers_required || {
+ # Replace the output file specification.
+ compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ link_command=$compile_command$compile_rpath
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.$objext"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.$objext"'
+ fi
+
+ exit $exit_status
+ }
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test yes = "$no_install"; then
+ # We don't need to create a wrapper script.
+ link_command=$compile_var$compile_command$compile_rpath
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ case $hardcode_action,$fast_install in
+ relink,*)
+ # Fast installation is not supported
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "'$output' will be relinked during installation"
+ ;;
+ *,yes)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ ;;
+ *,no)
+ link_command=$compile_var$compile_command$compile_rpath
+ relink_command=$finalize_var$finalize_command$finalize_rpath
+ ;;
+ *,needless)
+ link_command=$finalize_var$compile_command$finalize_rpath
+ relink_command=
+ ;;
+ esac
+
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output_objdir/$outputname"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource=$output_path/$objdir/lt-$output_name.c
+ cwrapper=$output_path/$output_name.exe
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host"; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ case $build_libtool_libs in
+ convenience)
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs=$convenience
+ build_libtool_libs=no
+ ;;
+ module)
+ oldobjs=$libobjs_save
+ addlibs=$old_convenience
+ build_libtool_libs=no
+ ;;
+ *)
+ oldobjs="$old_deplibs $non_pic_objects"
+ $preload && test -f "$symfileobj" \
+ && func_append oldobjs " $symfileobj"
+ addlibs=$old_convenience
+ ;;
+ esac
+
+ if test -n "$addlibs"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $addlibs
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test yes = "$build_libtool_libs"; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ echo "copying selected object files to avoid basename conflicts..."
+ gentop=$output_objdir/${outputname}x
+ func_append generated " $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase=$func_basename_result
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ func_append oldobjs " $gentop/$newobj"
+ ;;
+ *) func_append oldobjs " $obj" ;;
+ esac
+ done
+ fi
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+ eval cmds=\"$old_archive_cmds\"
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ elif test -n "$archiver_list_spec"; then
+ func_verbose "using command file archive linking..."
+ for obj in $oldobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > $output_objdir/$libname.libcmd
+ func_to_tool_file "$output_objdir/$libname.libcmd"
+ oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval test_cmds=\"$old_archive_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj"; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$old_archive_cmds\"
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test -z "$oldobjs"; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test yes = "$build_old_libs" && old_library=$libname.$libext
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ if test yes = "$hardcode_automatic"; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test yes = "$installed"; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output=$output_objdir/${outputname}i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name=$func_basename_result
+ func_resolve_sysroot "$deplib"
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+ test -z "$libdir" && \
+ func_fatal_error "'$deplib' is not a valid libtool archive"
+ func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ -L*)
+ func_stripname -L '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -L$func_replace_sysroot_result"
+ ;;
+ -R*)
+ func_stripname -R '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -R$func_replace_sysroot_result"
+ ;;
+ *) func_append newdependency_libs " $deplib" ;;
+ esac
+ done
+ dependency_libs=$newdependency_libs
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "'$lib' is not a valid libtool archive"
+ func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ *) func_append newdlfiles " $lib" ;;
+ esac
+ done
+ dlfiles=$newdlfiles
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name=$func_basename_result
+ eval libdir=`$SED -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "'$lib' is not a valid libtool archive"
+ func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles=$newdlprefiles
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlfiles " $abs"
+ done
+ dlfiles=$newdlfiles
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs=$lib ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlprefiles " $abs"
+ done
+ dlprefiles=$newdlprefiles
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ # In fact, it would be nice if we could use this code for all target
+ # systems that can't hard-code library paths into their executables
+ # and that have no shared library path variable independent of PATH,
+ # but it turns out we can't easily determine that from inspecting
+ # libtool variables, so we have to hard-code the OSs to which it
+ # applies here; at the moment, that means platforms that use the PE
+ # object format with DLL files. See the long comment at the top of
+ # tests/bindir.at for full details.
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ # If a -bindir argument was supplied, place the dll there.
+ if test -n "$bindir"; then
+ func_relative_path "$install_libdir" "$bindir"
+ tdlname=$func_relative_path_result/$dlname
+ else
+ # Otherwise fall back on heuristic.
+ tdlname=../bin/$dlname
+ fi
+ ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that cannot go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test no,yes = "$installed,$need_relink"; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+if test link = "$opt_mode" || test relink = "$opt_mode"; then
+ func_mode_link ${1+"$@"}
+fi
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $debug_cmd
+
+ RM=$nonopt
+ files=
+ rmforce=false
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic=$magic
+
+ for arg
+ do
+ case $arg in
+ -f) func_append RM " $arg"; rmforce=: ;;
+ -*) func_append RM " $arg" ;;
+ *) func_append files " $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir=$func_dirname_result
+ if test . = "$dir"; then
+ odir=$objdir
+ else
+ odir=$dir/$objdir
+ fi
+ func_basename "$file"
+ name=$func_basename_result
+ test uninstall = "$opt_mode" && odir=$dir
+
+ # Remember odir for removal later, being careful to avoid duplicates
+ if test clean = "$opt_mode"; then
+ case " $rmdirs " in
+ *" $odir "*) ;;
+ *) func_append rmdirs " $odir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif $rmforce; then
+ continue
+ fi
+
+ rmfiles=$file
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ func_append rmfiles " $odir/$n"
+ done
+ test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+ case $opt_mode in
+ clean)
+ case " $library_names " in
+ *" $dlname "*) ;;
+ *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+ esac
+ test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" '$rmforce || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" '$rmforce || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" && test none != "$pic_object"; then
+ func_append rmfiles " $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" && test none != "$non_pic_object"; then
+ func_append rmfiles " $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test clean = "$opt_mode"; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ func_append rmfiles " $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ func_append rmfiles " $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ func_append rmfiles " $odir/$name $odir/${name}S.$objext"
+ if test yes = "$fast_install" && test -n "$relink_command"; then
+ func_append rmfiles " $odir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name"; then
+ func_append rmfiles " $odir/lt-$noexename.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+
+ # Try to remove the $objdir's in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+if test uninstall = "$opt_mode" || test clean = "$opt_mode"; then
+ func_mode_uninstall ${1+"$@"}
+fi
+
+test -z "$opt_mode" && {
+ help=$generic_help
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode '$opt_mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# where we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
diff --git a/build-aux/missing b/build-aux/missing
new file mode 100755
index 0000000..8d0eaad
--- /dev/null
+++ b/build-aux/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=https://www.perl.org/
+flex_URL=https://github.com/westes/flex
+gnu_software_URL=https://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/build-aux/ylwrap b/build-aux/ylwrap
new file mode 100755
index 0000000..d153336
--- /dev/null
+++ b/build-aux/ylwrap
@@ -0,0 +1,247 @@
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2018-03-07.03; # UTC
+
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+get_dirname ()
+{
+ case $1 in
+ */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
+ # Otherwise, we want the empty string (not ".").
+ esac
+}
+
+# guard FILE
+# ----------
+# The CPP macro used to guard inclusion of FILE.
+guard ()
+{
+ printf '%s\n' "$1" \
+ | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \
+ -e 's/__*/_/g'
+}
+
+# quote_for_sed [STRING]
+# ----------------------
+# Return STRING (or stdin) quoted to be used as a sed pattern.
+quote_for_sed ()
+{
+ case $# in
+ 0) cat;;
+ 1) printf '%s\n' "$1";;
+ esac \
+ | sed -e 's|[][\\.*]|\\&|g'
+}
+
+case "$1" in
+ '')
+ echo "$0: No files given. Try '$0 --help' for more information." 1>&2
+ exit 1
+ ;;
+ --basedir)
+ basedir=$2
+ shift 2
+ ;;
+ -h|--h*)
+ cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+ INPUT is the input file
+ OUTPUT is one file PROG generates
+ DESIRED is the file we actually want instead of OUTPUT
+ PROGRAM is program to run
+ ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v|--v*)
+ echo "ylwrap $scriptversion"
+ exit $?
+ ;;
+esac
+
+
+# The input.
+input=$1
+shift
+# We'll later need for a correct munging of "#line" directives.
+input_sub_rx=`get_dirname "$input" | quote_for_sed`
+case $input in
+ [\\/]* | ?:[\\/]*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Relative path. Make it absolute.
+ input=`pwd`/$input
+ ;;
+esac
+input_rx=`get_dirname "$input" | quote_for_sed`
+
+# Since DOS filename conventions don't allow two dots,
+# the DOS version of Bison writes out y_tab.c instead of y.tab.c
+# and y_tab.h instead of y.tab.h. Test to see if this is the case.
+y_tab_nodot=false
+if test -f y_tab.c || test -f y_tab.h; then
+ y_tab_nodot=true
+fi
+
+# The parser itself, the first file, is the destination of the .y.c
+# rule in the Makefile.
+parser=$1
+
+# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
+# instance, we rename #include "y.tab.h" into #include "parse.h"
+# during the conversion from y.tab.c to parse.c.
+sed_fix_filenames=
+
+# Also rename header guards, as Bison 2.7 for instance uses its header
+# guard in its implementation file.
+sed_fix_header_guards=
+
+while test $# -ne 0; do
+ if test x"$1" = x"--"; then
+ shift
+ break
+ fi
+ from=$1
+ # Handle y_tab.c and y_tab.h output by DOS
+ if $y_tab_nodot; then
+ case $from in
+ "y.tab.c") from=y_tab.c;;
+ "y.tab.h") from=y_tab.h;;
+ esac
+ fi
+ shift
+ to=$1
+ shift
+ sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
+ sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
+done
+
+# The program to run.
+prog=$1
+shift
+# Make any relative path in $prog absolute.
+case $prog in
+ [\\/]* | ?:[\\/]*) ;;
+ *[\\/]*) prog=`pwd`/$prog ;;
+esac
+
+dirname=ylwrap$$
+do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
+trap "ret=129; $do_exit" 1
+trap "ret=130; $do_exit" 2
+trap "ret=141; $do_exit" 13
+trap "ret=143; $do_exit" 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+ 0) "$prog" "$input" ;;
+ *) "$prog" "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+ for from in *
+ do
+ to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
+ if test -f "$from"; then
+ # If $2 is an absolute path name, then just use that,
+ # otherwise prepend '../'.
+ case $to in
+ [\\/]* | ?:[\\/]*) target=$to;;
+ *) target=../$to;;
+ esac
+
+ # Do not overwrite unchanged header files to avoid useless
+ # recompilations. Always update the parser itself: it is the
+ # destination of the .y.c rule in the Makefile. Divert the
+ # output of all other files to a temporary file so we can
+ # compare them to existing versions.
+ if test $from != $parser; then
+ realtarget=$target
+ target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
+ fi
+
+ # Munge "#line" or "#" directives. Don't let the resulting
+ # debug information point at an absolute srcdir. Use the real
+ # output file name, not yy.lex.c for instance. Adjust the
+ # include guards too.
+ sed -e "/^#/!b" \
+ -e "s|$input_rx|$input_sub_rx|" \
+ -e "$sed_fix_filenames" \
+ -e "$sed_fix_header_guards" \
+ "$from" >"$target" || ret=$?
+
+ # Check whether files must be updated.
+ if test "$from" != "$parser"; then
+ if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+ echo "$to is unchanged"
+ rm -f "$target"
+ else
+ echo "updating $to"
+ mv -f "$target" "$realtarget"
+ fi
+ fi
+ else
+ # A missing file is only an error for the parser. This is a
+ # blatant hack to let us support using "yacc -d". If -d is not
+ # specified, don't fail when the header file is "missing".
+ if test "$from" = "$parser"; then
+ ret=1
+ fi
+ fi
+ done
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'before-save-hook 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..cce6652
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,133 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the declaration of `getprotobyname_r', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETPROTOBYNAME_R
+
+/* Define to 1 if you have the declaration of `getprotobynumber_r', and to 0
+ if you don't. */
+#undef HAVE_DECL_GETPROTOBYNUMBER_R
+
+/* Define to 1 if you have the declaration of `getservbyport_r', and to 0 if
+ you don't. */
+#undef HAVE_DECL_GETSERVBYPORT_R
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `edit' library (-ledit). */
+#undef HAVE_LIBEDIT
+
+/* Define to 1 if you have the `gmp' library (-lgmp). */
+#undef HAVE_LIBGMP
+
+/* Define if you have libjansson */
+#undef HAVE_LIBJANSSON
+
+/* Define to 1 if you have the `linenoise' library (-llinenoise). */
+#undef HAVE_LIBLINENOISE
+
+/* Define to 1 if you have the `readline' library (-lreadline). */
+#undef HAVE_LIBREADLINE
+
+/* 0 */
+#undef HAVE_LIBXTABLES
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* True if compiler supports -fvisibility=hidden */
+#undef HAVE_VISIBILITY_HIDDEN
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Release name */
+#undef RELEASE_NAME
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/configure b/configure
new file mode 100755
index 0000000..4a34132
--- /dev/null
+++ b/configure
@@ -0,0 +1,15963 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for nftables 1.0.9.
+#
+# Report bugs to <netfilter-devel@vger.kernel.org>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: netfilter-devel@vger.kernel.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='nftables'
+PACKAGE_TARNAME='nftables'
+PACKAGE_VERSION='1.0.9'
+PACKAGE_STRING='nftables 1.0.9'
+PACKAGE_BUGREPORT='netfilter-devel@vger.kernel.org'
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+BUILD_JSON_FALSE
+BUILD_JSON_TRUE
+BUILD_XTABLES_FALSE
+BUILD_XTABLES_TRUE
+XTABLES_LIBS
+XTABLES_CFLAGS
+BUILD_CLI_FALSE
+BUILD_CLI_TRUE
+BUILD_MINIGMP_FALSE
+BUILD_MINIGMP_TRUE
+LIBNFTNL_LIBS
+LIBNFTNL_CFLAGS
+LIBMNL_LIBS
+LIBMNL_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
+A2X
+GCC_FVISIBILITY_HIDDEN
+LT_SYS_LIBRARY_PATH
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+DLLTOOL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+ac_ct_AR
+AR
+YFLAGS
+YACC
+LEXLIB
+LEX_OUTPUT_ROOT
+LEX
+SED
+EGREP
+GREP
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+BUILD_MAN_FALSE
+BUILD_MAN_TRUE
+BUILD_DEBUG_FALSE
+BUILD_DEBUG_TRUE
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL
+am__quote'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_debug
+enable_man_doc
+enable_dependency_tracking
+enable_static
+enable_shared
+with_pic
+enable_fast_install
+with_aix_soname
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+with_mini_gmp
+with_cli
+with_xtables
+with_json
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+YACC
+YFLAGS
+LT_SYS_LIBRARY_PATH
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+LIBMNL_CFLAGS
+LIBMNL_LIBS
+LIBNFTNL_CFLAGS
+LIBNFTNL_LIBS
+XTABLES_CFLAGS
+XTABLES_LIBS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir runstatedir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures nftables 1.0.9 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/nftables]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of nftables 1.0.9:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-silent-rules less verbose build output (undo: "make V=1")
+ --disable-silent-rules verbose build output (undo: "make V=0")
+ --disable-debug Disable debugging symbols
+ --disable-man-doc Disable man page documentation
+ --enable-dependency-tracking
+ do not reject slow dependency extractors
+ --disable-dependency-tracking
+ speeds up one-time build
+ --enable-static[=PKGS] build static libraries [default=no]
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-aix-soname=aix|svr4|both
+ shared library versioning (aka "SONAME") variant to
+ provide on AIX, [default=aix].
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the
+ compiler's sysroot if not specified).
+ --with-mini-gmp Use builtin mini-gmp (for embedded builds)
+ --without-cli disable interactive CLI (libreadline, editline or
+ linenoise support)
+ --with-xtables Use libxtables for iptables interaction
+ --with-json Enable JSON output support
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ YACC The `Yet Another Compiler Compiler' implementation to use.
+ Defaults to the first program found out of: `bison -y', `byacc',
+ `yacc'.
+ YFLAGS The list of arguments that will be passed by default to $YACC.
+ This script will default YFLAGS to the empty string to avoid a
+ default value of `-d' given by some make applications.
+ LT_SYS_LIBRARY_PATH
+ User-defined run-time library search path.
+ PKG_CONFIG path to pkg-config utility
+ PKG_CONFIG_PATH
+ directories to add to pkg-config's search path
+ PKG_CONFIG_LIBDIR
+ path overriding pkg-config's built-in search path
+ LIBMNL_CFLAGS
+ C compiler flags for LIBMNL, overriding pkg-config
+ LIBMNL_LIBS linker flags for LIBMNL, overriding pkg-config
+ LIBNFTNL_CFLAGS
+ C compiler flags for LIBNFTNL, overriding pkg-config
+ LIBNFTNL_LIBS
+ linker flags for LIBNFTNL, overriding pkg-config
+ XTABLES_CFLAGS
+ C compiler flags for XTABLES, overriding pkg-config
+ XTABLES_LIBS
+ linker flags for XTABLES, overriding pkg-config
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <netfilter-devel@vger.kernel.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+nftables configure 1.0.9
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( $as_echo "## ---------------------------------------------- ##
+## Report this to netfilter-devel@vger.kernel.org ##
+## ---------------------------------------------- ##"
+ ) | sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ as_decl_name=`echo $2|sed 's/ *(.*//'`
+ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+ (void) $as_decl_use;
+#else
+ (void) $as_decl_name;
+#endif
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_decl
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by nftables $as_me 1.0.9, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+$as_echo "#define RELEASE_NAME \"Old Doc Yak #3\"" >>confdefs.h
+
+
+ac_aux_dir=
+for ac_dir in build-aux "$srcdir"/build-aux; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+am__api_version='1.16'
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+ if test "$2" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ MISSING="\${SHELL} '$am_aux_dir/missing'"
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if ${ac_cv_path_mkdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='nftables'
+ VERSION='1.0.9'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar pax cpio none'
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a pax tar archive" >&5
+$as_echo_n "checking how to create a pax tar archive... " >&6; }
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_pax-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ { echo "$as_me:$LINENO: $_am_tar --version" >&5
+ ($_am_tar --version) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && break
+ done
+ am__tar="$_am_tar --format=posix -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=posix -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x pax -w "$$tardir"'
+ am__tar_='pax -L -x pax -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H pax -L'
+ am__tar_='find "$tardir" -print | cpio -o -H pax -L'
+ am__untar='cpio -i -H pax -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_pax}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5
+ (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ { echo "$as_me:$LINENO: $am__untar <conftest.tar" >&5
+ ($am__untar <conftest.tar) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ { echo "$as_me:$LINENO: cat conftest.dir/file" >&5
+ (cat conftest.dir/file) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ if ${am_cv_prog_tar_pax+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ am_cv_prog_tar_pax=$_am_tool
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_pax" >&5
+$as_echo "$am_cv_prog_tar_pax" >&6; }
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <https://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+ fi
+fi
+
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+ enableval=$enable_debug;
+else
+ enable_debug=yes
+fi
+
+ if test "x$enable_debug" != xno; then
+ BUILD_DEBUG_TRUE=
+ BUILD_DEBUG_FALSE='#'
+else
+ BUILD_DEBUG_TRUE='#'
+ BUILD_DEBUG_FALSE=
+fi
+
+
+# Check whether --enable-man-doc was given.
+if test "${enable_man_doc+set}" = set; then :
+ enableval=$enable_man_doc;
+else
+ enable_man_doc=yes
+fi
+
+ if test "x$enable_man_doc" = "xyes" ; then
+ BUILD_MAN_TRUE=
+ BUILD_MAN_FALSE='#'
+else
+ BUILD_MAN_TRUE='#'
+ BUILD_MAN_FALSE=
+fi
+
+
+# Checks for programs.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5
+$as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; }
+cat > confinc.mk << 'END'
+am__doit:
+ @echo this is the am__doit target >confinc.out
+.PHONY: am__doit
+END
+am__include="#"
+am__quote=
+# BSD make does it like this.
+echo '.include "confinc.mk" # ignored' > confmf.BSD
+# Other make implementations (GNU, Solaris 10, AIX) do it like this.
+echo 'include confinc.mk # ignored' > confmf.GNU
+_am_result=no
+for s in GNU BSD; do
+ { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5
+ (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ case $?:`cat confinc.out 2>/dev/null` in #(
+ '0:this is the am__doit target') :
+ case $s in #(
+ BSD) :
+ am__include='.include' am__quote='"' ;; #(
+ *) :
+ am__include='include' am__quote='' ;;
+esac ;; #(
+ *) :
+ ;;
+esac
+ if test "$am__include" != "#"; then
+ _am_result="yes ($s style)"
+ break
+ fi
+done
+rm -f confinc.* confmf.*
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5
+$as_echo "${_am_result}" >&6; }
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+ MINIX=yes
+else
+ MINIX=
+fi
+
+
+ if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# define __EXTENSIONS__ 1
+ $ac_includes_default
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_safe_to_define___extensions__=yes
+else
+ ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+ $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+ $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+for ac_prog in flex lex
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LEX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LEX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5
+$as_echo "$LEX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+ cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */
+ yyless ((input () != 0)); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+ return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ { ac_try="$LEX conftest.l"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$LEX conftest.l") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5
+$as_echo_n "checking lex output file root... " >&6; }
+if ${ac_cv_prog_lex_root+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+if test -f lex.yy.c; then
+ ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+ ac_cv_prog_lex_root=lexyy
+else
+ as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5
+$as_echo "$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5
+$as_echo_n "checking lex library... " >&6; }
+if ${ac_cv_lib_lex+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS=$LIBS
+ ac_cv_lib_lex='none needed'
+ for ac_lib in '' -lfl -ll; do
+ LIBS="$ac_lib $ac_save_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_lex=$ac_lib
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ test "$ac_cv_lib_lex" != 'none needed' && break
+ done
+ LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5
+$as_echo "$ac_cv_lib_lex" >&6; }
+ test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5
+$as_echo_n "checking whether yytext is a pointer... " >&6; }
+if ${ac_cv_prog_lex_yytext_pointer+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent. Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_prog_lex_yytext_pointer=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5
+$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+for ac_prog in 'bison -y' byacc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_YACC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_YACC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+
+if test -z "$ac_cv_prog_YACC" -a ! -f "${srcdir}/src/parser_bison.c"
+then
+ echo "*** Error: No suitable bison/yacc found. ***"
+ echo " Please install the 'bison' package."
+ exit 1
+fi
+if test -z "$ac_cv_prog_LEX" -a ! -f "${srcdir}/src/scanner.c"
+then
+ echo "*** Error: No suitable flex/lex found. ***"
+ echo " Please install the 'flex' package."
+ exit 1
+fi
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar lib "link -lib"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar lib "link -lib"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+fi
+
+: ${AR=ar}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5
+$as_echo_n "checking the archiver ($AR) interface... " >&6; }
+if ${am_cv_ar_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ am_cv_ar_interface=ar
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int some_variable = 0;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+ (eval $am_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=ar
+ else
+ am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+ (eval $am_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=lib
+ else
+ am_cv_ar_interface=unknown
+ fi
+ fi
+ rm -f conftest.lib libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5
+$as_echo "$am_cv_ar_interface" >&6; }
+
+case $am_cv_ar_interface in
+ar)
+ ;;
+lib)
+ # Microsoft lib, so override with the ar-lib wrapper script.
+ # FIXME: It is wrong to rewrite AR.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__AR in this case,
+ # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+ # similar.
+ AR="$am_aux_dir/ar-lib $AR"
+ ;;
+unknown)
+ as_fn_error $? "could not determine $AR interface" "$LINENO" 5
+ ;;
+esac
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.6'
+macro_revision='2.4.6'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case $ECHO in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test no = "$withval" || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test yes = "$GCC"; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return, which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD=$ac_prog
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test yes = "$with_gnu_ld"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD=$ac_dir/$ac_prog
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test no != "$with_gnu_ld" && break
+ ;;
+ *)
+ test yes != "$with_gnu_ld" && break
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+else
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi
+fi
+
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM=$NM
+else
+ lt_nm_to_check=${ac_tool_prefix}nm
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break 2
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break 2
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols -headers"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring=ABCD
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test 17 != "$i" # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n "$lt_cv_sys_max_cmd_len"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test yes != "$GCC"; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cr}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ar_at_file=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test 0 -eq "$ac_status"; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test 0 -ne "$ac_status"; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test no = "$lt_cv_ar_at_file"; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ bitrig* | openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test ia64 = "$host_cpu"; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5
+ if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS=conftstm.$ac_objext
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest$ac_exeext; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test yes = "$pipe_works"; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+ withval=$with_sysroot;
+else
+ with_sysroot=no
+fi
+
+
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+ if test yes = "$GCC"; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sysroot" >&5
+$as_echo "$with_sysroot" >&6; }
+ as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+ ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a working dd" >&5
+$as_echo_n "checking for a working dd... " >&6; }
+if ${ac_cv_path_lt_DD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+if test -z "$lt_DD"; then
+ ac_path_lt_DD_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in dd; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_lt_DD="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_lt_DD" || continue
+if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi
+ $ac_path_lt_DD_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_lt_DD"; then
+ :
+ fi
+else
+ ac_cv_path_lt_DD=$lt_DD
+fi
+
+rm -f conftest.i conftest2.i conftest.out
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_lt_DD" >&5
+$as_echo "$ac_cv_path_lt_DD" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to truncate binary pipes" >&5
+$as_echo_n "checking how to truncate binary pipes... " >&6; }
+if ${lt_cv_truncate_bin+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_truncate_bin" >&5
+$as_echo "$lt_cv_truncate_bin" >&6; }
+
+
+
+
+
+
+
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in $*""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE=32
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE=64
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*linux*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*linux*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test yes != "$lt_cv_cc_needs_belf"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS=$SAVE_CFLAGS
+ fi
+ ;;
+*-*solaris*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*|x86_64-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD=${LD-ld}_sol2
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks=$enable_libtool_lock
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MANIFEST_TOOL"; then
+ ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+ ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+ # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_MANIFEST_TOOL"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_MANIFEST_TOOL" = x; then
+ MANIFEST_TOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+ fi
+else
+ MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&5
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test yes != "$lt_cv_path_mainfest_tool"; then
+ MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "$LT_MULTI_MODULE"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&5
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cr libconftest.a conftest.o" >&5
+ $AR cr libconftest.a conftest.o 2>&5
+ echo "$RANLIB libconftest.a" >&5
+ $RANLIB libconftest.a 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&5
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[912]*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[012][,.]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ 10.*|11.*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+ fi
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x$2 in
+ x)
+ ;;
+ *:)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+ ;;
+ x:*)
+ eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+ ;;
+ *)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ enable_static=no
+fi
+
+
+
+
+
+
+
+
+
+
+ enable_dlopen=no
+
+
+ enable_win32_dll=no
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for lt_pkg in $withval; do
+ IFS=$lt_save_ifs
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ pic_mode=default
+fi
+
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+ shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[5-9]*,yes)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking which variant of shared library versioning to provide" >&5
+$as_echo_n "checking which variant of shared library versioning to provide... " >&6; }
+
+# Check whether --with-aix-soname was given.
+if test "${with_aix_soname+set}" = set; then :
+ withval=$with_aix_soname; case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ as_fn_error $? "Unknown argument to --with-aix-soname" "$LINENO" 5
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname
+else
+ if ${lt_cv_with_aix_soname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_with_aix_soname=aix
+fi
+
+ with_aix_soname=$lt_cv_with_aix_soname
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_aix_soname" >&5
+$as_echo "$with_aix_soname" >&6; }
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+func_cc_basename $compiler
+cc_basename=$func_cc_basename_result
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/${ac_tool_prefix}file"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
+ ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/file"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
+ ;;
+esac
+fi
+
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC=$CC
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test yes = "$GCC"; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions" ## exclude from sc_useless_quotes_in_assignment
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_rtti_exceptions"; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+ if test yes = "$GCC"; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ case $host_os in
+ os2*)
+ lt_prog_compiler_static='$wl-static'
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ if test -n "$lt_prog_compiler_pic"; then
+ lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ case $host_os in
+ os2*)
+ lt_prog_compiler_static='$wl-static'
+ ;;
+ esac
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='$wl-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64, which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # flang / f18. f95 an alias for gfortran or flang on Debian
+ flang* | f18* | f95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Intel*\ [CF]*Compiler*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ *Portland\ Group*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms that do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC" ## exclude from sc_useless_quotes_in_assignment
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_pic_works"; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test yes = "$lt_cv_prog_compiler_static_works"; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links=nottested
+if test no = "$lt_cv_prog_compiler_c_o" && test no != "$need_locks"; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test no = "$hard_links"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: '$CC' does not support '-c -o', so 'make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test yes != "$GCC"; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd* | bitrig*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ link_all_deplibs=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test yes = "$with_gnu_ld"; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test yes = "$lt_use_gnu_ld_interface"; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='$wl'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ export_dynamic_flag_spec='$wl--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v | $SED -e 's/(^)\+)\s\+//' 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test ia64 != "$host_cpu"; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='$wl--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ shrext_cmds=.dll
+ archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ export_dynamic_flag_spec='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test linux-dietlibc = "$host_os"; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test no = "$tmp_diet"
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+ if test yes = "$supports_anon_versioning"; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ tcc*)
+ export_dynamic_flag_spec='-rdynamic'
+ ;;
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test no = "$ld_shlibs"; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ ;;
+ esac
+
+ if test yes = "$GCC"; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ export_dynamic_flag_spec='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test set = "${lt_cv_aix_libpath+set}"; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=/usr/lib:/lib
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ hardcode_libdir_flag_spec='$wl-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test set = "${lt_cv_aix_libpath+set}"; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=/usr/lib:/lib
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' $wl-bernotok'
+ allow_undefined_flag=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ archive_expsym_cmds='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([, ]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ archive_expsym_cmds="$archive_expsym_cmds"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ archive_expsym_cmds="$archive_expsym_cmds"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ archive_expsym_cmds="$archive_expsym_cmds"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ file_list_spec='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ archive_expsym_cmds='if test DEF = "`$SED -n -e '\''s/^[ ]*//'\'' -e '\''/^\(;.*\)*$/d'\'' -e '\''s/^\(EXPORTS\|LIBRARY\)\([ ].*\)*$/DEF/p'\'' -e q $export_symbols`" ; then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+ enable_shared_with_static_runtimes=yes
+ exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ old_postinstall_cmds='chmod 644 $oldlib'
+ postlink_cmds='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ enable_shared_with_static_runtimes=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test yes = "$lt_cv_ld_force_load"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag=$_lt_dar_allow_undefined
+ case $cc_basename in
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test yes = "$_lt_dar_can_shared"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ archive_expsym_cmds="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ module_expsym_cmds="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test yes = "$GCC"; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='$wl-E'
+ ;;
+
+ hpux10*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test no = "$with_gnu_ld"; then
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='$wl-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS=$save_LDFLAGS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test yes = "$lt_cv_prog_compiler__b"; then
+ archive_cmds='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test no = "$with_gnu_ld"; then
+ hardcode_libdir_flag_spec='$wl+b $wl$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='$wl-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_irix_exported_symbol=yes
+else
+ lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+ fi
+ link_all_deplibs=no
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ ld_shlibs=yes
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ export_dynamic_flag_spec='$wl-E'
+ else
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='$wl-rpath,$libdir'
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ shrext_cmds=.dll
+ archive_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ archive_expsym_cmds='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ osf3*)
+ if test yes = "$GCC"; then
+ allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test yes = "$GCC"; then
+ allow_undefined_flag=' $wl-expect_unresolved $wl\*'
+ archive_cmds='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ hardcode_libdir_flag_spec='$wl-rpath $wl$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ archive_cmds='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='$wl'
+ archive_cmds='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test yes = "$GCC"; then
+ whole_archive_flag_spec='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test sequent = "$host_vendor"; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='$wl-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='$wl-z,text'
+ allow_undefined_flag='$wl-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='$wl-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ archive_cmds='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test sni = "$host_vendor"; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='$wl-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test no = "$ld_shlibs" && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test yes,yes = "$GCC,$enable_shared"; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test yes = "$GCC"; then
+ case $host_os in
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([A-Za-z]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary...
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo = "/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's|/\([A-Za-z]:\)|\1|g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 supports IA64
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a(lib.so.V)'
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V($shared_archive_member_spec.o), lib.a(lib.so.V)"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a(lib.so.V), lib.so.V($shared_archive_member_spec.o)"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='$libname$shared_ext'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec=$LIB
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+ fi
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ hardcode_libdir_flag_spec='-L$libdir'
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd* | bitrig*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec=/usr/lib
+ need_lib_prefix=no
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
+ else
+ need_version=yes
+ fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+os2*)
+ libname_spec='$name'
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test yes = "$with_gnu_ld"; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=sco
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test yes = "$with_gnu_ld"; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test yes = "$hardcode_automatic"; then
+
+ # We can hardcode non-existent directories.
+ if test no != "$hardcode_direct" &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, )" &&
+ test no != "$hardcode_minus_L"; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test relink = "$hardcode_action" ||
+ test yes = "$inherit_rpath"; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test yes != "$enable_dlopen"; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen=load_add_on
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen=LoadLibrary
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+
+ lt_cv_dlopen=dyld
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+ lt_cv_dlopen=shl_load
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+ lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+ lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+ lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test no = "$lt_cv_dlopen"; then
+ enable_dlopen=no
+ else
+ enable_dlopen=yes
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS=$LDFLAGS
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS=$LIBS
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test yes = "$cross_compiling"; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test yes = "$lt_cv_dlopen_self"; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test yes = "$cross_compiling"; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "conftest$ac_exeext" 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP"; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report what library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC=$lt_save_CC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$saved_CFLAGS -fvisibility=hidden"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler accepts -fvisibility=hidden" >&5
+$as_echo_n "checking whether compiler accepts -fvisibility=hidden... " >&6; }
+if ${ac_cv_fvisibility_hidden+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_fvisibility_hidden=yes
+else
+ ac_cv_fvisibility_hidden=no
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_fvisibility_hidden" >&5
+$as_echo "$ac_cv_fvisibility_hidden" >&6; }
+ if test "$ac_cv_fvisibility_hidden" = "yes"; then
+
+$as_echo "#define HAVE_VISIBILITY_HIDDEN 1" >>confdefs.h
+
+ GCC_FVISIBILITY_HIDDEN=-fvisibility=hidden
+
+ fi
+ CFLAGS="$saved_CFLAGS"
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+if test "x$enable_man_doc" = "xyes"; then :
+
+ # Extract the first word of "a2x", so it can be a program name with args.
+set dummy a2x; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_A2X+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$A2X"; then
+ ac_cv_prog_A2X="$A2X" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_A2X="a2x"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_A2X" && ac_cv_prog_A2X="no"
+fi
+fi
+A2X=$ac_cv_prog_A2X
+if test -n "$A2X"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $A2X" >&5
+$as_echo "$A2X" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "$A2X" = "no" -a ! -f "${srcdir}/doc/nft.8"; then :
+ as_fn_error $? "a2x not found, please install asciidoc" "$LINENO" 5
+fi
+
+fi
+
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ PKG_CONFIG=""
+ fi
+fi
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libmnl >= 1.0.4" >&5
+$as_echo_n "checking for libmnl >= 1.0.4... " >&6; }
+
+if test -n "$LIBMNL_CFLAGS"; then
+ pkg_cv_LIBMNL_CFLAGS="$LIBMNL_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmnl >= 1.0.4\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libmnl >= 1.0.4") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBMNL_CFLAGS=`$PKG_CONFIG --cflags "libmnl >= 1.0.4" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LIBMNL_LIBS"; then
+ pkg_cv_LIBMNL_LIBS="$LIBMNL_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libmnl >= 1.0.4\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libmnl >= 1.0.4") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBMNL_LIBS=`$PKG_CONFIG --libs "libmnl >= 1.0.4" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LIBMNL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libmnl >= 1.0.4" 2>&1`
+ else
+ LIBMNL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libmnl >= 1.0.4" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBMNL_PKG_ERRORS" >&5
+
+ as_fn_error $? "Package requirements (libmnl >= 1.0.4) were not met:
+
+$LIBMNL_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables LIBMNL_CFLAGS
+and LIBMNL_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables LIBMNL_CFLAGS
+and LIBMNL_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ LIBMNL_CFLAGS=$pkg_cv_LIBMNL_CFLAGS
+ LIBMNL_LIBS=$pkg_cv_LIBMNL_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnftnl >= 1.2.6" >&5
+$as_echo_n "checking for libnftnl >= 1.2.6... " >&6; }
+
+if test -n "$LIBNFTNL_CFLAGS"; then
+ pkg_cv_LIBNFTNL_CFLAGS="$LIBNFTNL_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnftnl >= 1.2.6\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libnftnl >= 1.2.6") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBNFTNL_CFLAGS=`$PKG_CONFIG --cflags "libnftnl >= 1.2.6" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LIBNFTNL_LIBS"; then
+ pkg_cv_LIBNFTNL_LIBS="$LIBNFTNL_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libnftnl >= 1.2.6\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libnftnl >= 1.2.6") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBNFTNL_LIBS=`$PKG_CONFIG --libs "libnftnl >= 1.2.6" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LIBNFTNL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libnftnl >= 1.2.6" 2>&1`
+ else
+ LIBNFTNL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libnftnl >= 1.2.6" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBNFTNL_PKG_ERRORS" >&5
+
+ as_fn_error $? "Package requirements (libnftnl >= 1.2.6) were not met:
+
+$LIBNFTNL_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables LIBNFTNL_CFLAGS
+and LIBNFTNL_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables LIBNFTNL_CFLAGS
+and LIBNFTNL_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ LIBNFTNL_CFLAGS=$pkg_cv_LIBNFTNL_CFLAGS
+ LIBNFTNL_LIBS=$pkg_cv_LIBNFTNL_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+
+# Check whether --with-mini-gmp was given.
+if test "${with_mini_gmp+set}" = set; then :
+ withval=$with_mini_gmp;
+else
+ with_mini_gmp=no
+fi
+
+if test "x$with_mini_gmp" != xyes; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __gmpz_init in -lgmp" >&5
+$as_echo_n "checking for __gmpz_init in -lgmp... " >&6; }
+if ${ac_cv_lib_gmp___gmpz_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgmp $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char __gmpz_init ();
+int
+main ()
+{
+return __gmpz_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_gmp___gmpz_init=yes
+else
+ ac_cv_lib_gmp___gmpz_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gmp___gmpz_init" >&5
+$as_echo "$ac_cv_lib_gmp___gmpz_init" >&6; }
+if test "x$ac_cv_lib_gmp___gmpz_init" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBGMP 1
+_ACEOF
+
+ LIBS="-lgmp $LIBS"
+
+else
+ as_fn_error $? "No suitable version of libgmp found" "$LINENO" 5
+fi
+
+
+fi
+ if test "x$with_mini_gmp" = xyes; then
+ BUILD_MINIGMP_TRUE=
+ BUILD_MINIGMP_FALSE='#'
+else
+ BUILD_MINIGMP_TRUE='#'
+ BUILD_MINIGMP_FALSE=
+fi
+
+
+
+# Check whether --with-cli was given.
+if test "${with_cli+set}" = set; then :
+ withval=$with_cli;
+else
+ with_cli=editline
+fi
+
+
+if test "x$with_cli" = xreadline; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -lreadline" >&5
+$as_echo_n "checking for readline in -lreadline... " >&6; }
+if ${ac_cv_lib_readline_readline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lreadline $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char readline ();
+int
+main ()
+{
+return readline ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_readline_readline=yes
+else
+ ac_cv_lib_readline_readline=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_readline" >&5
+$as_echo "$ac_cv_lib_readline_readline" >&6; }
+if test "x$ac_cv_lib_readline_readline" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBREADLINE 1
+_ACEOF
+
+ LIBS="-lreadline $LIBS"
+
+else
+ as_fn_error $? "No suitable version of libreadline found" "$LINENO" 5
+fi
+
+$as_echo "#define HAVE_LIBREADLINE 1" >>confdefs.h
+
+
+elif test "x$with_cli" = xlinenoise; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linenoise in -llinenoise" >&5
+$as_echo_n "checking for linenoise in -llinenoise... " >&6; }
+if ${ac_cv_lib_linenoise_linenoise+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-llinenoise $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char linenoise ();
+int
+main ()
+{
+return linenoise ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_linenoise_linenoise=yes
+else
+ ac_cv_lib_linenoise_linenoise=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_linenoise_linenoise" >&5
+$as_echo "$ac_cv_lib_linenoise_linenoise" >&6; }
+if test "x$ac_cv_lib_linenoise_linenoise" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBLINENOISE 1
+_ACEOF
+
+ LIBS="-llinenoise $LIBS"
+
+else
+ as_fn_error $? "No suitable version of linenoise found" "$LINENO" 5
+fi
+
+$as_echo "#define HAVE_LIBLINENOISE 1" >>confdefs.h
+
+
+elif test "x$with_cli" = xeditline; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for readline in -ledit" >&5
+$as_echo_n "checking for readline in -ledit... " >&6; }
+if ${ac_cv_lib_edit_readline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ledit $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char readline ();
+int
+main ()
+{
+return readline ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_edit_readline=yes
+else
+ ac_cv_lib_edit_readline=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_edit_readline" >&5
+$as_echo "$ac_cv_lib_edit_readline" >&6; }
+if test "x$ac_cv_lib_edit_readline" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBEDIT 1
+_ACEOF
+
+ LIBS="-ledit $LIBS"
+
+else
+ as_fn_error $? "No suitable version of libedit found" "$LINENO" 5
+fi
+
+$as_echo "#define HAVE_LIBEDIT 1" >>confdefs.h
+
+
+elif test "x$with_cli" != xno; then :
+
+as_fn_error $? "unexpected CLI value: $with_cli" "$LINENO" 5
+
+fi
+ if test "x$with_cli" != xno; then
+ BUILD_CLI_TRUE=
+ BUILD_CLI_FALSE='#'
+else
+ BUILD_CLI_TRUE='#'
+ BUILD_CLI_FALSE=
+fi
+
+
+
+# Check whether --with-xtables was given.
+if test "${with_xtables+set}" = set; then :
+ withval=$with_xtables;
+else
+ with_xtables=no
+fi
+
+if test "x$with_xtables" != xno; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for xtables >= 1.6.1" >&5
+$as_echo_n "checking for xtables >= 1.6.1... " >&6; }
+
+if test -n "$XTABLES_CFLAGS"; then
+ pkg_cv_XTABLES_CFLAGS="$XTABLES_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xtables >= 1.6.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "xtables >= 1.6.1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_XTABLES_CFLAGS=`$PKG_CONFIG --cflags "xtables >= 1.6.1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$XTABLES_LIBS"; then
+ pkg_cv_XTABLES_LIBS="$XTABLES_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xtables >= 1.6.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "xtables >= 1.6.1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_XTABLES_LIBS=`$PKG_CONFIG --libs "xtables >= 1.6.1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ XTABLES_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xtables >= 1.6.1" 2>&1`
+ else
+ XTABLES_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xtables >= 1.6.1" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$XTABLES_PKG_ERRORS" >&5
+
+ as_fn_error $? "Package requirements (xtables >= 1.6.1) were not met:
+
+$XTABLES_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables XTABLES_CFLAGS
+and XTABLES_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables XTABLES_CFLAGS
+and XTABLES_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ XTABLES_CFLAGS=$pkg_cv_XTABLES_CFLAGS
+ XTABLES_LIBS=$pkg_cv_XTABLES_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+$as_echo "#define HAVE_LIBXTABLES 1" >>confdefs.h
+
+
+fi
+ if test "x$with_xtables" = xyes; then
+ BUILD_XTABLES_TRUE=
+ BUILD_XTABLES_FALSE='#'
+else
+ BUILD_XTABLES_TRUE='#'
+ BUILD_XTABLES_FALSE=
+fi
+
+
+
+# Check whether --with-json was given.
+if test "${with_json+set}" = set; then :
+ withval=$with_json;
+else
+ with_json=no
+fi
+
+if test "x$with_json" != xno; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for json_object in -ljansson" >&5
+$as_echo_n "checking for json_object in -ljansson... " >&6; }
+if ${ac_cv_lib_jansson_json_object+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljansson $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char json_object ();
+int
+main ()
+{
+return json_object ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_jansson_json_object=yes
+else
+ ac_cv_lib_jansson_json_object=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jansson_json_object" >&5
+$as_echo "$ac_cv_lib_jansson_json_object" >&6; }
+if test "x$ac_cv_lib_jansson_json_object" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBJANSSON 1
+_ACEOF
+
+ LIBS="-ljansson $LIBS"
+
+else
+ as_fn_error $? "No suitable version of libjansson found" "$LINENO" 5
+fi
+
+
+$as_echo "#define HAVE_LIBJANSSON 1" >>confdefs.h
+
+
+fi
+ if test "x$with_json" != xno; then
+ BUILD_JSON_TRUE=
+ BUILD_JSON_FALSE='#'
+else
+ BUILD_JSON_TRUE='#'
+ BUILD_JSON_FALSE=
+fi
+
+
+ac_fn_c_check_decl "$LINENO" "getprotobyname_r" "ac_cv_have_decl_getprotobyname_r" "
+#include <netdb.h>
+
+"
+if test "x$ac_cv_have_decl_getprotobyname_r" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETPROTOBYNAME_R $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "getprotobynumber_r" "ac_cv_have_decl_getprotobynumber_r" "
+#include <netdb.h>
+
+"
+if test "x$ac_cv_have_decl_getprotobynumber_r" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETPROTOBYNUMBER_R $ac_have_decl
+_ACEOF
+ac_fn_c_check_decl "$LINENO" "getservbyport_r" "ac_cv_have_decl_getservbyport_r" "
+#include <netdb.h>
+
+"
+if test "x$ac_cv_have_decl_getservbyport_r" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_GETSERVBYPORT_R $ac_have_decl
+_ACEOF
+
+
+ac_config_files="$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"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${BUILD_DEBUG_TRUE}" && test -z "${BUILD_DEBUG_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_DEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_MAN_TRUE}" && test -z "${BUILD_MAN_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_MAN\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_MINIGMP_TRUE}" && test -z "${BUILD_MINIGMP_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_MINIGMP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_CLI_TRUE}" && test -z "${BUILD_CLI_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_CLI\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_XTABLES_TRUE}" && test -z "${BUILD_XTABLES_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_XTABLES\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_JSON_TRUE}" && test -z "${BUILD_JSON_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_JSON\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by nftables $as_me 1.0.9, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <netfilter-devel@vger.kernel.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+nftables config.status 1.0.9
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+shared_archive_member_spec='`$ECHO "$shared_archive_member_spec" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_import='`$ECHO "$lt_cv_sys_global_symbol_to_import" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+lt_cv_nm_interface='`$ECHO "$lt_cv_nm_interface" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+lt_cv_truncate_bin='`$ECHO "$lt_cv_truncate_bin" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+configure_time_dlsearch_path='`$ECHO "$configure_time_dlsearch_path" | $SED "$delay_single_quote_subst"`'
+configure_time_lt_sys_library_path='`$ECHO "$configure_time_lt_sys_library_path" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_import \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_cv_nm_interface \
+nm_file_list_spec \
+lt_cv_truncate_bin \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+configure_time_dlsearch_path \
+configure_time_lt_sys_library_path; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "libnftables.pc") CONFIG_FILES="$CONFIG_FILES libnftables.pc" ;;
+ "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+ "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
+ "include/nftables/Makefile") CONFIG_FILES="$CONFIG_FILES include/nftables/Makefile" ;;
+ "include/linux/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/Makefile" ;;
+ "include/linux/netfilter/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/netfilter/Makefile" ;;
+ "include/linux/netfilter_arp/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/netfilter_arp/Makefile" ;;
+ "include/linux/netfilter_bridge/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/netfilter_bridge/Makefile" ;;
+ "include/linux/netfilter_ipv4/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/netfilter_ipv4/Makefile" ;;
+ "include/linux/netfilter_ipv6/Makefile") CONFIG_FILES="$CONFIG_FILES include/linux/netfilter_ipv6/Makefile" ;;
+ "files/Makefile") CONFIG_FILES="$CONFIG_FILES files/Makefile" ;;
+ "files/examples/Makefile") CONFIG_FILES="$CONFIG_FILES files/examples/Makefile" ;;
+ "files/nftables/Makefile") CONFIG_FILES="$CONFIG_FILES files/nftables/Makefile" ;;
+ "files/osf/Makefile") CONFIG_FILES="$CONFIG_FILES files/osf/Makefile" ;;
+ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "py/Makefile") CONFIG_FILES="$CONFIG_FILES py/Makefile" ;;
+ "examples/Makefile") CONFIG_FILES="$CONFIG_FILES examples/Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ # TODO: see whether this extra hack can be removed once we start
+ # requiring Autoconf 2.70 or later.
+ case $CONFIG_FILES in #(
+ *\'*) :
+ eval set x "$CONFIG_FILES" ;; #(
+ *) :
+ set x $CONFIG_FILES ;; #(
+ *) :
+ ;;
+esac
+ shift
+ # Used to flag and report bootstrapping failures.
+ am_rc=0
+ for am_mf
+ do
+ # Strip MF so we end up with the name of the file.
+ am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile which includes
+ # dependency-tracking related rules and includes.
+ # Grep'ing the whole file directly is not great: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \
+ || continue
+ am_dirpart=`$as_dirname -- "$am_mf" ||
+$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$am_mf" : 'X\(//\)[^/]' \| \
+ X"$am_mf" : 'X\(//\)$' \| \
+ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$am_mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ am_filepart=`$as_basename -- "$am_mf" ||
+$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$am_mf" : 'X\(//\)$' \| \
+ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$am_mf" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ { echo "$as_me:$LINENO: cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles" >&5
+ (cd "$am_dirpart" \
+ && sed -e '/# am--include-marker/d' "$am_filepart" \
+ | $MAKE -f - am--depfiles) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } || am_rc=$?
+ done
+ if test $am_rc -ne 0; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Something went wrong bootstrapping makefile fragments
+ for automatic dependency tracking. If GNU make was not used, consider
+ re-running the configure script with MAKE=\"gmake\" (or whatever is
+ necessary). You can also try re-running configure with the
+ '--disable-dependency-tracking' option to at least be able to build
+ the package (albeit without support for automatic dependency tracking).
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ { am_dirpart=; unset am_dirpart;}
+ { am_filepart=; unset am_filepart;}
+ { am_mf=; unset am_mf;}
+ { am_rc=; unset am_rc;}
+ rm -f conftest-deps.mk
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options that allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile=${ofile}T
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=''
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shared archive member basename,for filename based shared library versioning on AIX.
+shared_archive_member_spec=$shared_archive_member_spec
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm into a list of symbols to manually relocate.
+global_symbol_to_import=$lt_lt_cv_sys_global_symbol_to_import
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name lister interface.
+nm_interface=$lt_lt_cv_nm_interface
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and where our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# Command to truncate a binary pipe.
+lt_truncate_bin=$lt_lt_cv_truncate_bin
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Detected run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_configure_time_dlsearch_path
+
+# Explicit LT_SYS_LIBRARY_PATH set during ./configure time.
+configure_time_lt_sys_library_path=$lt_configure_time_lt_sys_library_path
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\$shared_ext during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \$shlibpath_var if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x$2 in
+ x)
+ ;;
+ *:)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'` \$$1\"
+ ;;
+ x:*)
+ eval $1=\"\$$1 `$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval $1=\"\$$1\ `$ECHO $2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval $1=\"`$ECHO $2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \$$1\"
+ ;;
+ *)
+ eval $1=\"`$ECHO $2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+
+
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in $*""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain=$ac_aux_dir/ltmain.sh
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+echo "
+nft configuration:
+ cli support: ${with_cli}
+ enable debugging symbols: ${enable_debug}
+ use mini-gmp: ${with_mini_gmp}
+ enable man page: ${enable_man_doc}
+ libxtables support: ${with_xtables}
+ json output support: ${with_json}"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..7bd33bd
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,146 @@
+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-xz 1.6])
+
+dnl kernel style compile messages
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_CONFIG_HEADERS([config.h])
+
+AC_ARG_ENABLE([debug],
+ AS_HELP_STRING([--disable-debug], [Disable debugging symbols]),
+ [], [enable_debug=yes])
+AM_CONDITIONAL([BUILD_DEBUG], [test "x$enable_debug" != xno])
+
+AC_ARG_ENABLE([man-doc],
+ AS_HELP_STRING([--disable-man-doc], [Disable man page documentation]),
+ [], [enable_man_doc=yes])
+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
+AC_PROG_LEX([noyywrap])
+AC_PROG_YACC
+
+if test -z "$ac_cv_prog_YACC" -a ! -f "${srcdir}/src/parser_bison.c"
+then
+ echo "*** Error: No suitable bison/yacc found. ***"
+ echo " Please install the 'bison' package."
+ exit 1
+fi
+if test -z "$ac_cv_prog_LEX" -a ! -f "${srcdir}/src/scanner.c"
+then
+ echo "*** Error: No suitable flex/lex found. ***"
+ echo " Please install the 'flex' package."
+ exit 1
+fi
+
+AM_PROG_AR
+LT_INIT([disable-static])
+AC_EXEEXT
+CHECK_GCC_FVISIBILITY
+
+AS_IF([test "x$enable_man_doc" = "xyes"], [
+ AC_CHECK_PROG(A2X, [a2x], [a2x], [no])
+ AS_IF([test "$A2X" = "no" -a ! -f "${srcdir}/doc/nft.8"],
+ [AC_MSG_ERROR([a2x not found, please install asciidoc])])
+])
+
+PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.4])
+PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.2.6])
+
+AC_ARG_WITH([mini-gmp], [AS_HELP_STRING([--with-mini-gmp],
+ [Use builtin mini-gmp (for embedded builds)])],
+ [], [with_mini_gmp=no])
+AS_IF([test "x$with_mini_gmp" != xyes], [
+AC_CHECK_LIB([gmp],[__gmpz_init], , AC_MSG_ERROR([No suitable version of libgmp found]))
+])
+AM_CONDITIONAL([BUILD_MINIGMP], [test "x$with_mini_gmp" = xyes])
+
+AC_ARG_WITH([cli], [AS_HELP_STRING([--without-cli],
+ [disable interactive CLI (libreadline, editline or linenoise support)])],
+ [], [with_cli=editline])
+
+AS_IF([test "x$with_cli" = xreadline], [
+AC_CHECK_LIB([readline], [readline], ,
+ AC_MSG_ERROR([No suitable version of libreadline found]))
+AC_DEFINE([HAVE_LIBREADLINE], [1], [])
+],
+ [test "x$with_cli" = xlinenoise], [
+AC_CHECK_LIB([linenoise], [linenoise], ,
+ AC_MSG_ERROR([No suitable version of linenoise found]))
+AC_DEFINE([HAVE_LIBLINENOISE], [1], [])
+],
+ [test "x$with_cli" = xeditline], [
+AC_CHECK_LIB([edit], [readline], ,
+ AC_MSG_ERROR([No suitable version of libedit found]))
+AC_DEFINE([HAVE_LIBEDIT], [1], [])
+],
+ [test "x$with_cli" != xno], [
+AC_MSG_ERROR([unexpected CLI value: $with_cli])
+])
+AM_CONDITIONAL([BUILD_CLI], [test "x$with_cli" != xno])
+
+AC_ARG_WITH([xtables], [AS_HELP_STRING([--with-xtables],
+ [Use libxtables for iptables interaction])],
+ [], [with_xtables=no])
+AS_IF([test "x$with_xtables" != xno], [
+PKG_CHECK_MODULES([XTABLES], [xtables >= 1.6.1])
+AC_DEFINE([HAVE_LIBXTABLES], [1], [0])
+])
+AM_CONDITIONAL([BUILD_XTABLES], [test "x$with_xtables" = xyes])
+
+AC_ARG_WITH([json], [AS_HELP_STRING([--with-json],
+ [Enable JSON output support])],
+ [], [with_json=no])
+AS_IF([test "x$with_json" != xno], [
+AC_CHECK_LIB([jansson], [json_object], ,
+ AC_MSG_ERROR([No suitable version of libjansson found]))
+AC_DEFINE([HAVE_LIBJANSSON], [1], [Define if you have libjansson])
+])
+AM_CONDITIONAL([BUILD_JSON], [test "x$with_json" != xno])
+
+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
+
+echo "
+nft configuration:
+ cli support: ${with_cli}
+ enable debugging symbols: ${enable_debug}
+ use mini-gmp: ${with_mini_gmp}
+ enable man page: ${enable_man_doc}
+ libxtables support: ${with_xtables}
+ json output support: ${with_json}"
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..b43cb08
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,30 @@
+if BUILD_MAN
+dist_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} 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} $<
+
+MAINTAINERCLEANFILES = ${dist_man_MANS}
+endif
diff --git a/doc/Makefile.in b/doc/Makefile.in
new file mode 100644
index 0000000..edffa60
--- /dev/null
+++ b/doc/Makefile.in
@@ -0,0 +1,652 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man3dir = $(mandir)/man3
+am__installdirs = "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(man5dir)" \
+ "$(DESTDIR)$(man8dir)"
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+NROFF = nroff
+MANS = $(dist_man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@BUILD_MAN_TRUE@dist_man_MANS = nft.8 libnftables-json.5 libnftables.3
+@BUILD_MAN_TRUE@A2X_OPTS_MANPAGE = -L --doctype manpage --format manpage -D ${builddir}
+@BUILD_MAN_TRUE@ASCIIDOC_MAIN = nft.txt
+@BUILD_MAN_TRUE@ASCIIDOC_INCLUDES = \
+@BUILD_MAN_TRUE@ data-types.txt \
+@BUILD_MAN_TRUE@ payload-expression.txt \
+@BUILD_MAN_TRUE@ primary-expression.txt \
+@BUILD_MAN_TRUE@ stateful-objects.txt \
+@BUILD_MAN_TRUE@ statements.txt
+
+@BUILD_MAN_TRUE@ASCIIDOCS = ${ASCIIDOC_MAIN} ${ASCIIDOC_INCLUDES}
+@BUILD_MAN_TRUE@EXTRA_DIST = ${ASCIIDOCS} libnftables-json.adoc libnftables.adoc
+@BUILD_MAN_TRUE@CLEANFILES = \
+@BUILD_MAN_TRUE@ *~
+
+@BUILD_MAN_TRUE@MAINTAINERCLEANFILES = ${dist_man_MANS}
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .3 .5 .adoc
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign doc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man3: $(dist_man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(dist_man_MANS)'; \
+ test -n "$(man3dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.3[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man3:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man3dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.3[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir)
+install-man5: $(dist_man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(dist_man_MANS)'; \
+ test -n "$(man5dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.5[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man5:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man5dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.5[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir)
+install-man8: $(dist_man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(dist_man_MANS)'; \
+ test -n "$(man8dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.8[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man8:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man8dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.8[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(man8dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man3 install-man5 install-man8
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man3 uninstall-man5 uninstall-man8
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man3 install-man5 install-man8 install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-man uninstall-man3 uninstall-man5 \
+ uninstall-man8
+
+.PRECIOUS: Makefile
+
+
+@BUILD_MAN_TRUE@nft.8: ${ASCIIDOCS}
+@BUILD_MAN_TRUE@ ${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
+
+@BUILD_MAN_TRUE@.adoc.3:
+@BUILD_MAN_TRUE@ ${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
+
+@BUILD_MAN_TRUE@.adoc.5:
+@BUILD_MAN_TRUE@ ${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/doc/data-types.txt b/doc/data-types.txt
new file mode 100644
index 0000000..961fc62
--- /dev/null
+++ b/doc/data-types.txt
@@ -0,0 +1,537 @@
+INTEGER TYPE
+~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|Integer |
+integer |
+variable |
+-
+|===================
+
+The integer type is used for numeric values. It may be specified as a decimal,
+hexadecimal or octal number. The integer type does not have a fixed size, its
+size is determined by the expression for which it is used.
+
+BITMASK TYPE
+~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|Bitmask |
+bitmask |
+variable |
+integer
+|===================
+
+The bitmask type (*bitmask*) is used for bitmasks.
+
+STRING TYPE
+~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|String |
+string |
+variable |
+-
+|===================
+
+The string type is used for character strings. A string begins with an
+alphabetic character (a-zA-Z) followed by zero or more alphanumeric characters
+or the characters /, -, _ and .. In addition, anything enclosed in double
+quotes (") is recognized as a string.
+
+.String specification
+----------------------
+# Interface name
+filter input iifname eth0
+
+# Weird interface name
+filter input iifname "(eth0)"
+----------------------------
+
+LINK LAYER ADDRESS TYPE
+~~~~~~~~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|Link layer address |
+lladdr|
+variable |
+integer
+|===================
+
+The link layer address type is used for link layer addresses. Link layer
+addresses are specified as a variable amount of groups of two hexadecimal digits
+separated using colons (:).
+
+.Link layer address specification
+----------------------
+# Ethernet destination MAC address
+filter input ether daddr 20:c9:d0:43:12:d9
+----------------------------
+
+IPV4 ADDRESS TYPE
+~~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|IPV4 address|
+ipv4_addr|
+32 bit|
+integer
+|===================
+
+The IPv4 address type is used for IPv4 addresses. Addresses are specified in
+either dotted decimal, dotted hexadecimal, dotted octal, decimal, hexadecimal,
+octal notation or as a host name. A host name will be resolved using the
+standard system resolver.
+
+.IPv4 address specification
+----------------------
+# dotted decimal notation
+filter output ip daddr 127.0.0.1
+
+# host name
+filter output ip daddr localhost
+----------------------------
+
+IPV6 ADDRESS TYPE
+~~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|IPv6 address|
+ipv6_addr|
+128 bit|
+integer
+|===================
+
+The IPv6 address type is used for IPv6 addresses. Addresses are specified as a
+host name or as hexadecimal halfwords separated by colons. Addresses might be
+enclosed in square brackets ("[]") to differentiate them from port numbers.
+
+.IPv6 address specification
+----------------------
+# abbreviated loopback address
+filter output ip6 daddr ::1
+----------------------------
+
+.IPv6 address specification with bracket notation
+----------------------
+# without [] the port number (22) would be parsed as part of the
+# ipv6 address
+ip6 nat prerouting tcp dport 2222 dnat to [1ce::d0]:22
+----------------------------
+
+BOOLEAN TYPE
+~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|Boolean |
+boolean |
+1 bit |
+integer
+|===================
+
+The boolean type is a syntactical helper type in userspace. Its use is in the
+right-hand side of a (typically implicit) relational expression to change the
+expression on the left-hand side into a boolean check (usually for existence). +
+
+.The following keywords will automatically resolve into a boolean type with given value
+
+[options="header"]
+|==================
+|Keyword | Value
+|exists |
+1 |
+missing |
+0
+|===================
+
+.expressions support a boolean comparison
+[options="header"]
+|======================================
+|Expression | Behaviour
+|fib |
+Check route existence.
+|exthdr|
+Check IPv6 extension header existence.
+|tcp option |
+Check TCP option header existence.
+|===================
+
+.Boolean specification
+----------------------
+# match if route exists
+filter input fib daddr . iif oif exists
+
+# match only non-fragmented packets in IPv6 traffic
+filter input exthdr frag missing
+
+# match if TCP timestamp option is present
+filter input tcp option timestamp exists
+------------------------------------------
+
+ICMP TYPE TYPE
+~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|ICMP Type |
+icmp_type |
+8 bit |
+integer
+|===================
+The ICMP Type type is used to conveniently specify the ICMP header's type field.
+
+.Keywords may be used when specifying the ICMP type
+[options="header"]
+|==================
+|Keyword | Value
+|echo-reply |
+0
+|destination-unreachable |
+3
+|source-quench|
+4
+|redirect|
+5
+|echo-request|
+8
+|router-advertisement|
+9
+|router-solicitation|
+10
+|time-exceeded|
+11
+|parameter-problem|
+12
+|timestamp-request|
+13
+|timestamp-reply|
+14
+|info-request|
+15
+|info-reply|
+16
+|address-mask-request|
+17
+|address-mask-reply|
+18
+|===================
+
+.ICMP Type specification
+------------------------
+# match ping packets
+filter output icmp type { echo-request, echo-reply }
+------------------------
+
+ICMP CODE TYPE
+~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|ICMP Code |
+icmp_code |
+8 bit |
+integer
+|===================
+
+The ICMP Code type is used to conveniently specify the ICMP header's code field.
+
+.Keywords may be used when specifying the ICMP code
+[options="header"]
+|==================
+|Keyword | Value
+|net-unreachable |
+0
+|host-unreachable |
+1
+|prot-unreachable|
+2
+|port-unreachable|
+3
+|frag-needed|
+4
+|net-prohibited|
+9
+|host-prohibited|
+10
+|admin-prohibited|
+13
+|===================
+
+ICMPV6 TYPE TYPE
+~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|ICMPv6 Type |
+icmpx_code |
+8 bit |
+integer
+|===================
+
+The ICMPv6 Type type is used to conveniently specify the ICMPv6 header's type field.
+
+.keywords may be used when specifying the ICMPv6 type:
+[options="header"]
+|==================
+|Keyword | Value
+|destination-unreachable |
+1
+|packet-too-big|
+2
+|time-exceeded|
+3
+|parameter-problem|
+4
+|echo-request|
+128
+|echo-reply|
+129
+|mld-listener-query|
+130
+|mld-listener-report|
+131
+|mld-listener-done |
+132
+|mld-listener-reduction|
+132
+|nd-router-solicit |
+133
+|nd-router-advert|
+134
+|nd-neighbor-solicit|
+135
+|nd-neighbor-advert|
+136
+|nd-redirect|
+137
+|router-renumbering|
+138
+|ind-neighbor-solicit|
+141
+|ind-neighbor-advert|
+142
+|mld2-listener-report|
+143
+|===================
+
+.ICMPv6 Type specification
+--------------------------
+# match ICMPv6 ping packets
+filter output icmpv6 type { echo-request, echo-reply }
+--------------------------
+
+ICMPV6 CODE TYPE
+~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|ICMPv6 Code |
+icmpv6_code |
+8 bit |
+integer
+|===================
+
+The ICMPv6 Code type is used to conveniently specify the ICMPv6 header's code field.
+
+.keywords may be used when specifying the ICMPv6 code
+[options="header"]
+|==================
+|Keyword |Value
+|no-route|
+0
+|admin-prohibited|
+1
+|addr-unreachable|
+3
+|port-unreachable|
+4
+|policy-fail|
+5
+|reject-route|
+6
+|==================
+
+ICMPVX CODE TYPE
+~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|ICMPvX Code |
+icmpv6_type |
+8 bit |
+integer
+|===================
+
+The ICMPvX Code type abstraction is a set of values which overlap between ICMP
+and ICMPv6 Code types to be used from the inet family.
+
+.keywords may be used when specifying the ICMPvX code
+[options="header"]
+|==================
+|Keyword |Value
+|no-route|
+0
+|port-unreachable|
+1
+|host-unreachable|
+2
+|admin-prohibited|
+3
+|=================
+
+CONNTRACK TYPES
+~~~~~~~~~~~~~~~
+
+.overview of types used in ct expression and statement
+[options="header"]
+|==================
+|Name | Keyword |Size |Base type
+|conntrack state|
+ct_state|
+4 byte|
+bitmask
+|conntrack direction|
+ct_dir |
+8 bit|
+integer
+|conntrack status|
+ct_status|
+4 byte|
+bitmask
+|conntrack event bits|
+ct_event |
+4 byte |
+bitmask
+|conntrack label|
+ct_label |
+128 bit|
+bitmask
+|=================
+
+For each of the types above, keywords are available for convenience:
+
+.conntrack state (ct_state)
+[options="header"]
+|==================
+|Keyword| Value
+|invalid|
+1
+|established|
+2
+|related|
+4
+|new|
+8
+|untracked|
+64
+|================
+
+.conntrack direction (ct_dir)
+[options="header"]
+|==================
+|Keyword| Value
+|original|
+0
+|reply|
+1
+|================
+
+.conntrack status (ct_status)
+[options="header"]
+|==================
+|Keyword| Value
+|expected|
+1
+|seen-reply|
+2
+|assured|
+4
+|confirmed|
+8
+|snat|
+16
+|dnat|
+32
+|dying|
+512
+|================
+
+.conntrack event bits (ct_event)
+[options="header"]
+|==================
+|Keyword| Value
+|new|
+1
+|related|
+2
+|destroy|
+4
+|reply|
+8
+|assured|
+16
+|protoinfo|
+32
+|helper|
+64
+|mark|
+128
+|seqadj|
+256
+|secmark|
+512
+|label|
+1024
+|==================
+
+Possible keywords for conntrack label type (ct_label) are read at runtime from /etc/connlabel.conf.
+
+DCCP PKTTYPE TYPE
+~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|DCCP packet type |
+dccp_pkttype |
+4 bit |
+integer
+|===================
+
+The DCCP packet type abstracts the different legal values of the respective
+four bit field in the DCCP header, as stated by RFC4340. Note that possible
+values 10-15 are considered reserved and therefore not allowed to be used. In
+iptables' *dccp* match, these values are aliased 'INVALID'. With nftables, one
+may simply match on the numeric value range, i.e. *10-15*.
+
+.keywords may be used when specifying the DCCP packet type
+[options="header"]
+|==================
+|Keyword |Value
+|request|
+0
+|response|
+1
+|data|
+2
+|ack|
+3
+|dataack|
+4
+|closereq|
+5
+|close|
+6
+|reset|
+7
+|sync|
+8
+|syncack|
+9
+|=================
diff --git a/doc/libnftables-json.5 b/doc/libnftables-json.5
new file mode 100644
index 0000000..4d4e3e2
--- /dev/null
+++ b/doc/libnftables-json.5
@@ -0,0 +1,2422 @@
+'\" t
+.\" Title: libnftables-json
+.\" Author: Phil Sutter <phil@nwl.cc>
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/11/2023
+.\" Manual: \ \&
+.\" Source: \ \&
+.\" Language: English
+.\"
+.TH "LIBNFTABLES\-JSON" "5" "10/11/2023" "\ \&" "\ \&"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+libnftables-json \- Supported JSON schema by libnftables
+.SH "SYNOPSIS"
+.sp
+\fB{ "nftables": [\fR \fIOBJECTS\fR \fB] }\fR
+.sp
+\fIOBJECTS\fR := \fILIST_OBJECTS\fR | \fICMD_OBJECTS\fR
+.sp
+\fILIST_OBJECTS\fR := \fILIST_OBJECT\fR [ \fB,\fR \fILIST_OBJECTS\fR ]
+.sp
+\fICMD_OBJECTS\fR := \fICMD_OBJECT\fR [ \fB,\fR \fICMD_OBJECTS\fR ]
+.sp
+\fICMD_OBJECT\fR := \fB{\fR \fICMD\fR\fB:\fR \fILIST_OBJECT\fR \fB}\fR | \fIMETAINFO_OBJECT\fR
+.sp
+\fICMD\fR := \fB"add"\fR | \fB"replace"\fR | \fB"create"\fR | \fB"insert"\fR | \fB"delete"\fR | \fB"list"\fR | \fB"reset"\fR | \fB"flush"\fR | \fB"rename"\fR
+.sp
+\fILIST_OBJECT\fR := \fITABLE\fR | \fICHAIN\fR | \fIRULE\fR | \fISET\fR | \fIMAP\fR | \fIELEMENT\fR | \fIFLOWTABLE\fR | \fICOUNTER\fR | \fIQUOTA\fR | \fICT_HELPER\fR | \fILIMIT\fR | \fIMETAINFO_OBJECT\fR | \fICT_TIMEOUT\fR | \fICT_EXPECTATION\fR
+.SH "DESCRIPTION"
+.sp
+libnftables supports JSON formatted input and output\&. This is implemented as an alternative frontend to the standard CLI syntax parser, therefore basic behaviour is identical and, for (almost) any operation available in standard syntax, there should be an equivalent one in JSON\&.
+.sp
+JSON input may be provided in a single string as parameter to \fBnft_run_cmd_from_buffer()\fR or in a file identified by the \fIfilename\fR parameter of the \fBnft_run_cmd_from_filename()\fR function\&.
+.sp
+JSON output has to be enabled via the \fBnft_ctx_output_set_json()\fR function, turning library standard output into JSON format\&. Error output remains unaffected\&.
+.SH "GLOBAL STRUCTURE"
+.sp
+In general, any JSON input or output is enclosed in an object with a single property named \fInftables\fR\&. Its value is an array containing commands (for input) or ruleset elements (for output)\&.
+.sp
+A command is an object with a single property whose name identifies the command\&. Its value is a ruleset element \- basically identical to output elements, apart from certain properties which may be interpreted differently or are required when output generally omits them\&.
+.SH "METAINFO OBJECT"
+.sp
+In output, the first object in an \fBnftables\fR array is a special one containing library information\&. Its content is as follows:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "metainfo": {
+ "version":\fR \fISTRING\fR\fB,
+ "release_name":\fR \fISTRING\fR\fB,
+ "json_schema_version":\fR \fINUMBER\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The values of \fBversion\fR and \fBrelease_name\fR properties are equal to the package version and release name as printed by \fBnft \-v\fR\&. The value of the \fBjson_schema_version\fR property is an integer indicating the schema version\&.
+.sp
+If supplied in library input, the parser will verify the \fBjson_schema_version\fR value to not exceed the internally hardcoded one (to make sure the given schema is fully understood)\&. In future, a lower number than the internal one may activate compatibility mode to parse outdated and incompatible JSON input\&.
+.SH "COMMAND OBJECTS"
+.sp
+The structure accepts an arbitrary amount of commands which are interpreted in order of appearance\&. For instance, the following standard syntax input:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+flush ruleset
+add table inet mytable
+add chain inet mytable mychain
+add rule inet mytable mychain tcp dport 22 accept
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+translates into JSON as such:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{ "nftables": [
+ { "flush": { "ruleset": null }},
+ { "add": { "table": {
+ "family": "inet",
+ "name": "mytable"
+ }}},
+ { "add": { "chain": {
+ "family": "inet",
+ "table": "mytable",
+ "name": "mychain"
+ }}},
+ { "add": { "rule": {
+ "family": "inet",
+ "table": "mytable",
+ "chain": "mychain",
+ "expr": [
+ { "match": {
+ "op": "==",
+ "left": { "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }},
+ "right": 22
+ }},
+ { "accept": null }
+ ]
+ }}}
+]}
+.fi
+.if n \{\
+.RE
+.\}
+.SS "ADD"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "add":\fR \fIADD_OBJECT\fR \fB}\fR
+
+\fIADD_OBJECT\fR := \fITABLE\fR | \fICHAIN\fR | \fIRULE\fR | \fISET\fR | \fIMAP\fR | \fIELEMENT\fR |
+ \fIFLOWTABLE\fR | \fICOUNTER\fR | \fIQUOTA\fR | \fICT_HELPER\fR | \fILIMIT\fR |
+ \fICT_TIMEOUT\fR | \fICT_EXPECTATION\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a new ruleset element to the kernel\&.
+.SS "REPLACE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "replace":\fR \fIRULE\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Replace a rule\&. In \fIRULE\fR, the \fBhandle\fR property is mandatory and identifies the rule to be replaced\&.
+.SS "CREATE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "create":\fR \fIADD_OBJECT\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Identical to \fBadd\fR command, but returns an error if the object already exists\&.
+.SS "INSERT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "insert":\fR \fIRULE\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This command is identical to \fBadd\fR for rules, but instead of appending the rule to the chain by default, it inserts at first position\&. If a \fBhandle\fR or \fBindex\fR property is given, the rule is inserted before the rule identified by those properties\&.
+.SS "DELETE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "delete":\fR \fIADD_OBJECT\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Delete an object from the ruleset\&. Only the minimal number of properties required to uniquely identify an object is generally needed in \fIADD_OBJECT\fR\&. For most ruleset elements, this is \fBfamily\fR and \fBtable\fR plus either \fBhandle\fR or \fBname\fR (except rules since they don\(cqt have a name)\&.
+.SS "LIST"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "list":\fR \fILIST_OBJECT\fR \fB}\fR
+
+\fILIST_OBJECT\fR := \fITABLE\fR | \fITABLES\fR | \fICHAIN\fR | \fICHAINS\fR | \fISET\fR | \fISETS\fR |
+ \fIMAP\fR | \fIMAPS | COUNTER\fR | \fICOUNTERS\fR | \fIQUOTA\fR | \fIQUOTAS\fR |
+ \fICT_HELPER\fR | \fICT_HELPERS\fR | \fILIMIT\fR | \fILIMITS\fR | \fIRULESET\fR |
+ \fIMETER\fR | \fIMETERS\fR | \fIFLOWTABLE\fR | \fIFLOWTABLES\fR |
+ \fICT_TIMEOUT\fR | \fICT_EXPECTATION\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+List ruleset elements\&. The plural forms are used to list all objects of that kind, optionally filtered by \fBfamily\fR and for some, also \fBtable\fR\&.
+.SS "RESET"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "reset":\fR \fIRESET_OBJECT\fR \fB}\fR
+
+\fIRESET_OBJECT\fR := \fICOUNTER\fR | \fICOUNTERS\fR | \fIQUOTA\fR | \fIQUOTAS\fR | \fIRULE\fR | \fIRULES\fR | \fISET\fR | \fIMAP\fR | \fIELEMENT\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Reset state in suitable objects, i\&.e\&. zero their internal counter\&.
+.SS "FLUSH"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "flush":\fR \fIFLUSH_OBJECT\fR \fB}\fR
+
+\fIFLUSH_OBJECT\fR := \fITABLE\fR | \fICHAIN\fR | \fISET\fR | \fIMAP\fR | \fIMETER\fR | \fIRULESET\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Empty contents in given object, e\&.g\&. remove all chains from given \fBtable\fR or remove all elements from given \fBset\fR\&.
+.SS "RENAME"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "rename":\fR \fICHAIN\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Rename a chain\&. The new name is expected in a dedicated property named \fBnewname\fR\&.
+.SH "RULESET ELEMENTS"
+.SS "TABLE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "table": {
+ "family":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object describes a table\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family, e\&.g\&.
+\fB"ip"\fR
+or
+\fB"ip6"\fR\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The table\(cqs handle\&. In input, it is used only in
+\fBdelete\fR
+command as alternative to
+\fBname\fR\&.
+.RE
+.SS "CHAIN"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "chain": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "newname":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "type":\fR \fISTRING\fR\fB,
+ "hook":\fR \fISTRING\fR\fB,
+ "prio":\fR \fINUMBER\fR\fB,
+ "dev":\fR \fISTRING\fR\fB,
+ "policy":\fR \fISTRING\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object describes a chain\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The chain\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The chain\(cqs handle\&. In input, it is used only in
+\fBdelete\fR
+command as alternative to
+\fBname\fR\&.
+.RE
+.PP
+\fBnewname\fR
+.RS 4
+A new name for the chain, only relevant in the
+\fBrename\fR
+command\&.
+.RE
+.sp
+The following properties are required for base chains:
+.PP
+\fBtype\fR
+.RS 4
+The chain\(cqs type\&.
+.RE
+.PP
+\fBhook\fR
+.RS 4
+The chain\(cqs hook\&.
+.RE
+.PP
+\fBprio\fR
+.RS 4
+The chain\(cqs priority\&.
+.RE
+.PP
+\fBdev\fR
+.RS 4
+The chain\(cqs bound interface (if in the netdev family)\&.
+.RE
+.PP
+\fBpolicy\fR
+.RS 4
+The chain\(cqs policy\&.
+.RE
+.SS "RULE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "rule": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "chain":\fR \fISTRING\fR\fB,
+ "expr": [\fR \fISTATEMENTS\fR \fB],
+ "handle":\fR \fINUMBER\fR\fB,
+ "index":\fR \fINUMBER\fR\fB,
+ "comment":\fR \fISTRING\fR
+\fB}}\fR
+
+\fISTATEMENTS\fR := \fISTATEMENT\fR [\fB,\fR \fISTATEMENTS\fR ]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object describes a rule\&. Basic building blocks of rules are statements\&. Each rule consists of at least one\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBchain\fR
+.RS 4
+The chain\(cqs name\&.
+.RE
+.PP
+\fBexpr\fR
+.RS 4
+An array of statements this rule consists of\&. In input, it is used in
+\fBadd\fR/\fBinsert\fR/\fBreplace\fR
+commands only\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The rule\(cqs handle\&. In
+\fBdelete\fR/\fBreplace\fR
+commands, it serves as an identifier of the rule to delete/replace\&. In
+\fBadd\fR/\fBinsert\fR
+commands, it serves as an identifier of an existing rule to append/prepend the rule to\&.
+.RE
+.PP
+\fBindex\fR
+.RS 4
+The rule\(cqs position for
+\fBadd\fR/\fBinsert\fR
+commands\&. It is used as an alternative to
+\fBhandle\fR
+then\&.
+.RE
+.PP
+\fBcomment\fR
+.RS 4
+Optional rule comment\&.
+.RE
+.SS "SET / MAP"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "set": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "type":\fR \fISET_TYPE\fR\fB,
+ "policy":\fR \fISET_POLICY\fR\fB,
+ "flags": [\fR \fISET_FLAG_LIST\fR \fB],
+ "elem":\fR \fISET_ELEMENTS\fR\fB,
+ "timeout":\fR \fINUMBER\fR\fB,
+ "gc\-interval":\fR \fINUMBER\fR\fB,
+ "size":\fR \fINUMBER\fR
+\fB}}\fR
+
+\fB{ "map": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "type":\fR \fISET_TYPE\fR\fB,
+ "map":\fR \fISTRING\fR\fB,
+ "policy":\fR \fISET_POLICY\fR\fB,
+ "flags": [\fR \fISET_FLAG_LIST\fR \fB],
+ "elem":\fR \fISET_ELEMENTS\fR\fB,
+ "timeout":\fR \fINUMBER\fR\fB,
+ "gc\-interval":\fR \fINUMBER\fR\fB,
+ "size":\fR \fINUMBER\fR
+\fB}}\fR
+
+\fISET_TYPE\fR := \fISTRING\fR | \fB[\fR \fISET_TYPE_LIST\fR \fB]\fR
+\fISET_TYPE_LIST\fR := \fISTRING\fR [\fB,\fR \fISET_TYPE_LIST\fR ]
+\fISET_POLICY\fR := \fB"performance"\fR | \fB"memory"\fR
+\fISET_FLAG_LIST\fR := \fISET_FLAG\fR [\fB,\fR \fISET_FLAG_LIST\fR ]
+\fISET_FLAG\fR := \fB"constant"\fR | \fB"interval"\fR | \fB"timeout"\fR
+\fISET_ELEMENTS\fR := \fIEXPRESSION\fR | \fB[\fR \fIEXPRESSION_LIST\fR \fB]\fR
+\fIEXPRESSION_LIST\fR := \fIEXPRESSION\fR [\fB,\fR \fIEXPRESSION_LIST\fR ]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+These objects describe a named set or map\&. Maps are a special form of sets in that they translate a unique key to a value\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The set\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The set\(cqs handle\&. For input, it is used in the
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBtype\fR
+.RS 4
+The set\(cqs datatype, see below\&.
+.RE
+.PP
+\fBmap\fR
+.RS 4
+Type of values this set maps to (i\&.e\&. this set is a map)\&.
+.RE
+.PP
+\fBpolicy\fR
+.RS 4
+The set\(cqs policy\&.
+.RE
+.PP
+\fBflags\fR
+.RS 4
+The set\(cqs flags\&.
+.RE
+.PP
+\fBelem\fR
+.RS 4
+Initial set element(s), see below\&.
+.RE
+.PP
+\fBtimeout\fR
+.RS 4
+Element timeout in seconds\&.
+.RE
+.PP
+\fBgc\-interval\fR
+.RS 4
+Garbage collector interval in seconds\&.
+.RE
+.PP
+\fBsize\fR
+.RS 4
+Maximum number of elements supported\&.
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBTYPE\fR
+.RS 4
+.sp
+The set type might be a string, such as \fB"ipv4_addr"\fR or an array consisting of strings (for concatenated types)\&.
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBELEM\fR
+.RS 4
+.sp
+A single set element might be given as string, integer or boolean value for simple cases\&. If additional properties are required, a formal \fBelem\fR object may be used\&.
+.sp
+Multiple elements may be given in an array\&.
+.RE
+.SS "ELEMENT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "element": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "elem":\fR \fISET_ELEM\fR
+\fB}}\fR
+
+\fISET_ELEM\fR := \fIEXPRESSION\fR | \fB[\fR \fIEXPRESSION_LIST\fR \fB]\fR
+\fIEXPRESSION_LIST\fR := \fIEXPRESSION\fR [\fB,\fR \fIEXPRESSION\fR ]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Manipulate element(s) in a named set\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The set\(cqs name\&.
+.RE
+.PP
+\fBelem\fR
+.RS 4
+See elem property of set object\&.
+.RE
+.SS "FLOWTABLE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "flowtable": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "hook":\fR \fISTRING\fR\fB,
+ "prio":\fR \fINUMBER\fR\fB,
+ "dev":\fR \fIFT_INTERFACE\fR
+\fB}}\fR
+
+\fIFT_INTERFACE\fR := \fISTRING\fR | \fB[\fR \fIFT_INTERFACE_LIST\fR \fB]\fR
+\fIFT_INTERFACE_LIST\fR := \fISTRING\fR [\fB,\fR \fISTRING\fR ]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a named flowtable\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The flow table\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The flow table\(cqs handle\&. In input, it is used by the
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBhook\fR
+.RS 4
+The flow table\(cqs hook\&.
+.RE
+.PP
+\fBprio\fR
+.RS 4
+The flow table\(cqs priority\&.
+.RE
+.PP
+\fBdev\fR
+.RS 4
+The flow table\(cqs interface(s)\&.
+.RE
+.SS "COUNTER"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "counter": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "packets":\fR \fINUMBER\fR\fB,
+ "bytes":\fR \fINUMBER\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a named counter\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The counter\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The counter\(cqs handle\&. In input, it is used by the
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBpackets\fR
+.RS 4
+Packet counter value\&.
+.RE
+.PP
+\fBbytes\fR
+.RS 4
+Byte counter value\&.
+.RE
+.SS "QUOTA"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "quota": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "bytes":\fR \fINUMBER\fR\fB,
+ "used":\fR \fINUMBER\fR\fB,
+ "inv":\fR \fIBOOLEAN\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a named quota\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The quota\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The quota\(cqs handle\&. In input, it is used by the
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBbytes\fR
+.RS 4
+Quota threshold\&.
+.RE
+.PP
+\fBused\fR
+.RS 4
+Quota used so far\&.
+.RE
+.PP
+\fBinv\fR
+.RS 4
+If true, match if the quota has been exceeded\&.
+.RE
+.SS "CT HELPER"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct helper": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fI\&... \*(Aq\fR\fI\fB,
+ "type":\fR\fR\fI \*(AqSTRING\fR\fB,
+ "protocol":\fR \fICTH_PROTO\fR\fB,
+ "l3proto":\fR \fISTRING\fR
+\fB}}\fR
+
+\fICTH_PROTO\fR := \fB"tcp"\fR | \fB"udp"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a named conntrack helper\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The ct helper\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The ct helper\(cqs handle\&. In input, it is used by the
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBtype\fR
+.RS 4
+The ct helper type name, e\&.g\&.
+\fB"ftp"\fR
+or
+\fB"tftp"\fR\&.
+.RE
+.PP
+\fBprotocol\fR
+.RS 4
+The ct helper\(cqs layer 4 protocol\&.
+.RE
+.PP
+\fBl3proto\fR
+.RS 4
+The ct helper\(cqs layer 3 protocol, e\&.g\&.
+\fB"ip"\fR
+or
+\fB"ip6"\fR\&.
+.RE
+.SS "LIMIT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "limit": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "rate":\fR \fINUMBER\fR\fB,
+ "per":\fR \fISTRING\fR\fB,
+ "burst":\fR \fINUMBER\fR\fB,
+ "unit":\fR \fILIMIT_UNIT\fR\fB,
+ "inv":\fR \fIBOOLEAN\fR
+\fB}}\fR
+
+\fILIMIT_UNIT\fR := \fB"packets"\fR | \fB"bytes"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a named limit\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The limit\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The limit\(cqs handle\&. In input, it is used by the
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBrate\fR
+.RS 4
+The limit\(cqs rate value\&.
+.RE
+.PP
+\fBper\fR
+.RS 4
+Time unit to apply the limit to, e\&.g\&.
+\fB"week"\fR,
+\fB"day"\fR,
+\fB"hour"\fR, etc\&. If omitted, defaults to
+\fB"second"\fR\&.
+.RE
+.PP
+\fBburst\fR
+.RS 4
+The limit\(cqs burst value\&. If omitted, defaults to
+\fB0\fR\&.
+.RE
+.PP
+\fBunit\fR
+.RS 4
+Unit of rate and burst values\&. If omitted, defaults to
+\fB"packets"\fR\&.
+.RE
+.PP
+\fBinv\fR
+.RS 4
+If true, match if limit was exceeded\&. If omitted, defaults to
+\fBfalse\fR\&.
+.RE
+.SS "CT TIMEOUT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct timeout": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "protocol":\fR \fICTH_PROTO\fR\fB,
+ "state":\fR \fISTRING\fR\fB,
+ "value:\fR \fINUMBER\fR\fB,
+ "l3proto":\fR \fISTRING\fR
+\fB}}\fR
+
+\fICTH_PROTO\fR := \fB"tcp"\fR | \fB"udp"\fR | \fB"dccp"\fR | \fB"sctp"\fR | \fB"gre"\fR | \fB"icmpv6"\fR | \fB"icmp"\fR | \fB"generic"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a named conntrack timeout policy\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The ct timeout object\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The ct timeout object\(cqs handle\&. In input, it is used by
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBprotocol\fR
+.RS 4
+The ct timeout object\(cqs layer 4 protocol\&.
+.RE
+.PP
+\fBstate\fR
+.RS 4
+The connection state name, e\&.g\&.
+\fB"established"\fR,
+\fB"syn_sent"\fR,
+\fB"close"\fR
+or
+\fB"close_wait"\fR, for which the timeout value has to be updated\&.
+.RE
+.PP
+\fBvalue\fR
+.RS 4
+The updated timeout value for the specified connection state\&.
+.RE
+.PP
+\fBl3proto\fR
+.RS 4
+The ct timeout object\(cqs layer 3 protocol, e\&.g\&.
+\fB"ip"\fR
+or
+\fB"ip6"\fR\&.
+.RE
+.SS "CT EXPECTATION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct expectation": {
+ "family":\fR \fISTRING\fR\fB,
+ "table":\fR \fISTRING\fR\fB,
+ "name":\fR \fISTRING\fR\fB,
+ "handle":\fR \fINUMBER\fR\fB,
+ "l3proto":\fR \fISTRING\fR
+ "protocol":* \fICTH_PROTO\fR\fB,
+ "dport":\fR \fINUMBER\fR\fB,
+ "timeout:\fR \fINUMBER\fR\fB,
+ "size:\fR \fINUMBER\fR\fB,
+*}}\fR
+
+\fICTH_PROTO\fR := \fB"tcp"\fR | \fB"udp"\fR | \fB"dccp"\fR | \fB"sctp"\fR | \fB"gre"\fR | \fB"icmpv6"\fR | \fB"icmp"\fR | \fB"generic"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a named conntrack expectation\&.
+.PP
+\fBfamily\fR
+.RS 4
+The table\(cqs family\&.
+.RE
+.PP
+\fBtable\fR
+.RS 4
+The table\(cqs name\&.
+.RE
+.PP
+\fBname\fR
+.RS 4
+The ct expectation object\(cqs name\&.
+.RE
+.PP
+\fBhandle\fR
+.RS 4
+The ct expectation object\(cqs handle\&. In input, it is used by
+\fBdelete\fR
+command only\&.
+.RE
+.PP
+\fBl3proto\fR
+.RS 4
+The ct expectation object\(cqs layer 3 protocol, e\&.g\&.
+\fB"ip"\fR
+or
+\fB"ip6"\fR\&.
+.RE
+.PP
+\fBprotocol\fR
+.RS 4
+The ct expectation object\(cqs layer 4 protocol\&.
+.RE
+.PP
+\fBdport\fR
+.RS 4
+The destination port of the expected connection\&.
+.RE
+.PP
+\fBtimeout\fR
+.RS 4
+The time in millisecond that this expectation will live\&.
+.RE
+.PP
+\fBsize\fR
+.RS 4
+The maximum count of expectations to be living in the same time\&.
+.RE
+.SH "STATEMENTS"
+.sp
+Statements are the building blocks for rules\&. Each rule consists of at least one\&.
+.SS "VERDICT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "accept": null }\fR
+\fB{ "drop": null }\fR
+\fB{ "continue": null }\fR
+\fB{ "return": null }\fR
+\fB{ "jump": { "target": * \fR\fB\fISTRING\fR\fR\fB *}}\fR
+\fB{ "goto": { "target": * \fR\fB\fISTRING\fR\fR\fB *}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A verdict either terminates packet traversal through the current chain or delegates to a different one\&.
+.sp
+\fBjump\fR and \fBgoto\fR statements expect a target chain name\&.
+.SS "MATCH"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "match": {
+ "left":\fR \fIEXPRESSION\fR\fB,
+ "right":\fR \fIEXPRESSION\fR\fB,
+ "op":\fR \fISTRING\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This matches the expression on left hand side (typically a packet header or packet meta info) with the expression on right hand side (typically a constant value)\&. If the statement evaluates to true, the next statement in this rule is considered\&. If not, processing continues with the next rule in the same chain\&.
+.PP
+\fBleft\fR
+.RS 4
+Left hand side of this match\&.
+.RE
+.PP
+\fBright\fR
+.RS 4
+Right hand side of this match\&.
+.RE
+.PP
+\fBop\fR
+.RS 4
+Operator indicating the type of comparison\&.
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOPERATORS\fR
+.RS 4
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fB&\fR
+T}:T{
+.sp
+Binary AND
+T}
+T{
+.sp
+\fB|\fR
+T}:T{
+.sp
+Binary OR
+T}
+T{
+.sp
+\fB^\fR
+T}:T{
+.sp
+Binary XOR
+T}
+T{
+.sp
+\fB<<\fR
+T}:T{
+.sp
+Left shift
+T}
+T{
+.sp
+\fB>>\fR
+T}:T{
+.sp
+Right shift
+T}
+T{
+.sp
+\fB==\fR
+T}:T{
+.sp
+Equal
+T}
+T{
+.sp
+\fB!=\fR
+T}:T{
+.sp
+Not equal
+T}
+T{
+.sp
+\fB<\fR
+T}:T{
+.sp
+Less than
+T}
+T{
+.sp
+\fB>\fR
+T}:T{
+.sp
+Greater than
+T}
+T{
+.sp
+\fB⇐\fR
+T}:T{
+.sp
+Less than or equal to
+T}
+T{
+.sp
+\fB>=\fR
+T}:T{
+.sp
+Greater than or equal to
+T}
+T{
+.sp
+\fBin\fR
+T}:T{
+.sp
+Perform a lookup, i\&.e\&. test if bits on RHS are contained in LHS value
+T}
+.TE
+.sp 1
+.sp
+Unlike with the standard API, the operator is mandatory here\&. In the standard API, a missing operator may be resolved in two ways, depending on the type of expression on the RHS:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If the RHS is a bitmask or a list of bitmasks, the expression resolves into a binary operation with the inequality operator, like this:
+\fILHS & RHS != 0\fR\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+In any other case, the equality operator is simply inserted\&.
+.RE
+.sp
+For the non\-trivial first case, the JSON API supports the \fBin\fR operator\&.
+.RE
+.SS "COUNTER"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "counter": {
+ "packets":\fR \fINUMBER\fR\fB,
+ "bytes":\fR \fINUMBER\fR
+\fB}}\fR
+
+\fB{ "counter":\fR \fISTRING\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object represents a byte/packet counter\&. In input, no properties are required\&. If given, they act as initial values for the counter\&.
+.sp
+The first form creates an anonymous counter which lives in the rule it appears in\&. The second form specifies a reference to a named counter object\&.
+.PP
+\fBpackets\fR
+.RS 4
+Packets counted\&.
+.RE
+.PP
+\fBbytes\fR
+.RS 4
+Bytes counted\&.
+.RE
+.SS "MANGLE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "mangle": {
+ "key":\fR \fIEXPRESSION\fR\fB,
+ "value":\fR \fIEXPRESSION\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This changes the packet data or meta info\&.
+.PP
+\fBkey\fR
+.RS 4
+The packet data to be changed, given as an
+\fBexthdr\fR,
+\fBpayload\fR,
+\fBmeta\fR,
+\fBct\fR
+or
+\fBct helper\fR
+expression\&.
+.RE
+.PP
+\fBvalue\fR
+.RS 4
+Value to change data to\&.
+.RE
+.SS "QUOTA"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "quota": {
+ "val":\fR \fINUMBER\fR\fB,
+ "val_unit":\fR \fISTRING\fR\fB,
+ "used":\fR \fINUMBER\fR\fB,
+ "used_unit":\fR \fISTRING\fR\fB,
+ "inv":\fR \fIBOOLEAN\fR
+\fB}}\fR
+
+\fB{ "quota":\fR \fISTRING\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The first form creates an anonymous quota which lives in the rule it appears in\&. The second form specifies a reference to a named quota object\&.
+.PP
+\fBval\fR
+.RS 4
+Quota value\&.
+.RE
+.PP
+\fBval_unit\fR
+.RS 4
+Unit of
+\fBval\fR, e\&.g\&.
+\fB"kbytes"\fR
+or
+\fB"mbytes"\fR\&. If omitted, defaults to
+\fB"bytes"\fR\&.
+.RE
+.PP
+\fBused\fR
+.RS 4
+Quota used so far\&. Optional on input\&. If given, serves as initial value\&.
+.RE
+.PP
+\fBused_unit\fR
+.RS 4
+Unit of
+\fBused\fR\&. Defaults to
+\fB"bytes"\fR\&.
+.RE
+.PP
+\fBinv\fR
+.RS 4
+If
+\fBtrue\fR, will match if quota was exceeded\&. Defaults to
+\fBfalse\fR\&.
+.RE
+.SS "LIMIT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "limit": {
+ "rate":\fR \fINUMBER\fR\fB,
+ "rate_unit":\fR \fISTRING\fR\fB,
+ "per":\fR \fISTRING\fR\fB,
+ "burst":\fR \fINUMBER\fR\fB,
+ "burst_unit":\fR \fISTRING\fR\fB,
+ "inv":\fR \fIBOOLEAN\fR
+\fB}}\fR
+
+\fB{ "limit":\fR \fISTRING\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The first form creates an anonymous limit which lives in the rule it appears in\&. The second form specifies a reference to a named limit object\&.
+.PP
+\fBrate\fR
+.RS 4
+Rate value to limit to\&.
+.RE
+.PP
+\fBrate_unit\fR
+.RS 4
+Unit of
+\fBrate\fR, e\&.g\&.
+\fB"packets"\fR
+or
+\fB"mbytes"\fR\&. Defaults to
+\fB"packets"\fR\&.
+.RE
+.PP
+\fBper\fR
+.RS 4
+Denominator of
+\fBrate\fR, e\&.g\&.
+\fB"week"\fR
+or
+\fB"minutes"\fR\&.
+.RE
+.PP
+\fBburst\fR
+.RS 4
+Burst value\&. Defaults to
+\fB0\fR\&.
+.RE
+.PP
+\fBburst_unit\fR
+.RS 4
+Unit of
+\fBburst\fR, ignored if
+\fBrate_unit\fR
+is
+\fB"packets"\fR\&. Defaults to
+\fB"bytes"\fR\&.
+.RE
+.PP
+\fBinv\fR
+.RS 4
+If
+\fBtrue\fR, matches if the limit was exceeded\&. Defaults to
+\fBfalse\fR\&.
+.RE
+.SS "FWD"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "fwd": {
+ "dev":\fR \fIEXPRESSION\fR\fB,
+ "family":\fR \fIFWD_FAMILY\fR\fB,
+ "addr":\fR \fIEXPRESSION\fR
+\fB}}\fR
+
+\fIFWD_FAMILY\fR := \fB"ip"\fR | \fB"ip6"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Forward a packet to a different destination\&.
+.PP
+\fBdev\fR
+.RS 4
+Interface to forward the packet on\&.
+.RE
+.PP
+\fBfamily\fR
+.RS 4
+Family of
+\fBaddr\fR\&.
+.RE
+.PP
+\fBaddr\fR
+.RS 4
+IP(v6) address to forward the packet to\&.
+.RE
+.sp
+Both \fBfamily\fR and \fBaddr\fR are optional, but if at least one is given, both must be present\&.
+.SS "NOTRACK"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "notrack": null }\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Disable connection tracking for the packet\&.
+.SS "DUP"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "dup": {
+ "addr":\fR \fIEXPRESSION\fR\fB,
+ "dev":\fR \fIEXPRESSION\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Duplicate a packet to a different destination\&.
+.PP
+\fBaddr\fR
+.RS 4
+Address to duplicate packet to\&.
+.RE
+.PP
+\fBdev\fR
+.RS 4
+Interface to duplicate packet on\&. May be omitted to not specify an interface explicitly\&.
+.RE
+.SS "NETWORK ADDRESS TRANSLATION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "snat": {
+ "addr":\fR \fIEXPRESSION\fR\fB,
+ "family":\fR \fISTRING\fR\fB,
+ "port":\fR \fIEXPRESSION\fR\fB,
+ "flags":\fR \fIFLAGS\fR
+\fB}}\fR
+
+\fB{ "dnat": {
+ "addr":\fR \fIEXPRESSION\fR\fB,
+ "family":\fR \fISTRING\fR\fB,
+ "port":\fR \fIEXPRESSION\fR\fB,
+ "flags":\fR \fIFLAGS\fR
+\fB}}\fR
+
+\fB{ "masquerade": {
+ "port":\fR \fIEXPRESSION\fR\fB,
+ "flags":\fR \fIFLAGS\fR
+\fB}}\fR
+
+\fB{ "redirect": {
+ "port":\fR \fIEXPRESSION\fR\fB,
+ "flags":\fR \fIFLAGS\fR
+\fB}}\fR
+
+\fIFLAGS\fR := \fIFLAG\fR | \fB[\fR \fIFLAG_LIST\fR \fB]\fR
+\fIFLAG_LIST\fR := \fIFLAG\fR [\fB,\fR \fIFLAG_LIST\fR ]
+\fIFLAG\fR := \fB"random"\fR | \fB"fully\-random"\fR | \fB"persistent"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Perform Network Address Translation\&.
+.PP
+\fBaddr\fR
+.RS 4
+Address to translate to\&.
+.RE
+.PP
+\fBfamily\fR
+.RS 4
+Family of
+\fBaddr\fR, either
+\fBip\fR
+or
+\fBip6\fR\&. Required in
+\fBinet\fR
+table family\&.
+.RE
+.PP
+\fBport\fR
+.RS 4
+Port to translate to\&.
+.RE
+.PP
+\fBflags\fR
+.RS 4
+Flag(s)\&.
+.RE
+.sp
+All properties are optional and default to none\&.
+.SS "REJECT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "reject": {
+ "type":\fR \fISTRING\fR\fB,
+ "expr":\fR \fIEXPRESSION\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Reject the packet and send the given error reply\&.
+.PP
+\fBtype\fR
+.RS 4
+Type of reject, either
+\fB"tcp reset"\fR,
+\fB"icmpx"\fR,
+\fB"icmp"\fR
+or
+\fB"icmpv6"\fR\&.
+.RE
+.PP
+\fBexpr\fR
+.RS 4
+ICMP code to reject with\&.
+.RE
+.sp
+All properties are optional\&.
+.SS "SET"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "set": {
+ "op":\fR \fISTRING\fR\fB,
+ "elem":\fR \fIEXPRESSION\fR\fB,
+ "set":\fR \fISTRING\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Dynamically add/update elements to a set\&.
+.PP
+\fBop\fR
+.RS 4
+Operator on set, either
+\fB"add"\fR
+or
+\fB"update"\fR\&.
+.RE
+.PP
+\fBelem\fR
+.RS 4
+Set element to add or update\&.
+.RE
+.PP
+\fBset\fR
+.RS 4
+Set reference\&.
+.RE
+.SS "LOG"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "log": {
+ "prefix":\fR \fISTRING\fR\fB,
+ "group":\fR \fINUMBER\fR\fB,
+ "snaplen":\fR \fINUMBER\fR\fB,
+ "queue\-threshold":\fR \fINUMBER\fR\fB,
+ "level":\fR \fILEVEL\fR\fB,
+ "flags":\fR \fIFLAGS\fR
+\fB}}\fR
+
+\fILEVEL\fR := \fB"emerg"\fR | \fB"alert"\fR | \fB"crit"\fR | \fB"err"\fR | \fB"warn"\fR | \fB"notice"\fR |
+ \fB"info"\fR | \fB"debug"\fR | \fB"audit"\fR
+
+\fIFLAGS\fR := \fIFLAG\fR | \fB[\fR \fIFLAG_LIST\fR \fB]\fR
+\fIFLAG_LIST\fR := \fIFLAG\fR [\fB,\fR \fIFLAG_LIST\fR ]
+\fIFLAG\fR := \fB"tcp sequence"\fR | \fB"tcp options"\fR | \fB"ip options"\fR | \fB"skuid"\fR |
+ \fB"ether"\fR | \fB"all"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Log the packet\&.
+.PP
+\fBprefix\fR
+.RS 4
+Prefix for log entries\&.
+.RE
+.PP
+\fBgroup\fR
+.RS 4
+Log group\&.
+.RE
+.PP
+\fBsnaplen\fR
+.RS 4
+Snaplen for logging\&.
+.RE
+.PP
+\fBqueue\-threshold\fR
+.RS 4
+Queue threshold\&.
+.RE
+.PP
+\fBlevel\fR
+.RS 4
+Log level\&. Defaults to
+\fB"warn"\fR\&.
+.RE
+.PP
+\fBflags\fR
+.RS 4
+Log flags\&.
+.RE
+.sp
+All properties are optional\&.
+.SS "CT HELPER"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct helper":\fR \fIEXPRESSION\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Enable the specified conntrack helper for this packet\&.
+.PP
+\fBct helper\fR
+.RS 4
+CT helper reference\&.
+.RE
+.SS "METER"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "meter": {
+ "name":\fR \fISTRING\fR\fB,
+ "key":\fR \fIEXPRESSION\fR\fB,
+ "stmt":\fR \fISTATEMENT\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Apply a given statement using a meter\&.
+.PP
+\fBname\fR
+.RS 4
+Meter name\&.
+.RE
+.PP
+\fBkey\fR
+.RS 4
+Meter key\&.
+.RE
+.PP
+\fBstmt\fR
+.RS 4
+Meter statement\&.
+.RE
+.SS "QUEUE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "queue": {
+ "num":\fR \fIEXPRESSION\fR\fB,
+ "flags":\fR \fIFLAGS\fR
+\fB}}\fR
+
+\fIFLAGS\fR := \fIFLAG\fR | \fB[\fR \fIFLAG_LIST\fR \fB]\fR
+\fIFLAG_LIST\fR := \fIFLAG\fR [\fB,\fR \fIFLAG_LIST\fR ]
+\fIFLAG\fR := \fB"bypass"\fR | \fB"fanout"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Queue the packet to userspace\&.
+.PP
+\fBnum\fR
+.RS 4
+Queue number\&.
+.RE
+.PP
+\fBflags\fR
+.RS 4
+Queue flags\&.
+.RE
+.SS "VERDICT MAP"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "vmap": {
+ "key":\fR \fIEXPRESSION\fR\fB,
+ "data":\fR \fIEXPRESSION\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Apply a verdict conditionally\&.
+.PP
+\fBkey\fR
+.RS 4
+Map key\&.
+.RE
+.PP
+\fBdata\fR
+.RS 4
+Mapping expression consisting of value/verdict pairs\&.
+.RE
+.SS "CT COUNT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct count": {
+ "val":\fR \fINUMBER\fR\fB,
+ "inv":\fR \fIBOOLEAN\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Limit the number of connections using conntrack\&.
+.PP
+\fBval\fR
+.RS 4
+Connection count threshold\&.
+.RE
+.PP
+\fBinv\fR
+.RS 4
+If
+\fBtrue\fR, match if
+\fBval\fR
+was exceeded\&. If omitted, defaults to
+\fBfalse\fR\&.
+.RE
+.SS "CT TIMEOUT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct timeout":\fR \fIEXPRESSION\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Assign connection tracking timeout policy\&.
+.PP
+\fBct timeout\fR
+.RS 4
+CT timeout reference\&.
+.RE
+.SS "CT EXPECTATION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct expectation":\fR \fIEXPRESSION\fR \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Assign connection tracking expectation\&.
+.PP
+\fBct expectation\fR
+.RS 4
+CT expectation reference\&.
+.RE
+.SS "XT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "xt": {
+ "type":\fR \fITYPENAME\fR\fB,
+ "name":\fR \fISTRING\fR
+\fB}}\fR
+
+\fITYPENAME\fR := \fBmatch\fR | \fBtarget\fR | \fBwatcher\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This represents an xt statement from xtables compat interface\&. It is a fallback if translation is not available or not complete\&.
+.sp
+Seeing this means the ruleset (or parts of it) were created by \fBiptables\-nft\fR and one should use that to manage it\&.
+.sp
+\fBBEWARE:\fR nftables won\(cqt restore these statements\&.
+.SH "EXPRESSIONS"
+.sp
+Expressions are the building blocks of (most) statements\&. In their most basic form, they are just immediate values represented as a JSON string, integer or boolean type\&.
+.SS "IMMEDIATES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fISTRING\fR
+\fINUMBER\fR
+\fIBOOLEAN\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Immediate expressions are typically used for constant values\&. For strings, there are two special cases:
+.PP
+\fB@STRING\fR
+.RS 4
+The remaining part is taken as set name to create a set reference\&.
+.RE
+.PP
+\fB\e\fR*
+.RS 4
+Construct a wildcard expression\&.
+.RE
+.SS "LISTS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIARRAY\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+List expressions are constructed by plain arrays containing of an arbitrary number of expressions\&.
+.SS "CONCAT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "concat":\fR \fICONCAT\fR \fB}\fR
+
+\fICONCAT\fR := \fB[\fR \fIEXPRESSION_LIST\fR \fB]\fR
+\fIEXPRESSION_LIST\fR := \fIEXPRESSION\fR [\fB,\fR \fIEXPRESSION_LIST\fR ]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Concatenate several expressions\&.
+.SS "SET"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "set":\fR \fISET\fR \fB}\fR
+
+\fISET\fR := \fIEXPRESSION\fR | \fB[\fR \fIEXPRESSION_LIST\fR \fB]\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This object constructs an anonymous set\&. For mappings, an array of arrays with exactly two elements is expected\&.
+.SS "MAP"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "map": {
+ "key":\fR \fIEXPRESSION\fR\fB,
+ "data":\fR \fIEXPRESSION\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Map a key to a value\&.
+.PP
+\fBkey\fR
+.RS 4
+Map key\&.
+.RE
+.PP
+\fBdata\fR
+.RS 4
+Mapping expression consisting of value/target pairs\&.
+.RE
+.SS "PREFIX"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "prefix": {
+ "addr":\fR \fIEXPRESSION\fR\fB,
+ "len":\fR \fINUMBER\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Construct an IPv4 or IPv6 prefix consisting of address part in \fBaddr\fR and prefix length in \fBlen\fR\&.
+.SS "RANGE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "range": [\fR \fIEXPRESSION\fR \fB,\fR \fIEXPRESSION\fR \fB] }\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Construct a range of values\&. The first array item denotes the lower boundary, the second one the upper boundary\&.
+.SS "PAYLOAD"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "payload": {
+ "base":\fR \fIBASE\fR\fB,
+ "offset":\fR \fINUMBER\fR\fB,
+ "len":\fR \fINUMBER\fR
+\fB}}\fR
+
+\fB{ "payload": {
+ "protocol":\fR \fISTRING\fR\fB,
+ "field":\fR \fISTRING\fR
+\fB}}\fR
+
+\fIBASE\fR := \fB"ll"\fR | \fB"nh"\fR | \fB"th"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Construct a payload expression, i\&.e\&. a reference to a certain part of packet data\&. The first form creates a raw payload expression to point at a random number (\fBlen\fR) of bytes at a certain offset (\fBoffset\fR) from a given reference point (\fBbase\fR)\&. The following \fBbase\fR values are accepted:
+.PP
+\fB"ll"\fR
+.RS 4
+The offset is relative to Link Layer header start offset\&.
+.RE
+.PP
+\fB"nh"\fR
+.RS 4
+The offset is relative to Network Layer header start offset\&.
+.RE
+.PP
+\fB"th"\fR
+.RS 4
+The offset is relative to Transport Layer header start offset\&.
+.RE
+.sp
+The second form allows one to reference a field by name (\fBfield\fR) in a named packet header (\fBprotocol\fR)\&.
+.SS "EXTHDR"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "exthdr": {
+ "name":\fR \fISTRING\fR\fB,
+ "field":\fR \fISTRING\fR\fB,
+ "offset":\fR \fINUMBER\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a reference to a field (\fBfield\fR) in an IPv6 extension header (\fBname\fR)\&. \fBoffset\fR is used only for \fBrt0\fR protocol\&.
+.sp
+If the \fBfield\fR property is not given, the expression is to be used as a header existence check in a \fBmatch\fR statement with a boolean on the right hand side\&.
+.SS "TCP OPTION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "tcp option": {
+ "name":\fR \fISTRING\fR\fB,
+ "field":\fR \fISTRING\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a reference to a field (\fBfield\fR) of a TCP option header (\fBname\fR)\&.
+.sp
+If the \fBfield\fR property is not given, the expression is to be used as a TCP option existence check in a \fBmatch\fR statement with a boolean on the right hand side\&.
+.SS "SCTP CHUNK"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "sctp chunk": {
+ "name":\fR \fISTRING\fR\fB,
+ "field":\fR \fISTRING\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a reference to a field (\fBfield\fR) of an SCTP chunk (\fBname\fR)\&.
+.sp
+If the \fBfield\fR property is not given, the expression is to be used as an SCTP chunk existence check in a \fBmatch\fR statement with a boolean on the right hand side\&.
+.SS "DCCP OPTION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "dccp option": {
+ "type":\fR \fINUMBER\fR*
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a reference to a DCCP option (\fBtype\fR)\&.
+.sp
+The expression is to be used as a DCCP option existence check in a \fBmatch\fR statement with a boolean on the right hand side\&.
+.SS "META"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "meta": {
+ "key":\fR \fIMETA_KEY\fR
+\fB}}\fR
+
+\fIMETA_KEY\fR := \fB"length"\fR | \fB"protocol"\fR | \fB"priority"\fR | \fB"random"\fR | \fB"mark"\fR |
+ \fB"iif"\fR | \fB"iifname"\fR | \fB"iiftype"\fR | \fB"oif"\fR | \fB"oifname"\fR |
+ \fB"oiftype"\fR | \fB"skuid"\fR | \fB"skgid"\fR | \fB"nftrace"\fR |
+ \fB"rtclassid"\fR | \fB"ibriport"\fR | \fB"obriport"\fR | \fB"ibridgename"\fR |
+ \fB"obridgename"\fR | \fB"pkttype"\fR | \fB"cpu"\fR | \fB"iifgroup"\fR |
+ \fB"oifgroup"\fR | \fB"cgroup"\fR | \fB"nfproto"\fR | \fB"l4proto"\fR |
+ \fB"secpath"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a reference to packet meta data\&.
+.SS "RT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "rt": {
+ "key":\fR \fIRT_KEY\fR\fB,
+ "family":\fR \fIRT_FAMILY\fR
+\fB}}\fR
+
+\fIRT_KEY\fR := \fB"classid"\fR | \fB"nexthop"\fR | \fB"mtu"\fR
+\fIRT_FAMILY\fR := \fB"ip"\fR | \fB"ip6"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a reference to packet routing data\&.
+.sp
+The \fBfamily\fR property is optional and defaults to unspecified\&.
+.SS "CT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "ct": {
+ "key":\fR \fISTRING\fR\fB,
+ "family":\fR \fICT_FAMILY\fR\fB,
+ "dir":\fR \fICT_DIRECTION\fR
+\fB}}\fR
+
+\fICT_FAMILY\fR := \fB"ip"\fR | \fB"ip6"\fR
+\fICT_DIRECTION\fR := \fB"original"\fR | \fB"reply"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a reference to packet conntrack data\&.
+.sp
+Some CT keys do not support a direction\&. In this case, \fBdir\fR must not be given\&.
+.SS "NUMGEN"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "numgen": {
+ "mode":\fR \fING_MODE\fR\fB,
+ "mod":\fR \fINUMBER\fR\fB,
+ "offset":\fR \fINUMBER\fR
+\fB}}\fR
+
+\fING_MODE\fR := \fB"inc"\fR | \fB"random"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a number generator\&.
+.sp
+The \fBoffset\fR property is optional and defaults to 0\&.
+.SS "HASH"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "jhash": {
+ "mod":\fR \fINUMBER\fR\fB,
+ "offset":\fR \fINUMBER\fR\fB,
+ "expr":\fR \fIEXPRESSION\fR\fB,
+ "seed":\fR \fINUMBER\fR
+\fB}}\fR
+
+\fB{ "symhash": {
+ "mod":\fR \fINUMBER\fR\fB,
+ "offset":\fR \fINUMBER\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Hash packet data\&.
+.sp
+The \fBoffset\fR and \fBseed\fR properties are optional and default to 0\&.
+.SS "FIB"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "fib": {
+ "result":\fR \fIFIB_RESULT\fR\fB,
+ "flags":\fR \fIFIB_FLAGS\fR
+\fB}}\fR
+
+\fIFIB_RESULT\fR := \fB"oif"\fR | \fB"oifname"\fR | \fB"type"\fR
+
+\fIFIB_FLAGS\fR := \fIFIB_FLAG\fR | \fB[\fR \fIFIB_FLAG_LIST\fR \fB]\fR
+\fIFIB_FLAG_LIST\fR := \fIFIB_FLAG\fR [\fB,\fR \fIFIB_FLAG_LIST\fR ]
+\fIFIB_FLAG\fR := \fB"saddr"\fR | \fB"daddr"\fR | \fB"mark"\fR | \fB"iif"\fR | \fB"oif"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Perform kernel Forwarding Information Base lookups\&.
+.SS "BINARY OPERATION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "|": [\fR \fIEXPRESSION\fR\fB,\fR \fIEXPRESSION\fR \fB] }\fR
+\fB{ "^": [\fR \fIEXPRESSION\fR\fB,\fR \fIEXPRESSION\fR \fB] }\fR
+\fB{ "&": [\fR \fIEXPRESSION\fR\fB,\fR \fIEXPRESSION\fR \fB] }\fR
+\fB{ "\fR\fB<<\fR\fB": [\fR \fIEXPRESSION\fR\fB,\fR \fIEXPRESSION\fR \fB] }\fR
+\fB{ ">>": [\fR \fIEXPRESSION\fR\fB,\fR \fIEXPRESSION\fR \fB] }\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+All binary operations expect an array of exactly two expressions, of which the first element denotes the left hand side and the second one the right hand side\&.
+.SS "VERDICT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "accept": null }\fR
+\fB{ "drop": null }\fR
+\fB{ "continue": null }\fR
+\fB{ "return": null }\fR
+\fB{ "jump": { "target":\fR \fISTRING\fR \fB}}\fR
+\fB{ "goto": { "target":\fR \fISTRING\fR \fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Same as the \fBverdict\fR statement, but for use in verdict maps\&.
+.sp
+\fBjump\fR and \fBgoto\fR verdicts expect a target chain name\&.
+.SS "ELEM"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "elem": {
+ "val":\fR \fIEXPRESSION\fR\fB,
+ "timeout":\fR \fINUMBER\fR\fB,
+ "expires":\fR \fINUMBER\fR\fB,
+ "comment":\fR \fISTRING\fR
+\fB}}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Explicitly set element object, in case \fBtimeout\fR, \fBexpires\fR or \fBcomment\fR are desired\&. Otherwise, it may be replaced by the value of \fBval\fR\&.
+.SS "SOCKET"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "socket": {
+ "key":\fR \fISOCKET_KEY\fR
+\fB}}\fR
+
+\fISOCKET_KEY\fR := \fB"transparent"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Construct a reference to packet\(cqs socket\&.
+.SS "OSF"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB{ "osf": {
+ "key":\fR \fIOSF_KEY\fR\fB,
+ "ttl":\fR \fIOSF_TTL\fR
+\fB}}\fR
+
+\fIOSF_KEY\fR := \fB"name"\fR
+\fIOSF_TTL\fR := \fB"loose"\fR | \fB"skip"\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Perform OS fingerprinting\&. This expression is typically used in the LHS of a \fBmatch\fR statement\&.
+.PP
+\fBkey\fR
+.RS 4
+Which part of the fingerprint info to match against\&. At this point, only the OS name is supported\&.
+.RE
+.PP
+\fBttl\fR
+.RS 4
+Define how the packet\(cqs TTL value is to be matched\&. This property is optional\&. If omitted, the TTL value has to match exactly\&. A value of
+\fBloose\fR
+accepts TTL values less than the fingerprint one\&. A value of
+\fBskip\fR
+omits TTL value comparison entirely\&.
+.RE
+.SH "AUTHOR"
+.PP
+\fBPhil Sutter\fR <\&phil@nwl\&.cc\&>
+.RS 4
+Author.
+.RE
diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc
new file mode 100644
index 0000000..3e6e1db
--- /dev/null
+++ b/doc/libnftables-json.adoc
@@ -0,0 +1,1416 @@
+libnftables-json(5)
+===================
+Phil Sutter <phil@nwl.cc>
+:doctype: manpage
+:compat-mode!:
+
+== NAME
+libnftables-json - Supported JSON schema by libnftables
+
+== SYNOPSIS
+*{ "nftables": [* 'OBJECTS' *] }*
+
+'OBJECTS' := 'LIST_OBJECTS' | 'CMD_OBJECTS'
+
+'LIST_OBJECTS' := 'LIST_OBJECT' [ *,* 'LIST_OBJECTS' ]
+
+'CMD_OBJECTS' := 'CMD_OBJECT' [ *,* 'CMD_OBJECTS' ]
+
+'CMD_OBJECT' := *{* 'CMD'*:* 'LIST_OBJECT' *}* | 'METAINFO_OBJECT'
+
+'CMD' := *"add"* | *"replace"* | *"create"* | *"insert"* | *"delete"* |
+ *"list"* | *"reset"* | *"flush"* | *"rename"*
+
+'LIST_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
+ 'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT' |
+ 'METAINFO_OBJECT' | 'CT_TIMEOUT' | 'CT_EXPECTATION'
+
+== DESCRIPTION
+libnftables supports JSON formatted input and output. This is implemented as an
+alternative frontend to the standard CLI syntax parser, therefore basic
+behaviour is identical and, for (almost) any operation available in standard
+syntax, there should be an equivalent one in JSON.
+
+JSON input may be provided in a single string as parameter to
+*nft_run_cmd_from_buffer()* or in a file identified by the 'filename' parameter
+of the *nft_run_cmd_from_filename()* function.
+
+JSON output has to be enabled via the *nft_ctx_output_set_json()* function, turning
+library standard output into JSON format. Error output remains unaffected.
+
+== GLOBAL STRUCTURE
+In general, any JSON input or output is enclosed in an object with a single
+property named 'nftables'. Its value is an array containing commands (for
+input) or ruleset elements (for output).
+
+A command is an object with a single property whose name identifies the command.
+Its value is a ruleset element - basically identical to output elements, apart
+from certain properties which may be interpreted differently or are required
+when output generally omits them.
+
+== METAINFO OBJECT
+In output, the first object in an *nftables* array is a special one containing
+library information. Its content is as follows:
+
+[verse]
+*{ "metainfo": {
+ "version":* 'STRING'*,
+ "release_name":* 'STRING'*,
+ "json_schema_version":* 'NUMBER'
+*}}*
+
+The values of *version* and *release_name* properties are equal to the package
+version and release name as printed by *nft -v*. The value of the
+*json_schema_version* property is an integer indicating the schema version.
+
+If supplied in library input, the parser will verify the *json_schema_version* value
+to not exceed the internally hardcoded one (to make sure the given schema is
+fully understood). In future, a lower number than the internal one may activate
+compatibility mode to parse outdated and incompatible JSON input.
+
+== COMMAND OBJECTS
+The structure accepts an arbitrary amount of commands which are interpreted in
+order of appearance. For instance, the following standard syntax input:
+
+----
+flush ruleset
+add table inet mytable
+add chain inet mytable mychain
+add rule inet mytable mychain tcp dport 22 accept
+----
+
+translates into JSON as such:
+
+----
+{ "nftables": [
+ { "flush": { "ruleset": null }},
+ { "add": { "table": {
+ "family": "inet",
+ "name": "mytable"
+ }}},
+ { "add": { "chain": {
+ "family": "inet",
+ "table": "mytable",
+ "name": "mychain"
+ }}},
+ { "add": { "rule": {
+ "family": "inet",
+ "table": "mytable",
+ "chain": "mychain",
+ "expr": [
+ { "match": {
+ "op": "==",
+ "left": { "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }},
+ "right": 22
+ }},
+ { "accept": null }
+ ]
+ }}}
+]}
+----
+
+=== ADD
+[verse]
+____
+*{ "add":* 'ADD_OBJECT' *}*
+
+'ADD_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
+ 'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT' |
+ 'CT_TIMEOUT' | 'CT_EXPECTATION'
+____
+
+Add a new ruleset element to the kernel.
+
+=== REPLACE
+[verse]
+*{ "replace":* 'RULE' *}*
+
+Replace a rule. In 'RULE', the *handle* property is mandatory and identifies the
+rule to be replaced.
+
+=== CREATE
+[verse]
+*{ "create":* 'ADD_OBJECT' *}*
+
+Identical to *add* command, but returns an error if the object already exists.
+
+=== INSERT
+[verse]
+*{ "insert":* 'RULE' *}*
+
+This command is identical to *add* for rules, but instead of appending the rule
+to the chain by default, it inserts at first position. If a *handle* or *index*
+property is given, the rule is inserted before the rule identified by those
+properties.
+
+=== DELETE
+[verse]
+*{ "delete":* 'ADD_OBJECT' *}*
+
+Delete an object from the ruleset. Only the minimal number of properties
+required to uniquely identify an object is generally needed in 'ADD_OBJECT'. For
+most ruleset elements, this is *family* and *table* plus either *handle* or
+*name* (except rules since they don't have a name).
+
+=== LIST
+[verse]
+____
+*{ "list":* 'LIST_OBJECT' *}*
+
+'LIST_OBJECT' := 'TABLE' | 'TABLES' | 'CHAIN' | 'CHAINS' | 'SET' | 'SETS' |
+ 'MAP' | 'MAPS | COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS' |
+ 'CT_HELPER' | 'CT_HELPERS' | 'LIMIT' | 'LIMITS' | 'RULESET' |
+ 'METER' | 'METERS' | 'FLOWTABLE' | 'FLOWTABLES' |
+ 'CT_TIMEOUT' | 'CT_EXPECTATION'
+____
+
+List ruleset elements. The plural forms are used to list all objects of that
+kind, optionally filtered by *family* and for some, also *table*.
+
+=== RESET
+[verse]
+____
+*{ "reset":* 'RESET_OBJECT' *}*
+
+'RESET_OBJECT' := 'COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS' | 'RULE' | 'RULES' | 'SET' | 'MAP' | 'ELEMENT'
+____
+
+Reset state in suitable objects, i.e. zero their internal counter.
+
+=== FLUSH
+[verse]
+____
+*{ "flush":* 'FLUSH_OBJECT' *}*
+
+'FLUSH_OBJECT' := 'TABLE' | 'CHAIN' | 'SET' | 'MAP' | 'METER' | 'RULESET'
+____
+
+Empty contents in given object, e.g. remove all chains from given *table* or
+remove all elements from given *set*.
+
+=== RENAME
+[verse]
+*{ "rename":* 'CHAIN' *}*
+
+Rename a chain. The new name is expected in a dedicated property named
+*newname*.
+
+== RULESET ELEMENTS
+
+=== TABLE
+[verse]
+*{ "table": {
+ "family":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'
+*}}*
+
+This object describes a table.
+
+*family*::
+ The table's family, e.g. *"ip"* or *"ip6"*.
+*name*::
+ The table's name.
+*handle*::
+ The table's handle. In input, it is used only in *delete* command as
+ alternative to *name*.
+
+=== CHAIN
+[verse]
+*{ "chain": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "newname":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "type":* 'STRING'*,
+ "hook":* 'STRING'*,
+ "prio":* 'NUMBER'*,
+ "dev":* 'STRING'*,
+ "policy":* 'STRING'
+*}}*
+
+This object describes a chain.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The chain's name.
+*handle*::
+ The chain's handle. In input, it is used only in *delete* command as
+ alternative to *name*.
+*newname*::
+ A new name for the chain, only relevant in the *rename* command.
+
+The following properties are required for base chains:
+
+*type*::
+ The chain's type.
+*hook*::
+ The chain's hook.
+*prio*::
+ The chain's priority.
+*dev*::
+ The chain's bound interface (if in the netdev family).
+*policy*::
+ The chain's policy.
+
+=== RULE
+[verse]
+____
+*{ "rule": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "chain":* 'STRING'*,
+ "expr": [* 'STATEMENTS' *],
+ "handle":* 'NUMBER'*,
+ "index":* 'NUMBER'*,
+ "comment":* 'STRING'
+*}}*
+
+'STATEMENTS' := 'STATEMENT' [*,* 'STATEMENTS' ]
+____
+
+This object describes a rule. Basic building blocks of rules are statements.
+Each rule consists of at least one.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*chain*::
+ The chain's name.
+*expr*::
+ An array of statements this rule consists of. In input, it is used in
+ *add*/*insert*/*replace* commands only.
+*handle*::
+ The rule's handle. In *delete*/*replace* commands, it serves as an identifier
+ of the rule to delete/replace. In *add*/*insert* commands, it serves as
+ an identifier of an existing rule to append/prepend the rule to.
+*index*::
+ The rule's position for *add*/*insert* commands. It is used as an alternative to
+ *handle* then.
+*comment*::
+ Optional rule comment.
+
+=== SET / MAP
+[verse]
+____
+*{ "set": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "type":* 'SET_TYPE'*,
+ "policy":* 'SET_POLICY'*,
+ "flags": [* 'SET_FLAG_LIST' *],
+ "elem":* 'SET_ELEMENTS'*,
+ "timeout":* 'NUMBER'*,
+ "gc-interval":* 'NUMBER'*,
+ "size":* 'NUMBER'
+*}}*
+
+*{ "map": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "type":* 'SET_TYPE'*,
+ "map":* 'STRING'*,
+ "policy":* 'SET_POLICY'*,
+ "flags": [* 'SET_FLAG_LIST' *],
+ "elem":* 'SET_ELEMENTS'*,
+ "timeout":* 'NUMBER'*,
+ "gc-interval":* 'NUMBER'*,
+ "size":* 'NUMBER'
+*}}*
+
+'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]*
+'SET_TYPE_LIST' := 'STRING' [*,* 'SET_TYPE_LIST' ]
+'SET_POLICY' := *"performance"* | *"memory"*
+'SET_FLAG_LIST' := 'SET_FLAG' [*,* 'SET_FLAG_LIST' ]
+'SET_FLAG' := *"constant"* | *"interval"* | *"timeout"*
+'SET_ELEMENTS' := 'EXPRESSION' | *[* 'EXPRESSION_LIST' *]*
+'EXPRESSION_LIST' := 'EXPRESSION' [*,* 'EXPRESSION_LIST' ]
+____
+
+These objects describe a named set or map. Maps are a special form of sets in
+that they translate a unique key to a value.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The set's name.
+*handle*::
+ The set's handle. For input, it is used in the *delete* command only.
+*type*::
+ The set's datatype, see below.
+*map*::
+ Type of values this set maps to (i.e. this set is a map).
+*policy*::
+ The set's policy.
+*flags*::
+ The set's flags.
+*elem*::
+ Initial set element(s), see below.
+*timeout*::
+ Element timeout in seconds.
+*gc-interval*::
+ Garbage collector interval in seconds.
+*size*::
+ Maximum number of elements supported.
+
+==== TYPE
+The set type might be a string, such as *"ipv4_addr"* or an array
+consisting of strings (for concatenated types).
+
+==== ELEM
+A single set element might be given as string, integer or boolean value for
+simple cases. If additional properties are required, a formal *elem* object may
+be used.
+
+Multiple elements may be given in an array.
+
+=== ELEMENT
+[verse]
+____
+*{ "element": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "elem":* 'SET_ELEM'
+*}}*
+
+'SET_ELEM' := 'EXPRESSION' | *[* 'EXPRESSION_LIST' *]*
+'EXPRESSION_LIST' := 'EXPRESSION' [*,* 'EXPRESSION' ]
+____
+
+Manipulate element(s) in a named set.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The set's name.
+*elem*::
+ See elem property of set object.
+
+=== FLOWTABLE
+[verse]
+____
+*{ "flowtable": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "hook":* 'STRING'*,
+ "prio":* 'NUMBER'*,
+ "dev":* 'FT_INTERFACE'
+*}}*
+
+'FT_INTERFACE' := 'STRING' | *[* 'FT_INTERFACE_LIST' *]*
+'FT_INTERFACE_LIST' := 'STRING' [*,* 'STRING' ]
+____
+
+This object represents a named flowtable.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The flow table's name.
+*handle*::
+ The flow table's handle. In input, it is used by the *delete* command only.
+*hook*::
+ The flow table's hook.
+*prio*::
+ The flow table's priority.
+*dev*::
+ The flow table's interface(s).
+
+=== COUNTER
+[verse]
+*{ "counter": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "packets":* 'NUMBER'*,
+ "bytes":* 'NUMBER'
+*}}*
+
+This object represents a named counter.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The counter's name.
+*handle*::
+ The counter's handle. In input, it is used by the *delete* command only.
+*packets*::
+ Packet counter value.
+*bytes*::
+ Byte counter value.
+
+=== QUOTA
+[verse]
+*{ "quota": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "bytes":* 'NUMBER'*,
+ "used":* 'NUMBER'*,
+ "inv":* 'BOOLEAN'
+*}}*
+
+This object represents a named quota.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The quota's name.
+*handle*::
+ The quota's handle. In input, it is used by the *delete* command only.
+*bytes*::
+ Quota threshold.
+*used*::
+ Quota used so far.
+*inv*::
+ If true, match if the quota has been exceeded.
+
+=== CT HELPER
+[verse]
+____
+*{ "ct helper": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* '... '*,
+ "type":* 'STRING'*,
+ "protocol":* 'CTH_PROTO'*,
+ "l3proto":* 'STRING'
+*}}*
+
+'CTH_PROTO' := *"tcp"* | *"udp"*
+____
+
+This object represents a named conntrack helper.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The ct helper's name.
+*handle*::
+ The ct helper's handle. In input, it is used by the *delete* command only.
+*type*::
+ The ct helper type name, e.g. *"ftp"* or *"tftp"*.
+*protocol*::
+ The ct helper's layer 4 protocol.
+*l3proto*::
+ The ct helper's layer 3 protocol, e.g. *"ip"* or *"ip6"*.
+
+=== LIMIT
+[verse]
+____
+*{ "limit": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "rate":* 'NUMBER'*,
+ "per":* 'STRING'*,
+ "burst":* 'NUMBER'*,
+ "unit":* 'LIMIT_UNIT'*,
+ "inv":* 'BOOLEAN'
+*}}*
+
+'LIMIT_UNIT' := *"packets"* | *"bytes"*
+____
+
+This object represents a named limit.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The limit's name.
+*handle*::
+ The limit's handle. In input, it is used by the *delete* command only.
+*rate*::
+ The limit's rate value.
+*per*::
+ Time unit to apply the limit to, e.g. *"week"*, *"day"*, *"hour"*, etc.
+ If omitted, defaults to *"second"*.
+*burst*::
+ The limit's burst value. If omitted, defaults to *0*.
+*unit*::
+ Unit of rate and burst values. If omitted, defaults to *"packets"*.
+*inv*::
+ If true, match if limit was exceeded. If omitted, defaults to *false*.
+
+=== CT TIMEOUT
+[verse]
+____
+*{ "ct timeout": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "protocol":* 'CTH_PROTO'*,
+ "state":* 'STRING'*,
+ "value:* 'NUMBER'*,
+ "l3proto":* 'STRING'
+*}}*
+
+'CTH_PROTO' := *"tcp"* | *"udp"* | *"dccp"* | *"sctp"* | *"gre"* | *"icmpv6"* | *"icmp"* | *"generic"*
+____
+
+This object represents a named conntrack timeout policy.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The ct timeout object's name.
+*handle*::
+ The ct timeout object's handle. In input, it is used by *delete* command only.
+*protocol*::
+ The ct timeout object's layer 4 protocol.
+*state*::
+ The connection state name, e.g. *"established"*, *"syn_sent"*, *"close"* or
+ *"close_wait"*, for which the timeout value has to be updated.
+*value*::
+ The updated timeout value for the specified connection state.
+*l3proto*::
+ The ct timeout object's layer 3 protocol, e.g. *"ip"* or *"ip6"*.
+
+=== CT EXPECTATION
+[verse]
+____
+*{ "ct expectation": {
+ "family":* 'STRING'*,
+ "table":* 'STRING'*,
+ "name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
+ "l3proto":* 'STRING'
+ "protocol":* 'CTH_PROTO'*,
+ "dport":* 'NUMBER'*,
+ "timeout:* 'NUMBER'*,
+ "size:* 'NUMBER'*,
+*}}*
+
+'CTH_PROTO' := *"tcp"* | *"udp"* | *"dccp"* | *"sctp"* | *"gre"* | *"icmpv6"* | *"icmp"* | *"generic"*
+____
+
+This object represents a named conntrack expectation.
+
+*family*::
+ The table's family.
+*table*::
+ The table's name.
+*name*::
+ The ct expectation object's name.
+*handle*::
+ The ct expectation object's handle. In input, it is used by *delete* command only.
+*l3proto*::
+ The ct expectation object's layer 3 protocol, e.g. *"ip"* or *"ip6"*.
+*protocol*::
+ The ct expectation object's layer 4 protocol.
+*dport*::
+ The destination port of the expected connection.
+*timeout*::
+ The time in millisecond that this expectation will live.
+*size*::
+ The maximum count of expectations to be living in the same time.
+
+== STATEMENTS
+Statements are the building blocks for rules. Each rule consists of at least
+one.
+
+=== VERDICT
+[verse]
+*{ "accept": null }*
+*{ "drop": null }*
+*{ "continue": null }*
+*{ "return": null }*
+*{ "jump": { "target": * 'STRING' *}}*
+*{ "goto": { "target": * 'STRING' *}}*
+
+A verdict either terminates packet traversal through the current chain or
+delegates to a different one.
+
+*jump* and *goto* statements expect a target chain name.
+
+=== MATCH
+[verse]
+*{ "match": {
+ "left":* 'EXPRESSION'*,
+ "right":* 'EXPRESSION'*,
+ "op":* 'STRING'
+*}}*
+
+This matches the expression on left hand side (typically a packet header or packet meta
+info) with the expression on right hand side (typically a constant value). If the
+statement evaluates to true, the next statement in this rule is considered. If not,
+processing continues with the next rule in the same chain.
+
+*left*::
+ Left hand side of this match.
+*right*::
+ Right hand side of this match.
+*op*::
+ Operator indicating the type of comparison.
+
+==== OPERATORS
+
+[horizontal]
+*&*:: Binary AND
+*|*:: Binary OR
+*^*:: Binary XOR
+*<<*:: Left shift
+*>>*:: Right shift
+*==*:: Equal
+*!=*:: Not equal
+*<*:: Less than
+*>*:: Greater than
+*<=*:: Less than or equal to
+*>=*:: Greater than or equal to
+*in*:: Perform a lookup, i.e. test if bits on RHS are contained in LHS value
+
+Unlike with the standard API, the operator is mandatory here. In the standard API,
+a missing operator may be resolved in two ways, depending on the type of expression
+on the RHS:
+
+- If the RHS is a bitmask or a list of bitmasks, the expression resolves into a
+ binary operation with the inequality operator, like this: '+LHS & RHS != 0+'.
+- In any other case, the equality operator is simply inserted.
+
+For the non-trivial first case, the JSON API supports the *in* operator.
+
+=== COUNTER
+[verse]
+____
+*{ "counter": {
+ "packets":* 'NUMBER'*,
+ "bytes":* 'NUMBER'
+*}}*
+
+*{ "counter":* 'STRING' *}*
+____
+
+This object represents a byte/packet counter. In input, no properties are
+required. If given, they act as initial values for the counter.
+
+The first form creates an anonymous counter which lives in the rule it appears
+in. The second form specifies a reference to a named counter object.
+
+*packets*::
+ Packets counted.
+*bytes*::
+ Bytes counted.
+
+=== MANGLE
+[verse]
+*{ "mangle": {
+ "key":* 'EXPRESSION'*,
+ "value":* 'EXPRESSION'
+*}}*
+
+This changes the packet data or meta info.
+
+*key*::
+ The packet data to be changed, given as an *exthdr*, *payload*, *meta*, *ct* or
+ *ct helper* expression.
+*value*::
+ Value to change data to.
+
+=== QUOTA
+[verse]
+____
+*{ "quota": {
+ "val":* 'NUMBER'*,
+ "val_unit":* 'STRING'*,
+ "used":* 'NUMBER'*,
+ "used_unit":* 'STRING'*,
+ "inv":* 'BOOLEAN'
+*}}*
+
+*{ "quota":* 'STRING' *}*
+____
+
+The first form creates an anonymous quota which lives in the rule it appears in.
+The second form specifies a reference to a named quota object.
+
+*val*::
+ Quota value.
+*val_unit*::
+ Unit of *val*, e.g. *"kbytes"* or *"mbytes"*. If omitted, defaults to
+ *"bytes"*.
+*used*::
+ Quota used so far. Optional on input. If given, serves as initial value.
+*used_unit*::
+ Unit of *used*. Defaults to *"bytes"*.
+*inv*::
+ If *true*, will match if quota was exceeded. Defaults to *false*.
+
+=== LIMIT
+[verse]
+____
+*{ "limit": {
+ "rate":* 'NUMBER'*,
+ "rate_unit":* 'STRING'*,
+ "per":* 'STRING'*,
+ "burst":* 'NUMBER'*,
+ "burst_unit":* 'STRING'*,
+ "inv":* 'BOOLEAN'
+*}}*
+
+*{ "limit":* 'STRING' *}*
+____
+
+The first form creates an anonymous limit which lives in the rule it appears in.
+The second form specifies a reference to a named limit object.
+
+*rate*::
+ Rate value to limit to.
+*rate_unit*::
+ Unit of *rate*, e.g. *"packets"* or *"mbytes"*. Defaults to *"packets"*.
+*per*::
+ Denominator of *rate*, e.g. *"week"* or *"minutes"*.
+*burst*::
+ Burst value. Defaults to *0*.
+*burst_unit*::
+ Unit of *burst*, ignored if *rate_unit* is *"packets"*. Defaults to
+ *"bytes"*.
+*inv*::
+ If *true*, matches if the limit was exceeded. Defaults to *false*.
+
+=== FWD
+[verse]
+____
+*{ "fwd": {
+ "dev":* 'EXPRESSION'*,
+ "family":* 'FWD_FAMILY'*,
+ "addr":* 'EXPRESSION'
+*}}*
+
+'FWD_FAMILY' := *"ip"* | *"ip6"*
+____
+
+Forward a packet to a different destination.
+
+*dev*::
+ Interface to forward the packet on.
+*family*::
+ Family of *addr*.
+*addr*::
+ IP(v6) address to forward the packet to.
+
+Both *family* and *addr* are optional, but if at least one is given, both must be present.
+
+=== NOTRACK
+[verse]
+*{ "notrack": null }*
+
+Disable connection tracking for the packet.
+
+=== DUP
+[verse]
+*{ "dup": {
+ "addr":* 'EXPRESSION'*,
+ "dev":* 'EXPRESSION'
+*}}*
+
+Duplicate a packet to a different destination.
+
+*addr*::
+ Address to duplicate packet to.
+*dev*::
+ Interface to duplicate packet on. May be omitted to not specify an
+ interface explicitly.
+
+=== NETWORK ADDRESS TRANSLATION
+[verse]
+____
+*{ "snat": {
+ "addr":* 'EXPRESSION'*,
+ "family":* 'STRING'*,
+ "port":* 'EXPRESSION'*,
+ "flags":* 'FLAGS'
+*}}*
+
+*{ "dnat": {
+ "addr":* 'EXPRESSION'*,
+ "family":* 'STRING'*,
+ "port":* 'EXPRESSION'*,
+ "flags":* 'FLAGS'
+*}}*
+
+*{ "masquerade": {
+ "port":* 'EXPRESSION'*,
+ "flags":* 'FLAGS'
+*}}*
+
+*{ "redirect": {
+ "port":* 'EXPRESSION'*,
+ "flags":* 'FLAGS'
+*}}*
+
+'FLAGS' := 'FLAG' | *[* 'FLAG_LIST' *]*
+'FLAG_LIST' := 'FLAG' [*,* 'FLAG_LIST' ]
+'FLAG' := *"random"* | *"fully-random"* | *"persistent"*
+____
+
+Perform Network Address Translation.
+
+*addr*::
+ Address to translate to.
+*family*::
+ Family of *addr*, either *ip* or *ip6*. Required in *inet*
+ table family.
+*port*::
+ Port to translate to.
+*flags*::
+ Flag(s).
+
+All properties are optional and default to none.
+
+=== REJECT
+[verse]
+*{ "reject": {
+ "type":* 'STRING'*,
+ "expr":* 'EXPRESSION'
+*}}*
+
+Reject the packet and send the given error reply.
+
+*type*::
+ Type of reject, either *"tcp reset"*, *"icmpx"*, *"icmp"* or *"icmpv6"*.
+*expr*::
+ ICMP code to reject with.
+
+All properties are optional.
+
+=== SET
+[verse]
+*{ "set": {
+ "op":* 'STRING'*,
+ "elem":* 'EXPRESSION'*,
+ "set":* 'STRING'
+*}}*
+
+Dynamically add/update elements to a set.
+
+*op*::
+ Operator on set, either *"add"* or *"update"*.
+*elem*::
+ Set element to add or update.
+*set*::
+ Set reference.
+
+=== LOG
+[verse]
+____
+*{ "log": {
+ "prefix":* 'STRING'*,
+ "group":* 'NUMBER'*,
+ "snaplen":* 'NUMBER'*,
+ "queue-threshold":* 'NUMBER'*,
+ "level":* 'LEVEL'*,
+ "flags":* 'FLAGS'
+*}}*
+
+'LEVEL' := *"emerg"* | *"alert"* | *"crit"* | *"err"* | *"warn"* | *"notice"* |
+ *"info"* | *"debug"* | *"audit"*
+
+'FLAGS' := 'FLAG' | *[* 'FLAG_LIST' *]*
+'FLAG_LIST' := 'FLAG' [*,* 'FLAG_LIST' ]
+'FLAG' := *"tcp sequence"* | *"tcp options"* | *"ip options"* | *"skuid"* |
+ *"ether"* | *"all"*
+____
+
+Log the packet.
+
+*prefix*::
+ Prefix for log entries.
+*group*::
+ Log group.
+*snaplen*::
+ Snaplen for logging.
+*queue-threshold*::
+ Queue threshold.
+*level*::
+ Log level. Defaults to *"warn"*.
+*flags*::
+ Log flags.
+
+All properties are optional.
+
+=== CT HELPER
+[verse]
+*{ "ct helper":* 'EXPRESSION' *}*
+
+Enable the specified conntrack helper for this packet.
+
+*ct helper*::
+ CT helper reference.
+
+=== METER
+[verse]
+*{ "meter": {
+ "name":* 'STRING'*,
+ "key":* 'EXPRESSION'*,
+ "stmt":* 'STATEMENT'
+*}}*
+
+Apply a given statement using a meter.
+
+*name*::
+ Meter name.
+*key*::
+ Meter key.
+*stmt*::
+ Meter statement.
+
+=== QUEUE
+[verse]
+____
+*{ "queue": {
+ "num":* 'EXPRESSION'*,
+ "flags":* 'FLAGS'
+*}}*
+
+'FLAGS' := 'FLAG' | *[* 'FLAG_LIST' *]*
+'FLAG_LIST' := 'FLAG' [*,* 'FLAG_LIST' ]
+'FLAG' := *"bypass"* | *"fanout"*
+____
+
+Queue the packet to userspace.
+
+*num*::
+ Queue number.
+*flags*::
+ Queue flags.
+
+=== VERDICT MAP
+[verse]
+*{ "vmap": {
+ "key":* 'EXPRESSION'*,
+ "data":* 'EXPRESSION'
+*}}*
+
+Apply a verdict conditionally.
+
+*key*::
+ Map key.
+*data*::
+ Mapping expression consisting of value/verdict pairs.
+
+=== CT COUNT
+[verse]
+*{ "ct count": {
+ "val":* 'NUMBER'*,
+ "inv":* 'BOOLEAN'
+*}}*
+
+Limit the number of connections using conntrack.
+
+*val*::
+ Connection count threshold.
+*inv*::
+ If *true*, match if *val* was exceeded. If omitted, defaults to
+ *false*.
+
+=== CT TIMEOUT
+[verse]
+*{ "ct timeout":* 'EXPRESSION' *}*
+
+Assign connection tracking timeout policy.
+
+*ct timeout*::
+ CT timeout reference.
+
+=== CT EXPECTATION
+[verse]
+*{ "ct expectation":* 'EXPRESSION' *}*
+
+Assign connection tracking expectation.
+
+*ct expectation*::
+ CT expectation reference.
+
+=== XT
+[verse]
+____
+*{ "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.
+
+*BEWARE:* nftables won't restore these statements.
+
+== EXPRESSIONS
+Expressions are the building blocks of (most) statements. In their most basic
+form, they are just immediate values represented as a JSON string, integer or
+boolean type.
+
+=== IMMEDIATES
+[verse]
+'STRING'
+'NUMBER'
+'BOOLEAN'
+
+Immediate expressions are typically used for constant values. For strings, there
+are two special cases:
+
+*@STRING*::
+ The remaining part is taken as set name to create a set reference.
+*\**::
+ Construct a wildcard expression.
+
+=== LISTS
+[verse]
+'ARRAY'
+
+List expressions are constructed by plain arrays containing of an arbitrary
+number of expressions.
+
+=== CONCAT
+[verse]
+____
+*{ "concat":* 'CONCAT' *}*
+
+'CONCAT' := *[* 'EXPRESSION_LIST' *]*
+'EXPRESSION_LIST' := 'EXPRESSION' [*,* 'EXPRESSION_LIST' ]
+____
+
+Concatenate several expressions.
+
+=== SET
+[verse]
+____
+*{ "set":* 'SET' *}*
+
+'SET' := 'EXPRESSION' | *[* 'EXPRESSION_LIST' *]*
+____
+
+This object constructs an anonymous set. For mappings, an array of arrays with
+exactly two elements is expected.
+
+=== MAP
+[verse]
+*{ "map": {
+ "key":* 'EXPRESSION'*,
+ "data":* 'EXPRESSION'
+*}}*
+
+Map a key to a value.
+
+*key*::
+ Map key.
+*data*::
+ Mapping expression consisting of value/target pairs.
+
+=== PREFIX
+[verse]
+*{ "prefix": {
+ "addr":* 'EXPRESSION'*,
+ "len":* 'NUMBER'
+*}}*
+
+Construct an IPv4 or IPv6 prefix consisting of address part in *addr* and prefix
+length in *len*.
+
+=== RANGE
+[verse]
+*{ "range": [* 'EXPRESSION' *,* 'EXPRESSION' *] }*
+
+Construct a range of values. The first array item denotes the lower boundary,
+the second one the upper boundary.
+
+=== PAYLOAD
+[verse]
+____
+*{ "payload": {
+ "base":* 'BASE'*,
+ "offset":* 'NUMBER'*,
+ "len":* 'NUMBER'
+*}}*
+
+*{ "payload": {
+ "protocol":* 'STRING'*,
+ "field":* 'STRING'
+*}}*
+
+'BASE' := *"ll"* | *"nh"* | *"th"*
+____
+
+Construct a payload expression, i.e. a reference to a certain part of packet
+data. The first form creates a raw payload expression to point at a random
+number (*len*) of bytes at a certain offset (*offset*) from a given reference
+point (*base*). The following *base* values are accepted:
+
+*"ll"*::
+ The offset is relative to Link Layer header start offset.
+*"nh"*::
+ The offset is relative to Network Layer header start offset.
+*"th"*::
+ The offset is relative to Transport Layer header start offset.
+
+The second form allows one to reference a field by name (*field*) in a named packet
+header (*protocol*).
+
+=== EXTHDR
+[verse]
+*{ "exthdr": {
+ "name":* 'STRING'*,
+ "field":* 'STRING'*,
+ "offset":* 'NUMBER'
+*}}*
+
+Create a reference to a field (*field*) in an IPv6 extension header (*name*).
+*offset* is used only for *rt0* protocol.
+
+If the *field* property is not given, the expression is to be used as a header
+existence check in a *match* statement with a boolean on the right hand side.
+
+=== TCP OPTION
+[verse]
+*{ "tcp option": {
+ "name":* 'STRING'*,
+ "field":* 'STRING'
+*}}*
+
+Create a reference to a field (*field*) of a TCP option header (*name*).
+
+If the *field* property is not given, the expression is to be used as a TCP option
+existence check in a *match* statement with a boolean on the right hand side.
+
+=== SCTP CHUNK
+[verse]
+*{ "sctp chunk": {
+ "name":* 'STRING'*,
+ "field":* 'STRING'
+*}}*
+
+Create a reference to a field (*field*) of an SCTP chunk (*name*).
+
+If the *field* property is not given, the expression is to be used as an SCTP
+chunk existence check in a *match* statement with a boolean on the right hand
+side.
+
+=== DCCP OPTION
+[verse]
+*{ "dccp option": {
+ "type":* 'NUMBER'*
+*}}*
+
+Create a reference to a DCCP option (*type*).
+
+The expression is to be used as a DCCP option existence check in a *match*
+statement with a boolean on the right hand side.
+
+=== META
+[verse]
+____
+*{ "meta": {
+ "key":* 'META_KEY'
+*}}*
+
+'META_KEY' := *"length"* | *"protocol"* | *"priority"* | *"random"* | *"mark"* |
+ *"iif"* | *"iifname"* | *"iiftype"* | *"oif"* | *"oifname"* |
+ *"oiftype"* | *"skuid"* | *"skgid"* | *"nftrace"* |
+ *"rtclassid"* | *"ibriport"* | *"obriport"* | *"ibridgename"* |
+ *"obridgename"* | *"pkttype"* | *"cpu"* | *"iifgroup"* |
+ *"oifgroup"* | *"cgroup"* | *"nfproto"* | *"l4proto"* |
+ *"secpath"*
+____
+
+Create a reference to packet meta data.
+
+=== RT
+[verse]
+____
+*{ "rt": {
+ "key":* 'RT_KEY'*,
+ "family":* 'RT_FAMILY'
+*}}*
+
+'RT_KEY' := *"classid"* | *"nexthop"* | *"mtu"*
+'RT_FAMILY' := *"ip"* | *"ip6"*
+____
+
+Create a reference to packet routing data.
+
+The *family* property is optional and defaults to unspecified.
+
+=== CT
+[verse]
+____
+*{ "ct": {
+ "key":* 'STRING'*,
+ "family":* 'CT_FAMILY'*,
+ "dir":* 'CT_DIRECTION'
+*}}*
+
+'CT_FAMILY' := *"ip"* | *"ip6"*
+'CT_DIRECTION' := *"original"* | *"reply"*
+____
+
+Create a reference to packet conntrack data.
+
+Some CT keys do not support a direction. In this case, *dir* must not be
+given.
+
+=== NUMGEN
+[verse]
+____
+*{ "numgen": {
+ "mode":* 'NG_MODE'*,
+ "mod":* 'NUMBER'*,
+ "offset":* 'NUMBER'
+*}}*
+
+'NG_MODE' := *"inc"* | *"random"*
+____
+
+Create a number generator.
+
+The *offset* property is optional and defaults to 0.
+
+=== HASH
+[verse]
+____
+*{ "jhash": {
+ "mod":* 'NUMBER'*,
+ "offset":* 'NUMBER'*,
+ "expr":* 'EXPRESSION'*,
+ "seed":* 'NUMBER'
+*}}*
+
+*{ "symhash": {
+ "mod":* 'NUMBER'*,
+ "offset":* 'NUMBER'
+*}}*
+____
+
+Hash packet data.
+
+The *offset* and *seed* properties are optional and default to 0.
+
+=== FIB
+[verse]
+____
+*{ "fib": {
+ "result":* 'FIB_RESULT'*,
+ "flags":* 'FIB_FLAGS'
+*}}*
+
+'FIB_RESULT' := *"oif"* | *"oifname"* | *"type"*
+
+'FIB_FLAGS' := 'FIB_FLAG' | *[* 'FIB_FLAG_LIST' *]*
+'FIB_FLAG_LIST' := 'FIB_FLAG' [*,* 'FIB_FLAG_LIST' ]
+'FIB_FLAG' := *"saddr"* | *"daddr"* | *"mark"* | *"iif"* | *"oif"*
+____
+
+Perform kernel Forwarding Information Base lookups.
+
+=== BINARY OPERATION
+[verse]
+*{ "|": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
+*{ "^": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
+*{ "&": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
+*{ "+<<+": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
+*{ ">>": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
+
+All binary operations expect an array of exactly two expressions, of which the
+first element denotes the left hand side and the second one the right hand
+side.
+
+=== VERDICT
+[verse]
+*{ "accept": null }*
+*{ "drop": null }*
+*{ "continue": null }*
+*{ "return": null }*
+*{ "jump": { "target":* 'STRING' *}}*
+*{ "goto": { "target":* 'STRING' *}}*
+
+Same as the *verdict* statement, but for use in verdict maps.
+
+*jump* and *goto* verdicts expect a target chain name.
+
+=== ELEM
+[verse]
+*{ "elem": {
+ "val":* 'EXPRESSION'*,
+ "timeout":* 'NUMBER'*,
+ "expires":* 'NUMBER'*,
+ "comment":* 'STRING'
+*}}*
+
+Explicitly set element object, in case *timeout*, *expires* or *comment* are
+desired. Otherwise, it may be replaced by the value of *val*.
+
+=== SOCKET
+[verse]
+____
+*{ "socket": {
+ "key":* 'SOCKET_KEY'
+*}}*
+
+'SOCKET_KEY' := *"transparent"*
+____
+
+Construct a reference to packet's socket.
+
+=== OSF
+[verse]
+____
+*{ "osf": {
+ "key":* 'OSF_KEY'*,
+ "ttl":* 'OSF_TTL'
+*}}*
+
+'OSF_KEY' := *"name"*
+'OSF_TTL' := *"loose"* | *"skip"*
+____
+
+Perform OS fingerprinting. This expression is typically used in the LHS of a *match*
+statement.
+
+*key*::
+ Which part of the fingerprint info to match against. At this point, only
+ the OS name is supported.
+*ttl*::
+ Define how the packet's TTL value is to be matched. This property is
+ optional. If omitted, the TTL value has to match exactly. A value of *loose*
+ accepts TTL values less than the fingerprint one. A value of *skip*
+ omits TTL value comparison entirely.
diff --git a/doc/libnftables.3 b/doc/libnftables.3
new file mode 100644
index 0000000..4778a8e
--- /dev/null
+++ b/doc/libnftables.3
@@ -0,0 +1,393 @@
+'\" t
+.\" Title: libnftables
+.\" Author: Phil Sutter <phil@nwl.cc>
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/11/2023
+.\" Manual: \ \&
+.\" Source: \ \&
+.\" Language: English
+.\"
+.TH "LIBNFTABLES" "3" "10/11/2023" "\ \&" "\ \&"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+libnftables \- nftables frontend library
+.SH "SYNOPSIS"
+.sp
+.nf
+\fB#include <nftables/libnftables\&.h>
+
+struct nft_ctx *nft_ctx_new(uint32_t\fR \fIflags\fR\fB);
+void nft_ctx_free(struct nft_ctx\fR \fI*ctx\fR\fB);
+
+bool nft_ctx_get_dry_run(struct nft_ctx\fR \fI*ctx\fR\fB);
+void nft_ctx_set_dry_run(struct nft_ctx\fR \fI*ctx\fR\fB, bool\fR \fIdry\fR\fB);
+
+unsigned int nft_ctx_input_get_flags(struct nft_ctx\fR \fI*ctx\fR\fB);
+unsigned int nft_ctx_input_set_flags(struct nft_ctx\fR \fI*ctx\fR\fB, unsigned int\fR \fIflags\fR\fB);
+
+unsigned int nft_ctx_output_get_flags(struct nft_ctx\fR \fI*ctx\fR\fB);
+void nft_ctx_output_set_flags(struct nft_ctx\fR \fI*ctx\fR\fB, unsigned int\fR \fIflags\fR\fB);
+
+unsigned int nft_ctx_output_get_debug(struct nft_ctx\fR \fI*ctx\fR\fB);
+void nft_ctx_output_set_debug(struct nft_ctx\fR \fI*ctx\fR\fB, unsigned int\fR \fImask\fR\fB);
+
+FILE *nft_ctx_set_output(struct nft_ctx\fR \fI*ctx\fR\fB, FILE\fR \fI*fp\fR\fB);
+int nft_ctx_buffer_output(struct nft_ctx\fR \fI*ctx\fR\fB);
+int nft_ctx_unbuffer_output(struct nft_ctx\fR \fI*ctx\fR\fB);
+const char *nft_ctx_get_output_buffer(struct nft_ctx\fR \fI*ctx\fR\fB);
+
+FILE *nft_ctx_set_error(struct nft_ctx\fR \fI*ctx\fR\fB, FILE\fR \fI*fp\fR\fB);
+int nft_ctx_buffer_error(struct nft_ctx\fR \fI*ctx\fR\fB);
+int nft_ctx_unbuffer_error(struct nft_ctx\fR \fI*ctx\fR\fB);
+const char *nft_ctx_get_error_buffer(struct nft_ctx\fR \fI*ctx\fR\fB);
+
+int nft_ctx_add_include_path(struct nft_ctx\fR \fI*ctx\fR\fB, const char\fR \fI*path\fR\fB);
+void nft_ctx_clear_include_paths(struct nft_ctx\fR \fI*ctx\fR\fB);
+
+int nft_ctx_add_var(struct nft_ctx\fR \fI*ctx\fR\fB, const char\fR \fI*var\fR\fB);
+void nft_ctx_clear_vars(struct nft_ctx \fR\fB\fI\e*ctx\fR\fR);
+
+int nft_run_cmd_from_buffer(struct nft_ctx* \fI*nft\fR\fB, const char\fR \fI*buf\fR\fB);
+int nft_run_cmd_from_filename(struct nft_ctx\fR \fI*nft\fR\fB,
+ const char\fR \fI*filename\fR\fB);\fR
+
+Link with \fI\-lnftables\fR\&.
+.fi
+.SH "DESCRIPTION"
+.sp
+This library was designed with nftables integration into applications in mind\&. Its API is therefore kept as simple as possible, which somewhat limits its flexibility\&. Due to support for JSON markup of input and output though, convenience in constructing and parsing of input and output data may be achieved by using a third\-party library such as \fBlibjansson\fR\&.
+.sp
+At the very basic level, one has to allocate a new object of type \fBstruct nft_ctx\fR using \fBnft_ctx_new\fR() function, then pass commands via \fBnft_run_cmd_from_buffer\fR() or \fBnft_run_cmd_from_filename\fR() functions\&. By default, any output is written to \fBstdout\fR (or \fBstderr\fR for error messages)\&. These file pointers may be changed using \fBnft_ctx_set_output\fR() and \fBnft_ctx_set_error\fR() functions\&. On top of that, it is possible to have any output buffered by the library for later retrieval as a static buffer\&. See \fBnft_ctx_buffer_output\fR() and \fBnft_ctx_buffer_error\fR() functions for details\&.
+.SS "nft_ctx_new() and nft_ctx_free()"
+.sp
+These functions aid in nft context management\&. In order to make use of the library, at least one context object has to be allocated\&. The context holds temporary data such as caches, library configuration and (if enabled) output and error buffers\&.
+.sp
+The \fBnft_ctx_new\fR() function allocates and returns a new context object\&. The parameter \fIflags\fR is unused at this point and should be set to zero\&. For convenience, the macro \fBNFT_CTX_DEFAULT\fR is defined to that value\&.
+.sp
+The \fBnft_ctx_free\fR() function frees the context object pointed to by \fIctx\fR, including any caches or buffers it may hold\&.
+.SS "nft_ctx_get_dry_run() and nft_ctx_set_dry_run()"
+.sp
+Dry\-run setting controls whether ruleset changes are actually committed on kernel side or not\&. It allows one to check whether a given operation would succeed without making actual changes to the ruleset\&. The default setting is \fBfalse\fR\&.
+.sp
+The \fBnft_ctx_get_dry_run\fR() function returns the dry\-run setting\(cqs value contained in \fIctx\fR\&.
+.sp
+The \fBnft_ctx_set_dry_run\fR() function sets the dry\-run setting in \fIctx\fR to the value of \fIdry\fR\&.
+.SS "nft_ctx_input_get_flags() and nft_ctx_input_set_flags()"
+.sp
+The flags setting controls the input format\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+enum {
+ NFT_CTX_INPUT_NO_DNS = (1 << 0),
+ NFT_CTX_INPUT_JSON = (1 << 1),
+};
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+NFT_CTX_INPUT_NO_DNS
+.RS 4
+Avoid resolving IP addresses with blocking getaddrinfo()\&. In that case, only plain IP addresses are accepted\&.
+.RE
+.sp
+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\&.
+.sp
+The \fBnft_ctx_input_get_flags\fR() function returns the input flags setting\(cqs value in \fIctx\fR\&.
+.sp
+The \fBnft_ctx_input_set_flags\fR() function sets the input flags setting in \fIctx\fR to the value of \fIval\fR and returns the previous flags\&.
+.SS "nft_ctx_output_get_flags() and nft_ctx_output_set_flags()"
+.sp
+The flags setting controls the output format\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+enum {
+ NFT_CTX_OUTPUT_REVERSEDNS = (1 << 0),
+ NFT_CTX_OUTPUT_SERVICE = (1 << 1),
+ NFT_CTX_OUTPUT_STATELESS = (1 << 2),
+ NFT_CTX_OUTPUT_HANDLE = (1 << 3),
+ NFT_CTX_OUTPUT_JSON = (1 << 4),
+ NFT_CTX_OUTPUT_ECHO = (1 << 5),
+ NFT_CTX_OUTPUT_GUID = (1 << 6),
+ NFT_CTX_OUTPUT_NUMERIC_PROTO = (1 << 7),
+ NFT_CTX_OUTPUT_NUMERIC_PRIO = (1 << 8),
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL = (1 << 9),
+ NFT_CTX_OUTPUT_NUMERIC_TIME = (1 << 10),
+ NFT_CTX_OUTPUT_NUMERIC_ALL = (NFT_CTX_OUTPUT_NUMERIC_PROTO |
+ NFT_CTX_OUTPUT_NUMERIC_PRIO |
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL |
+ NFT_CTX_OUTPUT_NUMERIC_TIME),
+ NFT_CTX_OUTPUT_TERSE = (1 << 11),
+};
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+NFT_CTX_OUTPUT_REVERSEDNS
+.RS 4
+Reverse DNS lookups are performed for IP addresses when printing\&. Note that this may add significant delay to
+\fBlist\fR
+commands depending on DNS resolver speed\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_SERVICE
+.RS 4
+Print port numbers as services as described in the /etc/services file\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_STATELESS
+.RS 4
+If stateless output has been requested, then stateful data is not printed\&. Stateful data refers to those objects that carry run\-time data, e\&.g\&. the
+\fBcounter\fR
+statement holds packet and byte counter values, making it stateful\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_HANDLE
+.RS 4
+Upon insertion into the ruleset, some elements are assigned a unique handle for identification purposes\&. For example, when deleting a table or chain, it may be identified either by name or handle\&. Rules on the other hand must be deleted by handle, because there is no other way to uniquely identify them\&. This flag makes ruleset listings include handle values\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_JSON
+.RS 4
+If enabled at compile\-time, libnftables accepts input in JSON format and is able to print output in JSON format as well\&. See
+\fBlibnftables\-json\fR(5) for a description of the supported schema\&. 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\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_ECHO
+.RS 4
+The echo setting makes libnftables print the changes once they are committed to the kernel, just like a running instance of
+\fBnft monitor\fR
+would\&. Amongst other things, this allows one to retrieve an added rule\(cqs handle atomically\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_GUID
+.RS 4
+Display UID and GID as described in the /etc/passwd and /etc/group files\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_NUMERIC_PROTO
+.RS 4
+Display layer 4 protocol numerically\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_NUMERIC_PRIO
+.RS 4
+Display base chain priority numerically\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_NUMERIC_SYMBOL
+.RS 4
+Display expression datatype as numeric value\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_NUMERIC_TIME
+.RS 4
+Display time, day and hour values in numeric format\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_NUMERIC_ALL
+.RS 4
+Display all numerically\&.
+.RE
+.PP
+NFT_CTX_OUTPUT_TERSE
+.RS 4
+If terse output has been requested, then the contents of sets are not printed\&.
+.RE
+.sp
+The \fBnft_ctx_output_get_flags\fR() function returns the output flags setting\(cqs value in \fIctx\fR\&.
+.sp
+The \fBnft_ctx_output_set_flags\fR() function sets the output flags setting in \fIctx\fR to the value of \fIval\fR\&.
+.SS "nft_ctx_output_get_debug() and nft_ctx_output_set_debug()"
+.sp
+Libnftables supports separate debugging of different parts of its internals\&. To facilitate this, debugging output is controlled via a bit mask\&. The bits are defined as such:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+enum nft_debug_level {
+ NFT_DEBUG_SCANNER = 0x1,
+ NFT_DEBUG_PARSER = 0x2,
+ NFT_DEBUG_EVALUATION = 0x4,
+ NFT_DEBUG_NETLINK = 0x8,
+ NFT_DEBUG_MNL = 0x10,
+ NFT_DEBUG_PROTO_CTX = 0x20,
+ NFT_DEBUG_SEGTREE = 0x40,
+};
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+NFT_DEBUG_SCANNER
+.RS 4
+Print LEX debug output\&.
+.RE
+.PP
+NFT_DEBUG_PARSER
+.RS 4
+Print YACC debug output\&.
+.RE
+.PP
+NFT_DEBUG_EVALUATION
+.RS 4
+Print debug information about evaluation phase\&.
+.RE
+.PP
+NFT_DEBUG_NETLINK
+.RS 4
+Print netlink debug output\&.
+.RE
+.PP
+NFT_DEBUG_MNL
+.RS 4
+Print libmnl debug output\&.
+.RE
+.PP
+NFT_DEBUG_PROTO_CTX
+.RS 4
+Print protocol context debug output\&.
+.RE
+.PP
+NFT_DEBUG_SEGTREE
+.RS 4
+Print segtree (i\&.e\&. interval sets) debug output\&.
+.RE
+.sp
+The \fBnft_ctx_output_get_debug\fR() function returns the debug output setting\(cqs value in \fIctx\fR\&.
+.sp
+The \fBnft_ctx_output_set_debug\fR() function sets the debug output setting in \fIctx\fR to the value of \fImask\fR\&.
+.SS "Controlling library standard and error output"
+.sp
+By default, any output from the library (e\&.g\&., after a \fBlist\fR command) is written to \fIstdout\fR and any error messages are written to \fIstderr\fR\&. To give applications control over them, there are functions to assign custom file pointers as well as having the library buffer what would be written for later retrieval in a static buffer\&. This buffer is guaranteed to be null\-terminated and must not be freed\&. Note that the retrieval functions rewind the buffer position indicator\&. Further library output will probably overwrite the buffer content and potentially render it invalid (due to reallocation)\&.
+.sp
+The \fBnft_ctx_set_output\fR() and \fBnft_ctx_set_error\fR() functions set the output or error file pointer in \fIctx\fR to the value of \fIfp\fR\&. They return the previous value to aid in temporary file pointer overrides\&. On error, these functions return NULL\&. This happens only if \fIfp\fR is NULL or invalid (tested using \fBferror\fR() function)\&.
+.sp
+The \fBnft_ctx_buffer_output\fR() and \fBnft_ctx_buffer_error\fR() functions enable library standard or error output buffering\&. The functions return zero on success, non\-zero otherwise\&. This may happen if the internal call to \fBfopencookie\fR() failed\&.
+.sp
+The \fBnft_ctx_unbuffer_output\fR() and \fBnft_ctx_unbuffer_error\fR() functions disable library standard or error output buffering\&. On failure, the functions return non\-zero which may only happen if buffering was not enabled at the time the function was called\&.
+.sp
+The \fBnft_ctx_get_output_buffer\fR() and \fBnft_ctx_get_error_buffer\fR() functions return a pointer to the buffered output (which may be empty)\&.
+.SS "nft_ctx_add_include_path() and nft_ctx_clear_include_path()"
+.sp
+The \fBinclude\fR 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 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 \fI/etc/\fR)\&.
+.sp
+The \fBnft_ctx_add_include_path\fR() function extends the list of include paths in \fIctx\fR by the one given in \fIpath\fR\&. The function returns zero on success or non\-zero if memory allocation failed\&.
+.sp
+The \fBnft_ctx_clear_include_paths\fR() function removes all include paths, even the built\-in default one\&.
+.SS "nft_ctx_add_var() and nft_ctx_clear_vars()"
+.sp
+The \fBdefine\fR command in nftables ruleset allows one to define variables\&.
+.sp
+The \fBnft_ctx_add_var\fR() function extends the list of variables in \fIctx\fR\&. The variable must be given in the format \fIkey=value\fR\&. The function returns zero on success or non\-zero if the variable is malformed\&.
+.sp
+The \fBnft_ctx_clear_vars\fR() function removes all variables\&.
+.SS "nft_run_cmd_from_buffer() and nft_run_cmd_from_filename()"
+.sp
+These functions perform the actual work of parsing user input into nftables commands and executing them\&.
+.sp
+The \fBnft_run_cmd_from_buffer\fR() function passes the command(s) contained in \fIbuf\fR (which must be null\-terminated) to the library, respecting settings and state in \fInft\fR\&.
+.sp
+The \fBnft_run_cmd_from_filename\fR() function passes the content of \fIfilename\fR to the library, respecting settings and state in \fInft\fR\&.
+.sp
+Both functions return zero on success\&. A non\-zero return code indicates an error while parsing or executing the command\&. This event should be accompanied by an error message written to library error output\&.
+.SH "EXAMPLE"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+#include <stdio\&.h>
+#include <string\&.h>
+#include <nftables/libnftables\&.h>
+
+int main(void)
+{
+ char *list_cmd = "list ruleset";
+ struct nft_ctx *nft;
+ const char *output, *p;
+ char buf[256];
+ int rc = 0;
+
+ nft = nft_ctx_new(NFT_CTX_DEFAULT);
+ if (!nft)
+ return 1;
+
+ while (1) {
+ if (nft_ctx_buffer_output(nft) ||
+ nft_run_cmd_from_buffer(nft, list_cmd)) {
+ rc = 1;
+ break;
+ }
+ output = nft_ctx_get_output_buffer(nft);
+ if (strlen(output)) {
+ printf("\enThis is the current ruleset:\en| ");
+ for (p = output; *(p + 1); p++) {
+ if (*p == \*(Aq\en\*(Aq)
+ printf("\en| ");
+ else
+ putchar(*p);
+ }
+ putchar(\*(Aq\en\*(Aq);
+ } else {
+ printf("\enCurrent ruleset is empty\&.\en");
+ }
+ nft_ctx_unbuffer_output(nft);
+
+ printf("\enEnter command (\*(Aqq\*(Aq to quit): ");
+ fflush(stdout);
+ fgets(buf, 256, stdin);
+ if (strlen(buf))
+ buf[strlen(buf) \- 1] = \*(Aq\e0\*(Aq;
+
+ if (buf[0] == \*(Aqq\*(Aq && buf[1] == \*(Aq\e0\*(Aq)
+ break;
+
+ if (nft_run_cmd_from_buffer(nft, buf)) {
+ rc = 1;
+ break;
+ }
+ }
+
+ nft_ctx_free(nft);
+ return rc;
+}
+.fi
+.if n \{\
+.RE
+.\}
+.SH "SEE ALSO"
+.sp
+\fBlibnftables\-json\fR(5), \fBnft\fR(8)
+.SH "AUTHOR"
+.PP
+\fBPhil Sutter\fR <\&phil@nwl\&.cc\&>
+.RS 4
+Author.
+.RE
diff --git a/doc/libnftables.adoc b/doc/libnftables.adoc
new file mode 100644
index 0000000..2cf78d7
--- /dev/null
+++ b/doc/libnftables.adoc
@@ -0,0 +1,319 @@
+libnftables(3)
+==============
+Phil Sutter <phil@nwl.cc>
+:doctype: manpage
+:compat-mode!:
+
+== NAME
+libnftables - nftables frontend library
+
+== SYNOPSIS
+[verse]
+____
+*#include <nftables/libnftables.h>
+
+struct nft_ctx *nft_ctx_new(uint32_t* 'flags'*);
+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'*);
+
+unsigned int nft_ctx_output_get_debug(struct nft_ctx* '\*ctx'*);
+void nft_ctx_output_set_debug(struct nft_ctx* '\*ctx'*, unsigned int* 'mask'*);
+
+FILE *nft_ctx_set_output(struct nft_ctx* '\*ctx'*, FILE* '\*fp'*);
+int nft_ctx_buffer_output(struct nft_ctx* '\*ctx'*);
+int nft_ctx_unbuffer_output(struct nft_ctx* '\*ctx'*);
+const char *nft_ctx_get_output_buffer(struct nft_ctx* '\*ctx'*);
+
+FILE *nft_ctx_set_error(struct nft_ctx* '\*ctx'*, FILE* '\*fp'*);
+int nft_ctx_buffer_error(struct nft_ctx* '\*ctx'*);
+int nft_ctx_unbuffer_error(struct nft_ctx* '\*ctx'*);
+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'*);*
+
+Link with '-lnftables'.
+____
+
+== DESCRIPTION
+This library was designed with nftables integration into applications in mind.
+Its API is therefore kept as simple as possible, which somewhat limits its flexibility.
+Due to support for JSON markup of input and output though, convenience in constructing and parsing of input and output data may be achieved by using a third-party library such as *libjansson*.
+
+At the very basic level, one has to allocate a new object of type *struct nft_ctx* using *nft_ctx_new*() function, then pass commands via *nft_run_cmd_from_buffer*() or *nft_run_cmd_from_filename*() functions.
+By default, any output is written to *stdout* (or *stderr* for error messages).
+These file pointers may be changed using *nft_ctx_set_output*() and *nft_ctx_set_error*() functions.
+On top of that, it is possible to have any output buffered by the library for later retrieval as a static buffer.
+See *nft_ctx_buffer_output*() and *nft_ctx_buffer_error*() functions for details.
+
+=== nft_ctx_new() and nft_ctx_free()
+These functions aid in nft context management.
+In order to make use of the library, at least one context object has to be allocated.
+The context holds temporary data such as caches, library configuration and (if enabled) output and error buffers.
+
+The *nft_ctx_new*() function allocates and returns a new context object.
+The parameter 'flags' is unused at this point and should be set to zero.
+For convenience, the macro *NFT_CTX_DEFAULT* is defined to that value.
+
+The *nft_ctx_free*() function frees the context object pointed to by 'ctx', including any caches or buffers it may hold.
+
+=== 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 one to check whether a given operation would succeed without making actual changes to the ruleset.
+The default setting is *false*.
+
+The *nft_ctx_get_dry_run*() function returns the dry-run setting's value contained in 'ctx'.
+
+The *nft_ctx_set_dry_run*() function sets the dry-run setting in 'ctx' to the value of 'dry'.
+
+=== nft_ctx_input_get_flags() and nft_ctx_input_set_flags()
+The flags setting controls the input format.
+
+----
+enum {
+ NFT_CTX_INPUT_NO_DNS = (1 << 0),
+ NFT_CTX_INPUT_JSON = (1 << 1),
+};
+----
+
+NFT_CTX_INPUT_NO_DNS::
+ Avoid resolving IP addresses with blocking getaddrinfo(). In that case,
+ only plain IP addresses are accepted.
+
+NFT_CTX_INPUT_JSON:
+ When parsing the input, first try to interpret the input as JSON before
+ falling back to the nftables format. This behavior is implied when setting
+ the NFT_CTX_OUTPUT_JSON flag.
+
+The *nft_ctx_input_get_flags*() function returns the input flags setting's value in 'ctx'.
+
+The *nft_ctx_input_set_flags*() function sets the input flags setting in 'ctx' to the value of 'val'
+and returns the previous flags.
+
+=== nft_ctx_output_get_flags() and nft_ctx_output_set_flags()
+The flags setting controls the output format.
+
+----
+enum {
+ NFT_CTX_OUTPUT_REVERSEDNS = (1 << 0),
+ NFT_CTX_OUTPUT_SERVICE = (1 << 1),
+ NFT_CTX_OUTPUT_STATELESS = (1 << 2),
+ NFT_CTX_OUTPUT_HANDLE = (1 << 3),
+ NFT_CTX_OUTPUT_JSON = (1 << 4),
+ NFT_CTX_OUTPUT_ECHO = (1 << 5),
+ NFT_CTX_OUTPUT_GUID = (1 << 6),
+ NFT_CTX_OUTPUT_NUMERIC_PROTO = (1 << 7),
+ NFT_CTX_OUTPUT_NUMERIC_PRIO = (1 << 8),
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL = (1 << 9),
+ NFT_CTX_OUTPUT_NUMERIC_TIME = (1 << 10),
+ NFT_CTX_OUTPUT_NUMERIC_ALL = (NFT_CTX_OUTPUT_NUMERIC_PROTO |
+ NFT_CTX_OUTPUT_NUMERIC_PRIO |
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL |
+ NFT_CTX_OUTPUT_NUMERIC_TIME),
+ NFT_CTX_OUTPUT_TERSE = (1 << 11),
+};
+----
+
+NFT_CTX_OUTPUT_REVERSEDNS::
+ Reverse DNS lookups are performed for IP addresses when printing.
+ Note that this may add significant delay to *list* commands depending on DNS resolver speed.
+NFT_CTX_OUTPUT_SERVICE::
+ Print port numbers as services as described in the /etc/services file.
+NFT_CTX_OUTPUT_STATELESS::
+ If stateless output has been requested, then stateful data is not printed.
+ Stateful data refers to those objects that carry run-time data, e.g. the *counter* statement holds packet and byte counter values, making it stateful.
+NFT_CTX_OUTPUT_HANDLE::
+ Upon insertion into the ruleset, some elements are assigned a unique handle for identification purposes.
+ For example, when deleting a table or chain, it may be identified either by name or handle.
+ Rules on the other hand must be deleted by handle, because there is no other way to uniquely identify them.
+ This flag makes ruleset listings include handle values.
+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 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 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::
+ Display layer 4 protocol numerically.
+NFT_CTX_OUTPUT_NUMERIC_PRIO::
+ Display base chain priority numerically.
+NFT_CTX_OUTPUT_NUMERIC_SYMBOL::
+ Display expression datatype as numeric value.
+NFT_CTX_OUTPUT_NUMERIC_TIME::
+ Display time, day and hour values in numeric format.
+NFT_CTX_OUTPUT_NUMERIC_ALL::
+ Display all numerically.
+NFT_CTX_OUTPUT_TERSE::
+ If terse output has been requested, then the contents of sets are not printed.
+
+The *nft_ctx_output_get_flags*() function returns the output flags setting's value in 'ctx'.
+
+The *nft_ctx_output_set_flags*() function sets the output flags setting in 'ctx' to the value of 'val'.
+
+=== nft_ctx_output_get_debug() and nft_ctx_output_set_debug()
+Libnftables supports separate debugging of different parts of its internals.
+To facilitate this, debugging output is controlled via a bit mask.
+The bits are defined as such:
+
+----
+enum nft_debug_level {
+ NFT_DEBUG_SCANNER = 0x1,
+ NFT_DEBUG_PARSER = 0x2,
+ NFT_DEBUG_EVALUATION = 0x4,
+ NFT_DEBUG_NETLINK = 0x8,
+ NFT_DEBUG_MNL = 0x10,
+ NFT_DEBUG_PROTO_CTX = 0x20,
+ NFT_DEBUG_SEGTREE = 0x40,
+};
+----
+
+NFT_DEBUG_SCANNER::
+ Print LEX debug output.
+NFT_DEBUG_PARSER::
+ Print YACC debug output.
+NFT_DEBUG_EVALUATION::
+ Print debug information about evaluation phase.
+NFT_DEBUG_NETLINK::
+ Print netlink debug output.
+NFT_DEBUG_MNL::
+ Print libmnl debug output.
+NFT_DEBUG_PROTO_CTX::
+ Print protocol context debug output.
+NFT_DEBUG_SEGTREE::
+ Print segtree (i.e. interval sets) debug output.
+
+The *nft_ctx_output_get_debug*() function returns the debug output setting's value in 'ctx'.
+
+The *nft_ctx_output_set_debug*() function sets the debug output setting in 'ctx' to the value of 'mask'.
+
+=== Controlling library standard and error output
+By default, any output from the library (e.g., after a *list* command) is written to 'stdout' and any error messages are written to 'stderr'.
+To give applications control over them, there are functions to assign custom file pointers as well as having the library buffer what would be written for later retrieval in a static buffer.
+This buffer is guaranteed to be null-terminated and must not be freed.
+Note that the retrieval functions rewind the buffer position indicator.
+Further library output will probably overwrite the buffer content and potentially render it invalid (due to reallocation).
+
+The *nft_ctx_set_output*() and *nft_ctx_set_error*() functions set the output or error file pointer in 'ctx' to the value of 'fp'.
+They return the previous value to aid in temporary file pointer overrides.
+On error, these functions return NULL.
+This happens only if 'fp' is NULL or invalid (tested using *ferror*() function).
+
+The *nft_ctx_buffer_output*() and *nft_ctx_buffer_error*() functions enable library standard or error output buffering.
+The functions return zero on success, non-zero otherwise.
+This may happen if the internal call to *fopencookie*() failed.
+
+The *nft_ctx_unbuffer_output*() and *nft_ctx_unbuffer_error*() functions disable library standard or error output buffering.
+On failure, the functions return non-zero which may only happen if buffering was not enabled at the time the function was called.
+
+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 one to outsource parts of the ruleset into a different file.
+The include path defines where these files are searched for.
+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'.
+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.
+
+The *nft_run_cmd_from_buffer*() function passes the command(s) contained in 'buf' (which must be null-terminated) to the library, respecting settings and state in 'nft'.
+
+The *nft_run_cmd_from_filename*() function passes the content of 'filename' to the library, respecting settings and state in 'nft'.
+
+Both functions return zero on success.
+A non-zero return code indicates an error while parsing or executing the command.
+This event should be accompanied by an error message written to library error output.
+
+== EXAMPLE
+----
+#include <stdio.h>
+#include <string.h>
+#include <nftables/libnftables.h>
+
+int main(void)
+{
+ char *list_cmd = "list ruleset";
+ struct nft_ctx *nft;
+ const char *output, *p;
+ char buf[256];
+ int rc = 0;
+
+ nft = nft_ctx_new(NFT_CTX_DEFAULT);
+ if (!nft)
+ return 1;
+
+ while (1) {
+ if (nft_ctx_buffer_output(nft) ||
+ nft_run_cmd_from_buffer(nft, list_cmd)) {
+ rc = 1;
+ break;
+ }
+ output = nft_ctx_get_output_buffer(nft);
+ if (strlen(output)) {
+ printf("\nThis is the current ruleset:\n| ");
+ for (p = output; *(p + 1); p++) {
+ if (*p == '\n')
+ printf("\n| ");
+ else
+ putchar(*p);
+ }
+ putchar('\n');
+ } else {
+ printf("\nCurrent ruleset is empty.\n");
+ }
+ nft_ctx_unbuffer_output(nft);
+
+ printf("\nEnter command ('q' to quit): ");
+ fflush(stdout);
+ fgets(buf, 256, stdin);
+ if (strlen(buf))
+ buf[strlen(buf) - 1] = '\0';
+
+ if (buf[0] == 'q' && buf[1] == '\0')
+ break;
+
+ if (nft_run_cmd_from_buffer(nft, buf)) {
+ rc = 1;
+ break;
+ }
+ }
+
+ nft_ctx_free(nft);
+ return rc;
+}
+----
+
+== SEE ALSO
+*libnftables-json*(5), *nft*(8)
diff --git a/doc/nft.8 b/doc/nft.8
new file mode 100644
index 0000000..4e914fb
--- /dev/null
+++ b/doc/nft.8
@@ -0,0 +1,9717 @@
+'\" t
+.\" Title: nft
+.\" Author: [see the "AUTHORS" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/11/2023
+.\" Manual: \ \&
+.\" Source: \ \&
+.\" Language: English
+.\"
+.TH "NFT" "8" "10/11/2023" "\ \&" "\ \&"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nft \- Administration tool of the nftables framework for packet filtering and classification
+.SH "SYNOPSIS"
+.sp
+.nf
+\fBnft\fR [ \fB\-nNscaeSupyjtT\fR ] [ \fB\-I\fR \fIdirectory\fR ] [ \fB\-f\fR \fIfilename\fR | \fB\-i\fR | \fIcmd\fR \&...]
+\fBnft\fR \fB\-h\fR
+\fBnft\fR \fB\-v\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+nft is the command line tool used to set up, maintain and inspect packet filtering and classification rules in the Linux kernel, in the nftables framework\&. The Linux kernel subsystem is known as nf_tables, and \(oqnf\(cq stands for Netfilter\&.
+.SH "OPTIONS"
+.sp
+The command accepts several different options which are documented here in groups for better understanding of their meaning\&. You can get information about options by running \fBnft \-\-help\fR\&.
+.PP
+\fBGeneral options:\fR
+.PP
+\fB\-h\fR, \fB\-\-help\fR
+.RS 4
+Show help message and all options\&.
+.RE
+.PP
+\fB\-v\fR, \fB\-\-version\fR
+.RS 4
+Show version\&.
+.RE
+.PP
+\fB\-V\fR
+.RS 4
+Show long version information, including compile\-time configuration\&.
+.RE
+.PP
+\fBRuleset input handling options that specify to how to load rulesets:\fR
+.PP
+\fB\-f\fR, \fB\-\-file \fR\fB\fIfilename\fR\fR
+.RS 4
+Read input from
+\fIfilename\fR\&. If
+\fIfilename\fR
+is \-, read from stdin\&.
+.RE
+.PP
+\fB\-D\fR, \fB\-\-define \fR\fB\fIname=value\fR\fR
+.RS 4
+Define a variable\&. You can only combine this option with
+\fI\-f\fR\&.
+.RE
+.PP
+\fB\-i\fR, \fB\-\-interactive\fR
+.RS 4
+Read input from an interactive readline CLI\&. You can use quit to exit, or use the EOF marker, normally this is CTRL\-D\&.
+.RE
+.PP
+\fB\-I\fR, \fB\-\-includepath directory\fR
+.RS 4
+Add the directory
+\fIdirectory\fR
+to the list of directories to be searched for included files\&. This option may be specified multiple times\&.
+.RE
+.PP
+\fB\-c\fR, \fB\-\-check\fR
+.RS 4
+Check commands validity without actually applying the changes\&.
+.RE
+.PP
+\fB\-o\fR, \fB\-\-optimize\fR
+.RS 4
+Optimize your ruleset\&. You can combine this option with
+\fI\-c\fR
+to inspect the proposed optimizations\&.
+.RE
+.PP
+\fBRuleset list output formatting that modify the output of the list ruleset command:\fR
+.PP
+\fB\-a\fR, \fB\-\-handle\fR
+.RS 4
+Show object handles in output\&.
+.RE
+.PP
+\fB\-s\fR, \fB\-\-stateless\fR
+.RS 4
+Omit stateful information of rules and stateful objects\&.
+.RE
+.PP
+\fB\-t\fR, \fB\-\-terse\fR
+.RS 4
+Omit contents of sets from output\&.
+.RE
+.PP
+\fB\-S\fR, \fB\-\-service\fR
+.RS 4
+Translate ports to service names as defined by /etc/services\&.
+.RE
+.PP
+\fB\-N\fR, \fB\-\-reversedns\fR
+.RS 4
+Translate IP address to names via reverse DNS lookup\&. This may slow down your listing since it generates network traffic\&.
+.RE
+.PP
+\fB\-u\fR, \fB\-\-guid\fR
+.RS 4
+Translate numeric UID/GID to names as defined by /etc/passwd and /etc/group\&.
+.RE
+.PP
+\fB\-n\fR, \fB\-\-numeric\fR
+.RS 4
+Print fully numerical output\&.
+.RE
+.PP
+\fB\-y\fR, \fB\-\-numeric\-priority\fR
+.RS 4
+Display base chain priority numerically\&.
+.RE
+.PP
+\fB\-p\fR, \fB\-\-numeric\-protocol\fR
+.RS 4
+Display layer 4 protocol numerically\&.
+.RE
+.PP
+\fB\-T\fR, \fB\-\-numeric\-time\fR
+.RS 4
+Show time, day and hour values in numeric format\&.
+.RE
+.PP
+\fBCommand output formatting:\fR
+.PP
+\fB\-e\fR, \fB\-\-echo\fR
+.RS 4
+When inserting items into the ruleset using
+\fBadd\fR,
+\fBinsert\fR
+or
+\fBreplace\fR
+commands, print notifications just like
+\fBnft monitor\fR\&.
+.RE
+.PP
+\fB\-j\fR, \fB\-\-json\fR
+.RS 4
+Format output in JSON\&. See libnftables\-json(5) for a schema description\&.
+.RE
+.PP
+\fB\-d\fR, \fB\-\-debug\fR \fIlevel\fR
+.RS 4
+Enable debugging output\&. The debug level can be any of
+\fBscanner\fR,
+\fBparser\fR,
+\fBeval\fR,
+\fBnetlink\fR,
+\fBmnl\fR,
+\fBproto\-ctx\fR,
+\fBsegtree\fR,
+\fBall\fR\&. You can combine more than one by separating by the
+\fI,\fR
+symbol, for example
+\fI\-d eval,mnl\fR\&.
+.RE
+.SH "INPUT FILE FORMATS"
+.SS "LEXICAL CONVENTIONS"
+.sp
+Input is parsed line\-wise\&. When the last character of a line, just before the newline character, is a non\-quoted backslash (\e), the next line is treated as a continuation\&. Multiple commands on the same line can be separated using a semicolon (;)\&.
+.sp
+A hash sign (#) begins a comment\&. All following characters on the same line are ignored\&.
+.sp
+Identifiers begin with an alphabetic character (a\-z,A\-Z), followed by zero or more alphanumeric characters (a\-z,A\-Z,0\-9) and the characters slash (/), backslash (\e), underscore (_) and dot (\&.)\&. Identifiers using different characters or clashing with a keyword need to be enclosed in double quotes (")\&.
+.SS "INCLUDE FILES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBinclude\fR \fIfilename\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Other files can be included by using the \fBinclude\fR statement\&. The directories to be searched for include files can be specified using the \fB\-I\fR/\fB\-\-includepath\fR option\&. You can override this behaviour either by prepending \(oq\&./\(cq to your path to force inclusion of files located in the current working directory (i\&.e\&. relative path) or / for file location expressed as an absolute path\&.
+.sp
+If \fB\-I\fR/\fB\-\-includepath\fR is not specified, then nft relies on the default directory that is specified at compile time\&. You can retrieve this default directory via the \fB\-h\fR/\fB\-\-help\fR option\&.
+.sp
+Include statements support the usual shell wildcard symbols (\fB,?,[])\&. Having no matches for an include statement is not an error, if wildcard symbols are used in the include statement\&. This allows having potentially empty include directories for statements like \fR\fB\fBinclude "/etc/firewall/rules/\fR\fR\fB"\fR\&. The wildcard matches are loaded in alphabetical order\&. Files beginning with dot (\&.) are not matched by include statements\&.
+.SS "SYMBOLIC VARIABLES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBdefine\fR \fIvariable\fR \fB=\fR \fIexpr\fR
+\fBundefine\fR \fIvariable\fR
+\fBredefine\fR \fIvariable\fR \fB=\fR \fIexpr\fR
+\fB$variable\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Symbolic variables can be defined using the \fBdefine\fR statement\&. Variable references are expressions and can be used to initialize other variables\&. The scope of a definition is the current block and all blocks contained within\&. Symbolic variables can be undefined using the \fBundefine\fR statement, and modified using the \fBredefine\fR statement\&.
+.PP
+\fBUsing symbolic variables\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+define int_if1 = eth0
+define int_if2 = eth1
+define int_ifs = { $int_if1, $int_if2 }
+redefine int_if2 = wlan0
+undefine int_if2
+
+filter input iif $int_ifs accept
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "ADDRESS FAMILIES"
+.sp
+Address families determine the type of packets which are processed\&. For each address family, the kernel contains so called hooks at specific stages of the packet processing paths, which invoke nftables if rules for these hooks exist\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBip\fR
+T}:T{
+.sp
+IPv4 address family\&.
+T}
+T{
+.sp
+\fBip6\fR
+T}:T{
+.sp
+IPv6 address family\&.
+T}
+T{
+.sp
+\fBinet\fR
+T}:T{
+.sp
+Internet (IPv4/IPv6) address family\&.
+T}
+T{
+.sp
+\fBarp\fR
+T}:T{
+.sp
+ARP address family, handling IPv4 ARP packets\&.
+T}
+T{
+.sp
+\fBbridge\fR
+T}:T{
+.sp
+Bridge address family, handling packets which traverse a bridge device\&.
+T}
+T{
+.sp
+\fBnetdev\fR
+T}:T{
+.sp
+Netdev address family, handling packets on ingress and egress\&.
+T}
+.TE
+.sp 1
+.sp
+All nftables objects exist in address family specific namespaces, therefore all identifiers include an address family\&. If an identifier is specified without an address family, the \fBip\fR family is used by default\&.
+.SS "IPV4/IPV6/INET ADDRESS FAMILIES"
+.sp
+The IPv4/IPv6/Inet address families handle IPv4, IPv6 or both types of packets\&. They contain five hooks at different packet processing stages in the network stack\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&1.\ \&IPv4/IPv6/Inet address family hooks
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Hook
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+prerouting
+T}:T{
+.sp
+All packets entering the system are processed by the prerouting hook\&. It is invoked before the routing process and is used for early filtering or changing packet attributes that affect routing\&.
+T}
+T{
+.sp
+input
+T}:T{
+.sp
+Packets delivered to the local system are processed by the input hook\&.
+T}
+T{
+.sp
+forward
+T}:T{
+.sp
+Packets forwarded to a different host are processed by the forward hook\&.
+T}
+T{
+.sp
+output
+T}:T{
+.sp
+Packets sent by local processes are processed by the output hook\&.
+T}
+T{
+.sp
+postrouting
+T}:T{
+.sp
+All packets leaving the system are processed by the postrouting hook\&.
+T}
+T{
+.sp
+ingress
+T}:T{
+.sp
+All packets entering the system are processed by this hook\&. It is invoked before layer 3 protocol handlers, hence before the prerouting hook, and it can be used for filtering and policing\&. Ingress is only available for Inet family (since Linux kernel 5\&.10)\&.
+T}
+.TE
+.sp 1
+.SS "ARP ADDRESS FAMILY"
+.sp
+The ARP address family handles ARP packets received and sent by the system\&. It is commonly used to mangle ARP packets for clustering\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&2.\ \&ARP address family hooks
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Hook
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+input
+T}:T{
+.sp
+Packets delivered to the local system are processed by the input hook\&.
+T}
+T{
+.sp
+output
+T}:T{
+.sp
+Packets send by the local system are processed by the output hook\&.
+T}
+.TE
+.sp 1
+.SS "BRIDGE ADDRESS FAMILY"
+.sp
+The bridge address family handles Ethernet packets traversing bridge devices\&.
+.sp
+The list of supported hooks is identical to IPv4/IPv6/Inet address families above\&.
+.SS "NETDEV ADDRESS FAMILY"
+.sp
+The Netdev address family handles packets from the device ingress and egress path\&. This family allows you to filter packets of any ethertype such as ARP, VLAN 802\&.1q, VLAN 802\&.1ad (Q\-in\-Q) as well as IPv4 and IPv6 packets\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&3.\ \&Netdev address family hooks
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Hook
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+ingress
+T}:T{
+.sp
+All packets entering the system are processed by this hook\&. It is invoked after the network taps (ie\&. \fBtcpdump\fR), right after \fBtc\fR ingress and before layer 3 protocol handlers, it can be used for early filtering and policing\&.
+T}
+T{
+.sp
+egress
+T}:T{
+.sp
+All packets leaving the system are processed by this hook\&. It is invoked after layer 3 protocol handlers and before \fBtc\fR egress\&. It can be used for late filtering and policing\&.
+T}
+.TE
+.sp 1
+.sp
+Tunneled packets (such as \fBvxlan\fR) are processed by netdev family hooks both in decapsulated and encapsulated (tunneled) form\&. So a packet can be filtered on the overlay network as well as on the underlying network\&.
+.sp
+Note that the order of netfilter and \fBtc\fR is mirrored on ingress versus egress\&. This ensures symmetry for NAT and other packet mangling\&.
+.sp
+Ingress packets which are redirected out some other interface are only processed by netfilter on egress if they have passed through netfilter ingress processing before\&. Thus, ingress packets which are redirected by \fBtc\fR are not subjected to netfilter\&. But they are if they are redirected by \fBnetfilter\fR on ingress\&. Conceptually, tc and netfilter can be thought of as layers, with netfilter layered above tc: If the packet hasn\(cqt been passed up from the tc layer to the netfilter layer, it\(cqs not subjected to netfilter on egress\&.
+.SH "RULESET"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBlist\fR | \fBflush\fR} \fBruleset\fR [\fIfamily\fR]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The \fBruleset\fR keyword is used to identify the whole set of tables, chains, etc\&. currently in place in kernel\&. The following \fBruleset\fR commands exist:
+.TS
+tab(:);
+lt lt
+lt lt.
+T{
+.sp
+\fBlist\fR
+T}:T{
+.sp
+Print the ruleset in human\-readable format\&.
+T}
+T{
+.sp
+\fBflush\fR
+T}:T{
+.sp
+Clear the whole ruleset\&. Note that, unlike iptables, this will remove all tables and whatever they contain, effectively leading to an empty ruleset \- no packet filtering will happen anymore, so the kernel accepts any valid packet it receives\&.
+T}
+.TE
+.sp 1
+.sp
+It is possible to limit \fBlist\fR and \fBflush\fR to a specific address family only\&. For a list of valid family names, see the section called \(lqADDRESS FAMILIES\(rq above\&.
+.sp
+By design, \fBlist ruleset\fR command output may be used as input to \fBnft \-f\fR\&. Effectively, this is the nft\-equivalent of \fBiptables\-save\fR and \fBiptables\-restore\fR\&.
+.SH "TABLES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBadd\fR | \fBcreate\fR} \fBtable\fR [\fIfamily\fR] \fItable\fR [ {\fBcomment\fR \fIcomment\fR \fB;\fR\fI} \fR\fI\fB{ flags\fR\fR\fI \*(Aqflags\fR \fB; }\fR]
+{\fBdelete\fR | \fBdestroy\fR | \fBlist\fR | \fBflush\fR} \fBtable\fR [\fIfamily\fR] \fItable\fR
+\fBlist tables\fR [\fIfamily\fR]
+\fBdelete table\fR [\fIfamily\fR] \fBhandle\fR \fIhandle\fR
+\fBdestroy table\fR [\fIfamily\fR] \fBhandle\fR \fIhandle\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 \fBip\fR, \fBip6\fR, \fBinet\fR, \fBarp\fR, \fBbridge\fR, \fBnetdev\fR\&. The \fBinet\fR address family is a dummy family which is used to create hybrid IPv4/IPv6 tables\&. The \fBmeta expression nfproto\fR keyword can be used to test which family (ipv4 or ipv6) context the packet is being processed in\&. When no address family is specified, \fBip\fR is used by default\&. The only difference between add and create is that the former will not return an error if the specified table already exists while \fBcreate\fR will return an error\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&4.\ \&Table flags
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Flag
+T}:T{
+Description
+T}
+.T&
+lt lt.
+T{
+.sp
+dormant
+T}:T{
+.sp
+table is not evaluated any more (base chains are unregistered)\&.
+T}
+.TE
+.sp 1
+.PP
+\fBAdd, change, delete a table\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# start nft in interactive mode
+nft \-\-interactive
+
+# create a new table\&.
+create table inet mytable
+
+# add a new base chain: get input packets
+add chain inet mytable myin { type filter hook input priority filter; }
+
+# add a single counter to the chain
+add rule inet mytable myin counter
+
+# disable the table temporarily \-\- rules are not evaluated anymore
+add table inet mytable { flags dormant; }
+
+# make table active again:
+add table inet mytable
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBadd\fR
+T}:T{
+.sp
+Add a new table for the given family with the given name\&.
+T}
+T{
+.sp
+\fBdelete\fR
+T}:T{
+.sp
+Delete the specified table\&.
+T}
+T{
+.sp
+\fBdestroy\fR
+T}:T{
+.sp
+Delete the specified table, it does not fail if it does not exist\&.
+T}
+T{
+.sp
+\fBlist\fR
+T}:T{
+.sp
+List all chains and rules of the specified table\&.
+T}
+T{
+.sp
+\fBflush\fR
+T}:T{
+.sp
+Flush all chains and rules of the specified table\&.
+T}
+.TE
+.sp 1
+.SH "CHAINS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBadd\fR | \fBcreate\fR} \fBchain\fR [\fIfamily\fR] \fItable\fR \fIchain\fR [\fB{ type\fR \fItype\fR \fBhook\fR \fIhook\fR [\fBdevice\fR \fIdevice\fR] \fBpriority\fR \fIpriority\fR \fB;\fR [\fBpolicy\fR \fIpolicy\fR \fB;\fR] [\fBcomment\fR \fIcomment\fR \fB;\fR\fI] \fR\fI\fB}\fR\fR\fI]
+{\fR\fI\fBdelete\fR\fR\fI | \fR\fI\fBdestroy\fR\fR\fI | \fR\fI\fBlist\fR\fR\fI | \fR\fI\fBflush\fR\fR\fI} \fR\fI\fBchain\fR\fR\fI [\*(Aqfamily\fR] \fItable\fR \fIchain\fR
+\fBlist chains\fR [\fIfamily\fR]
+\fBdelete chain\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBdestroy chain\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBrename chain\fR [\fIfamily\fR] \fItable\fR \fIchain\fR \fInewname\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Chains are containers for rules\&. They exist in two kinds, base chains and regular chains\&. A base chain is an entry point for packets from the networking stack, a regular chain may be used as jump target and is used for better rule organization\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBadd\fR
+T}:T{
+.sp
+Add a new chain in the specified table\&. When a hook and priority value are specified, the chain is created as a base chain and hooked up to the networking stack\&.
+T}
+T{
+.sp
+\fBcreate\fR
+T}:T{
+.sp
+Similar to the \fBadd\fR command, but returns an error if the chain already exists\&.
+T}
+T{
+.sp
+\fBdelete\fR
+T}:T{
+.sp
+Delete the specified chain\&. The chain must not contain any rules or be used as jump target\&.
+T}
+T{
+.sp
+\fBdestroy\fR
+T}:T{
+.sp
+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\&.
+T}
+T{
+.sp
+\fBrename\fR
+T}:T{
+.sp
+Rename the specified chain\&.
+T}
+T{
+.sp
+\fBlist\fR
+T}:T{
+.sp
+List all rules of the specified chain\&.
+T}
+T{
+.sp
+\fBflush\fR
+T}:T{
+.sp
+Flush all rules of the specified chain\&.
+T}
+.TE
+.sp 1
+.sp
+For base chains, \fBtype\fR, \fBhook\fR and \fBpriority\fR parameters are mandatory\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&5.\ \&Supported chain types
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Type
+T}:T{
+Families
+T}:T{
+Hooks
+T}:T{
+Description
+T}
+.T&
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt.
+T{
+.sp
+filter
+T}:T{
+.sp
+all
+T}:T{
+.sp
+all
+T}:T{
+.sp
+Standard chain type to use in doubt\&.
+T}
+T{
+.sp
+nat
+T}:T{
+.sp
+ip, ip6, inet
+T}:T{
+.sp
+prerouting, input, output, postrouting
+T}:T{
+.sp
+Chains of this type perform Native Address Translation based on conntrack entries\&. Only the first packet of a connection actually traverses this chain \- its rules usually define details of the created conntrack entry (NAT statements for instance)\&.
+T}
+T{
+.sp
+route
+T}:T{
+.sp
+ip, ip6
+T}:T{
+.sp
+output
+T}:T{
+.sp
+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 one to e\&.g\&. implement policy routing selectors in nftables\&.
+T}
+.TE
+.sp 1
+.sp
+Apart from the special cases illustrated above (e\&.g\&. \fBnat\fR type not supporting \fBforward\fR hook or \fBroute\fR type only supporting \fBoutput\fR hook), there are three further quirks worth noticing:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The netdev family supports merely two combinations, namely
+\fBfilter\fR
+type with
+\fBingress\fR
+hook and
+\fBfilter\fR
+type with
+\fBegress\fR
+hook\&. Base chains in this family also require the
+\fBdevice\fR
+parameter to be present since they exist per interface only\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The arp family supports only the
+\fBinput\fR
+and
+\fBoutput\fR
+hooks, both in chains of type
+\fBfilter\fR\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The inet family also supports the
+\fBingress\fR
+hook (since Linux kernel 5\&.10), to filter IPv4 and IPv6 packet at the same location as the netdev
+\fBingress\fR
+hook\&. This inet hook allows you to share sets and maps between the usual
+\fBprerouting\fR,
+\fBinput\fR,
+\fBforward\fR,
+\fBoutput\fR,
+\fBpostrouting\fR
+and this
+\fBingress\fR
+hook\&.
+.RE
+.sp
+The \fBdevice\fR 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 \fBdevice\fR parameter\&.
+.sp
+The \fBpriority\fR parameter accepts a signed integer value or a standard priority name which specifies the order in which chains with the same \fBhook\fR value are traversed\&. The ordering is ascending, i\&.e\&. lower priority values have precedence over higher ones\&.
+.sp
+With \fBnat\fR type chains, there\(cqs a lower excluding limit of \-200 for \fBpriority\fR values, because conntrack hooks at this priority and NAT requires it\&.
+.sp
+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\&.
+.sp
+These names and values are defined and made available based on what priorities are used by xtables when registering their default chains\&.
+.sp
+Most of the families use the same values, but bridge uses different ones from the others\&. See the following tables that describe the values and compatibility\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&6.\ \&Standard priority names, family and hook compatibility matrix
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Value
+T}:T{
+Families
+T}:T{
+Hooks
+T}
+.T&
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt.
+T{
+.sp
+raw
+T}:T{
+.sp
+\-300
+T}:T{
+.sp
+ip, ip6, inet
+T}:T{
+.sp
+all
+T}
+T{
+.sp
+mangle
+T}:T{
+.sp
+\-150
+T}:T{
+.sp
+ip, ip6, inet
+T}:T{
+.sp
+all
+T}
+T{
+.sp
+dstnat
+T}:T{
+.sp
+\-100
+T}:T{
+.sp
+ip, ip6, inet
+T}:T{
+.sp
+prerouting
+T}
+T{
+.sp
+filter
+T}:T{
+.sp
+0
+T}:T{
+.sp
+ip, ip6, inet, arp, netdev
+T}:T{
+.sp
+all
+T}
+T{
+.sp
+security
+T}:T{
+.sp
+50
+T}:T{
+.sp
+ip, ip6, inet
+T}:T{
+.sp
+all
+T}
+T{
+.sp
+srcnat
+T}:T{
+.sp
+100
+T}:T{
+.sp
+ip, ip6, inet
+T}:T{
+.sp
+postrouting
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&7.\ \&Standard priority names and hook compatibility for the bridge family
+.TS
+allbox tab(:);
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+Name
+T}:T{
+.sp
+Value
+T}:T{
+.sp
+Hooks
+T}
+T{
+.sp
+dstnat
+T}:T{
+.sp
+\-300
+T}:T{
+.sp
+prerouting
+T}
+T{
+.sp
+filter
+T}:T{
+.sp
+\-200
+T}:T{
+.sp
+all
+T}
+T{
+.sp
+out
+T}:T{
+.sp
+100
+T}:T{
+.sp
+output
+T}
+T{
+.sp
+srcnat
+T}:T{
+.sp
+300
+T}:T{
+.sp
+postrouting
+T}
+.TE
+.sp 1
+.sp
+Basic arithmetic expressions (addition and subtraction) can also be achieved with these standard names to ease relative prioritizing, e\&.g\&. \fBmangle \- 5\fR stands for \fB\-155\fR\&. Values will also be printed like this until the value is not further than 10 from the standard value\&.
+.sp
+Base chains also allow one to set the chain\(cqs \fBpolicy\fR, i\&.e\&. what happens to packets not explicitly accepted or refused in contained rules\&. Supported policy values are \fBaccept\fR (which is the default) or \fBdrop\fR\&.
+.SH "RULES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBadd\fR | \fBinsert\fR} \fBrule\fR [\fIfamily\fR] \fItable\fR \fIchain\fR [\fBhandle\fR \fIhandle\fR | \fBindex\fR \fIindex\fR] \fIstatement\fR \&... [\fBcomment\fR \fIcomment\fR]
+\fBreplace rule\fR [\fIfamily\fR] \fItable\fR \fIchain\fR \fBhandle\fR \fIhandle\fR \fIstatement\fR \&... [\fBcomment\fR \fIcomment\fR]
+{\fBdelete\fR | \fBreset\fR} \fBrule\fR [\fIfamily\fR] \fItable\fR \fIchain\fR \fBhandle\fR \fIhandle\fR
+\fBdestroy rule\fR [\fIfamily\fR] \fItable\fR \fIchain\fR \fBhandle\fR \fIhandle\fR
+\fBreset rules\fR [\fIfamily\fR] [\fItable\fR [\fIchain\fR]]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 to a set of grammatical rules: expressions and statements\&.
+.sp
+The add and insert commands support an optional location specifier, which is either a \fIhandle\fR or the \fIindex\fR (starting at zero) of an existing rule\&. Internally, rule locations are always identified by \fIhandle\fR and the translation from \fIindex\fR happens in userspace\&. This has two potential implications in case a concurrent ruleset change happens after the translation was done: The effective rule index might change if a rule was inserted or deleted before the referred one\&. If the referred rule was deleted, the command is rejected by the kernel just as if an invalid \fIhandle\fR was given\&.
+.sp
+A \fIcomment\fR is a single word or a double\-quoted (") multi\-word string which can be used to make notes regarding the actual rule\&. \fBNote:\fR If you use bash for adding rules, you have to escape the quotation marks, e\&.g\&. \e"enable ssh for servers\e"\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBadd\fR
+T}:T{
+.sp
+Add a new rule described by the list of statements\&. The rule is appended to the given chain unless a location is specified, in which case the rule is inserted after the specified rule\&.
+T}
+T{
+.sp
+\fBinsert\fR
+T}:T{
+.sp
+Same as \fBadd\fR except the rule is inserted at the beginning of the chain or before the specified rule\&.
+T}
+T{
+.sp
+\fBreplace\fR
+T}:T{
+.sp
+Similar to \fBadd\fR, but the rule replaces the specified rule\&.
+T}
+T{
+.sp
+\fBdelete\fR
+T}:T{
+.sp
+Delete the specified rule\&.
+T}
+T{
+.sp
+\fBdestroy\fR
+T}:T{
+.sp
+Delete the specified rule, it does not fail if it does not exist\&.
+T}
+T{
+.sp
+\fBreset\fR
+T}:T{
+.sp
+Reset rule\-contained state, e\&.g\&. counter and quota statement values\&.
+T}
+.TE
+.sp 1
+.PP
+\fBadd a rule to ip table output chain\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add rule filter output ip daddr 192\&.168\&.0\&.0/24 accept # \*(Aqip filter\*(Aq is assumed
+# same command, slightly more verbose
+nft add rule ip filter output ip daddr 192\&.168\&.0\&.0/24 accept
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBdelete rule from inet table\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nft \-a list ruleset
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ct state established,related accept # handle 4
+ ip saddr 10\&.1\&.1\&.1 tcp dport ssh accept # handle 5
+ \&.\&.\&.
+# delete the rule with handle 5
+nft delete rule inet filter input handle 5
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "SETS"
+.sp
+nftables offers two kinds of set concepts\&. Anonymous sets are sets that have no specific name\&. The set members are enclosed in curly braces, with commas to separate elements when creating the rule the set is used in\&. Once that rule is removed, the set is removed as well\&. They cannot be updated, i\&.e\&. once an anonymous set is declared it cannot be changed anymore except by removing/altering the rule that uses the anonymous set\&.
+.PP
+\fBUsing anonymous sets to accept particular subnets and ports\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add rule filter input ip saddr { 10\&.0\&.0\&.0/8, 192\&.168\&.0\&.0/16 } tcp dport { 22, 443 } accept
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Named sets are sets that need to be defined first before they can be referenced in rules\&. Unlike anonymous sets, elements can be added to or removed from a named set at any time\&. Sets are referenced from rules using an @ prefixed to the sets name\&.
+.PP
+\fBUsing named sets to accept addresses and ports\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add rule filter input ip saddr @allowed_hosts tcp dport @allowed_ports accept
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The sets allowed_hosts and allowed_ports need to be created first\&. The next section describes nft set syntax in more detail\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBadd set\fR [\fIfamily\fR] \fItable\fR \fIset\fR \fB{ type\fR \fItype\fR | \fBtypeof\fR \fIexpression\fR \fB;\fR [\fBflags\fR \fIflags\fR \fB;\fR] [\fBtimeout\fR \fItimeout\fR \fB;\fR] [\fBgc\-interval\fR \fIgc\-interval\fR \fB;\fR] [\fBelements = {\fR \fIelement\fR[\fB,\fR \&...] \fB} ;\fR] [\fBsize\fR \fIsize\fR \fB;\fR] [\fBcomment\fR \fIcomment\fR \fB;\fR\fI] [\fR\fI\fBpolicy\fR\fR\fI \*(Aqpolicy\fR \fB;\fR] [\fBauto\-merge ;\fR] \fB}\fR
+{\fBdelete\fR | \fBdestroy\fR | \fBlist\fR | \fBflush\fR | \fBreset\fR } \fBset\fR [\fIfamily\fR] \fItable\fR \fIset\fR
+\fBlist sets\fR [\fIfamily\fR]
+\fBdelete set\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+{\fBadd\fR | \fBdelete\fR | \fBdestroy\fR } \fBelement\fR [\fIfamily\fR] \fItable\fR \fIset\fR \fB{\fR \fIelement\fR[\fB,\fR \&...] \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Sets are element containers of a user\-defined data type, they are uniquely identified by a user\-defined name and attached to tables\&. Their behaviour can be tuned with the flags that can be specified at set creation time\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBadd\fR
+T}:T{
+.sp
+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\&.
+T}
+T{
+.sp
+\fBdelete\fR
+T}:T{
+.sp
+Delete the specified set\&.
+T}
+T{
+.sp
+\fBdestroy\fR
+T}:T{
+.sp
+Delete the specified set, it does not fail if it does not exist\&.
+T}
+T{
+.sp
+\fBlist\fR
+T}:T{
+.sp
+Display the elements in the specified set\&.
+T}
+T{
+.sp
+\fBflush\fR
+T}:T{
+.sp
+Remove all elements from the specified set\&.
+T}
+T{
+.sp
+\fBreset\fR
+T}:T{
+.sp
+Reset state in all contained elements, e\&.g\&. counter and quota statement values\&.
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&8.\ \&Set specifications
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+type
+T}:T{
+.sp
+data type of set elements
+T}:T{
+.sp
+string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark
+T}
+T{
+.sp
+typeof
+T}:T{
+.sp
+data type of set element
+T}:T{
+.sp
+expression to derive the data type from
+T}
+T{
+.sp
+flags
+T}:T{
+.sp
+set flags
+T}:T{
+.sp
+string: constant, dynamic, interval, timeout\&. Used to describe the sets properties\&.
+T}
+T{
+.sp
+timeout
+T}:T{
+.sp
+time an element stays in the set, mandatory if set is added to from the packet path (ruleset)
+T}:T{
+.sp
+string, decimal followed by unit\&. Units are: d, h, m, s
+T}
+T{
+.sp
+gc\-interval
+T}:T{
+.sp
+garbage collection interval, only available when timeout or flag timeout are active
+T}:T{
+.sp
+string, decimal followed by unit\&. Units are: d, h, m, s
+T}
+T{
+.sp
+elements
+T}:T{
+.sp
+elements contained by the set
+T}:T{
+.sp
+set data type
+T}
+T{
+.sp
+size
+T}:T{
+.sp
+maximum number of elements in the set, mandatory if set is added to from the packet path (ruleset)
+T}:T{
+.sp
+unsigned integer (64 bit)
+T}
+T{
+.sp
+policy
+T}:T{
+.sp
+set policy
+T}:T{
+.sp
+string: performance [default], memory
+T}
+T{
+.sp
+auto\-merge
+T}:T{
+.sp
+automatic merge of adjacent/overlapping set elements (only for interval sets)
+T}:T{
+.sp
+T}
+.TE
+.sp 1
+.SH "MAPS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBadd map\fR [\fIfamily\fR] \fItable\fR \fImap\fR \fB{ type\fR \fItype\fR | \fBtypeof\fR \fIexpression\fR [\fBflags\fR \fIflags\fR \fB;\fR] [\fBelements = {\fR \fIelement\fR[\fB,\fR \&...] \fB} ;\fR] [\fBsize\fR \fIsize\fR \fB;\fR] [\fBcomment\fR \fIcomment\fR \fB;\fR\fI] [\fR\fI\fBpolicy\fR\fR\fI \*(Aqpolicy\fR \fB;\fR] \fB}\fR
+{\fBdelete\fR | \fBdestroy\fR | \fBlist\fR | \fBflush\fR | \fBreset\fR } \fBmap\fR [\fIfamily\fR] \fItable\fR \fImap\fR
+\fBlist maps\fR [\fIfamily\fR]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Maps store data based on some specific key used as input\&. They are uniquely identified by a user\-defined name and attached to tables\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBadd\fR
+T}:T{
+.sp
+Add a new map in the specified table\&.
+T}
+T{
+.sp
+\fBdelete\fR
+T}:T{
+.sp
+Delete the specified map\&.
+T}
+T{
+.sp
+\fBdestroy\fR
+T}:T{
+.sp
+Delete the specified map, it does not fail if it does not exist\&.
+T}
+T{
+.sp
+\fBlist\fR
+T}:T{
+.sp
+Display the elements in the specified map\&.
+T}
+T{
+.sp
+\fBflush\fR
+T}:T{
+.sp
+Remove all elements from the specified map\&.
+T}
+T{
+.sp
+\fBreset\fR
+T}:T{
+.sp
+Reset state in all contained elements, e\&.g\&. counter and quota statement values\&.
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&9.\ \&Map specifications
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+type
+T}:T{
+.sp
+data type of map elements
+T}:T{
+.sp
+string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark, counter, quota\&. Counter and quota can\(cqt be used as keys
+T}
+T{
+.sp
+typeof
+T}:T{
+.sp
+data type of set element
+T}:T{
+.sp
+expression to derive the data type from
+T}
+T{
+.sp
+flags
+T}:T{
+.sp
+map flags
+T}:T{
+.sp
+string, same as set flags
+T}
+T{
+.sp
+elements
+T}:T{
+.sp
+elements contained by the map
+T}:T{
+.sp
+map data type
+T}
+T{
+.sp
+size
+T}:T{
+.sp
+maximum number of elements in the map
+T}:T{
+.sp
+unsigned integer (64 bit)
+T}
+T{
+.sp
+policy
+T}:T{
+.sp
+map policy
+T}:T{
+.sp
+string: performance [default], memory
+T}
+.TE
+.sp 1
+.sp
+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\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&10.\ \&Set and Map flags
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Flag
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+constant
+T}:T{
+.sp
+Set contents will never change after creation
+T}
+T{
+.sp
+dynamic
+T}:T{
+.sp
+Set must support updates from the packet path with the \fBadd\fR, \fBupdate\fR or \fBdelete\fR keywords\&.
+T}
+T{
+.sp
+interval
+T}:T{
+.sp
+Set must be able to store intervals (ranges)
+T}
+T{
+.sp
+timeout
+T}:T{
+.sp
+Set must support element timeouts (auto\-removal of elements once they expire)\&.
+T}
+.TE
+.sp 1
+.SH "ELEMENTS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBadd\fR | \fBcreate\fR | \fBdelete\fR | \fBdestroy\fR | \fBget\fR | \fBreset\fR } \fBelement\fR [\fIfamily\fR] \fItable\fR \fIset\fR \fB{\fR \fIELEMENT\fR[\fB,\fR \&...] \fB}\fR
+
+\fIELEMENT\fR := \fIkey_expression\fR \fIOPTIONS\fR [\fB:\fR \fIvalue_expression\fR]
+\fIOPTIONS\fR := [\fBtimeout\fR \fITIMESPEC\fR] [\fBexpires\fR \fITIMESPEC\fR] [\fBcomment\fR \fIstring\fR]
+\fITIMESPEC\fR := [\fInum\fR\fBd\fR][\fInum\fR\fBh\fR][\fInum\fR\fBm\fR][\fInum\fR[\fBs\fR]]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Element\-related commands allow one to change contents of named sets and maps\&. \fIkey_expression\fR is typically a value matching the set type\&. \fIvalue_expression\fR is not allowed in sets but mandatory when adding to maps, where it matches the data part in its type definition\&. When deleting from maps, it may be specified but is optional as \fIkey_expression\fR uniquely identifies the element\&.
+.sp
+\fBcreate\fR command is similar to \fBadd\fR with the exception that none of the listed elements may already exist\&.
+.sp
+\fBget\fR command is useful to check if an element is contained in a set which may be non\-trivial in very large and/or interval sets\&. In the latter case, the containing interval is returned instead of just the element itself\&.
+.sp
+\fBreset\fR command resets state attached to the given element(s), e\&.g\&. counter and quota statement values\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&11.\ \&Element options
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Option
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+timeout
+T}:T{
+.sp
+timeout value for sets/maps with flag \fBtimeout\fR
+T}
+T{
+.sp
+expires
+T}:T{
+.sp
+the time until given element expires, useful for ruleset replication only
+T}
+T{
+.sp
+comment
+T}:T{
+.sp
+per element comment field
+T}
+.TE
+.sp 1
+.SH "FLOWTABLES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBadd\fR | \fBcreate\fR} \fBflowtable\fR [\fIfamily\fR] \fItable\fR \fIflowtable\fR \fB{ hook\fR \fIhook\fR \fBpriority\fR \fIpriority\fR \fB; devices = {\fR \fIdevice\fR[\fB,\fR \&...] \fB} ; }\fR
+\fBlist flowtables\fR [\fIfamily\fR]
+{\fBdelete\fR | \fBdestroy\fR | \fBlist\fR} \fBflowtable\fR [\fIfamily\fR] \fItable\fR \fIflowtable\fR
+\fBdelete\fR \fBflowtable\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Flowtables allow you to accelerate packet forwarding in software\&. Flowtables entries are represented through a tuple that is composed of the input interface, source and destination address, source and destination port; and layer 3/4 protocols\&. Each entry also caches the destination interface and the gateway address \- to update the destination link\-layer address \- to forward packets\&. The ttl and hoplimit fields are also decremented\&. Hence, flowtables provides an alternative path that allow packets to bypass the classic forwarding path\&. Flowtables reside in the ingress hook that is located before the prerouting hook\&. You can select which flows you want to offload through the flow expression from the forward chain\&. Flowtables are identified by their address family and their name\&. The address family must be one of ip, ip6, or inet\&. The inet address family is a dummy family which is used to create hybrid IPv4/IPv6 tables\&. When no address family is specified, ip is used by default\&.
+.sp
+The \fBpriority\fR can be a signed integer or \fBfilter\fR which stands for 0\&. Addition and subtraction can be used to set relative priority, e\&.g\&. filter + 5 equals to 5\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBadd\fR
+T}:T{
+.sp
+Add a new flowtable for the given family with the given name\&.
+T}
+T{
+.sp
+\fBdelete\fR
+T}:T{
+.sp
+Delete the specified flowtable\&.
+T}
+T{
+.sp
+\fBdestroy\fR
+T}:T{
+.sp
+Delete the specified flowtable, it does not fail if it does not exist\&.
+T}
+T{
+.sp
+\fBlist\fR
+T}:T{
+.sp
+List all flowtables\&.
+T}
+.TE
+.sp 1
+.SH "LISTING"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBlist { secmarks | synproxys | flow tables | meters | hooks }\fR [\fIfamily\fR]
+\fBlist { secmarks | synproxys | flow tables | meters | hooks } table\fR [\fIfamily\fR] \fItable\fR
+\fBlist ct { timeout | expectation | helper | helpers } table\fR [\fIfamily\fR] \fItable\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Inspect configured objects\&. \fBlist hooks\fR shows the full hook pipeline, including those registered by kernel modules, such as nf_conntrack\&.
+.SH "STATEFUL OBJECTS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBadd\fR | \fBdelete\fR | \fBdestroy\fR | \fBlist\fR | \fBreset\fR} \fBcounter\fR [\fIfamily\fR] \fItable\fR \fIobject\fR
+{\fBadd\fR | \fBdelete\fR | \fBdestroy\fR | \fBlist\fR | \fBreset\fR} \fBquota\fR [\fIfamily\fR] \fItable\fR \fIobject\fR
+{\fBadd\fR | \fBdelete\fR | \fBdestroy\fR | \fBlist\fR} \fBlimit\fR [\fIfamily\fR] \fItable\fR \fIobject\fR
+\fBdelete\fR \fIcounter\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBdelete\fR \fIquota\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBdelete\fR \fIlimit\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBdestroy\fR \fIcounter\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBdestroy\fR \fIquota\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBdestroy\fR \fIlimit\fR [\fIfamily\fR] \fItable\fR \fBhandle\fR \fIhandle\fR
+\fBlist counters\fR [\fIfamily\fR]
+\fBlist quotas\fR [\fIfamily\fR]
+\fBlist limits\fR [\fIfamily\fR]
+\fBreset counters\fR [\fIfamily\fR]
+\fBreset quotas\fR [\fIfamily\fR]
+\fBreset counters\fR [\fIfamily\fR] \fItable\fR
+\fBreset quotas\fR [\fIfamily\fR] \fItable\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Stateful objects are attached to tables and are identified by a unique name\&. They group stateful information from rules, to reference them in rules the keywords "type name" are used e\&.g\&. "counter name"\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBadd\fR
+T}:T{
+.sp
+Add a new stateful object in the specified table\&.
+T}
+T{
+.sp
+\fBdelete\fR
+T}:T{
+.sp
+Delete the specified object\&.
+T}
+T{
+.sp
+\fBdestroy\fR
+T}:T{
+.sp
+Delete the specified object, it does not fail if it does not exist\&.
+T}
+T{
+.sp
+\fBlist\fR
+T}:T{
+.sp
+Display stateful information the object holds\&.
+T}
+T{
+.sp
+\fBreset\fR
+T}:T{
+.sp
+List\-and\-reset stateful object\&.
+T}
+.TE
+.sp 1
+.SS "CT HELPER"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBadd\fR \fBct helper\fR [\fIfamily\fR] \fItable\fR \fIname\fR \fB{ type\fR \fItype\fR \fBprotocol\fR \fIprotocol\fR \fB;\fR [\fBl3proto\fR \fIfamily\fR \fB;\fR] \fB}\fR
+\fBdelete\fR \fBct helper\fR [\fIfamily\fR] \fItable\fR \fIname\fR
+\fBlist\fR \fBct helpers\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Ct helper is used to define connection tracking helpers that can then be used in combination with the \fBct helper set\fR statement\&. \fItype\fR and \fIprotocol\fR are mandatory, l3proto is derived from the table family by default, i\&.e\&. in the inet table the kernel will try to load both the ipv4 and ipv6 helper backends, if they are supported by the kernel\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&12.\ \&conntrack helper specifications
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+type
+T}:T{
+.sp
+name of helper type
+T}:T{
+.sp
+quoted string (e\&.g\&. "ftp")
+T}
+T{
+.sp
+protocol
+T}:T{
+.sp
+layer 4 protocol of the helper
+T}:T{
+.sp
+string (e\&.g\&. ip)
+T}
+T{
+.sp
+l3proto
+T}:T{
+.sp
+layer 3 protocol of the helper
+T}:T{
+.sp
+address family (e\&.g\&. ip)
+T}
+T{
+.sp
+comment
+T}:T{
+.sp
+per ct helper comment field
+T}:T{
+.sp
+string
+T}
+.TE
+.sp 1
+.PP
+\fBdefining and assigning ftp helper\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Unlike iptables, helper assignment needs to be performed after the conntrack
+lookup has completed, for example with the default 0 hook priority\&.
+
+table inet myhelpers {
+ ct helper ftp\-standard {
+ type "ftp" protocol tcp
+ }
+ chain prerouting {
+ type filter hook prerouting priority filter;
+ tcp dport 21 ct helper set "ftp\-standard"
+ }
+}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "CT TIMEOUT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBadd\fR \fBct timeout\fR [\fIfamily\fR] \fItable\fR \fIname\fR \fB{ protocol\fR \fIprotocol\fR \fB; policy = {\fR \fIstate\fR\fB:\fR \fIvalue\fR [\fB,\fR \&...] \fB} ;\fR [\fBl3proto\fR \fIfamily\fR \fB;\fR] \fB}\fR
+\fBdelete\fR \fBct timeout\fR [\fIfamily\fR] \fItable\fR \fIname\fR
+\fBlist\fR \fBct timeouts\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Ct timeout is used to update connection tracking timeout values\&.Timeout policies are assigned with the \fBct timeout set\fR statement\&. \fIprotocol\fR and \fIpolicy\fR are mandatory, l3proto is derived from the table family by default\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&13.\ \&conntrack timeout specifications
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+protocol
+T}:T{
+.sp
+layer 4 protocol of the timeout object
+T}:T{
+.sp
+string (e\&.g\&. ip)
+T}
+T{
+.sp
+state
+T}:T{
+.sp
+connection state name
+T}:T{
+.sp
+string (e\&.g\&. "established")
+T}
+T{
+.sp
+value
+T}:T{
+.sp
+timeout value for connection state
+T}:T{
+.sp
+unsigned integer
+T}
+T{
+.sp
+l3proto
+T}:T{
+.sp
+layer 3 protocol of the timeout object
+T}:T{
+.sp
+address family (e\&.g\&. ip)
+T}
+T{
+.sp
+comment
+T}:T{
+.sp
+per ct timeout comment field
+T}:T{
+.sp
+string
+T}
+.TE
+.sp 1
+.sp
+tcp connection state names that can have a specific timeout value are:
+.sp
+\fIclose\fR, \fIclose_wait\fR, \fIestablished\fR, \fIfin_wait\fR, \fIlast_ack\fR, \fIretrans\fR, \fIsyn_recv\fR, \fIsyn_sent\fR, \fItime_wait\fR and \fIunack\fR\&.
+.sp
+You can use \fIsysctl \-a |grep net\&.netfilter\&.nf_conntrack_tcp_timeout_\fR to view and change the system\-wide defaults\&. \fIct timeout\fR allows for flow\-specific settings, without changing the global timeouts\&.
+.sp
+For example, tcp port 53 could have much lower settings than other traffic\&.
+.sp
+udp state names that can have a specific timeout value are \fIreplied\fR and \fIunreplied\fR\&.
+.PP
+\fBdefining and assigning ct timeout policy\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+table ip filter {
+ ct timeout customtimeout {
+ protocol tcp;
+ l3proto ip
+ policy = { established: 2m, close: 20s }
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ ct timeout set "customtimeout"
+ }
+}
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBtesting the updated timeout policy\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+% conntrack \-E
+
+It should display:
+
+[UPDATE] tcp 6 120 ESTABLISHED src=172\&.16\&.19\&.128 dst=172\&.16\&.19\&.1
+sport=22 dport=41360 [UNREPLIED] src=172\&.16\&.19\&.1 dst=172\&.16\&.19\&.128
+sport=41360 dport=22
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "CT EXPECTATION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBadd\fR \fBct expectation\fR [\fIfamily\fR] \fItable\fR \fIname\fR \fB{ protocol\fR \fIprotocol\fR \fB; dport\fR \fIdport\fR \fB; timeout\fR \fItimeout\fR \fB; size\fR \fIsize\fR \fB; [*l3proto\fR \fIfamily\fR \fB;\fR] \fB}\fR
+\fBdelete\fR \fBct expectation\fR [\fIfamily\fR] \fItable\fR \fIname\fR
+\fBlist\fR \fBct expectations\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Ct expectation is used to create connection expectations\&. Expectations are assigned with the \fBct expectation set\fR statement\&. \fIprotocol\fR, \fIdport\fR, \fItimeout\fR and \fIsize\fR are mandatory, l3proto is derived from the table family by default\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&14.\ \&conntrack expectation specifications
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+protocol
+T}:T{
+.sp
+layer 4 protocol of the expectation object
+T}:T{
+.sp
+string (e\&.g\&. ip)
+T}
+T{
+.sp
+dport
+T}:T{
+.sp
+destination port of expected connection
+T}:T{
+.sp
+unsigned integer
+T}
+T{
+.sp
+timeout
+T}:T{
+.sp
+timeout value for expectation
+T}:T{
+.sp
+unsigned integer
+T}
+T{
+.sp
+size
+T}:T{
+.sp
+size value for expectation
+T}:T{
+.sp
+unsigned integer
+T}
+T{
+.sp
+l3proto
+T}:T{
+.sp
+layer 3 protocol of the expectation object
+T}:T{
+.sp
+address family (e\&.g\&. ip)
+T}
+T{
+.sp
+comment
+T}:T{
+.sp
+per ct expectation comment field
+T}:T{
+.sp
+string
+T}
+.TE
+.sp 1
+.PP
+\fBdefining and assigning ct expectation policy\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+table ip filter {
+ ct expectation expect {
+ protocol udp
+ dport 9876
+ timeout 2m
+ size 8
+ l3proto ip
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ct expectation set "expect"
+ }
+}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "COUNTER"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBadd\fR \fBcounter\fR [\fIfamily\fR] \fItable\fR \fIname\fR [\fB{\fR [ \fBpackets\fR \fIpackets\fR \fBbytes\fR \fIbytes\fR \fI;\fR ] [ \fBcomment\fR \fIcomment\fR \fI;\fR \fB}\fR]
+\fBdelete\fR \fBcounter\fR [\fIfamily\fR] \fItable\fR \fIname\fR
+\fBlist\fR \fBcounters\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&15.\ \&Counter specifications
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+packets
+T}:T{
+.sp
+initial count of packets
+T}:T{
+.sp
+unsigned integer (64 bit)
+T}
+T{
+.sp
+bytes
+T}:T{
+.sp
+initial count of bytes
+T}:T{
+.sp
+unsigned integer (64 bit)
+T}
+T{
+.sp
+comment
+T}:T{
+.sp
+per counter comment field
+T}:T{
+.sp
+string
+T}
+.TE
+.sp 1
+.PP
+\fBUsing named counters\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add counter filter http
+nft add rule filter input tcp dport 80 counter name \e"http\e"
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBUsing named counters with maps\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add counter filter http
+nft add counter filter https
+nft add rule filter input counter name tcp dport map { 80 : \e"http\e", 443 : \e"https\e" }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "QUOTA"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBadd\fR \fBquota\fR [\fIfamily\fR] \fItable\fR \fIname\fR \fB{\fR [\fBover\fR|\fBuntil\fR] \fIbytes\fR \fIBYTE_UNIT\fR [ \fBused\fR \fIbytes\fR \fIBYTE_UNIT\fR ] \fI;\fR [ \fBcomment\fR \fIcomment\fR \fI;\fR ] \fB}\fR
+BYTE_UNIT := bytes | kbytes | mbytes
+\fBdelete\fR \fBquota\fR [\fIfamily\fR] \fItable\fR \fIname\fR
+\fBlist\fR \fBquotas\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&16.\ \&Quota specifications
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+quota
+T}:T{
+.sp
+quota limit, used as the quota name
+T}:T{
+.sp
+Two arguments, unsigned integer (64 bit) and string: bytes, kbytes, mbytes\&. "over" and "until" go before these arguments
+T}
+T{
+.sp
+used
+T}:T{
+.sp
+initial value of used quota
+T}:T{
+.sp
+Two arguments, unsigned integer (64 bit) and string: bytes, kbytes, mbytes
+T}
+T{
+.sp
+comment
+T}:T{
+.sp
+per quota comment field
+T}:T{
+.sp
+string
+T}
+.TE
+.sp 1
+.PP
+\fBUsing named quotas\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add quota filter user123 { over 20 mbytes }
+nft add rule filter input ip saddr 192\&.168\&.10\&.123 quota name \e"user123\e"
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBUsing named quotas with maps\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add quota filter user123 { over 20 mbytes }
+nft add quota filter user124 { over 20 mbytes }
+nft add rule filter input quota name ip saddr map { 192\&.168\&.10\&.123 : \e"user123\e", 192\&.168\&.10\&.124 : \e"user124\e" }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "EXPRESSIONS"
+.sp
+Expressions represent values, either constants like network addresses, port numbers, etc\&., or data gathered from the packet during ruleset evaluation\&. Expressions can be combined using binary, logical, relational and other types of expressions to form complex or relational (match) expressions\&. They are also used as arguments to certain types of operations, like NAT, packet marking etc\&.
+.sp
+Each expression has a data type, which determines the size, parsing and representation of symbolic values and type compatibility with other expressions\&.
+.SS "DESCRIBE COMMAND"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBdescribe\fR \fIexpression\fR | \fIdata type\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The \fBdescribe\fR command shows information about the type of an expression and its data type\&. A data type may also be given, in which nft will display more information about the type\&.
+.PP
+\fBThe describe command\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+$ nft describe tcp flags
+payload expression, datatype tcp_flag (TCP flag) (basetype bitmask, integer), 8 bits
+
+predefined symbolic constants:
+fin 0x01
+syn 0x02
+rst 0x04
+psh 0x08
+ack 0x10
+urg 0x20
+ecn 0x40
+cwr 0x80
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "DATA TYPES"
+.sp
+Data types determine the size, parsing and representation of symbolic values and type compatibility of expressions\&. A number of global data types exist, in addition some expression types define further data types specific to the expression type\&. Most data types have a fixed size, some however may have a dynamic size, f\&.i\&. the string type\&. Some types also have predefined symbolic constants\&. Those can be listed using the nft \fBdescribe\fR command:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+$ nft describe ct_state
+datatype ct_state (conntrack state) (basetype bitmask, integer), 32 bits
+
+pre\-defined symbolic constants (in hexadecimal):
+invalid 0x00000001
+new \&.\&.\&.
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Types may be derived from lower order types, f\&.i\&. the IPv4 address type is derived from the integer type, meaning an IPv4 address can also be specified as an integer value\&.
+.sp
+In certain contexts (set and map definitions), it is necessary to explicitly specify a data type\&. Each type has a name which is used for this\&.
+.SS "INTEGER TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+Integer
+T}:T{
+.sp
+integer
+T}:T{
+.sp
+variable
+T}:T{
+.sp
+\-
+T}
+.TE
+.sp 1
+.sp
+The integer type is used for numeric values\&. It may be specified as a decimal, hexadecimal or octal number\&. The integer type does not have a fixed size, its size is determined by the expression for which it is used\&.
+.SS "BITMASK TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+Bitmask
+T}:T{
+.sp
+bitmask
+T}:T{
+.sp
+variable
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The bitmask type (\fBbitmask\fR) is used for bitmasks\&.
+.SS "STRING TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+String
+T}:T{
+.sp
+string
+T}:T{
+.sp
+variable
+T}:T{
+.sp
+\-
+T}
+.TE
+.sp 1
+.sp
+The string type is used for character strings\&. A string begins with an alphabetic character (a\-zA\-Z) followed by zero or more alphanumeric characters or the characters /, \-, _ and \&.\&. In addition, anything enclosed in double quotes (") is recognized as a string\&.
+.PP
+\fBString specification\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# Interface name
+filter input iifname eth0
+
+# Weird interface name
+filter input iifname "(eth0)"
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "LINK LAYER ADDRESS TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+Link layer address
+T}:T{
+.sp
+lladdr
+T}:T{
+.sp
+variable
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The link layer address type is used for link layer addresses\&. Link layer addresses are specified as a variable amount of groups of two hexadecimal digits separated using colons (:)\&.
+.PP
+\fBLink layer address specification\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# Ethernet destination MAC address
+filter input ether daddr 20:c9:d0:43:12:d9
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "IPV4 ADDRESS TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+IPV4 address
+T}:T{
+.sp
+ipv4_addr
+T}:T{
+.sp
+32 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The IPv4 address type is used for IPv4 addresses\&. Addresses are specified in either dotted decimal, dotted hexadecimal, dotted octal, decimal, hexadecimal, octal notation or as a host name\&. A host name will be resolved using the standard system resolver\&.
+.PP
+\fBIPv4 address specification\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# dotted decimal notation
+filter output ip daddr 127\&.0\&.0\&.1
+
+# host name
+filter output ip daddr localhost
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "IPV6 ADDRESS TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+IPv6 address
+T}:T{
+.sp
+ipv6_addr
+T}:T{
+.sp
+128 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The IPv6 address type is used for IPv6 addresses\&. Addresses are specified as a host name or as hexadecimal halfwords separated by colons\&. Addresses might be enclosed in square brackets ("[]") to differentiate them from port numbers\&.
+.PP
+\fBIPv6 address specification\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# abbreviated loopback address
+filter output ip6 daddr ::1
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBIPv6 address specification with bracket notation\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# without [] the port number (22) would be parsed as part of the
+# ipv6 address
+ip6 nat prerouting tcp dport 2222 dnat to [1ce::d0]:22
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "BOOLEAN TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+Boolean
+T}:T{
+.sp
+boolean
+T}:T{
+.sp
+1 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The boolean type is a syntactical helper type in userspace\&. Its use is in the right\-hand side of a (typically implicit) relational expression to change the expression on the left\-hand side into a boolean check (usually for existence)\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&17.\ \&The following keywords will automatically resolve into a boolean type with given value
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+exists
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+missing
+T}:T{
+.sp
+0
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&18.\ \&expressions support a boolean comparison
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Expression
+T}:T{
+Behaviour
+T}
+.T&
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+fib
+T}:T{
+.sp
+Check route existence\&.
+T}
+T{
+.sp
+exthdr
+T}:T{
+.sp
+Check IPv6 extension header existence\&.
+T}
+T{
+.sp
+tcp option
+T}:T{
+.sp
+Check TCP option header existence\&.
+T}
+.TE
+.sp 1
+.PP
+\fBBoolean specification\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# match if route exists
+filter input fib daddr \&. iif oif exists
+
+# match only non\-fragmented packets in IPv6 traffic
+filter input exthdr frag missing
+
+# match if TCP timestamp option is present
+filter input tcp option timestamp exists
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "ICMP TYPE TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+ICMP Type
+T}:T{
+.sp
+icmp_type
+T}:T{
+.sp
+8 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The ICMP Type type is used to conveniently specify the ICMP header\(cqs type field\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&19.\ \&Keywords may be used when specifying the ICMP type
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+echo\-reply
+T}:T{
+.sp
+0
+T}
+T{
+.sp
+destination\-unreachable
+T}:T{
+.sp
+3
+T}
+T{
+.sp
+source\-quench
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+redirect
+T}:T{
+.sp
+5
+T}
+T{
+.sp
+echo\-request
+T}:T{
+.sp
+8
+T}
+T{
+.sp
+router\-advertisement
+T}:T{
+.sp
+9
+T}
+T{
+.sp
+router\-solicitation
+T}:T{
+.sp
+10
+T}
+T{
+.sp
+time\-exceeded
+T}:T{
+.sp
+11
+T}
+T{
+.sp
+parameter\-problem
+T}:T{
+.sp
+12
+T}
+T{
+.sp
+timestamp\-request
+T}:T{
+.sp
+13
+T}
+T{
+.sp
+timestamp\-reply
+T}:T{
+.sp
+14
+T}
+T{
+.sp
+info\-request
+T}:T{
+.sp
+15
+T}
+T{
+.sp
+info\-reply
+T}:T{
+.sp
+16
+T}
+T{
+.sp
+address\-mask\-request
+T}:T{
+.sp
+17
+T}
+T{
+.sp
+address\-mask\-reply
+T}:T{
+.sp
+18
+T}
+.TE
+.sp 1
+.PP
+\fBICMP Type specification\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# match ping packets
+filter output icmp type { echo\-request, echo\-reply }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "ICMP CODE TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+ICMP Code
+T}:T{
+.sp
+icmp_code
+T}:T{
+.sp
+8 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The ICMP Code type is used to conveniently specify the ICMP header\(cqs code field\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&20.\ \&Keywords may be used when specifying the ICMP code
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+net\-unreachable
+T}:T{
+.sp
+0
+T}
+T{
+.sp
+host\-unreachable
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+prot\-unreachable
+T}:T{
+.sp
+2
+T}
+T{
+.sp
+port\-unreachable
+T}:T{
+.sp
+3
+T}
+T{
+.sp
+frag\-needed
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+net\-prohibited
+T}:T{
+.sp
+9
+T}
+T{
+.sp
+host\-prohibited
+T}:T{
+.sp
+10
+T}
+T{
+.sp
+admin\-prohibited
+T}:T{
+.sp
+13
+T}
+.TE
+.sp 1
+.SS "ICMPV6 TYPE TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+ICMPv6 Type
+T}:T{
+.sp
+icmpx_code
+T}:T{
+.sp
+8 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The ICMPv6 Type type is used to conveniently specify the ICMPv6 header\(cqs type field\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&21.\ \&keywords may be used when specifying the ICMPv6 type:
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+destination\-unreachable
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+packet\-too\-big
+T}:T{
+.sp
+2
+T}
+T{
+.sp
+time\-exceeded
+T}:T{
+.sp
+3
+T}
+T{
+.sp
+parameter\-problem
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+echo\-request
+T}:T{
+.sp
+128
+T}
+T{
+.sp
+echo\-reply
+T}:T{
+.sp
+129
+T}
+T{
+.sp
+mld\-listener\-query
+T}:T{
+.sp
+130
+T}
+T{
+.sp
+mld\-listener\-report
+T}:T{
+.sp
+131
+T}
+T{
+.sp
+mld\-listener\-done
+T}:T{
+.sp
+132
+T}
+T{
+.sp
+mld\-listener\-reduction
+T}:T{
+.sp
+132
+T}
+T{
+.sp
+nd\-router\-solicit
+T}:T{
+.sp
+133
+T}
+T{
+.sp
+nd\-router\-advert
+T}:T{
+.sp
+134
+T}
+T{
+.sp
+nd\-neighbor\-solicit
+T}:T{
+.sp
+135
+T}
+T{
+.sp
+nd\-neighbor\-advert
+T}:T{
+.sp
+136
+T}
+T{
+.sp
+nd\-redirect
+T}:T{
+.sp
+137
+T}
+T{
+.sp
+router\-renumbering
+T}:T{
+.sp
+138
+T}
+T{
+.sp
+ind\-neighbor\-solicit
+T}:T{
+.sp
+141
+T}
+T{
+.sp
+ind\-neighbor\-advert
+T}:T{
+.sp
+142
+T}
+T{
+.sp
+mld2\-listener\-report
+T}:T{
+.sp
+143
+T}
+.TE
+.sp 1
+.PP
+\fBICMPv6 Type specification\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# match ICMPv6 ping packets
+filter output icmpv6 type { echo\-request, echo\-reply }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "ICMPV6 CODE TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+ICMPv6 Code
+T}:T{
+.sp
+icmpv6_code
+T}:T{
+.sp
+8 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The ICMPv6 Code type is used to conveniently specify the ICMPv6 header\(cqs code field\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&22.\ \&keywords may be used when specifying the ICMPv6 code
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+no\-route
+T}:T{
+.sp
+0
+T}
+T{
+.sp
+admin\-prohibited
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+addr\-unreachable
+T}:T{
+.sp
+3
+T}
+T{
+.sp
+port\-unreachable
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+policy\-fail
+T}:T{
+.sp
+5
+T}
+T{
+.sp
+reject\-route
+T}:T{
+.sp
+6
+T}
+.TE
+.sp 1
+.SS "ICMPVX CODE TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+ICMPvX Code
+T}:T{
+.sp
+icmpv6_type
+T}:T{
+.sp
+8 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The ICMPvX Code type abstraction is a set of values which overlap between ICMP and ICMPv6 Code types to be used from the inet family\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&23.\ \&keywords may be used when specifying the ICMPvX code
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+no\-route
+T}:T{
+.sp
+0
+T}
+T{
+.sp
+port\-unreachable
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+host\-unreachable
+T}:T{
+.sp
+2
+T}
+T{
+.sp
+admin\-prohibited
+T}:T{
+.sp
+3
+T}
+.TE
+.sp 1
+.SS "CONNTRACK TYPES"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&24.\ \&overview of types used in ct expression and statement
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt.
+T{
+.sp
+conntrack state
+T}:T{
+.sp
+ct_state
+T}:T{
+.sp
+4 byte
+T}:T{
+.sp
+bitmask
+T}
+T{
+.sp
+conntrack direction
+T}:T{
+.sp
+ct_dir
+T}:T{
+.sp
+8 bit
+T}:T{
+.sp
+integer
+T}
+T{
+.sp
+conntrack status
+T}:T{
+.sp
+ct_status
+T}:T{
+.sp
+4 byte
+T}:T{
+.sp
+bitmask
+T}
+T{
+.sp
+conntrack event bits
+T}:T{
+.sp
+ct_event
+T}:T{
+.sp
+4 byte
+T}:T{
+.sp
+bitmask
+T}
+T{
+.sp
+conntrack label
+T}:T{
+.sp
+ct_label
+T}:T{
+.sp
+128 bit
+T}:T{
+.sp
+bitmask
+T}
+.TE
+.sp 1
+.sp
+For each of the types above, keywords are available for convenience:
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&25.\ \&conntrack state (ct_state)
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+invalid
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+established
+T}:T{
+.sp
+2
+T}
+T{
+.sp
+related
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+new
+T}:T{
+.sp
+8
+T}
+T{
+.sp
+untracked
+T}:T{
+.sp
+64
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&26.\ \&conntrack direction (ct_dir)
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+original
+T}:T{
+.sp
+0
+T}
+T{
+.sp
+reply
+T}:T{
+.sp
+1
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&27.\ \&conntrack status (ct_status)
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+expected
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+seen\-reply
+T}:T{
+.sp
+2
+T}
+T{
+.sp
+assured
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+confirmed
+T}:T{
+.sp
+8
+T}
+T{
+.sp
+snat
+T}:T{
+.sp
+16
+T}
+T{
+.sp
+dnat
+T}:T{
+.sp
+32
+T}
+T{
+.sp
+dying
+T}:T{
+.sp
+512
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&28.\ \&conntrack event bits (ct_event)
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+new
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+related
+T}:T{
+.sp
+2
+T}
+T{
+.sp
+destroy
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+reply
+T}:T{
+.sp
+8
+T}
+T{
+.sp
+assured
+T}:T{
+.sp
+16
+T}
+T{
+.sp
+protoinfo
+T}:T{
+.sp
+32
+T}
+T{
+.sp
+helper
+T}:T{
+.sp
+64
+T}
+T{
+.sp
+mark
+T}:T{
+.sp
+128
+T}
+T{
+.sp
+seqadj
+T}:T{
+.sp
+256
+T}
+T{
+.sp
+secmark
+T}:T{
+.sp
+512
+T}
+T{
+.sp
+label
+T}:T{
+.sp
+1024
+T}
+.TE
+.sp 1
+.sp
+Possible keywords for conntrack label type (ct_label) are read at runtime from /etc/connlabel\&.conf\&.
+.SS "DCCP PKTTYPE TYPE"
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Keyword
+T}:T{
+Size
+T}:T{
+Base type
+T}
+.T&
+lt lt lt lt.
+T{
+.sp
+DCCP packet type
+T}:T{
+.sp
+dccp_pkttype
+T}:T{
+.sp
+4 bit
+T}:T{
+.sp
+integer
+T}
+.TE
+.sp 1
+.sp
+The DCCP packet type abstracts the different legal values of the respective four bit field in the DCCP header, as stated by RFC4340\&. Note that possible values 10\-15 are considered reserved and therefore not allowed to be used\&. In iptables\*(Aq \fBdccp\fR match, these values are aliased \fIINVALID\fR\&. With nftables, one may simply match on the numeric value range, i\&.e\&. \fB10\-15\fR\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&29.\ \&keywords may be used when specifying the DCCP packet type
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Value
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+request
+T}:T{
+.sp
+0
+T}
+T{
+.sp
+response
+T}:T{
+.sp
+1
+T}
+T{
+.sp
+data
+T}:T{
+.sp
+2
+T}
+T{
+.sp
+ack
+T}:T{
+.sp
+3
+T}
+T{
+.sp
+dataack
+T}:T{
+.sp
+4
+T}
+T{
+.sp
+closereq
+T}:T{
+.sp
+5
+T}
+T{
+.sp
+close
+T}:T{
+.sp
+6
+T}
+T{
+.sp
+reset
+T}:T{
+.sp
+7
+T}
+T{
+.sp
+sync
+T}:T{
+.sp
+8
+T}
+T{
+.sp
+syncack
+T}:T{
+.sp
+9
+T}
+.TE
+.sp 1
+.SH "PRIMARY EXPRESSIONS"
+.sp
+The lowest order expression is a primary expression, representing either a constant or a single datum from a packet\(cqs payload, meta data or a stateful module\&.
+.SS "META EXPRESSIONS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBmeta\fR {\fBlength\fR | \fBnfproto\fR | \fBl4proto\fR | \fBprotocol\fR | \fBpriority\fR}
+[\fBmeta\fR] {\fBmark\fR | \fBiif\fR | \fBiifname\fR | \fBiiftype\fR | \fBoif\fR | \fBoifname\fR | \fBoiftype\fR | \fBskuid\fR | \fBskgid\fR | \fBnftrace\fR | \fBrtclassid\fR | \fBibrname\fR | \fBobrname\fR | \fBpkttype\fR | \fBcpu\fR | \fBiifgroup\fR | \fBoifgroup\fR | \fBcgroup\fR | \fBrandom\fR | \fBipsec\fR | \fBiifkind\fR | \fBoifkind\fR | \fBtime\fR | \fBhour\fR | \fBday\fR }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A meta expression refers to meta data associated with a packet\&.
+.sp
+There are two types of meta expressions: unqualified and qualified meta expressions\&. Qualified meta expressions require the meta keyword before the meta key, unqualified meta expressions can be specified by using the meta key directly or as qualified meta expressions\&. Meta l4proto is useful to match a particular transport protocol that is part of either an IPv4 or IPv6 packet\&. It will also skip any IPv6 extension headers present in an IPv6 packet\&.
+.sp
+meta iif, oif, iifname and oifname are used to match the interface a packet arrived on or is about to be sent out on\&.
+.sp
+iif and oif are used to match on the interface index, whereas iifname and oifname are used to match on the interface name\&. This is not the same \(em assuming the rule
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+filter input meta iif "foo"
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Then this rule can only be added if the interface "foo" exists\&. Also, the rule will continue to match even if the interface "foo" is renamed to "bar"\&.
+.sp
+This is because internally the interface index is used\&. In case of dynamically created interfaces, such as tun/tap or dialup interfaces (ppp for example), it might be better to use iifname or oifname instead\&.
+.sp
+In these cases, the name is used so the interface doesn\(cqt have to exist to add such a rule, it will stop matching if the interface gets renamed and it will match again in case interface gets deleted and later a new interface with the same name is created\&.
+.sp
+Like with iptables, wildcard matching on interface name prefixes is available for \fBiifname\fR and \fBoifname\fR matches by appending an asterisk (*) character\&. Note however that unlike iptables, nftables does not accept interface names consisting of the wildcard character only \- users are supposed to just skip those always matching expressions\&. In order to match on literal asterisk character, one may escape it using backslash (\e)\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&30.\ \&Meta expression types
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+length
+T}:T{
+.sp
+Length of the packet in bytes
+T}:T{
+.sp
+integer (32\-bit)
+T}
+T{
+.sp
+nfproto
+T}:T{
+.sp
+real hook protocol family, useful only in inet table
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+l4proto
+T}:T{
+.sp
+layer 4 protocol, skips ipv6 extension headers
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+protocol
+T}:T{
+.sp
+EtherType protocol value
+T}:T{
+.sp
+ether_type
+T}
+T{
+.sp
+priority
+T}:T{
+.sp
+TC packet priority
+T}:T{
+.sp
+tc_handle
+T}
+T{
+.sp
+mark
+T}:T{
+.sp
+Packet mark
+T}:T{
+.sp
+mark
+T}
+T{
+.sp
+iif
+T}:T{
+.sp
+Input interface index
+T}:T{
+.sp
+iface_index
+T}
+T{
+.sp
+iifname
+T}:T{
+.sp
+Input interface name
+T}:T{
+.sp
+ifname
+T}
+T{
+.sp
+iiftype
+T}:T{
+.sp
+Input interface type
+T}:T{
+.sp
+iface_type
+T}
+T{
+.sp
+oif
+T}:T{
+.sp
+Output interface index
+T}:T{
+.sp
+iface_index
+T}
+T{
+.sp
+oifname
+T}:T{
+.sp
+Output interface name
+T}:T{
+.sp
+ifname
+T}
+T{
+.sp
+oiftype
+T}:T{
+.sp
+Output interface hardware type
+T}:T{
+.sp
+iface_type
+T}
+T{
+.sp
+sdif
+T}:T{
+.sp
+Slave device input interface index
+T}:T{
+.sp
+iface_index
+T}
+T{
+.sp
+sdifname
+T}:T{
+.sp
+Slave device interface name
+T}:T{
+.sp
+ifname
+T}
+T{
+.sp
+skuid
+T}:T{
+.sp
+UID associated with originating socket
+T}:T{
+.sp
+uid
+T}
+T{
+.sp
+skgid
+T}:T{
+.sp
+GID associated with originating socket
+T}:T{
+.sp
+gid
+T}
+T{
+.sp
+rtclassid
+T}:T{
+.sp
+Routing realm
+T}:T{
+.sp
+realm
+T}
+T{
+.sp
+ibrname
+T}:T{
+.sp
+Input bridge interface name
+T}:T{
+.sp
+ifname
+T}
+T{
+.sp
+obrname
+T}:T{
+.sp
+Output bridge interface name
+T}:T{
+.sp
+ifname
+T}
+T{
+.sp
+pkttype
+T}:T{
+.sp
+packet type
+T}:T{
+.sp
+pkt_type
+T}
+T{
+.sp
+cpu
+T}:T{
+.sp
+cpu number processing the packet
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+iifgroup
+T}:T{
+.sp
+incoming device group
+T}:T{
+.sp
+devgroup
+T}
+T{
+.sp
+oifgroup
+T}:T{
+.sp
+outgoing device group
+T}:T{
+.sp
+devgroup
+T}
+T{
+.sp
+cgroup
+T}:T{
+.sp
+control group id
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+random
+T}:T{
+.sp
+pseudo\-random number
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+ipsec
+T}:T{
+.sp
+true if packet was ipsec encrypted
+T}:T{
+.sp
+boolean (1 bit)
+T}
+T{
+.sp
+iifkind
+T}:T{
+.sp
+Input interface kind
+T}:T{
+.sp
+T}
+T{
+.sp
+oifkind
+T}:T{
+.sp
+Output interface kind
+T}:T{
+.sp
+T}
+T{
+.sp
+time
+T}:T{
+.sp
+Absolute time of packet reception
+T}:T{
+.sp
+Integer (32 bit) or string
+T}
+T{
+.sp
+day
+T}:T{
+.sp
+Day of week
+T}:T{
+.sp
+Integer (8 bit) or string
+T}
+T{
+.sp
+hour
+T}:T{
+.sp
+Hour of day
+T}:T{
+.sp
+String
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&31.\ \&Meta expression specific types
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Type
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+iface_index
+T}:T{
+.sp
+Interface index (32 bit number)\&. Can be specified numerically or as name of an existing interface\&.
+T}
+T{
+.sp
+ifname
+T}:T{
+.sp
+Interface name (16 byte string)\&. Does not have to exist\&.
+T}
+T{
+.sp
+iface_type
+T}:T{
+.sp
+Interface type (16 bit number)\&.
+T}
+T{
+.sp
+uid
+T}:T{
+.sp
+User ID (32 bit number)\&. Can be specified numerically or as user name\&.
+T}
+T{
+.sp
+gid
+T}:T{
+.sp
+Group ID (32 bit number)\&. Can be specified numerically or as group name\&.
+T}
+T{
+.sp
+realm
+T}:T{
+.sp
+Routing Realm (32 bit number)\&. Can be specified numerically or as symbolic name defined in /etc/iproute2/rt_realms\&.
+T}
+T{
+.sp
+devgroup_type
+T}:T{
+.sp
+Device group (32 bit number)\&. Can be specified numerically or as symbolic name defined in /etc/iproute2/group\&.
+T}
+T{
+.sp
+pkt_type
+T}:T{
+.sp
+Packet type: \fBhost\fR (addressed to local host), \fBbroadcast\fR (to all), \fBmulticast\fR (to group), \fBother\fR (addressed to another host)\&.
+T}
+T{
+.sp
+ifkind
+T}:T{
+.sp
+Interface kind (16 byte string)\&. See TYPES in ip\-link(8) for a list\&.
+T}
+T{
+.sp
+time
+T}:T{
+.sp
+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"\&. When an integer is given, it is assumed to be a UNIX timestamp\&.
+T}
+T{
+.sp
+day
+T}:T{
+.sp
+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\&.
+T}
+T{
+.sp
+hour
+T}:T{
+.sp
+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\&.
+T}
+.TE
+.sp 1
+.PP
+\fBUsing meta expressions\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# qualified meta expression
+filter output meta oif eth0
+filter forward meta iifkind { "tun", "veth" }
+
+# unqualified meta expression
+filter output oif eth0
+
+# incoming packet was subject to ipsec processing
+raw prerouting meta ipsec exists accept
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "SOCKET EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBsocket\fR {\fBtransparent\fR | \fBmark\fR | \fBwildcard\fR}
+\fBsocket\fR \fBcgroupv2\fR \fBlevel\fR \fINUM\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Socket expression can be used to search for an existing open TCP/UDP socket and its attributes that can be associated with a packet\&. It looks for an established or non\-zero bound listening socket (possibly with a non\-local address)\&. You can also use it to match on the socket cgroupv2 at a given ancestor level, e\&.g\&. if the socket belongs to cgroupv2 \fIa/b\fR, ancestor level 1 checks for a matching on cgroup \fIa\fR and ancestor level 2 checks for a matching on cgroup \fIb\fR\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&32.\ \&Available socket attributes
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Name
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+transparent
+T}:T{
+.sp
+Value of the IP_TRANSPARENT socket option in the found socket\&. It can be 0 or 1\&.
+T}:T{
+.sp
+boolean (1 bit)
+T}
+T{
+.sp
+mark
+T}:T{
+.sp
+Value of the socket mark (SOL_SOCKET, SO_MARK)\&.
+T}:T{
+.sp
+mark
+T}
+T{
+.sp
+wildcard
+T}:T{
+.sp
+Indicates whether the socket is wildcard\-bound (e\&.g\&. 0\&.0\&.0\&.0 or ::0)\&.
+T}:T{
+.sp
+boolean (1 bit)
+T}
+T{
+.sp
+cgroupv2
+T}:T{
+.sp
+cgroup version 2 for this socket (path from /sys/fs/cgroup)
+T}:T{
+.sp
+cgroupv2
+T}
+.TE
+.sp 1
+.PP
+\fBUsing socket expression\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# Mark packets that correspond to a transparent socket\&. "socket wildcard 0"
+# means that zero\-bound listener sockets are NOT matched (which is usually
+# exactly what you want)\&.
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ socket transparent 1 socket wildcard 0 mark set 0x00000001 accept
+ }
+}
+
+# Trace packets that corresponds to a socket with a mark value of 15
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ socket mark 0x0000000f nftrace set 1
+ }
+}
+
+# Set packet mark to socket mark
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport 8080 mark set socket mark
+ }
+}
+
+# Count packets for cgroupv2 "user\&.slice" at level 1
+table inet x {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ socket cgroupv2 level 1 "user\&.slice" counter
+ }
+}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "OSF EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBosf\fR [\fBttl\fR {\fBloose\fR | \fBskip\fR}] {\fBname\fR | \fBversion\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The osf expression does passive operating system fingerprinting\&. This expression compares some data (Window Size, MSS, options and their order, DF, and others) from packets with the SYN bit set\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&33.\ \&Available osf attributes
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Name
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+ttl
+T}:T{
+.sp
+Do TTL checks on the packet to determine the operating system\&.
+T}:T{
+.sp
+string
+T}
+T{
+.sp
+version
+T}:T{
+.sp
+Do OS version checks on the packet\&.
+T}:T{
+.sp
+T}
+T{
+.sp
+name
+T}:T{
+.sp
+Name of the OS signature to match\&. All signatures can be found at pf\&.os file\&. Use "unknown" for OS signatures that the expression could not detect\&.
+T}:T{
+.sp
+string
+T}
+.TE
+.sp 1
+.PP
+\fBAvailable ttl values\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+If no TTL attribute is passed, make a true IP header and fingerprint TTL true comparison\&. This generally works for LANs\&.
+
+* loose: Check if the IP header\*(Aqs TTL is less than the fingerprint one\&. Works for globally\-routable addresses\&.
+* skip: Do not compare the TTL at all\&.
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBUsing osf expression\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# Accept packets that match the "Linux" OS genre signature without comparing TTL\&.
+table inet x {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ osf ttl skip name "Linux"
+ }
+}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "FIB EXPRESSIONS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfib\fR {\fBsaddr\fR | \fBdaddr\fR | \fBmark\fR | \fBiif\fR | \fBoif\fR} [\fB\&.\fR \&...] {\fBoif\fR | \fBoifname\fR | \fBtype\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A fib expression queries the fib (forwarding information base) to obtain information such as the output interface index a particular address would use\&. The input is a tuple of elements that is used as input to the fib lookup functions\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&34.\ \&fib expression specific types
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+oif
+T}:T{
+.sp
+Output interface index
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+oifname
+T}:T{
+.sp
+Output interface name
+T}:T{
+.sp
+string
+T}
+T{
+.sp
+type
+T}:T{
+.sp
+Address type
+T}:T{
+.sp
+fib_addrtype
+T}
+.TE
+.sp 1
+.sp
+Use \fBnft\fR \fBdescribe\fR \fBfib_addrtype\fR to get a list of all address types\&.
+.PP
+\fBUsing fib expressions\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# drop packets without a reverse path
+filter prerouting fib saddr \&. iif oif missing drop
+
+In this example, \*(Aqsaddr \&. iif\*(Aq looks up routing information based on the source address and the input interface\&.
+oif picks the output interface index from the routing information\&.
+If no route was found for the source address/input interface combination, the output interface index is zero\&.
+In case the input interface is specified as part of the input key, the output interface index is always the same as the input interface index or zero\&.
+If only \*(Aqsaddr oif\*(Aq is given, then oif can be any interface index or zero\&.
+
+# drop packets to address not configured on incoming interface
+filter prerouting fib daddr \&. iif type != { local, broadcast, multicast } drop
+
+# perform lookup in a specific \*(Aqblackhole\*(Aq table (0xdead, needs ip appropriate ip rule)
+filter prerouting meta mark set 0xdead fib daddr \&. mark type vmap { blackhole : drop, prohibit : jump prohibited, unreachable : drop }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "ROUTING EXPRESSIONS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBrt\fR [\fBip\fR | \fBip6\fR] {\fBclassid\fR | \fBnexthop\fR | \fBmtu\fR | \fBipsec\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A routing expression refers to routing data associated with a packet\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&35.\ \&Routing expression types
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+classid
+T}:T{
+.sp
+Routing realm
+T}:T{
+.sp
+realm
+T}
+T{
+.sp
+nexthop
+T}:T{
+.sp
+Routing nexthop
+T}:T{
+.sp
+ipv4_addr/ipv6_addr
+T}
+T{
+.sp
+mtu
+T}:T{
+.sp
+TCP maximum segment size of route
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+ipsec
+T}:T{
+.sp
+route via ipsec tunnel or transport
+T}:T{
+.sp
+boolean
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&36.\ \&Routing expression specific types
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Type
+T}:T{
+Description
+T}
+.T&
+lt lt.
+T{
+.sp
+realm
+T}:T{
+.sp
+Routing Realm (32 bit number)\&. Can be specified numerically or as symbolic name defined in /etc/iproute2/rt_realms\&.
+T}
+.TE
+.sp 1
+.PP
+\fBUsing routing expressions\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# IP family independent rt expression
+filter output rt classid 10
+
+# IP family dependent rt expressions
+ip filter output rt nexthop 192\&.168\&.0\&.1
+ip6 filter output rt nexthop fd00::1
+inet filter output rt ip nexthop 192\&.168\&.0\&.1
+inet filter output rt ip6 nexthop fd00::1
+
+# outgoing packet will be encapsulated/encrypted by ipsec
+filter output rt ipsec exists
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "IPSEC EXPRESSIONS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBipsec\fR {\fBin\fR | \fBout\fR} [ \fBspnum\fR \fINUM\fR ] {\fBreqid\fR | \fBspi\fR}
+\fBipsec\fR {\fBin\fR | \fBout\fR} [ \fBspnum\fR \fINUM\fR ] {\fBip\fR | \fBip6\fR} {\fBsaddr\fR | \fBdaddr\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+An ipsec expression refers to ipsec data associated with a packet\&.
+.sp
+The \fIin\fR or \fIout\fR keyword needs to be used to specify if the expression should examine inbound or outbound policies\&. The \fIin\fR keyword can be used in the prerouting, input and forward hooks\&. The \fIout\fR keyword applies to forward, output and postrouting hooks\&. The optional keyword spnum can be used to match a specific state in a chain, it defaults to 0\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&37.\ \&Ipsec expression types
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+reqid
+T}:T{
+.sp
+Request ID
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+spi
+T}:T{
+.sp
+Security Parameter Index
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+saddr
+T}:T{
+.sp
+Source address of the tunnel
+T}:T{
+.sp
+ipv4_addr/ipv6_addr
+T}
+T{
+.sp
+daddr
+T}:T{
+.sp
+Destination address of the tunnel
+T}:T{
+.sp
+ipv4_addr/ipv6_addr
+T}
+.TE
+.sp 1
+.sp
+\fBNote:\fR 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\&.
+.SS "NUMGEN EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBnumgen\fR {\fBinc\fR | \fBrandom\fR} \fBmod\fR \fINUM\fR [ \fBoffset\fR \fINUM\fR ]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a number generator\&. The \fBinc\fR or \fBrandom\fR keywords control its operation mode: In \fBinc\fR mode, the last returned value is simply incremented\&. In \fBrandom\fR mode, a new random number is returned\&. The value after \fBmod\fR keyword specifies an upper boundary (read: modulus) which is not reached by returned numbers\&. The optional \fBoffset\fR allows one to increment the returned value by a fixed offset\&.
+.sp
+A typical use\-case for \fBnumgen\fR is load\-balancing:
+.PP
+\fBUsing numgen expression\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# round\-robin between 192\&.168\&.10\&.100 and 192\&.168\&.20\&.200:
+add rule nat prerouting dnat to numgen inc mod 2 map \e
+ { 0 : 192\&.168\&.10\&.100, 1 : 192\&.168\&.20\&.200 }
+
+# probability\-based with odd bias using intervals:
+add rule nat prerouting dnat to numgen random mod 10 map \e
+ { 0\-2 : 192\&.168\&.10\&.100, 3\-9 : 192\&.168\&.20\&.200 }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "HASH EXPRESSIONS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBjhash\fR {\fBip saddr\fR | \fBip6 daddr\fR | \fBtcp dport\fR | \fBudp sport\fR | \fBether saddr\fR} [\fB\&.\fR \&...] \fBmod\fR \fINUM\fR [ \fBseed\fR \fINUM\fR ] [ \fBoffset\fR \fINUM\fR ]
+\fBsymhash\fR \fBmod\fR \fINUM\fR [ \fBoffset\fR \fINUM\fR ]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Use a hashing function to generate a number\&. The functions available are \fBjhash\fR, known as Jenkins Hash, and \fBsymhash\fR, for Symmetric Hash\&. The \fBjhash\fR requires an expression to determine the parameters of the packet header to apply the hashing, concatenations are possible as well\&. The value after \fBmod\fR keyword specifies an upper boundary (read: modulus) which is not reached by returned numbers\&. The optional \fBseed\fR is used to specify an init value used as seed in the hashing function\&. The optional \fBoffset\fR allows one to increment the returned value by a fixed offset\&.
+.sp
+A typical use\-case for \fBjhash\fR and \fBsymhash\fR is load\-balancing:
+.PP
+\fBUsing hash expressions\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# load balance based on source ip between 2 ip addresses:
+add rule nat prerouting dnat to jhash ip saddr mod 2 map \e
+ { 0 : 192\&.168\&.10\&.100, 1 : 192\&.168\&.20\&.200 }
+
+# symmetric load balancing between 2 ip addresses:
+add rule nat prerouting dnat to symhash mod 2 map \e
+ { 0 : 192\&.168\&.10\&.100, 1 : 192\&.168\&.20\&.200 }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "PAYLOAD EXPRESSIONS"
+.sp
+Payload expressions refer to data from the packet\(cqs payload\&.
+.SS "ETHERNET HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBether\fR {\fBdaddr\fR | \fBsaddr\fR | \fBtype\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&38.\ \&Ethernet header expression types
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+daddr
+T}:T{
+.sp
+Destination MAC address
+T}:T{
+.sp
+ether_addr
+T}
+T{
+.sp
+saddr
+T}:T{
+.sp
+Source MAC address
+T}:T{
+.sp
+ether_addr
+T}
+T{
+.sp
+type
+T}:T{
+.sp
+EtherType
+T}:T{
+.sp
+ether_type
+T}
+.TE
+.sp 1
+.SS "VLAN HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvlan\fR {\fBid\fR | \fBdei\fR | \fBpcp\fR | \fBtype\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The vlan expression is used to match on the vlan header fields\&. This expression will not work in the \fBip\fR, \fBip6\fR and \fBinet\fR families, unless the vlan interface is configured with the \fBreorder_hdr off\fR setting\&. The default is \fBreorder_hdr on\fR 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 \fBmeta iif\fR or \fBmeta iifname\fR expression\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&39.\ \&VLAN header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+id
+T}:T{
+.sp
+VLAN ID (VID)
+T}:T{
+.sp
+integer (12 bit)
+T}
+T{
+.sp
+dei
+T}:T{
+.sp
+Drop Eligible Indicator
+T}:T{
+.sp
+integer (1 bit)
+T}
+T{
+.sp
+pcp
+T}:T{
+.sp
+Priority code point
+T}:T{
+.sp
+integer (3 bit)
+T}
+T{
+.sp
+type
+T}:T{
+.sp
+EtherType
+T}:T{
+.sp
+ether_type
+T}
+.TE
+.sp 1
+.SS "ARP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBarp\fR {\fBhtype\fR | \fBptype\fR | \fBhlen\fR | \fBplen\fR | \fBoperation\fR | \fBsaddr\fR { \fBip\fR | \fBether\fR } | \fBdaddr\fR { \fBip\fR | \fBether\fR }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&40.\ \&ARP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+htype
+T}:T{
+.sp
+ARP hardware type
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+ptype
+T}:T{
+.sp
+EtherType
+T}:T{
+.sp
+ether_type
+T}
+T{
+.sp
+hlen
+T}:T{
+.sp
+Hardware address len
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+plen
+T}:T{
+.sp
+Protocol address len
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+operation
+T}:T{
+.sp
+Operation
+T}:T{
+.sp
+arp_op
+T}
+T{
+.sp
+saddr ether
+T}:T{
+.sp
+Ethernet sender address
+T}:T{
+.sp
+ether_addr
+T}
+T{
+.sp
+daddr ether
+T}:T{
+.sp
+Ethernet target address
+T}:T{
+.sp
+ether_addr
+T}
+T{
+.sp
+saddr ip
+T}:T{
+.sp
+IPv4 sender address
+T}:T{
+.sp
+ipv4_addr
+T}
+T{
+.sp
+daddr ip
+T}:T{
+.sp
+IPv4 target address
+T}:T{
+.sp
+ipv4_addr
+T}
+.TE
+.sp 1
+.SS "IPV4 HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBip\fR {\fBversion\fR | \fBhdrlength\fR | \fBdscp\fR | \fBecn\fR | \fBlength\fR | \fBid\fR | \fBfrag\-off\fR | \fBttl\fR | \fBprotocol\fR | \fBchecksum\fR | \fBsaddr\fR | \fBdaddr\fR }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&41.\ \&IPv4 header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+version
+T}:T{
+.sp
+IP header version (4)
+T}:T{
+.sp
+integer (4 bit)
+T}
+T{
+.sp
+hdrlength
+T}:T{
+.sp
+IP header length including options
+T}:T{
+.sp
+integer (4 bit) FIXME scaling
+T}
+T{
+.sp
+dscp
+T}:T{
+.sp
+Differentiated Services Code Point
+T}:T{
+.sp
+dscp
+T}
+T{
+.sp
+ecn
+T}:T{
+.sp
+Explicit Congestion Notification
+T}:T{
+.sp
+ecn
+T}
+T{
+.sp
+length
+T}:T{
+.sp
+Total packet length
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+id
+T}:T{
+.sp
+IP ID
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+frag\-off
+T}:T{
+.sp
+Fragment offset
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+ttl
+T}:T{
+.sp
+Time to live
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+protocol
+T}:T{
+.sp
+Upper layer protocol
+T}:T{
+.sp
+inet_proto
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+IP header checksum
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+saddr
+T}:T{
+.sp
+Source address
+T}:T{
+.sp
+ipv4_addr
+T}
+T{
+.sp
+daddr
+T}:T{
+.sp
+Destination address
+T}:T{
+.sp
+ipv4_addr
+T}
+.TE
+.sp 1
+.sp
+Careful with matching on \fBip length\fR: 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 \fBip length\fR might be 0 for such jumbo packets\&. \fBmeta length\fR allows you to match on the packet length including the IP header size\&. If you want to perform heuristics on the \fBip length\fR field, then disable GRO/GSO\&.
+.SS "ICMP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBicmp\fR {\fBtype\fR | \fBcode\fR | \fBchecksum\fR | \fBid\fR | \fBsequence\fR | \fBgateway\fR | \fBmtu\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This expression refers to ICMP header fields\&. When using it in \fBinet\fR, \fBbridge\fR or \fBnetdev\fR families, it will cause an implicit dependency on IPv4 to be created\&. To match on unusual cases like ICMP over IPv6, one has to add an explicit \fBmeta protocol ip6\fR match to the rule\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&42.\ \&ICMP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+type
+T}:T{
+.sp
+ICMP type field
+T}:T{
+.sp
+icmp_type
+T}
+T{
+.sp
+code
+T}:T{
+.sp
+ICMP code field
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+ICMP checksum field
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+id
+T}:T{
+.sp
+ID of echo request/response
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+sequence
+T}:T{
+.sp
+sequence number of echo request/response
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+gateway
+T}:T{
+.sp
+gateway of redirects
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+mtu
+T}:T{
+.sp
+MTU of path MTU discovery
+T}:T{
+.sp
+integer (16 bit)
+T}
+.TE
+.sp 1
+.SS "IGMP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBigmp\fR {\fBtype\fR | \fBmrt\fR | \fBchecksum\fR | \fBgroup\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This expression refers to IGMP header fields\&. When using it in \fBinet\fR, \fBbridge\fR or \fBnetdev\fR families, it will cause an implicit dependency on IPv4 to be created\&. To match on unusual cases like IGMP over IPv6, one has to add an explicit \fBmeta protocol ip6\fR match to the rule\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&43.\ \&IGMP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+type
+T}:T{
+.sp
+IGMP type field
+T}:T{
+.sp
+igmp_type
+T}
+T{
+.sp
+mrt
+T}:T{
+.sp
+IGMP maximum response time field
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+IGMP checksum field
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+group
+T}:T{
+.sp
+Group address
+T}:T{
+.sp
+integer (32 bit)
+T}
+.TE
+.sp 1
+.SS "IPV6 HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBip6\fR {\fBversion\fR | \fBdscp\fR | \fBecn\fR | \fBflowlabel\fR | \fBlength\fR | \fBnexthdr\fR | \fBhoplimit\fR | \fBsaddr\fR | \fBdaddr\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This expression refers to the ipv6 header fields\&. Caution when using \fBip6 nexthdr\fR, the value only refers to the next header, i\&.e\&. \fBip6 nexthdr tcp\fR will only match if the ipv6 packet does not contain any extension headers\&. Packets that are fragmented or e\&.g\&. contain a routing extension headers will not be matched\&. Please use \fBmeta l4proto\fR if you wish to match the real transport header and ignore any additional extension headers instead\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&44.\ \&IPv6 header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+version
+T}:T{
+.sp
+IP header version (6)
+T}:T{
+.sp
+integer (4 bit)
+T}
+T{
+.sp
+dscp
+T}:T{
+.sp
+Differentiated Services Code Point
+T}:T{
+.sp
+dscp
+T}
+T{
+.sp
+ecn
+T}:T{
+.sp
+Explicit Congestion Notification
+T}:T{
+.sp
+ecn
+T}
+T{
+.sp
+flowlabel
+T}:T{
+.sp
+Flow label
+T}:T{
+.sp
+integer (20 bit)
+T}
+T{
+.sp
+length
+T}:T{
+.sp
+Payload length
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+nexthdr
+T}:T{
+.sp
+Nexthdr protocol
+T}:T{
+.sp
+inet_proto
+T}
+T{
+.sp
+hoplimit
+T}:T{
+.sp
+Hop limit
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+saddr
+T}:T{
+.sp
+Source address
+T}:T{
+.sp
+ipv6_addr
+T}
+T{
+.sp
+daddr
+T}:T{
+.sp
+Destination address
+T}:T{
+.sp
+ipv6_addr
+T}
+.TE
+.sp 1
+.sp
+Careful with matching on \fBip6 length\fR: 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 \fBip6 length\fR might be 0 for such jumbo packets\&. \fBmeta length\fR allows you to match on the packet length including the IP header size\&. If you want to perform heuristics on the \fBip6 length\fR field, then disable GRO/GSO\&.
+.PP
+\fBUsing ip6 header expressions\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# matching if first extension header indicates a fragment
+ip6 nexthdr ipv6\-frag
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "ICMPV6 HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBicmpv6\fR {\fBtype\fR | \fBcode\fR | \fBchecksum\fR | \fBparameter\-problem\fR | \fBpacket\-too\-big\fR | \fBid\fR | \fBsequence\fR | \fBmax\-delay\fR | \fBtaddr\fR | \fBdaddr\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This expression refers to ICMPv6 header fields\&. When using it in \fBinet\fR, \fBbridge\fR or \fBnetdev\fR families, it will cause an implicit dependency on IPv6 to be created\&. To match on unusual cases like ICMPv6 over IPv4, one has to add an explicit \fBmeta protocol ip\fR match to the rule\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&45.\ \&ICMPv6 header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+type
+T}:T{
+.sp
+ICMPv6 type field
+T}:T{
+.sp
+icmpv6_type
+T}
+T{
+.sp
+code
+T}:T{
+.sp
+ICMPv6 code field
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+ICMPv6 checksum field
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+parameter\-problem
+T}:T{
+.sp
+pointer to problem
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+packet\-too\-big
+T}:T{
+.sp
+oversized MTU
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+id
+T}:T{
+.sp
+ID of echo request/response
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+sequence
+T}:T{
+.sp
+sequence number of echo request/response
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+max\-delay
+T}:T{
+.sp
+maximum response delay of MLD queries
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+taddr
+T}:T{
+.sp
+target address of neighbor solicit/advert, redirect or MLD
+T}:T{
+.sp
+ipv6_addr
+T}
+T{
+.sp
+daddr
+T}:T{
+.sp
+destination address of redirect
+T}:T{
+.sp
+ipv6_addr
+T}
+.TE
+.sp 1
+.SS "TCP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBtcp\fR {\fBsport\fR | \fBdport\fR | \fBsequence\fR | \fBackseq\fR | \fBdoff\fR | \fBreserved\fR | \fBflags\fR | \fBwindow\fR | \fBchecksum\fR | \fBurgptr\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&46.\ \&TCP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+sport
+T}:T{
+.sp
+Source port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+dport
+T}:T{
+.sp
+Destination port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+sequence
+T}:T{
+.sp
+Sequence number
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+ackseq
+T}:T{
+.sp
+Acknowledgement number
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+doff
+T}:T{
+.sp
+Data offset
+T}:T{
+.sp
+integer (4 bit) FIXME scaling
+T}
+T{
+.sp
+reserved
+T}:T{
+.sp
+Reserved area
+T}:T{
+.sp
+integer (4 bit)
+T}
+T{
+.sp
+flags
+T}:T{
+.sp
+TCP flags
+T}:T{
+.sp
+tcp_flag
+T}
+T{
+.sp
+window
+T}:T{
+.sp
+Window
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+Checksum
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+urgptr
+T}:T{
+.sp
+Urgent pointer
+T}:T{
+.sp
+integer (16 bit)
+T}
+.TE
+.sp 1
+.SS "UDP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBudp\fR {\fBsport\fR | \fBdport\fR | \fBlength\fR | \fBchecksum\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&47.\ \&UDP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+sport
+T}:T{
+.sp
+Source port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+dport
+T}:T{
+.sp
+Destination port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+length
+T}:T{
+.sp
+Total packet length
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+Checksum
+T}:T{
+.sp
+integer (16 bit)
+T}
+.TE
+.sp 1
+.SS "UDP\-LITE HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBudplite\fR {\fBsport\fR | \fBdport\fR | \fBchecksum\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&48.\ \&UDP\-Lite header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+sport
+T}:T{
+.sp
+Source port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+dport
+T}:T{
+.sp
+Destination port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+Checksum
+T}:T{
+.sp
+integer (16 bit)
+T}
+.TE
+.sp 1
+.SS "SCTP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBsctp\fR {\fBsport\fR | \fBdport\fR | \fBvtag\fR | \fBchecksum\fR}
+\fBsctp chunk\fR \fICHUNK\fR [ \fIFIELD\fR ]
+
+\fICHUNK\fR := \fBdata\fR | \fBinit\fR | \fBinit\-ack\fR | \fBsack\fR | \fBheartbeat\fR |
+ \fBheartbeat\-ack\fR | \fBabort\fR | \fBshutdown\fR | \fBshutdown\-ack\fR | \fBerror\fR |
+ \fBcookie\-echo\fR | \fBcookie\-ack\fR | \fBecne\fR | \fBcwr\fR | \fBshutdown\-complete\fR
+ | \fBasconf\-ack\fR | \fBforward\-tsn\fR | \fBasconf\fR
+
+\fIFIELD\fR := \fICOMMON_FIELD\fR | \fIDATA_FIELD\fR | \fIINIT_FIELD\fR | \fIINIT_ACK_FIELD\fR |
+ \fISACK_FIELD\fR | \fISHUTDOWN_FIELD\fR | \fIECNE_FIELD\fR | \fICWR_FIELD\fR |
+ \fIASCONF_ACK_FIELD\fR | \fIFORWARD_TSN_FIELD\fR | \fIASCONF_FIELD\fR
+
+\fICOMMON_FIELD\fR := \fBtype\fR | \fBflags\fR | \fBlength\fR
+\fIDATA_FIELD\fR := \fBtsn\fR | \fBstream\fR | \fBssn\fR | \fBppid\fR
+\fIINIT_FIELD\fR := \fBinit\-tag\fR | \fBa\-rwnd\fR | \fBnum\-outbound\-streams\fR |
+ \fBnum\-inbound\-streams\fR | \fBinitial\-tsn\fR
+\fIINIT_ACK_FIELD\fR := \fIINIT_FIELD\fR
+\fISACK_FIELD\fR := \fBcum\-tsn\-ack\fR | \fBa\-rwnd\fR | \fBnum\-gap\-ack\-blocks\fR |
+ \fBnum\-dup\-tsns\fR
+\fISHUTDOWN_FIELD\fR := \fBcum\-tsn\-ack\fR
+\fIECNE_FIELD\fR := \fBlowest\-tsn\fR
+\fICWR_FIELD\fR := \fBlowest\-tsn\fR
+\fIASCONF_ACK_FIELD\fR := \fBseqno\fR
+\fIFORWARD_TSN_FIELD\fR := \fBnew\-cum\-tsn\fR
+\fIASCONF_FIELD\fR := \fBseqno\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&49.\ \&SCTP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+sport
+T}:T{
+.sp
+Source port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+dport
+T}:T{
+.sp
+Destination port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+vtag
+T}:T{
+.sp
+Verification Tag
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+checksum
+T}:T{
+.sp
+Checksum
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+chunk
+T}:T{
+.sp
+Search chunk in packet
+T}:T{
+.sp
+without \fIFIELD\fR, boolean indicating existence
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&50.\ \&SCTP chunk fields
+.TS
+allbox tab(:);
+ltB ltB ltB ltB.
+T{
+Name
+T}:T{
+Width in bits
+T}:T{
+Chunk
+T}:T{
+Notes
+T}
+.T&
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt
+lt lt lt lt.
+T{
+.sp
+type
+T}:T{
+.sp
+8
+T}:T{
+.sp
+all
+T}:T{
+.sp
+not useful, defined by chunk type
+T}
+T{
+.sp
+flags
+T}:T{
+.sp
+8
+T}:T{
+.sp
+all
+T}:T{
+.sp
+semantics defined on per\-chunk basis
+T}
+T{
+.sp
+length
+T}:T{
+.sp
+16
+T}:T{
+.sp
+all
+T}:T{
+.sp
+length of this chunk in bytes excluding padding
+T}
+T{
+.sp
+tsn
+T}:T{
+.sp
+32
+T}:T{
+.sp
+data
+T}:T{
+.sp
+transmission sequence number
+T}
+T{
+.sp
+stream
+T}:T{
+.sp
+16
+T}:T{
+.sp
+data
+T}:T{
+.sp
+stream identifier
+T}
+T{
+.sp
+ssn
+T}:T{
+.sp
+16
+T}:T{
+.sp
+data
+T}:T{
+.sp
+stream sequence number
+T}
+T{
+.sp
+ppid
+T}:T{
+.sp
+32
+T}:T{
+.sp
+data
+T}:T{
+.sp
+payload protocol identifier
+T}
+T{
+.sp
+init\-tag
+T}:T{
+.sp
+32
+T}:T{
+.sp
+init, init\-ack
+T}:T{
+.sp
+initiate tag
+T}
+T{
+.sp
+a\-rwnd
+T}:T{
+.sp
+32
+T}:T{
+.sp
+init, init\-ack, sack
+T}:T{
+.sp
+advertised receiver window credit
+T}
+T{
+.sp
+num\-outbound\-streams
+T}:T{
+.sp
+16
+T}:T{
+.sp
+init, init\-ack
+T}:T{
+.sp
+number of outbound streams
+T}
+T{
+.sp
+num\-inbound\-streams
+T}:T{
+.sp
+16
+T}:T{
+.sp
+init, init\-ack
+T}:T{
+.sp
+number of inbound streams
+T}
+T{
+.sp
+initial\-tsn
+T}:T{
+.sp
+32
+T}:T{
+.sp
+init, init\-ack
+T}:T{
+.sp
+initial transmit sequence number
+T}
+T{
+.sp
+cum\-tsn\-ack
+T}:T{
+.sp
+32
+T}:T{
+.sp
+sack, shutdown
+T}:T{
+.sp
+cumulative transmission sequence number acknowledged
+T}
+T{
+.sp
+num\-gap\-ack\-blocks
+T}:T{
+.sp
+16
+T}:T{
+.sp
+sack
+T}:T{
+.sp
+number of Gap Ack Blocks included
+T}
+T{
+.sp
+num\-dup\-tsns
+T}:T{
+.sp
+16
+T}:T{
+.sp
+sack
+T}:T{
+.sp
+number of duplicate transmission sequence numbers received
+T}
+T{
+.sp
+lowest\-tsn
+T}:T{
+.sp
+32
+T}:T{
+.sp
+ecne, cwr
+T}:T{
+.sp
+lowest transmission sequence number
+T}
+T{
+.sp
+seqno
+T}:T{
+.sp
+32
+T}:T{
+.sp
+asconf\-ack, asconf
+T}:T{
+.sp
+sequence number
+T}
+T{
+.sp
+new\-cum\-tsn
+T}:T{
+.sp
+32
+T}:T{
+.sp
+forward\-tsn
+T}:T{
+.sp
+new cumulative transmission sequence number
+T}
+.TE
+.sp 1
+.SS "DCCP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBdccp\fR {\fBsport\fR | \fBdport\fR | \fBtype\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&51.\ \&DCCP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+sport
+T}:T{
+.sp
+Source port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+dport
+T}:T{
+.sp
+Destination port
+T}:T{
+.sp
+inet_service
+T}
+T{
+.sp
+type
+T}:T{
+.sp
+Packet type
+T}:T{
+.sp
+dccp_pkttype
+T}
+.TE
+.sp 1
+.SS "AUTHENTICATION HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBah\fR {\fBnexthdr\fR | \fBhdrlength\fR | \fBreserved\fR | \fBspi\fR | \fBsequence\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&52.\ \&AH header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+nexthdr
+T}:T{
+.sp
+Next header protocol
+T}:T{
+.sp
+inet_proto
+T}
+T{
+.sp
+hdrlength
+T}:T{
+.sp
+AH Header length
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+reserved
+T}:T{
+.sp
+Reserved area
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+spi
+T}:T{
+.sp
+Security Parameter Index
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+sequence
+T}:T{
+.sp
+Sequence number
+T}:T{
+.sp
+integer (32 bit)
+T}
+.TE
+.sp 1
+.SS "ENCRYPTED SECURITY PAYLOAD HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBesp\fR {\fBspi\fR | \fBsequence\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&53.\ \&ESP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt.
+T{
+.sp
+spi
+T}:T{
+.sp
+Security Parameter Index
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+sequence
+T}:T{
+.sp
+Sequence number
+T}:T{
+.sp
+integer (32 bit)
+T}
+.TE
+.sp 1
+.SS "IPCOMP HEADER EXPRESSION"
+.sp
+\fBcomp\fR {\fBnexthdr\fR | \fBflags\fR | \fBcpi\fR}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&54.\ \&IPComp header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+nexthdr
+T}:T{
+.sp
+Next header protocol
+T}:T{
+.sp
+inet_proto
+T}
+T{
+.sp
+flags
+T}:T{
+.sp
+Flags
+T}:T{
+.sp
+bitmask
+T}
+T{
+.sp
+cpi
+T}:T{
+.sp
+compression Parameter Index
+T}:T{
+.sp
+integer (16 bit)
+T}
+.TE
+.sp 1
+.SS "GRE HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBgre\fR {\fBflags\fR | \fBversion\fR | \fBprotocol\fR}
+\fBgre\fR \fBip\fR {\fBversion\fR | \fBhdrlength\fR | \fBdscp\fR | \fBecn\fR | \fBlength\fR | \fBid\fR | \fBfrag\-off\fR | \fBttl\fR | \fBprotocol\fR | \fBchecksum\fR | \fBsaddr\fR | \fBdaddr\fR }
+\fBgre\fR \fBip6\fR {\fBversion\fR | \fBdscp\fR | \fBecn\fR | \fBflowlabel\fR | \fBlength\fR | \fBnexthdr\fR | \fBhoplimit\fR | \fBsaddr\fR | \fBdaddr\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&55.\ \&GRE header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+flags
+T}:T{
+.sp
+checksum, routing, key, sequence and strict source route flags
+T}:T{
+.sp
+integer (5 bit)
+T}
+T{
+.sp
+version
+T}:T{
+.sp
+gre version field, 0 for GRE and 1 for PPTP
+T}:T{
+.sp
+integer (3 bit)
+T}
+T{
+.sp
+protocol
+T}:T{
+.sp
+EtherType of encapsulated packet
+T}:T{
+.sp
+integer (16 bit)
+T}
+.TE
+.sp 1
+.PP
+\fBMatching inner IPv4 destination address encapsulated in gre\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+netdev filter ingress gre ip daddr 9\&.9\&.9\&.9 counter
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "GENEVE HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBgeneve\fR {\fBvni\fR | \fBflags\fR}
+\fBgeneve\fR \fBether\fR {\fBdaddr\fR | \fBsaddr\fR | \fBtype\fR}
+\fBgeneve\fR \fBvlan\fR {\fBid\fR | \fBdei\fR | \fBpcp\fR | \fBtype\fR}
+\fBgeneve\fR \fBip\fR {\fBversion\fR | \fBhdrlength\fR | \fBdscp\fR | \fBecn\fR | \fBlength\fR | \fBid\fR | \fBfrag\-off\fR | \fBttl\fR | \fBprotocol\fR | \fBchecksum\fR | \fBsaddr\fR | \fBdaddr\fR }
+\fBgeneve\fR \fBip6\fR {\fBversion\fR | \fBdscp\fR | \fBecn\fR | \fBflowlabel\fR | \fBlength\fR | \fBnexthdr\fR | \fBhoplimit\fR | \fBsaddr\fR | \fBdaddr\fR}
+\fBgeneve\fR \fBtcp\fR {\fBsport\fR | \fBdport\fR | \fBsequence\fR | \fBackseq\fR | \fBdoff\fR | \fBreserved\fR | \fBflags\fR | \fBwindow\fR | \fBchecksum\fR | \fBurgptr\fR}
+\fBgeneve\fR \fBudp\fR {\fBsport\fR | \fBdport\fR | \fBlength\fR | \fBchecksum\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The geneve expression is used to match on the geneve header fields\&. The geneve header encapsulates a ethernet frame within a \fBudp\fR packet\&. This expression requires that you restrict the matching to \fBudp\fR packets (usually at port 6081 according to IANA\-assigned ports)\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&56.\ \&GENEVE header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt.
+T{
+.sp
+protocol
+T}:T{
+.sp
+EtherType of encapsulated packet
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+vni
+T}:T{
+.sp
+Virtual Network ID (VNI)
+T}:T{
+.sp
+integer (24 bit)
+T}
+.TE
+.sp 1
+.PP
+\fBMatching inner TCP destination port encapsulated in geneve\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+netdev filter ingress udp dport 4789 geneve tcp dport 80 counter
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "GRETAP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBgretap\fR {\fBvni\fR | \fBflags\fR}
+\fBgretap\fR \fBether\fR {\fBdaddr\fR | \fBsaddr\fR | \fBtype\fR}
+\fBgretap\fR \fBvlan\fR {\fBid\fR | \fBdei\fR | \fBpcp\fR | \fBtype\fR}
+\fBgretap\fR \fBip\fR {\fBversion\fR | \fBhdrlength\fR | \fBdscp\fR | \fBecn\fR | \fBlength\fR | \fBid\fR | \fBfrag\-off\fR | \fBttl\fR | \fBprotocol\fR | \fBchecksum\fR | \fBsaddr\fR | \fBdaddr\fR }
+\fBgretap\fR \fBip6\fR {\fBversion\fR | \fBdscp\fR | \fBecn\fR | \fBflowlabel\fR | \fBlength\fR | \fBnexthdr\fR | \fBhoplimit\fR | \fBsaddr\fR | \fBdaddr\fR}
+\fBgretap\fR \fBtcp\fR {\fBsport\fR | \fBdport\fR | \fBsequence\fR | \fBackseq\fR | \fBdoff\fR | \fBreserved\fR | \fBflags\fR | \fBwindow\fR | \fBchecksum\fR | \fBurgptr\fR}
+\fBgretap\fR \fBudp\fR {\fBsport\fR | \fBdport\fR | \fBlength\fR | \fBchecksum\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The gretap expression is used to match on the encapsulated ethernet frame within the gre header\&. Use the \fBgre\fR expression to match on the \fBgre\fR header fields\&.
+.PP
+\fBMatching inner TCP destination port encapsulated in gretap\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+netdev filter ingress gretap tcp dport 80 counter
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "VXLAN HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvxlan\fR {\fBvni\fR | \fBflags\fR}
+\fBvxlan\fR \fBether\fR {\fBdaddr\fR | \fBsaddr\fR | \fBtype\fR}
+\fBvxlan\fR \fBvlan\fR {\fBid\fR | \fBdei\fR | \fBpcp\fR | \fBtype\fR}
+\fBvxlan\fR \fBip\fR {\fBversion\fR | \fBhdrlength\fR | \fBdscp\fR | \fBecn\fR | \fBlength\fR | \fBid\fR | \fBfrag\-off\fR | \fBttl\fR | \fBprotocol\fR | \fBchecksum\fR | \fBsaddr\fR | \fBdaddr\fR }
+\fBvxlan\fR \fBip6\fR {\fBversion\fR | \fBdscp\fR | \fBecn\fR | \fBflowlabel\fR | \fBlength\fR | \fBnexthdr\fR | \fBhoplimit\fR | \fBsaddr\fR | \fBdaddr\fR}
+\fBvxlan\fR \fBtcp\fR {\fBsport\fR | \fBdport\fR | \fBsequence\fR | \fBackseq\fR | \fBdoff\fR | \fBreserved\fR | \fBflags\fR | \fBwindow\fR | \fBchecksum\fR | \fBurgptr\fR}
+\fBvxlan\fR \fBudp\fR {\fBsport\fR | \fBdport\fR | \fBlength\fR | \fBchecksum\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The vxlan expression is used to match on the vxlan header fields\&. The vxlan header encapsulates a ethernet frame within a \fBudp\fR packet\&. This expression requires that you restrict the matching to \fBudp\fR packets (usually at port 4789 according to IANA\-assigned ports)\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&57.\ \&VXLAN header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt.
+T{
+.sp
+flags
+T}:T{
+.sp
+vxlan flags
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+vni
+T}:T{
+.sp
+Virtual Network ID (VNI)
+T}:T{
+.sp
+integer (24 bit)
+T}
+.TE
+.sp 1
+.PP
+\fBMatching inner TCP destination port encapsulated in vxlan\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+netdev filter ingress udp dport 4789 vxlan tcp dport 80 counter
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "ARP HEADER EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBarp\fR {\fBhtype\fR | \fBptype\fR | \fBhlen\fR | \fBplen\fR | \fBoperation\fR | \fBsaddr\fR { \fBip\fR | \fBether\fR } | \fBdaddr\fR { \fBip\fR | \fBether\fR }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&58.\ \&ARP header expression
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+htype
+T}:T{
+.sp
+ARP hardware type
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+ptype
+T}:T{
+.sp
+EtherType
+T}:T{
+.sp
+ether_type
+T}
+T{
+.sp
+hlen
+T}:T{
+.sp
+Hardware address len
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+plen
+T}:T{
+.sp
+Protocol address len
+T}:T{
+.sp
+integer (8 bit)
+T}
+T{
+.sp
+operation
+T}:T{
+.sp
+Operation
+T}:T{
+.sp
+arp_op
+T}
+T{
+.sp
+saddr ether
+T}:T{
+.sp
+Ethernet sender address
+T}:T{
+.sp
+ether_addr
+T}
+T{
+.sp
+daddr ether
+T}:T{
+.sp
+Ethernet target address
+T}:T{
+.sp
+ether_addr
+T}
+T{
+.sp
+saddr ip
+T}:T{
+.sp
+IPv4 sender address
+T}:T{
+.sp
+ipv4_addr
+T}
+T{
+.sp
+daddr ip
+T}:T{
+.sp
+IPv4 target address
+T}:T{
+.sp
+ipv4_addr
+T}
+.TE
+.sp 1
+.SS "RAW PAYLOAD EXPRESSION"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fB@\fR\fIbase\fR\fB,\fR\fIoffset\fR\fB,\fR\fIlength\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The raw payload expression instructs to load \fIlength\fR bits starting at \fIoffset\fR bits\&. Bit 0 refers to the very first bit \(em in the C programming language, this corresponds to the topmost bit, i\&.e\&. 0x80 in case of an octet\&. They are useful to match headers that do not have a human\-readable template expression yet\&. Note that nft will not add dependencies for Raw payload expressions\&. If you e\&.g\&. want to match protocol fields of a transport header with protocol number 5, you need to manually exclude packets that have a different transport header, for instance by using \fBmeta l4proto 5\fR before the raw expression\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&59.\ \&Supported payload protocol bases
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Base
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+ll
+T}:T{
+.sp
+Link layer, for example the Ethernet header
+T}
+T{
+.sp
+nh
+T}:T{
+.sp
+Network header, for example IPv4 or IPv6
+T}
+T{
+.sp
+th
+T}:T{
+.sp
+Transport Header, for example TCP
+T}
+T{
+.sp
+ih
+T}:T{
+.sp
+Inner Header / Payload, i\&.e\&. after the L4 transport level header
+T}
+.TE
+.sp 1
+.PP
+\fBMatching destination port of both UDP and TCP\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+inet filter input meta l4proto {tcp, udp} @th,16,16 { 53, 80 }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The above can also be written as
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+inet filter input meta l4proto {tcp, udp} th dport { 53, 80 }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+it is more convenient, but like the raw expression notation no dependencies are created or checked\&. It is the users responsibility to restrict matching to those header types that have a notion of ports\&. Otherwise, rules using raw expressions will errnously match unrelated packets, e\&.g\&. mis\-interpreting ESP packets SPI field as a port\&.
+.PP
+\fBRewrite arp packet target hardware address if target protocol address matches a given address\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+input meta iifname enp2s0 arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566 accept
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "EXTENSION HEADER EXPRESSIONS"
+.sp
+Extension header expressions refer to data from variable\-sized protocol headers, such as IPv6 extension headers, TCP options and IPv4 options\&.
+.sp
+nftables currently supports matching (finding) a given ipv6 extension header, TCP option or IPv4 option\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBhbh\fR {\fBnexthdr\fR | \fBhdrlength\fR}
+\fBfrag\fR {\fBnexthdr\fR | \fBfrag\-off\fR | \fBmore\-fragments\fR | \fBid\fR}
+\fBrt\fR {\fBnexthdr\fR | \fBhdrlength\fR | \fBtype\fR | \fBseg\-left\fR}
+\fBdst\fR {\fBnexthdr\fR | \fBhdrlength\fR}
+\fBmh\fR {\fBnexthdr\fR | \fBhdrlength\fR | \fBchecksum\fR | \fBtype\fR}
+\fBsrh\fR {\fBflags\fR | \fBtag\fR | \fBsid\fR | \fBseg\-left\fR}
+\fBtcp option\fR {\fBeol\fR | \fBnop\fR | \fBmaxseg\fR | \fBwindow\fR | \fBsack\-perm\fR | \fBsack\fR | \fBsack0\fR | \fBsack1\fR | \fBsack2\fR | \fBsack3\fR | \fBtimestamp\fR} \fItcp_option_field\fR
+\fBip option\fR { lsrr | ra | rr | ssrr } \fIip_option_field\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The following syntaxes are valid only in a relational expression with boolean type on right\-hand side for checking header existence only:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBexthdr\fR {\fBhbh\fR | \fBfrag\fR | \fBrt\fR | \fBdst\fR | \fBmh\fR}
+\fBtcp option\fR {\fBeol\fR | \fBnop\fR | \fBmaxseg\fR | \fBwindow\fR | \fBsack\-perm\fR | \fBsack\fR | \fBsack0\fR | \fBsack1\fR | \fBsack2\fR | \fBsack3\fR | \fBtimestamp\fR}
+\fBip option\fR { lsrr | ra | rr | ssrr }
+\fBdccp option\fR \fIdccp_option_type\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&60.\ \&IPv6 extension headers
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+hbh
+T}:T{
+.sp
+Hop by Hop
+T}
+T{
+.sp
+rt
+T}:T{
+.sp
+Routing Header
+T}
+T{
+.sp
+frag
+T}:T{
+.sp
+Fragmentation header
+T}
+T{
+.sp
+dst
+T}:T{
+.sp
+dst options
+T}
+T{
+.sp
+mh
+T}:T{
+.sp
+Mobility Header
+T}
+T{
+.sp
+srh
+T}:T{
+.sp
+Segment Routing Header
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&61.\ \&TCP Options
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+TCP option fields
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+eol
+T}:T{
+.sp
+End if option list
+T}:T{
+.sp
+\-
+T}
+T{
+.sp
+nop
+T}:T{
+.sp
+1 Byte TCP Nop padding option
+T}:T{
+.sp
+\-
+T}
+T{
+.sp
+maxseg
+T}:T{
+.sp
+TCP Maximum Segment Size
+T}:T{
+.sp
+length, size
+T}
+T{
+.sp
+window
+T}:T{
+.sp
+TCP Window Scaling
+T}:T{
+.sp
+length, count
+T}
+T{
+.sp
+sack\-perm
+T}:T{
+.sp
+TCP SACK permitted
+T}:T{
+.sp
+length
+T}
+T{
+.sp
+sack
+T}:T{
+.sp
+TCP Selective Acknowledgement (alias of block 0)
+T}:T{
+.sp
+length, left, right
+T}
+T{
+.sp
+sack0
+T}:T{
+.sp
+TCP Selective Acknowledgement (block 0)
+T}:T{
+.sp
+length, left, right
+T}
+T{
+.sp
+sack1
+T}:T{
+.sp
+TCP Selective Acknowledgement (block 1)
+T}:T{
+.sp
+length, left, right
+T}
+T{
+.sp
+sack2
+T}:T{
+.sp
+TCP Selective Acknowledgement (block 2)
+T}:T{
+.sp
+length, left, right
+T}
+T{
+.sp
+sack3
+T}:T{
+.sp
+TCP Selective Acknowledgement (block 3)
+T}:T{
+.sp
+length, left, right
+T}
+T{
+.sp
+timestamp
+T}:T{
+.sp
+TCP Timestamps
+T}:T{
+.sp
+length, tsval, tsecr
+T}
+.TE
+.sp 1
+.sp
+TCP option matching also supports raw expression syntax to access arbitrary options:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBtcp option\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBtcp option\fR \fB@\fR\fInumber\fR\fB,\fR\fIoffset\fR\fB,\fR\fIlength\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&62.\ \&IP Options
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+IP option fields
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+lsrr
+T}:T{
+.sp
+Loose Source Route
+T}:T{
+.sp
+type, length, ptr, addr
+T}
+T{
+.sp
+ra
+T}:T{
+.sp
+Router Alert
+T}:T{
+.sp
+type, length, value
+T}
+T{
+.sp
+rr
+T}:T{
+.sp
+Record Route
+T}:T{
+.sp
+type, length, ptr, addr
+T}
+T{
+.sp
+ssrr
+T}:T{
+.sp
+Strict Source Route
+T}:T{
+.sp
+type, length, ptr, addr
+T}
+.TE
+.sp 1
+.PP
+\fBfinding TCP options\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+filter input tcp option sack\-perm exists counter
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBmatching TCP options\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+filter input tcp option maxseg size lt 536
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBmatching IPv6 exthdr\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ip6 filter input frag more\-fragments 1 counter
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBfinding IP option\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+filter input ip option lsrr exists counter
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBfinding DCCP option\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+filter input dccp option 40 exists counter
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "CONNTRACK EXPRESSIONS"
+.sp
+Conntrack expressions refer to meta data of the connection tracking entry associated with a packet\&.
+.sp
+There are three types of conntrack expressions\&. Some conntrack expressions require the flow direction before the conntrack key, others must be used directly because they are direction agnostic\&. The \fBpackets\fR, \fBbytes\fR and \fBavgpkt\fR keywords can be used with or without a direction\&. If the direction is omitted, the sum of the original and the reply direction is returned\&. The same is true for the \fBzone\fR, if a direction is given, the zone is only matched if the zone id is tied to the given direction\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBct\fR {\fBstate\fR | \fBdirection\fR | \fBstatus\fR | \fBmark\fR | \fBexpiration\fR | \fBhelper\fR | \fBlabel\fR | \fBcount\fR | \fBid\fR}
+\fBct\fR [\fBoriginal\fR | \fBreply\fR] {\fBl3proto\fR | \fBprotocol\fR | \fBbytes\fR | \fBpackets\fR | \fBavgpkt\fR | \fBzone\fR}
+\fBct\fR {\fBoriginal\fR | \fBreply\fR} {\fBproto\-src\fR | \fBproto\-dst\fR}
+\fBct\fR {\fBoriginal\fR | \fBreply\fR} {\fBip\fR | \fBip6\fR} {\fBsaddr\fR | \fBdaddr\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The conntrack\-specific types in this table are described in the sub\-section CONNTRACK TYPES above\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&63.\ \&Conntrack expressions
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+state
+T}:T{
+.sp
+State of the connection
+T}:T{
+.sp
+ct_state
+T}
+T{
+.sp
+direction
+T}:T{
+.sp
+Direction of the packet relative to the connection
+T}:T{
+.sp
+ct_dir
+T}
+T{
+.sp
+status
+T}:T{
+.sp
+Status of the connection
+T}:T{
+.sp
+ct_status
+T}
+T{
+.sp
+mark
+T}:T{
+.sp
+Connection mark
+T}:T{
+.sp
+mark
+T}
+T{
+.sp
+expiration
+T}:T{
+.sp
+Connection expiration time
+T}:T{
+.sp
+time
+T}
+T{
+.sp
+helper
+T}:T{
+.sp
+Helper associated with the connection
+T}:T{
+.sp
+string
+T}
+T{
+.sp
+label
+T}:T{
+.sp
+Connection tracking label bit or symbolic name defined in connlabel\&.conf in the nftables include path
+T}:T{
+.sp
+ct_label
+T}
+T{
+.sp
+l3proto
+T}:T{
+.sp
+Layer 3 protocol of the connection
+T}:T{
+.sp
+nf_proto
+T}
+T{
+.sp
+saddr
+T}:T{
+.sp
+Source address of the connection for the given direction
+T}:T{
+.sp
+ipv4_addr/ipv6_addr
+T}
+T{
+.sp
+daddr
+T}:T{
+.sp
+Destination address of the connection for the given direction
+T}:T{
+.sp
+ipv4_addr/ipv6_addr
+T}
+T{
+.sp
+protocol
+T}:T{
+.sp
+Layer 4 protocol of the connection for the given direction
+T}:T{
+.sp
+inet_proto
+T}
+T{
+.sp
+proto\-src
+T}:T{
+.sp
+Layer 4 protocol source for the given direction
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+proto\-dst
+T}:T{
+.sp
+Layer 4 protocol destination for the given direction
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+packets
+T}:T{
+.sp
+packet count seen in the given direction or sum of original and reply
+T}:T{
+.sp
+integer (64 bit)
+T}
+T{
+.sp
+bytes
+T}:T{
+.sp
+byte count seen, see description for \fBpackets\fR keyword
+T}:T{
+.sp
+integer (64 bit)
+T}
+T{
+.sp
+avgpkt
+T}:T{
+.sp
+average bytes per packet, see description for \fBpackets\fR keyword
+T}:T{
+.sp
+integer (64 bit)
+T}
+T{
+.sp
+zone
+T}:T{
+.sp
+conntrack zone
+T}:T{
+.sp
+integer (16 bit)
+T}
+T{
+.sp
+count
+T}:T{
+.sp
+number of current connections
+T}:T{
+.sp
+integer (32 bit)
+T}
+T{
+.sp
+id
+T}:T{
+.sp
+Connection id
+T}:T{
+.sp
+ct_id
+T}
+.TE
+.sp 1
+.PP
+\fBrestrict the number of parallel connections to a server\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+nft add set filter ssh_flood \*(Aq{ type ipv4_addr; flags dynamic; }\*(Aq
+nft add rule filter input tcp dport 22 add @ssh_flood \*(Aq{ ip saddr ct count over 2 }\*(Aq reject
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "STATEMENTS"
+.sp
+Statements represent actions to be performed\&. They can alter control flow (return, jump to a different chain, accept or drop the packet) or can perform actions, such as logging, rejecting a packet, etc\&.
+.sp
+Statements exist in two kinds\&. Terminal statements unconditionally terminate evaluation of the current rule, non\-terminal statements either only conditionally or never terminate evaluation of the current rule, in other words, they are passive from the ruleset evaluation perspective\&. There can be an arbitrary amount of non\-terminal statements in a rule, but only a single terminal statement as the final statement\&.
+.SS "VERDICT STATEMENT"
+.sp
+The verdict statement alters control flow in the ruleset and issues policy decisions for packets\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBaccept\fR | \fBdrop\fR | \fBqueue\fR | \fBcontinue\fR | \fBreturn\fR}
+{\fBjump\fR | \fBgoto\fR} \fIchain\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+\fBaccept\fR and \fBdrop\fR are absolute verdicts \(em they terminate ruleset evaluation immediately\&.
+.TS
+tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBaccept\fR
+T}:T{
+.sp
+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 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\&.
+T}
+T{
+.sp
+\fBdrop\fR
+T}:T{
+.sp
+Terminate ruleset evaluation and drop the packet\&. The drop occurs instantly, no further chains or hooks are evaluated\&. It is not possible to accept the packet in a later chain again, as those are not evaluated anymore for the packet\&.
+T}
+T{
+.sp
+\fBqueue\fR
+T}:T{
+.sp
+Terminate ruleset evaluation and queue the packet to userspace\&. Userspace must provide a drop or accept verdict\&. In case of accept, processing resumes with the next base chain hook, not the rule following the queue verdict\&.
+T}
+T{
+.sp
+\fBcontinue\fR
+T}:T{
+.sp
+Continue ruleset evaluation with the next rule\&. This is the default behaviour in case a rule issues no verdict\&.
+T}
+T{
+.sp
+\fBreturn\fR
+T}:T{
+.sp
+Return from the current chain and continue evaluation at the next rule in the last chain\&. If issued in a base chain, it is equivalent to the base chain policy\&.
+T}
+T{
+.sp
+\fBjump\fR \fIchain\fR
+T}:T{
+.sp
+Continue evaluation at the first rule in \fIchain\fR\&. The current position in the ruleset is pushed to a call stack and evaluation will continue there when the new chain is entirely evaluated or a \fBreturn\fR verdict is issued\&. In case an absolute verdict is issued by a rule in the chain, ruleset evaluation terminates immediately and the specific action is taken\&.
+T}
+T{
+.sp
+\fBgoto\fR \fIchain\fR
+T}:T{
+.sp
+Similar to \fBjump\fR, but the current position is not pushed to the call stack, meaning that after the new chain evaluation will continue at the last chain instead of the one containing the goto statement\&.
+T}
+.TE
+.sp 1
+.PP
+\fBUsing verdict statements\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# process packets from eth0 and the internal network in from_lan
+# chain, drop all packets from eth0 with different source addresses\&.
+
+filter input iif eth0 ip saddr 192\&.168\&.0\&.0/24 jump from_lan
+filter input iif eth0 drop
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "PAYLOAD STATEMENT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIpayload_expression\fR \fBset\fR \fIvalue\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The payload statement alters packet content\&. It can be used for example to set ip DSCP (diffserv) header field or ipv6 flow labels\&.
+.PP
+\fBroute some packets instead of bridging\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# redirect tcp:http from 192\&.160\&.0\&.0/16 to local machine for routing instead of bridging
+# assumes 00:11:22:33:44:55 is local MAC address\&.
+bridge input meta iif eth0 ip saddr 192\&.168\&.0\&.0/16 tcp dport 80 meta pkttype set unicast ether daddr set 00:11:22:33:44:55
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBSet IPv4 DSCP header field\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ip forward ip dscp set 42
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "EXTENSION HEADER STATEMENT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIextension_header_expression\fR \fBset\fR \fIvalue\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The extension header statement alters packet content in variable\-sized headers\&. This can currently be used to alter the TCP Maximum segment size of packets, similar to the TCPMSS target in iptables\&.
+.PP
+\fBchange tcp mss\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+tcp flags syn tcp option maxseg size set 1360
+# set a size based on route information:
+tcp flags syn tcp option maxseg size set rt mtu
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+You can also remove tcp options via reset keyword\&.
+.PP
+\fBremove tcp option\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+tcp flags syn reset tcp option sack\-perm
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "LOG STATEMENT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBlog\fR [\fBprefix\fR \fIquoted_string\fR] [\fBlevel\fR \fIsyslog\-level\fR] [\fBflags\fR \fIlog\-flags\fR]
+\fBlog\fR \fBgroup\fR \fInflog_group\fR [\fBprefix\fR \fIquoted_string\fR] [\fBqueue\-threshold\fR \fIvalue\fR] [\fBsnaplen\fR \fIsize\fR]
+\fBlog level audit\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The log statement enables logging of matching packets\&. When this statement is used from a rule, the Linux kernel will print some information on all matching packets, such as header fields, via the kernel log (where it can be read with dmesg(1) or read in the syslog)\&.
+.sp
+In the second form of invocation (if \fInflog_group\fR is specified), the Linux kernel will pass the packet to nfnetlink_log which will send the log through a netlink socket to the specified group\&. One userspace process may subscribe to the group to receive the logs, see man(8) ulogd for the Netfilter userspace log daemon and libnetfilter_log documentation for details in case you would like to develop a custom program to digest your logs\&.
+.sp
+In the third form of invocation (if level audit is specified), the Linux kernel writes a message into the audit buffer suitably formatted for reading with auditd\&. Therefore no further formatting options (such as prefix or flags) are allowed in this mode\&.
+.sp
+This is a non\-terminating statement, so the rule evaluation continues after the packet is logged\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&64.\ \&log statement options
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+prefix
+T}:T{
+.sp
+Log message prefix
+T}:T{
+.sp
+quoted string
+T}
+T{
+.sp
+level
+T}:T{
+.sp
+Syslog level of logging
+T}:T{
+.sp
+string: emerg, alert, crit, err, warn [default], notice, info, debug, audit
+T}
+T{
+.sp
+group
+T}:T{
+.sp
+NFLOG group to send messages to
+T}:T{
+.sp
+unsigned integer (16 bit)
+T}
+T{
+.sp
+snaplen
+T}:T{
+.sp
+Length of packet payload to include in netlink message
+T}:T{
+.sp
+unsigned integer (32 bit)
+T}
+T{
+.sp
+queue\-threshold
+T}:T{
+.sp
+Number of packets to queue inside the kernel before sending them to userspace
+T}:T{
+.sp
+unsigned integer (32 bit)
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&65.\ \&log\-flags
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Flag
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+tcp sequence
+T}:T{
+.sp
+Log TCP sequence numbers\&.
+T}
+T{
+.sp
+tcp options
+T}:T{
+.sp
+Log options from the TCP packet header\&.
+T}
+T{
+.sp
+ip options
+T}:T{
+.sp
+Log options from the IP/IPv6 packet header\&.
+T}
+T{
+.sp
+skuid
+T}:T{
+.sp
+Log the userid of the process which generated the packet\&.
+T}
+T{
+.sp
+ether
+T}:T{
+.sp
+Decode MAC addresses and protocol\&.
+T}
+T{
+.sp
+all
+T}:T{
+.sp
+Enable all log flags listed above\&.
+T}
+.TE
+.sp 1
+.PP
+\fBUsing log statement\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# log the UID which generated the packet and ip options
+ip filter output log flags skuid flags ip options
+
+# log the tcp sequence numbers and tcp options from the TCP packet
+ip filter output log flags tcp sequence,options
+
+# enable all supported log flags
+ip6 filter output log flags all
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "REJECT STATEMENT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBreject\fR [ \fBwith\fR \fIREJECT_WITH\fR ]
+
+\fIREJECT_WITH\fR := \fBicmp\fR \fIicmp_code\fR |
+ \fBicmpv6\fR \fIicmpv6_code\fR |
+ \fBicmpx\fR \fIicmpx_code\fR |
+ \fBtcp reset\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 \fBinput\fR, \fBforward\fR or \fBoutput\fR hooks, and user\-defined chains which are only called from those chains\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&66.\ \&different ICMP reject variants are meant for use in different table families
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Variant
+T}:T{
+Family
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+icmp
+T}:T{
+.sp
+ip
+T}:T{
+.sp
+icmp_code
+T}
+T{
+.sp
+icmpv6
+T}:T{
+.sp
+ip6
+T}:T{
+.sp
+icmpv6_code
+T}
+T{
+.sp
+icmpx
+T}:T{
+.sp
+inet
+T}:T{
+.sp
+icmpx_code
+T}
+.TE
+.sp 1
+.sp
+For a description of the different types and a list of supported keywords refer to DATA TYPES section above\&. The common default reject value is \fBport\-unreachable\fR\&.
+.sp
+Note that in bridge family, reject statement is only allowed in base chains which hook into input or prerouting\&.
+.SS "COUNTER STATEMENT"
+.sp
+A counter statement sets the hit count of packets along with the number of bytes\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBcounter\fR \fBpackets\fR \fInumber\fR \fBbytes\fR \fInumber\fR
+\fBcounter\fR { \fBpackets\fR \fInumber\fR | \fBbytes\fR \fInumber\fR }
+.fi
+.if n \{\
+.RE
+.\}
+.SS "CONNTRACK STATEMENT"
+.sp
+The conntrack statement can be used to set the conntrack mark and conntrack labels\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBct\fR {\fBmark\fR | \fBevent\fR | \fBlabel\fR | \fBzone\fR} \fBset\fR \fIvalue\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The ct statement sets meta data associated with a connection\&. The zone id has to be assigned before a conntrack lookup takes place, i\&.e\&. this has to be done in prerouting and possibly output (if locally generated packets need to be placed in a distinct zone), with a hook priority of \fBraw\fR (\-300)\&.
+.sp
+Unlike iptables, where the helper assignment happens in the raw table, the helper needs to be assigned after a conntrack entry has been found, i\&.e\&. it will not work when used with hook priorities equal or before \-200\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&67.\ \&Conntrack statement types
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Value
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+event
+T}:T{
+.sp
+conntrack event bits
+T}:T{
+.sp
+bitmask, integer (32 bit)
+T}
+T{
+.sp
+helper
+T}:T{
+.sp
+name of ct helper object to assign to the connection
+T}:T{
+.sp
+quoted string
+T}
+T{
+.sp
+mark
+T}:T{
+.sp
+Connection tracking mark
+T}:T{
+.sp
+mark
+T}
+T{
+.sp
+label
+T}:T{
+.sp
+Connection tracking label
+T}:T{
+.sp
+label
+T}
+T{
+.sp
+zone
+T}:T{
+.sp
+conntrack zone
+T}:T{
+.sp
+integer (16 bit)
+T}
+.TE
+.sp 1
+.PP
+\fBsave packet nfmark in conntrack\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ct mark set meta mark
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBset zone mapped via interface\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+table inet raw {
+ chain prerouting {
+ type filter hook prerouting priority raw;
+ ct zone set iif map { "eth1" : 1, "veth1" : 2 }
+ }
+ chain output {
+ type filter hook output priority raw;
+ ct zone set oif map { "eth1" : 1, "veth1" : 2 }
+ }
+}
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBrestrict events reported by ctnetlink\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ct event set new,related,destroy
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "NOTRACK STATEMENT"
+.sp
+The notrack statement allows one to disable connection tracking for certain packets\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBnotrack\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Note that for this statement to be effective, it has to be applied to packets before a conntrack lookup happens\&. Therefore, it needs to sit in a chain with either prerouting or output hook and a hook priority of \-300 (\fBraw\fR) or less\&.
+.sp
+See SYNPROXY STATEMENT for an example usage\&.
+.SS "META STATEMENT"
+.sp
+A meta statement sets the value of a meta expression\&. The existing meta fields are: priority, mark, pkttype, nftrace\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBmeta\fR {\fBmark\fR | \fBpriority\fR | \fBpkttype\fR | \fBnftrace\fR | \fBbroute\fR} \fBset\fR \fIvalue\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+A meta statement sets meta data associated with a packet\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&68.\ \&Meta statement types
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Keyword
+T}:T{
+Description
+T}:T{
+Value
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+priority
+T}:T{
+.sp
+TC packet priority
+T}:T{
+.sp
+tc_handle
+T}
+T{
+.sp
+mark
+T}:T{
+.sp
+Packet mark
+T}:T{
+.sp
+mark
+T}
+T{
+.sp
+pkttype
+T}:T{
+.sp
+packet type
+T}:T{
+.sp
+pkt_type
+T}
+T{
+.sp
+nftrace
+T}:T{
+.sp
+ruleset packet tracing on/off\&. Use \fBmonitor trace\fR command to watch traces
+T}:T{
+.sp
+0, 1
+T}
+T{
+.sp
+broute
+T}:T{
+.sp
+broute on/off\&. packets are routed instead of being bridged
+T}:T{
+.sp
+0, 1
+T}
+.TE
+.sp 1
+.SS "LIMIT STATEMENT"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBlimit rate\fR [\fBover\fR] \fIpacket_number\fR \fB/\fR \fITIME_UNIT\fR [\fBburst\fR \fIpacket_number\fR \fBpackets\fR]
+\fBlimit rate\fR [\fBover\fR] \fIbyte_number\fR \fIBYTE_UNIT\fR \fB/\fR \fITIME_UNIT\fR [\fBburst\fR \fIbyte_number\fR \fIBYTE_UNIT\fR]
+
+\fITIME_UNIT\fR := \fBsecond\fR | \fBminute\fR | \fBhour\fR | \fBday\fR
+\fIBYTE_UNIT\fR := \fBbytes\fR | \fBkbytes\fR | \fBmbytes\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+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 \fBover\fR keyword makes it match over the specified rate\&.
+.sp
+The \fBburst\fR value influences the bucket size, i\&.e\&. jitter tolerance\&. With packet\-based \fBlimit\fR, the bucket holds exactly \fBburst\fR packets, by default five\&. If you specify packet \fBburst\fR, it must be a non\-zero value\&. With byte\-based \fBlimit\fR, the bucket\(cqs minimum size is the given rate\(cqs byte value and the \fBburst\fR value adds to that, by default zero bytes\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&69.\ \&limit statement values
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Value
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt.
+T{
+.sp
+packet_number
+T}:T{
+.sp
+Number of packets
+T}:T{
+.sp
+unsigned integer (32 bit)
+T}
+T{
+.sp
+byte_number
+T}:T{
+.sp
+Number of bytes
+T}:T{
+.sp
+unsigned integer (32 bit)
+T}
+.TE
+.sp 1
+.SS "NAT STATEMENTS"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBsnat\fR [[\fBip\fR | \fBip6\fR] [ \fBprefix\fR ] \fBto\fR] \fIADDR_SPEC\fR [\fB:\fR\fIPORT_SPEC\fR] [\fIFLAGS\fR]
+\fBdnat\fR [[\fBip\fR | \fBip6\fR] [ \fBprefix\fR ] \fBto\fR] \fIADDR_SPEC\fR [\fB:\fR\fIPORT_SPEC\fR] [\fIFLAGS\fR]
+\fBmasquerade\fR [\fBto :\fR\fIPORT_SPEC\fR] [\fIFLAGS\fR]
+\fBredirect\fR [\fBto :\fR\fIPORT_SPEC\fR] [\fIFLAGS\fR]
+
+\fIADDR_SPEC\fR := \fIaddress\fR | \fIaddress\fR \fB\-\fR \fIaddress\fR
+\fIPORT_SPEC\fR := \fIport\fR | \fIport\fR \fB\-\fR \fIport\fR
+
+\fIFLAGS\fR := \fIFLAG\fR [\fB,\fR \fIFLAGS\fR]
+\fIFLAG\fR := \fBpersistent\fR | \fBrandom\fR | \fBfully\-random\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The nat statements are only valid from nat chain types\&.
+.sp
+The \fBsnat\fR and \fBmasquerade\fR statements specify that the source address of the packet should be modified\&. While \fBsnat\fR is only valid in the postrouting and input chains, \fBmasquerade\fR makes sense only in postrouting\&. The dnat and redirect statements are only valid in the prerouting and output chains, they specify that the destination address of the packet should be modified\&. You can use non\-base chains which are called from base chains of nat chain type too\&. All future packets in this connection will also be mangled, and rules should cease being examined\&.
+.sp
+The \fBmasquerade\fR statement is a special form of snat which always uses the outgoing interface\(cqs IP address to translate to\&. It is particularly useful on gateways with dynamic (public) IP addresses\&.
+.sp
+The \fBredirect\fR statement is a special form of dnat which always translates the destination address to the local host\(cqs one\&. It comes in handy if one only wants to alter the destination port of incoming traffic on different interfaces\&.
+.sp
+When used in the inet family (available with kernel 5\&.2), the dnat and snat statements require the use of the ip and ip6 keyword in case an address is provided, see the examples below\&.
+.sp
+Before kernel 4\&.18 nat statements require both prerouting and postrouting base chains to be present since otherwise packets on the return path won\(cqt be seen by netfilter and therefore no reverse translation will take place\&.
+.sp
+The optional \fBprefix\fR keyword allows to map to map \fBn\fR source addresses to \fBn\fR destination addresses\&. See \fIAdvanced NAT examples\fR below\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&70.\ \&NAT statement values
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Expression
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt.
+T{
+.sp
+address
+T}:T{
+.sp
+Specifies that the source/destination address of the packet should be modified\&. You may specify a mapping to relate a list of tuples composed of arbitrary expression key with address value\&.
+T}:T{
+.sp
+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 }
+T}
+T{
+.sp
+port
+T}:T{
+.sp
+Specifies that the source/destination port of the packet should be modified\&.
+T}:T{
+.sp
+port number (16 bit)
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&71.\ \&NAT statement flags
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Flag
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+persistent
+T}:T{
+.sp
+Gives a client the same source\-/destination\-address for each connection\&.
+T}
+T{
+.sp
+random
+T}:T{
+.sp
+In kernel 5\&.0 and newer this is the same as fully\-random\&. In earlier kernels the port mapping will be randomized using a seeded MD5 hash mix using source and destination address and destination port\&.
+T}
+T{
+.sp
+fully\-random
+T}:T{
+.sp
+If used then port mapping is generated based on a 32\-bit pseudo\-random algorithm\&.
+T}
+.TE
+.sp 1
+.PP
+\fBUsing NAT statements\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# create a suitable table/chain setup for all further examples
+add table nat
+add chain nat prerouting { type nat hook prerouting priority dstnat; }
+add chain nat postrouting { type nat hook postrouting priority srcnat; }
+
+# translate source addresses of all packets leaving via eth0 to address 1\&.2\&.3\&.4
+add rule nat postrouting oif eth0 snat to 1\&.2\&.3\&.4
+
+# redirect all traffic entering via eth0 to destination address 192\&.168\&.1\&.120
+add rule nat prerouting iif eth0 dnat to 192\&.168\&.1\&.120
+
+# translate source addresses of all packets leaving via eth0 to whatever
+# locally generated packets would use as source to reach the same destination
+add rule nat postrouting oif eth0 masquerade
+
+# redirect incoming TCP traffic for port 22 to port 2222
+add rule nat prerouting tcp dport 22 redirect to :2222
+
+# inet family:
+# handle ip dnat:
+add rule inet nat prerouting dnat ip to 10\&.0\&.2\&.99
+# handle ip6 dnat:
+add rule inet nat prerouting dnat ip6 to fe80::dead
+# this masquerades both ipv4 and ipv6:
+add rule inet nat postrouting meta oif ppp0 masquerade
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBAdvanced NAT examples\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# 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\&.
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "TPROXY STATEMENT"
+.sp
+Tproxy redirects the packet to a local socket without changing the packet header in any way\&. If any of the arguments is missing the data of the incoming packet is used as parameter\&. Tproxy matching requires another rule that ensures the presence of transport protocol header is specified\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBtproxy to\fR \fIaddress\fR\fB:\fR\fIport\fR
+\fBtproxy to\fR {\fIaddress\fR | \fB:\fR\fIport\fR}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This syntax can be used in \fBip/ip6\fR tables where network layer protocol is obvious\&. Either IP address or port can be specified, but at least one of them is necessary\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBtproxy\fR {\fBip\fR | \fBip6\fR} \fBto\fR \fIaddress\fR[\fB:\fR\fIport\fR]
+\fBtproxy to :\fR\fIport\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+This syntax can be used in \fBinet\fR tables\&. The \fBip/ip6\fR parameter defines the family the rule will match\&. The \fBaddress\fR parameter must be of this family\&. When only \fBport\fR is defined, the address family should not be specified\&. In this case the rule will match for both families\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&72.\ \&tproxy attributes
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Name
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+address
+T}:T{
+.sp
+IP address the listening socket with IP_TRANSPARENT option is bound to\&.
+T}
+T{
+.sp
+port
+T}:T{
+.sp
+Port the listening socket with IP_TRANSPARENT option is bound to\&.
+T}
+.TE
+.sp 1
+.PP
+\fBExample ruleset for tproxy statement\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+table ip x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport ntp tproxy to 1\&.1\&.1\&.1
+ udp dport ssh tproxy to :2222
+ }
+}
+table ip6 x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport ntp tproxy to [dead::beef]
+ udp dport ssh tproxy to :2222
+ }
+}
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport 321 tproxy to :ssh
+ tcp dport 99 tproxy ip to 1\&.1\&.1\&.1:999
+ udp dport 155 tproxy ip6 to [dead::beef]:smux
+ }
+}
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "SYNPROXY STATEMENT"
+.sp
+This statement will process TCP three\-way\-handshake parallel in netfilter context to protect either local or backend system\&. This statement requires connection tracking because sequence numbers need to be translated\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBsynproxy\fR [\fBmss\fR \fImss_value\fR] [\fBwscale\fR \fIwscale_value\fR] [\fISYNPROXY_FLAGS\fR]
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&73.\ \&synproxy statement attributes
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Name
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+mss
+T}:T{
+.sp
+Maximum segment size announced to clients\&. This must match the backend\&.
+T}
+T{
+.sp
+wscale
+T}:T{
+.sp
+Window scale announced to clients\&. This must match the backend\&.
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&74.\ \&synproxy statement flags
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Flag
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+sack\-perm
+T}:T{
+.sp
+Pass client selective acknowledgement option to backend (will be disabled if not present)\&.
+T}
+T{
+.sp
+timestamp
+T}:T{
+.sp
+Pass client timestamp option to backend (will be disabled if not present, also needed for selective acknowledgement and window scaling)\&.
+T}
+.TE
+.sp 1
+.PP
+\fBExample ruleset for synproxy statement\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Determine tcp options used by backend, from an external system
+
+ tcpdump \-pni eth0 \-c 1 \*(Aqtcp[tcpflags] == (tcp\-syn|tcp\-ack)\*(Aq
+ port 80 &
+ telnet 192\&.0\&.2\&.42 80
+ 18:57:24\&.693307 IP 192\&.0\&.2\&.42\&.80 > 192\&.0\&.2\&.43\&.48757:
+ Flags [S\&.], seq 360414582, ack 788841994, win 14480,
+ options [mss 1460,sackOK,
+ TS val 1409056151 ecr 9690221,
+ nop,wscale 9],
+ length 0
+
+Switch tcp_loose mode off, so conntrack will mark out\-of\-flow packets as state INVALID\&.
+
+ echo 0 > /proc/sys/net/netfilter/nf_conntrack_tcp_loose
+
+Make SYN packets untracked\&.
+
+ table ip x {
+ chain y {
+ type filter hook prerouting priority raw; policy accept;
+ tcp flags syn notrack
+ }
+ }
+
+Catch UNTRACKED (SYN packets) and INVALID (3WHS ACK packets) states and send
+them to SYNPROXY\&. This rule will respond to SYN packets with SYN+ACK
+syncookies, create ESTABLISHED for valid client response (3WHS ACK packets) and
+drop incorrect cookies\&. Flags combinations not expected during 3WHS will not
+match and continue (e\&.g\&. SYN+FIN, SYN+ACK)\&. Finally, drop invalid packets, this
+will be out\-of\-flow packets that were not matched by SYNPROXY\&.
+
+ table ip x {
+ chain z {
+ type filter hook input priority filter; policy accept;
+ ct state invalid, untracked synproxy mss 1460 wscale 9 timestamp sack\-perm
+ ct state invalid drop
+ }
+ }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "FLOW STATEMENT"
+.sp
+A flow statement allows us to select what flows you want to accelerate forwarding through layer 3 network stack bypass\&. You have to specify the flowtable name where you want to offload this flow\&.
+.sp
+\fBflow add @\fR\fIflowtable\fR
+.SS "QUEUE STATEMENT"
+.sp
+This statement passes the packet to userspace using the nfnetlink_queue handler\&. The packet is put into the queue identified by its 16\-bit queue number\&. Userspace can inspect and modify the packet if desired\&. Userspace must then drop or re\-inject the packet into the kernel\&. See libnetfilter_queue documentation for details\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBqueue\fR [\fBflags\fR \fIQUEUE_FLAGS\fR] [\fBto\fR \fIqueue_number\fR]
+\fBqueue\fR [\fBflags\fR \fIQUEUE_FLAGS\fR] [\fBto\fR \fIqueue_number_from\fR \- \fIqueue_number_to\fR]
+\fBqueue\fR [\fBflags\fR \fIQUEUE_FLAGS\fR] [\fBto\fR \fIQUEUE_EXPRESSION\fR ]
+
+\fIQUEUE_FLAGS\fR := \fIQUEUE_FLAG\fR [\fB,\fR \fIQUEUE_FLAGS\fR]
+\fIQUEUE_FLAG\fR := \fBbypass\fR | \fBfanout\fR
+\fIQUEUE_EXPRESSION\fR := \fBnumgen\fR | \fBhash\fR | \fBsymhash\fR | \fBMAP STATEMENT\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+QUEUE_EXPRESSION can be used to compute a queue number at run\-time with the hash or numgen expressions\&. It also allows one to use the map statement to assign fixed queue numbers based on external inputs such as the source ip address or interface names\&.
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&75.\ \&queue statement values
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Value
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt
+lt lt lt.
+T{
+.sp
+queue_number
+T}:T{
+.sp
+Sets queue number, default is 0\&.
+T}:T{
+.sp
+unsigned integer (16 bit)
+T}
+T{
+.sp
+queue_number_from
+T}:T{
+.sp
+Sets initial queue in the range, if fanout is used\&.
+T}:T{
+.sp
+unsigned integer (16 bit)
+T}
+T{
+.sp
+queue_number_to
+T}:T{
+.sp
+Sets closing queue in the range, if fanout is used\&.
+T}:T{
+.sp
+unsigned integer (16 bit)
+T}
+.TE
+.sp 1
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&76.\ \&queue statement flags
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Flag
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt.
+T{
+.sp
+bypass
+T}:T{
+.sp
+Let packets go through if userspace application cannot back off\&. Before using this flag, read libnetfilter_queue documentation for performance tuning recommendations\&.
+T}
+T{
+.sp
+fanout
+T}:T{
+.sp
+Distribute packets between several queues\&.
+T}
+.TE
+.sp 1
+.SS "DUP STATEMENT"
+.sp
+The dup statement is used to duplicate a packet and send the copy to a different destination\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBdup to\fR \fIdevice\fR
+\fBdup to\fR \fIaddress\fR \fBdevice\fR \fIdevice\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.B Table\ \&77.\ \&Dup statement values
+.TS
+allbox tab(:);
+ltB ltB ltB.
+T{
+Expression
+T}:T{
+Description
+T}:T{
+Type
+T}
+.T&
+lt lt lt
+lt lt lt.
+T{
+.sp
+address
+T}:T{
+.sp
+Specifies that the copy of the packet should be sent to a new gateway\&.
+T}:T{
+.sp
+ipv4_addr, ipv6_addr, e\&.g\&. abcd::1234, or you can use a mapping, e\&.g\&. ip saddr map { 192\&.168\&.1\&.2 : 10\&.1\&.1\&.1 }
+T}
+T{
+.sp
+device
+T}:T{
+.sp
+Specifies that the copy should be transmitted via device\&.
+T}:T{
+.sp
+string
+T}
+.TE
+.sp 1
+.PP
+\fBUsing the dup statement\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# send to machine with ip address 10\&.2\&.3\&.4 on eth0
+ip filter forward dup to 10\&.2\&.3\&.4 device "eth0"
+
+# copy raw frame to another interface
+netdev ingress dup to "eth0"
+dup to "eth0"
+
+# combine with map dst addr to gateways
+dup to ip daddr map { 192\&.168\&.7\&.1 : "eth0", 192\&.168\&.7\&.2 : "eth1" }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "FWD STATEMENT"
+.sp
+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\&.
+.sp
+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\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBfwd to\fR \fIdevice\fR
+\fBfwd\fR [\fBip\fR | \fBip6\fR] \fBto\fR \fIaddress\fR \fBdevice\fR \fIdevice\fR
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBUsing the fwd statement\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# 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"
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "SET STATEMENT"
+.sp
+The set statement is used to dynamically add or update elements in a set from the packet path\&. The set setname must already exist in the given table and must have been created with one or both of the dynamic and the timeout flags\&. The dynamic flag is required if the set statement expression includes a stateful object\&. The timeout flag is implied if the set is created with a timeout, and is required if the set statement updates elements, rather than adding them\&. Furthermore, these sets should specify both a maximum set size (to prevent memory exhaustion), and their elements should have a timeout (so their number will not grow indefinitely) either from the set definition or from the statement that adds or updates them\&. The set statement can be used to e\&.g\&. create dynamic blacklists\&.
+.sp
+Dynamic updates are also supported with maps\&. In this case, the \fBadd\fR or \fBupdate\fR rule needs to provide both the key and the data element (value), separated via \fI:\fR\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+{\fBadd\fR | \fBupdate\fR} \fB@\fR\fIsetname\fR \fB{\fR \fIexpression\fR [\fBtimeout\fR \fItimeout\fR] [\fBcomment\fR \fIstring\fR] \fB}\fR
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBExample for simple blacklist\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# declare a set, bound to table "filter", in family "ip"\&.
+# Timeout and size are mandatory because we will add elements from packet path\&.
+# Entries will timeout after one minute, after which they might be
+# re\-added if limit condition persists\&.
+nft add set ip filter blackhole \e
+ "{ type ipv4_addr; flags dynamic; timeout 1m; size 65536; }"
+
+# declare a set to store the limit per saddr\&.
+# This must be separate from blackhole since the timeout is different
+nft add set ip filter flood \e
+ "{ type ipv4_addr; flags dynamic; timeout 10s; size 128000; }"
+
+# whitelist internal interface\&.
+nft add rule ip filter input meta iifname "internal" accept
+
+# drop packets coming from blacklisted ip addresses\&.
+nft add rule ip filter input ip saddr @blackhole counter drop
+
+# add source ip addresses to the blacklist if more than 10 tcp connection
+# requests occurred per second and ip address\&.
+nft add rule ip filter input tcp flags syn tcp dport ssh \e
+ add @flood { ip saddr limit rate over 10/second } \e
+ add @blackhole { ip saddr } \e
+ drop
+
+# inspect state of the sets\&.
+nft list set ip filter flood
+nft list set ip filter blackhole
+
+# manually add two addresses to the blackhole\&.
+nft add element filter blackhole { 10\&.2\&.3\&.4, 10\&.23\&.1\&.42 }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "MAP STATEMENT"
+.sp
+The map statement is used to lookup data based on some specific input key\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIexpression\fR \fBmap\fR \fB{\fR \fIMAP_ELEMENTS\fR \fB}\fR
+
+\fIMAP_ELEMENTS\fR := \fIMAP_ELEMENT\fR [\fB,\fR \fIMAP_ELEMENTS\fR]
+\fIMAP_ELEMENT\fR := \fIkey\fR \fB:\fR \fIvalue\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The \fIkey\fR is a value returned by \fIexpression\fR\&.
+.PP
+\fBUsing the map statement\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# select DNAT target based on TCP dport:
+# connections to port 80 are redirected to 192\&.168\&.1\&.100,
+# connections to port 8888 are redirected to 192\&.168\&.1\&.101
+nft add rule ip nat prerouting dnat tcp dport map { 80 : 192\&.168\&.1\&.100, 8888 : 192\&.168\&.1\&.101 }
+
+# source address based SNAT:
+# packets from net 192\&.168\&.1\&.0/24 will appear as originating from 10\&.0\&.0\&.1,
+# packets from net 192\&.168\&.2\&.0/24 will appear as originating from 10\&.0\&.0\&.2
+nft add rule ip nat postrouting snat to ip saddr map { 192\&.168\&.1\&.0/24 : 10\&.0\&.0\&.1, 192\&.168\&.2\&.0/24 : 10\&.0\&.0\&.2 }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "VMAP STATEMENT"
+.sp
+The verdict map (vmap) statement works analogous to the map statement, but contains verdicts as values\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fIexpression\fR \fBvmap\fR \fB{\fR \fIVMAP_ELEMENTS\fR \fB}\fR
+
+\fIVMAP_ELEMENTS\fR := \fIVMAP_ELEMENT\fR [\fB,\fR \fIVMAP_ELEMENTS\fR]
+\fIVMAP_ELEMENT\fR := \fIkey\fR \fB:\fR \fIverdict\fR
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBUsing the vmap statement\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# 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 }
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SS "XT STATEMENT"
+.sp
+This represents an xt statement from xtables compat interface\&. It is a fallback if translation is not available or not complete\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBxt\fR \fITYPE\fR \fINAME\fR
+
+\fITYPE\fR := \fBmatch\fR | \fBtarget\fR | \fBwatcher\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Seeing this means the ruleset (or parts of it) were created by \fBiptables\-nft\fR and one should use that to manage it\&.
+.sp
+\fBBEWARE:\fR nftables won\(cqt restore these statements\&.
+.SH "ADDITIONAL COMMANDS"
+.sp
+These are some additional commands included in nft\&.
+.SS "MONITOR"
+.sp
+The monitor command allows you to listen to Netlink events produced by the nf_tables subsystem\&. These are either related to creation and deletion of objects or to packets for which \fBmeta nftrace\fR was enabled\&. When they occur, nft will print to stdout the monitored events in either JSON or native nft format\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBmonitor\fR [\fBnew\fR | \fBdestroy\fR] \fIMONITOR_OBJECT\fR
+\fBmonitor\fR \fBtrace\fR
+
+\fIMONITOR_OBJECT\fR := \fBtables\fR | \fBchains\fR | \fBsets\fR | \fBrules\fR | \fBelements\fR | \fBruleset\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+To filter events related to a concrete object, use one of the keywords in \fIMONITOR_OBJECT\fR\&.
+.sp
+To filter events related to a concrete action, use keyword \fBnew\fR or \fBdestroy\fR\&.
+.sp
+The second form of invocation takes no further options and exclusively prints events generated for packets with \fBnftrace\fR enabled\&.
+.sp
+Hit ^C to finish the monitor operation\&.
+.PP
+\fBListen to all events, report in native nft format\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+% nft monitor
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBListen to deleted rules, report in JSON format\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+% nft \-j monitor destroy rules
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBListen to both new and destroyed chains, in native nft format\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+% nft monitor chains
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBListen to ruleset events such as table, chain, rule, set, counters and quotas, in native nft format\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+% nft monitor ruleset
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBTrace incoming packets from host 10.0.0.1\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+% nft add rule filter input ip saddr 10\&.0\&.0\&.1 meta nftrace set 1
+% nft monitor trace
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "ERROR REPORTING"
+.sp
+When an error is detected, nft shows the line(s) containing the error, the position of the erroneous parts in the input stream and marks up the erroneous parts using carets (^)\&. If the error results from the combination of two expressions or statements, the part imposing the constraints which are violated is marked using tildes (~)\&.
+.sp
+For errors returned by the kernel, nft cannot detect which parts of the input caused the error and the entire command is marked\&.
+.PP
+\fBError caused by single incorrect expression\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+<cmdline>:1:19\-22: Error: Interface does not exist
+filter output oif eth0
+ ^^^^
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBError caused by invalid combination of two expressions\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+<cmdline>:1:28\-36: Error: Right hand side of relational expression (==) must be constant
+filter output tcp dport == tcp dport
+ ~~ ^^^^^^^^^
+.fi
+.if n \{\
+.RE
+.\}
+.PP
+\fBError returned by the kernel\fR.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+<cmdline>:0:0\-23: Error: Could not process rule: Operation not permitted
+filter output oif wlan0
+^^^^^^^^^^^^^^^^^^^^^^^
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "EXIT STATUS"
+.sp
+On success, nft exits with a status of 0\&. Unspecified errors cause it to exit with a status of 1, memory allocation errors with a status of 2, unable to open Netlink socket with 3\&.
+.SH "SEE ALSO"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+libnftables(3), libnftables\-json(5), iptables(8), ip6tables(8), arptables(8), ebtables(8), ip(8), tc(8)
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+There is an official wiki at: https://wiki\&.nftables\&.org
+.SH "AUTHORS"
+.sp
+nftables was written by Patrick McHardy and Pablo Neira Ayuso, among many other contributors from the Netfilter community\&.
+.SH "COPYRIGHT"
+.sp
+Copyright \(co 2008\-2014 Patrick McHardy <kaber@trash\&.net> Copyright \(co 2013\-2018 Pablo Neira Ayuso <pablo@netfilter\&.org>
+.sp
+nftables 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\&.
+.sp
+This documentation is licensed under the terms of the Creative Commons Attribution\-ShareAlike 4\&.0 license, CC BY\-SA 4\&.0 http://creativecommons\&.org/licenses/by\-sa/4\&.0/\&.
diff --git a/doc/nft.txt b/doc/nft.txt
new file mode 100644
index 0000000..b08e32f
--- /dev/null
+++ b/doc/nft.txt
@@ -0,0 +1,1009 @@
+nft(8)
+======
+
+NAME
+----
+nft - Administration tool of the nftables framework for packet filtering and classification
+
+
+SYNOPSIS
+--------
+[verse]
+*nft* [ *-nNscaeSupyjtT* ] [ *-I* 'directory' ] [ *-f* 'filename' | *-i* | 'cmd' ...]
+*nft* *-h*
+*nft* *-v*
+
+DESCRIPTION
+-----------
+nft is the command line tool used to set up, maintain and inspect packet
+filtering and classification rules in the Linux kernel, in the nftables
+framework. The Linux kernel subsystem is known as nf_tables, and `nf' stands
+for Netfilter.
+
+OPTIONS
+-------
+The command accepts several different options which are documented here in groups for better
+understanding of their meaning. You can get information about options by running *nft --help*.
+
+.General options:
+
+*-h*::
+*--help*::
+ Show help message and all options.
+
+*-v*::
+*--version*::
+ Show version.
+
+*-V*::
+ Show long version information, including compile-time configuration.
+
+.Ruleset input handling options that specify to how to load rulesets:
+
+*-f*::
+*--file 'filename'*::
+ Read input from 'filename'. If 'filename' is -, read from stdin.
+
+*-D*::
+*--define 'name=value'*::
+ Define a variable. You can only combine this option with '-f'.
+
+*-i*::
+*--interactive*::
+ Read input from an interactive readline CLI. You can use quit to exit, or use the EOF marker,
+ normally this is CTRL-D.
+
+*-I*::
+*--includepath directory*::
+ Add the directory 'directory' to the list of directories to be searched for included files. This
+ option may be specified multiple times.
+
+*-c*::
+*--check*::
+ Check commands validity without actually applying the changes.
+
+*-o*::
+*--optimize*::
+ Optimize your ruleset. You can combine this option with '-c' to inspect
+ the proposed optimizations.
+
+.Ruleset list output formatting that modify the output of the list ruleset command:
+
+*-a*::
+*--handle*::
+ Show object handles in output.
+
+*-s*::
+*--stateless*::
+ Omit stateful information of rules and stateful objects.
+
+*-t*::
+*--terse*::
+ Omit contents of sets from output.
+
+*-S*::
+*--service*::
+ Translate ports to service names as defined by /etc/services.
+
+*-N*::
+*--reversedns*::
+ Translate IP address to names via reverse DNS lookup. This may slow down
+ your listing since it generates network traffic.
+
+*-u*::
+*--guid*::
+ Translate numeric UID/GID to names as defined by /etc/passwd and /etc/group.
+
+*-n*::
+*--numeric*::
+ Print fully numerical output.
+
+*-y*::
+*--numeric-priority*::
+ Display base chain priority numerically.
+
+*-p*::
+*--numeric-protocol*::
+ Display layer 4 protocol numerically.
+
+*-T*::
+*--numeric-time*::
+ Show time, day and hour values in numeric format.
+
+.Command output formatting:
+
+*-e*::
+*--echo*::
+ When inserting items into the ruleset using *add*, *insert* or *replace* commands, print notifications
+ just like *nft monitor*.
+
+*-j*::
+*--json*::
+ Format output in JSON. See libnftables-json(5) for a schema description.
+
+*-d*::
+*--debug* 'level'::
+ Enable debugging output. The debug level can be any of *scanner*, *parser*, *eval*,
+ *netlink*, *mnl*, *proto-ctx*, *segtree*, *all*. You can combine more than one by
+ separating by the ',' symbol, for example '-d eval,mnl'.
+
+INPUT FILE FORMATS
+------------------
+LEXICAL CONVENTIONS
+~~~~~~~~~~~~~~~~~~~
+Input is parsed line-wise. When the last character of a line, just before the
+newline character, is a non-quoted backslash (\), the next line is treated as a
+continuation. Multiple commands on the same line can be separated using a
+semicolon (;). +
+
+A hash sign (#) begins a comment. All following characters on the same line are
+ignored. +
+
+Identifiers begin with an alphabetic character (a-z,A-Z), followed by zero or more
+alphanumeric characters (a-z,A-Z,0-9) and the characters slash (/), backslash
+(\), underscore (_) and dot (.). Identifiers using different characters or
+clashing with a keyword need to be enclosed in double quotes (").
+
+INCLUDE FILES
+~~~~~~~~~~~~~
+[verse]
+*include* 'filename'
+
+Other files can be included by using the *include* statement. The directories to
+be searched for include files can be specified using the *-I*/*--includepath*
+option. You can override this behaviour either by prepending `./' to your path
+to force inclusion of files located in the current working directory (i.e.
+relative path) or / for file location expressed as an absolute path. +
+
+If *-I*/*--includepath* is not specified, then nft relies on the default
+directory that is specified at compile time. You can retrieve this default
+directory via the *-h*/*--help* option. +
+
+Include statements support the usual shell wildcard symbols (*,?,[]). Having no
+matches for an include statement is not an error, if wildcard symbols are used
+in the include statement. This allows having potentially empty include
+directories for statements like **include "/etc/firewall/rules/*"**. The wildcard
+matches are loaded in alphabetical order. Files beginning with dot (.) are not
+matched by include statements.
+
+SYMBOLIC VARIABLES
+~~~~~~~~~~~~~~~~~~
+[verse]
+*define* 'variable' *=* 'expr'
+*undefine* 'variable'
+*redefine* 'variable' *=* 'expr'
+*$variable*
+
+Symbolic variables can be defined using the *define* statement. Variable
+references are expressions and can be used to initialize other variables. The scope
+of a definition is the current block and all blocks contained within.
+Symbolic variables can be undefined using the *undefine* statement, and modified
+using the *redefine* statement.
+
+.Using symbolic variables
+---------------------------------------
+define int_if1 = eth0
+define int_if2 = eth1
+define int_ifs = { $int_if1, $int_if2 }
+redefine int_if2 = wlan0
+undefine int_if2
+
+filter input iif $int_ifs accept
+---------------------------------------
+
+[[ADDRESS_FAMILIES]]
+ADDRESS FAMILIES
+----------------
+Address families determine the type of packets which are processed. For each
+address family, the kernel contains so called hooks at specific stages of the
+packet processing paths, which invoke nftables if rules for these hooks exist.
+
+[horizontal]
+*ip*:: IPv4 address family.
+*ip6*:: IPv6 address family.
+*inet*:: Internet (IPv4/IPv6) address family.
+*arp*:: ARP address family, handling IPv4 ARP packets.
+*bridge*:: Bridge address family, handling packets which traverse a bridge device.
+*netdev*:: Netdev address family, handling packets on ingress and egress.
+
+All nftables objects exist in address family specific namespaces, therefore all
+identifiers include an address family. If an identifier is specified without an
+address family, the *ip* family is used by default.
+
+IPV4/IPV6/INET ADDRESS FAMILIES
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The IPv4/IPv6/Inet address families handle IPv4, IPv6 or both types of packets.
+They contain five hooks at different packet processing stages in the network
+stack.
+
+.IPv4/IPv6/Inet address family hooks
+[options="header"]
+|==================
+|Hook | Description
+|prerouting |
+All packets entering the system are processed by the prerouting hook. It is
+invoked before the routing process and is used for early filtering or changing
+packet attributes that affect routing.
+|input |
+Packets delivered to the local system are processed by the input hook.
+|forward |
+Packets forwarded to a different host are processed by the forward hook.
+|output |
+Packets sent by local processes are processed by the output hook.
+|postrouting |
+All packets leaving the system are processed by the postrouting hook.
+|ingress |
+All packets entering the system are processed by this hook. It is invoked before
+layer 3 protocol handlers, hence before the prerouting hook, and it can be used
+for filtering and policing. Ingress is only available for Inet family (since
+Linux kernel 5.10).
+|===================
+
+ARP ADDRESS FAMILY
+~~~~~~~~~~~~~~~~~~
+The ARP address family handles ARP packets received and sent by the system. It
+is commonly used to mangle ARP packets for clustering.
+
+.ARP address family hooks
+[options="header"]
+|=================
+|Hook | Description
+|input |
+Packets delivered to the local system are processed by the input hook.
+|output |
+Packets send by the local system are processed by the output hook.
+|=================
+
+BRIDGE ADDRESS FAMILY
+~~~~~~~~~~~~~~~~~~~~~
+The bridge address family handles Ethernet packets traversing bridge devices.
+
+The list of supported hooks is identical to IPv4/IPv6/Inet address families above.
+
+NETDEV ADDRESS FAMILY
+~~~~~~~~~~~~~~~~~~~~
+The Netdev address family handles packets from the device ingress and egress
+path. This family allows you to filter packets of any ethertype such as ARP,
+VLAN 802.1q, VLAN 802.1ad (Q-in-Q) as well as IPv4 and IPv6 packets.
+
+.Netdev address family hooks
+[options="header"]
+|=================
+|Hook | Description
+|ingress |
+All packets entering the system are processed by this hook. It is invoked after
+the network taps (ie. *tcpdump*), right after *tc* ingress and before layer 3
+protocol handlers, it can be used for early filtering and policing.
+|egress |
+All packets leaving the system are processed by this hook. It is invoked after
+layer 3 protocol handlers and before *tc* egress. It can be used for late
+filtering and policing.
+|=================
+
+Tunneled packets (such as *vxlan*) are processed by netdev family hooks both
+in decapsulated and encapsulated (tunneled) form. So a packet can be filtered
+on the overlay network as well as on the underlying network.
+
+Note that the order of netfilter and *tc* is mirrored on ingress versus egress.
+This ensures symmetry for NAT and other packet mangling.
+
+Ingress packets which are redirected out some other interface are only
+processed by netfilter on egress if they have passed through netfilter ingress
+processing before. Thus, ingress packets which are redirected by *tc* are not
+subjected to netfilter. But they are if they are redirected by *netfilter* on
+ingress. Conceptually, tc and netfilter can be thought of as layers, with
+netfilter layered above tc: If the packet hasn't been passed up from the
+tc layer to the netfilter layer, it's not subjected to netfilter on egress.
+
+RULESET
+-------
+[verse]
+{*list* | *flush*} *ruleset* ['family']
+
+The *ruleset* keyword is used to identify the whole set of tables, chains, etc.
+currently in place in kernel. The following *ruleset* commands exist:
+
+[horizontal]
+*list*:: Print the ruleset in human-readable format.
+
+*flush*:: Clear the whole ruleset. Note that, unlike iptables, this will remove
+all tables and whatever they contain, effectively leading to an empty ruleset -
+no packet filtering will happen anymore, so the kernel accepts any valid packet
+it receives.
+
+It is possible to limit *list* and *flush* to a specific address family only.
+For a list of valid family names, see <<ADDRESS_FAMILIES>> above.
+
+By design, *list ruleset* command output may be used as input to *nft -f*.
+Effectively, this is the nft-equivalent of *iptables-save* and
+*iptables-restore*.
+
+TABLES
+------
+[verse]
+{*add* | *create*} *table* ['family'] 'table' [ {*comment* 'comment' *;*'} *{ flags* 'flags' *; }*]
+{*delete* | *destroy* | *list* | *flush*} *table* ['family'] 'table'
+*list tables* ['family']
+*delete table* ['family'] *handle* 'handle'
+*destroy table* ['family'] *handle* 'handle'
+
+Tables are containers for chains, sets and stateful objects. They are identified
+by their address family and their name. The address family must be one of *ip*,
+*ip6*, *inet*, *arp*, *bridge*, *netdev*. The *inet* address family is a dummy
+family which is used to create hybrid IPv4/IPv6 tables. The *meta expression
+nfproto* keyword can be used to test which family (ipv4 or ipv6) context the
+packet is being processed in. When no address family is specified, *ip* is used
+by default. The only difference between add and create is that the former will
+not return an error if the specified table already exists while *create* will
+return an error.
+
+.Table flags
+[options="header"]
+|=================
+|Flag | Description
+|dormant |
+table is not evaluated any more (base chains are unregistered).
+|=================
+
+.*Add, change, delete a table*
+---------------------------------------
+# start nft in interactive mode
+nft --interactive
+
+# create a new table.
+create table inet mytable
+
+# add a new base chain: get input packets
+add chain inet mytable myin { type filter hook input priority filter; }
+
+# add a single counter to the chain
+add rule inet mytable myin counter
+
+# disable the table temporarily -- rules are not evaluated anymore
+add table inet mytable { flags dormant; }
+
+# make table active again:
+add table inet mytable
+---------------------------------------
+
+[horizontal]
+*add*:: Add a new table for the given family with the given name.
+*delete*:: Delete the specified table.
+*destroy*:: Delete the specified table, it does not fail if it does not exist.
+*list*:: List all chains and rules of the specified table.
+*flush*:: Flush all chains and rules of the specified table.
+
+CHAINS
+------
+[verse]
+{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' [*device* 'device'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*'] *}*]
+{*delete* | *destroy* | *list* | *flush*} *chain* ['family'] 'table' 'chain'
+*list chains* ['family']
+*delete chain* ['family'] 'table' *handle* 'handle'
+*destroy chain* ['family'] 'table' *handle* 'handle'
+*rename chain* ['family'] 'table' 'chain' 'newname'
+
+Chains are containers for rules. They exist in two kinds, base chains and
+regular chains. A base chain is an entry point for packets from the networking
+stack, a regular chain may be used as jump target and is used for better rule
+organization.
+
+[horizontal]
+*add*:: Add a new chain in the specified table. When a hook and priority value
+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.
+
+For base chains, *type*, *hook* and *priority* parameters are mandatory.
+
+.Supported chain types
+[options="header"]
+|=================
+|Type | Families | Hooks | Description
+|filter | all | all |
+Standard chain type to use in doubt.
+|nat | ip, ip6, inet |
+prerouting, input, output, postrouting |
+Chains of this type perform Native Address Translation based on conntrack
+entries. Only the first packet of a connection actually traverses this chain -
+its rules usually define details of the created conntrack entry (NAT
+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 one to e.g. implement policy routing selectors in nftables.
+|=================
+
+Apart from the special cases illustrated above (e.g. *nat* type not supporting
+*forward* hook or *route* type only supporting *output* hook), there are three
+further quirks worth noticing:
+
+* The netdev family supports merely two combinations, namely *filter* type with
+ *ingress* hook and *filter* type with *egress* hook. Base chains in this
+ family also require the *device* parameter to be present since they exist per
+ interface only.
+* The arp family supports only the *input* and *output* hooks, both in chains of type
+ *filter*.
+* The inet family also supports the *ingress* hook (since Linux kernel 5.10),
+ to filter IPv4 and IPv6 packet at the same location as the netdev *ingress*
+ hook. This inet hook allows you to share sets and maps between the usual
+ *prerouting*, *input*, *forward*, *output*, *postrouting* and this *ingress*
+ hook.
+
+The *device* parameter accepts a network interface name as a string, and is
+required when adding a base chain that filters traffic on the ingress or
+egress hooks. Any ingress or egress chains will only filter traffic from the
+interface specified in the *device* parameter.
+
+The *priority* parameter accepts a signed integer value or a standard priority
+name which specifies the order in which chains with 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.
+
+These names and values are defined and made available based on what priorities
+are used by xtables when registering their default chains.
+
+Most of the families use the same values, but bridge uses different ones from
+the others. See the following tables that describe the values and compatibility.
+
+.Standard priority names, family and hook compatibility matrix
+[options="header"]
+|==================
+| Name | Value | Families | Hooks
+| raw | -300 | ip, ip6, inet | all
+| mangle | -150 | ip, ip6, inet | all
+| dstnat | -100 | ip, ip6, inet | prerouting
+| filter | 0 | ip, ip6, inet, arp, netdev | all
+| security | 50 | ip, ip6, inet | all
+| srcnat | 100 | ip, ip6, inet | postrouting
+|===================
+
+.Standard priority names and hook compatibility for the bridge family
+[option="header"]
+|==================
+| Name | Value | Hooks
+| dstnat | -300 | prerouting
+| filter | -200 | all
+| out | 100 | output
+| srcnat | 300 | postrouting
+|==================
+
+Basic arithmetic expressions (addition and subtraction) can also be achieved
+with these standard names to ease relative prioritizing, e.g. *mangle - 5* stands
+for *-155*. Values will also be printed like this until the value is not
+further than 10 from the standard value.
+
+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*.
+
+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* | *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
+to a set of grammatical rules: expressions and statements.
+
+The add and insert commands support an optional location specifier, which is
+either a 'handle' or the 'index' (starting at zero) of an existing rule.
+Internally, rule locations are always identified by 'handle' and the translation
+from 'index' happens in userspace. This has two potential implications in case a
+concurrent ruleset change happens after the translation was done: The effective
+rule index might change if a rule was inserted or deleted before the referred
+one. If the referred rule was deleted, the command is rejected by the kernel
+just as if an invalid 'handle' was given.
+
+A 'comment' is a single word or a double-quoted (") multi-word string which can
+be used to make notes regarding the actual rule. *Note:* If you use bash for
+adding rules, you have to escape the quotation marks, e.g. \"enable ssh for
+servers\".
+
+[horizontal]
+*add*:: Add a new rule described by the list of statements. The
+rule is appended to the given chain unless a location is specified, in which
+case the rule is inserted after the specified rule.
+*insert*:: Same as *add* except the rule is inserted at the
+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*
+-------------
+nft add rule filter output ip daddr 192.168.0.0/24 accept # 'ip filter' is assumed
+# same command, slightly more verbose
+nft add rule ip filter output ip daddr 192.168.0.0/24 accept
+--------------
+
+.*delete rule from inet table*
+-----------------------
+# nft -a list ruleset
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ct state established,related accept # handle 4
+ ip saddr 10.1.1.1 tcp dport ssh accept # handle 5
+ ...
+# delete the rule with handle 5
+nft delete rule inet filter input handle 5
+-------------------------
+
+SETS
+----
+nftables offers two kinds of set concepts. Anonymous sets are sets that have no
+specific name. The set members are enclosed in curly braces, with commas to
+separate elements when creating the rule the set is used in. Once that rule is
+removed, the set is removed as well. They cannot be updated, i.e. once an
+anonymous set is declared it cannot be changed anymore except by
+removing/altering the rule that uses the anonymous set.
+
+.*Using anonymous sets to accept particular subnets and ports*
+----------
+nft add rule filter input ip saddr { 10.0.0.0/8, 192.168.0.0/16 } tcp dport { 22, 443 } accept
+----------
+
+Named sets are sets that need to be defined first before they can be referenced
+in rules. Unlike anonymous sets, elements can be added to or removed from a
+named set at any time. Sets are referenced from rules using an @ prefixed to the
+sets name.
+
+.*Using named sets to accept addresses and ports*
+------------------
+nft add rule filter input ip saddr @allowed_hosts tcp dport @allowed_ports accept
+------------------
+
+The sets allowed_hosts and allowed_ports need to be created first. The next
+section describes nft set syntax in more detail.
+
+[verse]
+*add set* ['family'] 'table' 'set' *{ type* 'type' | *typeof* 'expression' *;* [*flags* 'flags' *;*] [*timeout* 'timeout' *;*] [*gc-interval* 'gc-interval' *;*] [*elements = {* 'element'[*,* ...] *} ;*] [*size* 'size' *;*] [*comment* 'comment' *;*'] [*policy* 'policy' *;*] [*auto-merge ;*] *}*
+{*delete* | *destroy* | *list* | *flush* | *reset* } *set* ['family'] 'table' 'set'
+*list sets* ['family']
+*delete set* ['family'] 'table' *handle* 'handle'
+{*add* | *delete* | *destroy* } *element* ['family'] 'table' 'set' *{* 'element'[*,* ...] *}*
+
+Sets are element containers of a user-defined data type, they are uniquely
+identified by a user-defined name and attached to tables. Their behaviour can
+be tuned with the flags that can be specified at set creation time.
+
+[horizontal]
+*add*:: Add a new set in the specified table. See the Set specification table below for more information about how to specify 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"]
+|=================
+|Keyword | Description | Type
+|type |
+data type of set elements |
+string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark
+|typeof |
+data type of set element |
+expression to derive the data type from
+|flags |
+set flags | string: constant, dynamic, interval, timeout. 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
+|gc-interval |
+garbage collection interval, only available when timeout or flag timeout are
+active |
+string, decimal followed by unit. Units are: d, h, m, s
+|elements |
+elements contained by the set |
+set data type
+|size |
+maximum number of elements in the set, mandatory if set is added to from the packet path (ruleset)|
+unsigned integer (64 bit)
+|policy |
+set policy |
+string: performance [default], memory
+|auto-merge |
+automatic merge of adjacent/overlapping set elements (only for interval sets) |
+|=================
+
+
+MAPS
+-----
+[verse]
+*add map* ['family'] 'table' 'map' *{ type* 'type' | *typeof* 'expression' [*flags* 'flags' *;*] [*elements = {* 'element'[*,* ...] *} ;*] [*size* 'size' *;*] [*comment* 'comment' *;*'] [*policy* 'policy' *;*] *}*
+{*delete* | *destroy* | *list* | *flush* | *reset* } *map* ['family'] 'table' 'map'
+*list maps* ['family']
+
+Maps store data based on some specific key used as input. They are uniquely identified by a user-defined name and attached to tables.
+
+[horizontal]
+*add*:: Add a new map in the specified table.
+*delete*:: Delete the specified map.
+*destroy*:: Delete the specified map, it does not fail if it does not exist.
+*list*:: Display the elements in the specified map.
+*flush*:: Remove all elements from the specified map.
+*reset*:: Reset state in all contained elements, e.g. counter and quota statement values.
+
+.Map specifications
+[options="header"]
+|=================
+|Keyword | Description | Type
+|type |
+data type of map elements |
+string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark, counter, quota. Counter and quota can't be used as keys
+|typeof |
+data type of set element |
+expression to derive the data type from
+|flags |
+map flags |
+string, same as set flags
+|elements |
+elements contained by the map |
+map data type
+|size |
+maximum number of elements in the map |
+unsigned integer (64 bit)
+| policy |
+map policy |
+string: performance [default], memory
+|=================
+
+Users can specifiy the properties/features that the set/map must support.
+This allows the kernel to pick an optimal internal representation.
+If a required flag is missing, the ruleset might still work, as
+nftables will auto-enable features if it can infer this from the ruleset.
+This may not work for all cases, however, so it is recommended to
+specify all required features in the set/map definition manually.
+
+.Set and Map flags
+[options="header"]
+|=================
+|Flag | Description
+|constant | Set contents will never change after creation
+|dynamic | Set must support updates from the packet path with the *add*, *update* or *delete* keywords.
+|interval | Set must be able to store intervals (ranges)
+|timeout | Set must support element timeouts (auto-removal of elements once they expire).
+|=================
+
+ELEMENTS
+--------
+[verse]
+____
+{*add* | *create* | *delete* | *destroy* | *get* | *reset* } *element* ['family'] 'table' 'set' *{* 'ELEMENT'[*,* ...] *}*
+
+'ELEMENT' := 'key_expression' 'OPTIONS' [*:* 'value_expression']
+'OPTIONS' := [*timeout* 'TIMESPEC'] [*expires* 'TIMESPEC'] [*comment* 'string']
+'TIMESPEC' := ['num'*d*]['num'*h*]['num'*m*]['num'[*s*]]
+____
+Element-related commands allow one to change contents of named sets and maps.
+'key_expression' is typically a value matching the set type.
+'value_expression' is not allowed in sets but mandatory when adding to maps, where it
+matches the data part in its type definition. When deleting from maps, it may
+be specified but is optional as 'key_expression' uniquely identifies the
+element.
+
+*create* command is similar to *add* with the exception that none of the
+listed elements may already exist.
+
+*get* command is useful to check if an element is contained in a set which may
+be non-trivial in very large and/or interval sets. In the latter case, the
+containing interval is returned instead of just the element itself.
+
+*reset* command resets state attached to the given element(s), e.g. counter and
+quota statement values.
+
+.Element options
+[options="header"]
+|=================
+|Option | Description
+|timeout |
+timeout value for sets/maps with flag *timeout*
+|expires |
+the time until given element expires, useful for ruleset replication only
+|comment |
+per element comment field
+|=================
+
+
+FLOWTABLES
+-----------
+[verse]
+{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'device'[*,* ...] *} ; }*
+*list flowtables* ['family']
+{*delete* | *destroy* | *list*} *flowtable* ['family'] 'table' 'flowtable'
+*delete* *flowtable* ['family'] 'table' *handle* 'handle'
+
+Flowtables allow you to accelerate packet forwarding in software. Flowtables
+entries are represented through a tuple that is composed of the input interface,
+source and destination address, source and destination port; and layer 3/4
+protocols. Each entry also caches the destination interface and the gateway
+address - to update the destination link-layer address - to forward packets.
+The ttl and hoplimit fields are also decremented. Hence, flowtables provides an
+alternative path that allow packets to bypass the classic forwarding path.
+Flowtables reside in the ingress hook that is located before the prerouting
+hook. You can select which flows you want to offload through the flow
+expression from the forward chain. Flowtables are identified by their address
+family and their name. The address family must be one of ip, ip6, or inet. The inet
+address family is a dummy family which is used to create hybrid IPv4/IPv6
+tables. When no address family is specified, ip is used by default.
+
+The *priority* can be a signed integer or *filter* which stands for 0. Addition
+and subtraction can be used to set relative priority, e.g. filter + 5 equals to
+5.
+
+[horizontal]
+*add*:: Add a new flowtable for the given family with the given name.
+*delete*:: Delete the specified flowtable.
+*destroy*:: Delete the specified flowtable, it does not fail if it does not exist.
+*list*:: List all flowtables.
+
+LISTING
+-------
+[verse]
+*list { secmarks | synproxys | flow tables | meters | hooks }* ['family']
+*list { secmarks | synproxys | flow tables | meters | hooks } table* ['family'] 'table'
+*list ct { timeout | expectation | helper | helpers } table* ['family'] 'table'
+
+Inspect configured objects.
+*list hooks* shows the full hook pipeline, including those registered by
+kernel modules, such as nf_conntrack.
+
+STATEFUL OBJECTS
+----------------
+[verse]
+{*add* | *delete* | *destroy* | *list* | *reset*} *counter* ['family'] 'table' 'object'
+{*add* | *delete* | *destroy* | *list* | *reset*} *quota* ['family'] 'table' 'object'
+{*add* | *delete* | *destroy* | *list*} *limit* ['family'] 'table' 'object'
+*delete* 'counter' ['family'] 'table' *handle* 'handle'
+*delete* 'quota' ['family'] 'table' *handle* 'handle'
+*delete* 'limit' ['family'] 'table' *handle* 'handle'
+*destroy* 'counter' ['family'] 'table' *handle* 'handle'
+*destroy* 'quota' ['family'] 'table' *handle* 'handle'
+*destroy* 'limit' ['family'] 'table' *handle* 'handle'
+*list counters* ['family']
+*list quotas* ['family']
+*list limits* ['family']
+*reset counters* ['family']
+*reset quotas* ['family']
+*reset counters* ['family'] 'table'
+*reset quotas* ['family'] 'table'
+
+Stateful objects are attached to tables and are identified by a unique name.
+They group stateful information from rules, to reference them in rules the
+keywords "type name" are used e.g. "counter name".
+
+[horizontal]
+*add*:: Add a new stateful object in the specified table.
+*delete*:: Delete the specified object.
+*destroy*:: Delete the specified object, it does not fail if it does not exist.
+*list*:: Display stateful information the object holds.
+*reset*:: List-and-reset stateful object.
+
+include::stateful-objects.txt[]
+
+EXPRESSIONS
+------------
+Expressions represent values, either constants like network addresses, port
+numbers, etc., or data gathered from the packet during ruleset evaluation.
+Expressions can be combined using binary, logical, relational and other types of
+expressions to form complex or relational (match) expressions. They are also
+used as arguments to certain types of operations, like NAT, packet marking etc.
+
+Each expression has a data type, which determines the size, parsing and
+representation of symbolic values and type compatibility with other expressions.
+
+DESCRIBE COMMAND
+~~~~~~~~~~~~~~~~
+[verse]
+*describe* 'expression' | 'data type'
+
+The *describe* command shows information about the type of an expression and its data type.
+A data type may also be given, in which nft will display more information
+about the type.
+
+.The describe command
+---------------------
+$ nft describe tcp flags
+payload expression, datatype tcp_flag (TCP flag) (basetype bitmask, integer), 8 bits
+
+predefined symbolic constants:
+fin 0x01
+syn 0x02
+rst 0x04
+psh 0x08
+ack 0x10
+urg 0x20
+ecn 0x40
+cwr 0x80
+---------------------
+
+DATA TYPES
+----------
+
+Data types determine the size, parsing and representation of symbolic values
+and type compatibility of expressions. A number of global data types exist, in
+addition some expression types define further data types specific to the
+expression type. Most data types have a fixed size, some however may have a
+dynamic size, f.i. the string type. +
+Some types also have predefined symbolic constants. Those can be listed
+using the nft *describe* command:
+
+---------------------
+$ nft describe ct_state
+datatype ct_state (conntrack state) (basetype bitmask, integer), 32 bits
+
+pre-defined symbolic constants (in hexadecimal):
+invalid 0x00000001
+new ...
+---------------------
+
+Types may be derived from lower order types, f.i. the IPv4 address type is
+derived from the integer type, meaning an IPv4 address can also be specified as
+an integer value. +
+
+In certain contexts (set and map definitions), it is necessary to explicitly
+specify a data type. Each type has a name which is used for this.
+
+include::data-types.txt[]
+
+PRIMARY EXPRESSIONS
+-------------------
+The lowest order expression is a primary expression, representing either a
+constant or a single datum from a packet's payload, meta data or a stateful
+module.
+
+include::primary-expression.txt[]
+
+PAYLOAD EXPRESSIONS
+-------------------
+Payload expressions refer to data from the packet's payload.
+
+include::payload-expression.txt[]
+
+STATEMENTS
+----------
+Statements represent actions to be performed. They can alter control flow
+(return, jump to a different chain, accept or drop the packet) or can perform
+actions, such as logging, rejecting a packet, etc. +
+
+Statements exist in two kinds. Terminal statements unconditionally terminate
+evaluation of the current rule, non-terminal statements either only
+conditionally or never terminate evaluation of the current rule, in other words,
+they are passive from the ruleset evaluation perspective. There can be an
+arbitrary amount of non-terminal statements in a rule, but only a single
+terminal statement as the final statement.
+
+include::statements.txt[]
+
+ADDITIONAL COMMANDS
+-------------------
+These are some additional commands included in nft.
+
+MONITOR
+~~~~~~~~
+The monitor command allows you to listen to Netlink events produced by the
+nf_tables subsystem. These are either related to creation and deletion of
+objects or to packets for which *meta nftrace* was enabled. When they
+occur, nft will print to stdout the monitored events in either JSON or
+native nft format. +
+
+[verse]
+____
+*monitor* [*new* | *destroy*] 'MONITOR_OBJECT'
+*monitor* *trace*
+
+'MONITOR_OBJECT' := *tables* | *chains* | *sets* | *rules* | *elements* | *ruleset*
+____
+
+To filter events related to a concrete object, use one of the keywords in
+'MONITOR_OBJECT'.
+
+To filter events related to a concrete action, use keyword *new* or *destroy*.
+
+The second form of invocation takes no further options and exclusively prints
+events generated for packets with *nftrace* enabled.
+
+Hit ^C to finish the monitor operation.
+
+.Listen to all events, report in native nft format
+--------------------------------------------------
+% nft monitor
+--------------------------------------------------
+
+.Listen to deleted rules, report in JSON format
+-----------------------------------------------
+% nft -j monitor destroy rules
+-----------------------------------------------
+
+.Listen to both new and destroyed chains, in native nft format
+-----------------------------------------------------------------
+% nft monitor chains
+-------------------------------
+
+.Listen to ruleset events such as table, chain, rule, set, counters and quotas, in native nft format
+----------------------------------------------------------------------------------------------------
+% nft monitor ruleset
+---------------------
+
+.Trace incoming packets from host 10.0.0.1
+------------------------------------------
+% nft add rule filter input ip saddr 10.0.0.1 meta nftrace set 1
+% nft monitor trace
+------------------------------------------
+
+ERROR REPORTING
+---------------
+When an error is detected, nft shows the line(s) containing the error, the
+position of the erroneous parts in the input stream and marks up the erroneous
+parts using carets (^). If the error results from the combination of two
+expressions or statements, the part imposing the constraints which are violated
+is marked using tildes (~). +
+
+For errors returned by the kernel, nft cannot detect which parts of the input
+caused the error and the entire command is marked.
+
+.Error caused by single incorrect expression
+--------------------------------------------
+<cmdline>:1:19-22: Error: Interface does not exist
+filter output oif eth0
+ ^^^^
+--------------------------------------------
+
+.Error caused by invalid combination of two expressions
+-------------------------------------------------------
+<cmdline>:1:28-36: Error: Right hand side of relational expression (==) must be constant
+filter output tcp dport == tcp dport
+ ~~ ^^^^^^^^^
+-------------------------------------------------------
+
+.Error returned by the kernel
+-----------------------------
+<cmdline>:0:0-23: Error: Could not process rule: Operation not permitted
+filter output oif wlan0
+^^^^^^^^^^^^^^^^^^^^^^^
+---------------------------------
+
+EXIT STATUS
+-----------
+On success, nft exits with a status of 0. Unspecified errors cause it to exit
+with a status of 1, memory allocation errors with a status of 2, unable to open
+Netlink socket with 3.
+
+SEE ALSO
+--------
+[verse]
+libnftables(3), libnftables-json(5), iptables(8), ip6tables(8), arptables(8), ebtables(8), ip(8), tc(8)
+
+There is an official wiki at: https://wiki.nftables.org
+
+AUTHORS
+-------
+nftables was written by Patrick McHardy and Pablo Neira Ayuso, among many other contributors from the Netfilter community.
+
+COPYRIGHT
+---------
+Copyright © 2008-2014 Patrick McHardy <kaber@trash.net> Copyright © 2013-2018 Pablo Neira Ayuso <pablo@netfilter.org> +
+
+nftables 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. +
+
+This documentation is licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 license, CC BY-SA 4.0 http://creativecommons.org/licenses/by-sa/4.0/.
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
new file mode 100644
index 0000000..c7c267d
--- /dev/null
+++ b/doc/payload-expression.txt
@@ -0,0 +1,973 @@
+ETHERNET HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*ether* {*daddr* | *saddr* | *type*}
+
+.Ethernet header expression types
+[options="header"]
+|==================
+|Keyword| Description| Type
+|daddr|
+Destination MAC address|
+ether_addr
+|saddr|
+Source MAC address|
+ether_addr
+|type|
+EtherType|
+ether_type
+|==================
+
+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"]
+|==================
+|Keyword| Description| Type
+|id|
+VLAN ID (VID) |
+integer (12 bit)
+|dei|
+Drop Eligible Indicator|
+integer (1 bit)
+|pcp|
+Priority code point|
+integer (3 bit)
+|type|
+EtherType|
+ether_type
+|==================
+
+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
+|======================
+
+IPV4 HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* }
+
+.IPv4 header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|version|
+IP header version (4)|
+integer (4 bit)
+|hdrlength|
+IP header length including options|
+integer (4 bit) FIXME scaling
+|dscp|
+Differentiated Services Code Point|
+dscp
+|ecn|
+Explicit Congestion Notification|
+ecn
+|length|
+Total packet length |
+integer (16 bit)
+|id|
+IP ID|
+integer (16 bit)
+|frag-off|
+Fragment offset |
+integer (16 bit)
+|ttl|
+Time to live|
+integer (8 bit)
+|protocol|
+Upper layer protocol |
+inet_proto
+|checksum|
+IP header checksum|
+integer (16 bit)
+|saddr|
+Source address|
+ipv4_addr
+|daddr|
+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]
+*icmp* {*type* | *code* | *checksum* | *id* | *sequence* | *gateway* | *mtu*}
+
+This expression refers to ICMP header fields. When using it in *inet*,
+*bridge* or *netdev* families, it will cause an implicit dependency on IPv4 to
+be created. To match on unusual cases like ICMP over IPv6, one has to add an
+explicit *meta protocol ip6* match to the rule.
+
+.ICMP header expression
+[options="header"]
+|==================
+|Keyword|Description| Type
+|type|
+ICMP type field |
+icmp_type
+|code|
+ICMP code field |
+integer (8 bit)
+|checksum|
+ICMP checksum field |
+integer (16 bit)
+|id|
+ID of echo request/response |
+integer (16 bit)
+|sequence|
+sequence number of echo request/response|
+integer (16 bit)
+|gateway|
+gateway of redirects|
+integer (32 bit)
+|mtu|
+MTU of path MTU discovery|
+integer (16 bit)
+|============================
+
+IGMP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*igmp* {*type* | *mrt* | *checksum* | *group*}
+
+This expression refers to IGMP header fields. When using it in *inet*,
+*bridge* or *netdev* families, it will cause an implicit dependency on IPv4 to
+be created. To match on unusual cases like IGMP over IPv6, one has to add an
+explicit *meta protocol ip6* match to the rule.
+
+.IGMP header expression
+[options="header"]
+|==================
+|Keyword|Description| Type
+|type|
+IGMP type field |
+igmp_type
+|mrt|
+IGMP maximum response time field |
+integer (8 bit)
+|checksum|
+IGMP checksum field |
+integer (16 bit)
+|group|
+Group address|
+integer (32 bit)
+|============================
+
+IPV6 HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*}
+
+This expression refers to the ipv6 header fields. Caution when using *ip6
+nexthdr*, the value only refers to the next header, i.e. *ip6 nexthdr tcp* will
+only match if the ipv6 packet does not contain any extension headers. Packets
+that are fragmented or e.g. contain a routing extension headers will not be
+matched. Please use *meta l4proto* if you wish to match the real transport header
+and ignore any additional extension headers instead.
+
+.IPv6 header expression
+[options="header"]
+|==================
+|Keyword|Description| Type
+|version|
+IP header version (6)|
+integer (4 bit)
+|dscp|
+Differentiated Services Code Point|
+dscp
+|ecn|
+Explicit Congestion Notification|
+ecn
+|flowlabel|
+Flow label|
+integer (20 bit)
+|length|
+Payload length|
+integer (16 bit)
+|nexthdr|
+Nexthdr protocol|
+inet_proto
+|hoplimit|
+Hop limit|
+integer (8 bit)
+|saddr|
+Source address|
+ipv6_addr
+|daddr|
+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
+ip6 nexthdr ipv6-frag
+-----------------------------
+
+ICMPV6 HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*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
+be created. To match on unusual cases like ICMPv6 over IPv4, one has to add an
+explicit *meta protocol ip* match to the rule.
+
+.ICMPv6 header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|type|
+ICMPv6 type field|
+icmpv6_type
+|code|
+ICMPv6 code field|
+integer (8 bit)
+|checksum|
+ICMPv6 checksum field|
+integer (16 bit)
+|parameter-problem|
+pointer to problem|
+integer (32 bit)
+|packet-too-big|
+oversized MTU|
+integer (32 bit)
+|id|
+ID of echo request/response |
+integer (16 bit)
+|sequence|
+sequence number of echo request/response|
+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
+~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*tcp* {*sport* | *dport* | *sequence* | *ackseq* | *doff* | *reserved* | *flags* | *window* | *checksum* | *urgptr*}
+
+.TCP header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|sport|
+Source port|
+inet_service
+|dport|
+Destination port|
+inet_service
+|sequence|
+Sequence number|
+integer (32 bit)
+|ackseq|
+Acknowledgement number |
+integer (32 bit)
+|doff|
+Data offset |
+integer (4 bit) FIXME scaling
+|reserved|
+Reserved area |
+integer (4 bit)
+|flags|
+TCP flags|
+tcp_flag
+|window|
+Window|
+integer (16 bit)
+|checksum|
+Checksum|
+integer (16 bit)
+|urgptr|
+Urgent pointer|
+integer (16 bit)
+|======================
+
+UDP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*udp* {*sport* | *dport* | *length* | *checksum*}
+
+.UDP header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|sport|
+Source port|
+inet_service
+|dport|
+Destination port|
+inet_service
+|length|
+Total packet length|
+integer (16 bit)
+|checksum|
+Checksum|
+integer (16 bit)
+|================
+
+UDP-LITE HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*udplite* {*sport* | *dport* | *checksum*}
+
+.UDP-Lite header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|sport|
+Source port|
+inet_service
+|dport|
+Destination port|
+inet_service
+|checksum|
+Checksum|
+integer (16 bit)
+|================
+
+SCTP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+____
+*sctp* {*sport* | *dport* | *vtag* | *checksum*}
+*sctp chunk* 'CHUNK' [ 'FIELD' ]
+
+'CHUNK' := *data* | *init* | *init-ack* | *sack* | *heartbeat* |
+ *heartbeat-ack* | *abort* | *shutdown* | *shutdown-ack* | *error* |
+ *cookie-echo* | *cookie-ack* | *ecne* | *cwr* | *shutdown-complete*
+ | *asconf-ack* | *forward-tsn* | *asconf*
+
+'FIELD' := 'COMMON_FIELD' | 'DATA_FIELD' | 'INIT_FIELD' | 'INIT_ACK_FIELD' |
+ 'SACK_FIELD' | 'SHUTDOWN_FIELD' | 'ECNE_FIELD' | 'CWR_FIELD' |
+ 'ASCONF_ACK_FIELD' | 'FORWARD_TSN_FIELD' | 'ASCONF_FIELD'
+
+'COMMON_FIELD' := *type* | *flags* | *length*
+'DATA_FIELD' := *tsn* | *stream* | *ssn* | *ppid*
+'INIT_FIELD' := *init-tag* | *a-rwnd* | *num-outbound-streams* |
+ *num-inbound-streams* | *initial-tsn*
+'INIT_ACK_FIELD' := 'INIT_FIELD'
+'SACK_FIELD' := *cum-tsn-ack* | *a-rwnd* | *num-gap-ack-blocks* |
+ *num-dup-tsns*
+'SHUTDOWN_FIELD' := *cum-tsn-ack*
+'ECNE_FIELD' := *lowest-tsn*
+'CWR_FIELD' := *lowest-tsn*
+'ASCONF_ACK_FIELD' := *seqno*
+'FORWARD_TSN_FIELD' := *new-cum-tsn*
+'ASCONF_FIELD' := *seqno*
+____
+
+.SCTP header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|sport|
+Source port|
+inet_service
+|dport|
+Destination port|
+inet_service
+|vtag|
+Verification Tag|
+integer (32 bit)
+|checksum|
+Checksum|
+integer (32 bit)
+|chunk|
+Search chunk in packet|
+without 'FIELD', boolean indicating existence
+|================
+
+.SCTP chunk fields
+[options="header"]
+|==================
+|Name| Width in bits | Chunk | Notes
+|type| 8 | all | not useful, defined by chunk type
+|flags| 8 | all | semantics defined on per-chunk basis
+|length| 16 | all | length of this chunk in bytes excluding padding
+|tsn| 32 | data | transmission sequence number
+|stream| 16 | data | stream identifier
+|ssn| 16 | data | stream sequence number
+|ppid| 32 | data | payload protocol identifier
+|init-tag| 32 | init, init-ack | initiate tag
+|a-rwnd| 32 | init, init-ack, sack | advertised receiver window credit
+|num-outbound-streams| 16 | init, init-ack | number of outbound streams
+|num-inbound-streams| 16 | init, init-ack | number of inbound streams
+|initial-tsn| 32 | init, init-ack | initial transmit sequence number
+|cum-tsn-ack| 32 | sack, shutdown | cumulative transmission sequence number acknowledged
+|num-gap-ack-blocks| 16 | sack | number of Gap Ack Blocks included
+|num-dup-tsns| 16 | sack | number of duplicate transmission sequence numbers received
+|lowest-tsn| 32 | ecne, cwr | lowest transmission sequence number
+|seqno| 32 | asconf-ack, asconf | sequence number
+|new-cum-tsn| 32 | forward-tsn | new cumulative transmission sequence number
+|==================
+
+DCCP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*dccp* {*sport* | *dport* | *type*}
+
+.DCCP header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|sport|
+Source port|
+inet_service
+|dport|
+Destination port|
+inet_service
+|type|
+Packet type|
+dccp_pkttype
+|========================
+
+AUTHENTICATION HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*ah* {*nexthdr* | *hdrlength* | *reserved* | *spi* | *sequence*}
+
+.AH header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|nexthdr|
+Next header protocol|
+inet_proto
+|hdrlength|
+AH Header length|
+integer (8 bit)
+|reserved|
+Reserved area|
+integer (16 bit)
+|spi|
+Security Parameter Index |
+integer (32 bit)
+|sequence|
+Sequence number|
+integer (32 bit)
+|========================
+
+ENCRYPTED SECURITY PAYLOAD HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*esp* {*spi* | *sequence*}
+
+.ESP header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|spi|
+Security Parameter Index |
+integer (32 bit)
+|sequence|
+Sequence number|
+integer (32 bit)
+|===========================
+
+IPCOMP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~~
+*comp* {*nexthdr* | *flags* | *cpi*}
+
+.IPComp header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|nexthdr|
+Next header protocol|
+inet_proto
+|flags|
+Flags|
+bitmask
+|cpi|
+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]
+*@*'base'*,*'offset'*,*'length'
+
+The raw payload expression instructs to load 'length' bits starting at 'offset' bits.
+Bit 0 refers to the very first bit -- in the C programming language, this
+corresponds to the topmost bit, i.e. 0x80 in case of an octet. They are useful
+to match headers that do not have a human-readable template expression yet. Note
+that nft will not add dependencies for Raw payload expressions. If you e.g. want
+to match protocol fields of a transport header with protocol number 5, you need
+to manually exclude packets that have a different transport header, for instance
+by using *meta l4proto 5* before the raw expression.
+
+.Supported payload protocol bases
+[options="header"]
+|==================
+|Base| Description
+|ll|
+Link layer, for example the Ethernet header
+|nh|
+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
+----------------------------------------------
+inet filter input meta l4proto {tcp, udp} @th,16,16 { 53, 80 }
+-----------------------------------------------------------------
+The above can also be written as
+-----------------------------------------------------------------
+inet filter input meta l4proto {tcp, udp} th dport { 53, 80 }
+-----------------------------------------------------------------
+it is more convenient, but like the raw expression notation no
+dependencies are created or checked. It is the users responsibility
+to restrict matching to those header types that have a notion of ports.
+Otherwise, rules using raw expressions will errnously match unrelated
+packets, e.g. mis-interpreting ESP packets SPI field as a port.
+
+.Rewrite arp packet target hardware address if target protocol address matches a given address
+----------------------------------------------------------------------------------------------
+input meta iifname enp2s0 arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566 accept
+-----------------------------------------------------------------------------------------------
+
+EXTENSION HEADER EXPRESSIONS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Extension header expressions refer to data from variable-sized protocol headers, such as IPv6 extension headers, TCP options and IPv4 options.
+
+nftables currently supports matching (finding) a given ipv6 extension header, TCP option or IPv4 option.
+[verse]
+*hbh* {*nexthdr* | *hdrlength*}
+*frag* {*nexthdr* | *frag-off* | *more-fragments* | *id*}
+*rt* {*nexthdr* | *hdrlength* | *type* | *seg-left*}
+*dst* {*nexthdr* | *hdrlength*}
+*mh* {*nexthdr* | *hdrlength* | *checksum* | *type*}
+*srh* {*flags* | *tag* | *sid* | *seg-left*}
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
+*ip option* { lsrr | ra | rr | ssrr } 'ip_option_field'
+
+The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only:
+[verse]
+*exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
+*tcp option* {*eol* | *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"]
+|==================
+|Keyword| Description
+|hbh|
+Hop by Hop
+|rt|
+Routing Header
+|frag|
+Fragmentation header
+|dst|
+dst options
+|mh|
+Mobility Header
+|srh|
+Segment Routing Header
+|=====================
+
+.TCP Options
+[options="header"]
+|==================
+|Keyword| Description | TCP option fields
+|eol|
+End if option list|
+-
+|nop|
+1 Byte TCP Nop padding option |
+-
+|maxseg|
+TCP Maximum Segment Size|
+length, size
+|window|
+TCP Window Scaling |
+length, count
+|sack-perm |
+TCP SACK permitted |
+length
+|sack|
+TCP Selective Acknowledgement (alias of block 0) |
+length, left, right
+|sack0|
+TCP Selective Acknowledgement (block 0) |
+length, left, right
+|sack1|
+TCP Selective Acknowledgement (block 1) |
+length, left, right
+|sack2|
+TCP Selective Acknowledgement (block 2) |
+length, left, right
+|sack3|
+TCP Selective Acknowledgement (block 3) |
+length, left, right
+|timestamp|
+TCP Timestamps |
+length, tsval, tsecr
+|============================
+
+TCP option matching also supports raw expression syntax to access arbitrary options:
+[verse]
+*tcp option*
+[verse]
+*tcp option* *@*'number'*,*'offset'*,*'length'
+
+.IP Options
+[options="header"]
+|==================
+|Keyword| Description | IP option fields
+|lsrr|
+Loose Source Route |
+type, length, ptr, addr
+|ra|
+Router Alert |
+type, length, value
+|rr|
+Record Route |
+type, length, ptr, addr
+|ssrr|
+Strict Source Route |
+type, length, ptr, addr
+|============================
+
+.finding TCP options
+--------------------
+filter input tcp option sack-perm exists counter
+--------------------
+
+.matching TCP options
+--------------------
+filter input tcp option maxseg size lt 536
+--------------------
+
+.matching IPv6 exthdr
+---------------------
+ip6 filter input frag more-fragments 1 counter
+---------------------------------------
+
+.finding IP option
+------------------
+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. +
+
+There are three types of conntrack expressions. Some conntrack expressions
+require the flow direction before the conntrack key, others must be used
+directly because they are direction agnostic. The *packets*, *bytes* and
+*avgpkt* keywords can be used with or without a direction. If the direction is
+omitted, the sum of the original and the reply direction is returned. The same
+is true for the *zone*, if a direction is given, the zone is only matched if the
+zone id is tied to the given direction. +
+
+[verse]
+*ct* {*state* | *direction* | *status* | *mark* | *expiration* | *helper* | *label* | *count* | *id*}
+*ct* [*original* | *reply*] {*l3proto* | *protocol* | *bytes* | *packets* | *avgpkt* | *zone*}
+*ct* {*original* | *reply*} {*proto-src* | *proto-dst*}
+*ct* {*original* | *reply*} {*ip* | *ip6*} {*saddr* | *daddr*}
+
+The conntrack-specific types in this table are described in the sub-section CONNTRACK TYPES above.
+
+.Conntrack expressions
+[options="header"]
+|==================
+|Keyword| Description | Type
+|state|
+State of the connection |
+ct_state
+|direction|
+Direction of the packet relative to the connection |
+ct_dir
+|status|
+Status of the connection |
+ct_status
+|mark|
+Connection mark |
+mark
+|expiration|
+Connection expiration time |
+time
+|helper|
+Helper associated with the connection|
+string
+|label|
+Connection tracking label bit or symbolic name defined in connlabel.conf in the nftables include path|
+ct_label
+|l3proto|
+Layer 3 protocol of the connection|
+nf_proto
+|saddr|
+Source address of the connection for the given direction |
+ipv4_addr/ipv6_addr
+|daddr|
+Destination address of the connection for the given direction |
+ipv4_addr/ipv6_addr
+|protocol|
+Layer 4 protocol of the connection for the given direction |
+inet_proto
+|proto-src|
+Layer 4 protocol source for the given direction|
+integer (16 bit)
+|proto-dst|
+Layer 4 protocol destination for the given direction |
+integer (16 bit)
+|packets|
+packet count seen in the given direction or sum of original and reply |
+integer (64 bit)
+|bytes|
+byte count seen, see description for *packets* keyword |
+integer (64 bit)
+|avgpkt|
+average bytes per packet, see description for *packets* keyword |
+integer (64 bit)
+|zone|
+conntrack zone |
+integer (16 bit)
+|count|
+number of current connections|
+integer (32 bit)
+|id|
+Connection id|
+ct_id|
+|==========================================
+
+.restrict the number of parallel connections to a server
+--------------------
+nft add set filter ssh_flood '{ type ipv4_addr; flags dynamic; }'
+nft add rule filter input tcp dport 22 add @ssh_flood '{ ip saddr ct count over 2 }' reject
+--------------------
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
new file mode 100644
index 0000000..e13970c
--- /dev/null
+++ b/doc/primary-expression.txt
@@ -0,0 +1,488 @@
+META EXPRESSIONS
+~~~~~~~~~~~~~~~~
+[verse]
+*meta* {*length* | *nfproto* | *l4proto* | *protocol* | *priority*}
+[*meta*] {*mark* | *iif* | *iifname* | *iiftype* | *oif* | *oifname* | *oiftype* | *skuid* | *skgid* | *nftrace* | *rtclassid* | *ibrname* | *obrname* | *pkttype* | *cpu* | *iifgroup* | *oifgroup* | *cgroup* | *random* | *ipsec* | *iifkind* | *oifkind* | *time* | *hour* | *day* }
+
+A meta expression refers to meta data associated with a packet.
+
+There are two types of meta expressions: unqualified and qualified meta
+expressions. Qualified meta expressions require the meta keyword before the meta
+key, unqualified meta expressions can be specified by using the meta key
+directly or as qualified meta expressions. Meta l4proto is useful to match a
+particular transport protocol that is part of either an IPv4 or IPv6 packet. It
+will also skip any IPv6 extension headers present in an IPv6 packet.
+
+meta iif, oif, iifname and oifname are used to match the interface a packet
+arrived on or is about to be sent out on.
+
+iif and oif are used to match on the interface index, whereas iifname and
+oifname are used to match on the interface name.
+This is not the same -- assuming the rule
+
+ filter input meta iif "foo"
+
+Then this rule can only be added if the interface "foo" exists.
+Also, the rule will continue to match even if the
+interface "foo" is renamed to "bar".
+
+This is because internally the interface index is used.
+In case of dynamically created interfaces, such as tun/tap or dialup
+interfaces (ppp for example), it might be better to use iifname or oifname
+instead.
+
+In these cases, the name is used so the interface doesn't have to exist to
+add such a rule, it will stop matching if the interface gets renamed and it
+will match again in case interface gets deleted and later a new interface
+with the same name is created.
+
+Like with iptables, wildcard matching on interface name prefixes is available for
+*iifname* and *oifname* matches by appending an asterisk (*) character. Note
+however that unlike iptables, nftables does not accept interface names
+consisting of the wildcard character only - users are supposed to just skip
+those always matching expressions. In order to match on literal asterisk
+character, one may escape it using backslash (\).
+
+.Meta expression types
+[options="header"]
+|==================
+|Keyword | Description | Type
+|length|
+Length of the packet in bytes|
+integer (32-bit)
+|nfproto|
+real hook protocol family, useful only in inet table|
+integer (32 bit)
+|l4proto|
+layer 4 protocol, skips ipv6 extension headers|
+integer (8 bit)
+|protocol|
+EtherType protocol value|
+ether_type
+|priority|
+TC packet priority|
+tc_handle
+|mark|
+Packet mark |
+mark
+|iif|
+Input interface index |
+iface_index
+|iifname|
+Input interface name |
+ifname
+|iiftype|
+Input interface type|
+iface_type
+|oif|
+Output interface index|
+iface_index
+|oifname|
+Output interface name|
+ifname
+|oiftype|
+Output interface hardware type|
+iface_type
+|sdif|
+Slave device input interface index |
+iface_index
+|sdifname|
+Slave device interface name|
+ifname
+|skuid|
+UID associated with originating socket|
+uid
+|skgid|
+GID associated with originating socket|
+gid
+|rtclassid|
+Routing realm|
+realm
+|ibrname|
+Input bridge interface name|
+ifname
+|obrname|
+Output bridge interface name|
+ifname
+|pkttype|
+packet type|
+pkt_type
+|cpu|
+cpu number processing the packet|
+integer (32 bit)
+|iifgroup|
+incoming device group|
+devgroup
+|oifgroup|
+outgoing device group|
+devgroup
+|cgroup|
+control group id |
+integer (32 bit)
+|random|
+pseudo-random number|
+integer (32 bit)
+|ipsec|
+true if packet was ipsec encrypted |
+boolean (1 bit)
+|iifkind|
+Input interface kind |
+|oifkind|
+Output interface kind|
+|time|
+Absolute time of packet reception|
+Integer (32 bit) or string
+|day|
+Day of week|
+Integer (8 bit) or string
+|hour|
+Hour of day|
+String
+|====================
+
+.Meta expression specific types
+[options="header"]
+|==================
+|Type | Description
+|iface_index |
+Interface index (32 bit number). Can be specified numerically or as name of an existing interface.
+|ifname|
+Interface name (16 byte string). Does not have to exist.
+|iface_type|
+Interface type (16 bit number).
+|uid|
+User ID (32 bit number). Can be specified numerically or as user name.
+|gid|
+Group ID (32 bit number). Can be specified numerically or as group name.
+|realm|
+Routing Realm (32 bit number). Can be specified numerically or as symbolic name defined in /etc/iproute2/rt_realms.
+|devgroup_type|
+Device group (32 bit number). Can be specified numerically or as symbolic name defined in /etc/iproute2/group.
+|pkt_type|
+Packet type: *host* (addressed to local host), *broadcast* (to all),
+*multicast* (to group), *other* (addressed to another host).
+|ifkind|
+Interface kind (16 byte string). See TYPES in ip-link(8) for a list.
+|time|
+Either an integer or a date in ISO format. For example: "2019-06-06 17:00".
+Hour and seconds are optional and can be omitted if desired. If omitted,
+midnight will be assumed.
+The following three would be equivalent: "2019-06-06", "2019-06-06 00:00"
+and "2019-06-06 00:00:00".
+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.
+|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.
+|=============================
+
+.Using meta expressions
+-----------------------
+# qualified meta expression
+filter output meta oif eth0
+filter forward meta iifkind { "tun", "veth" }
+
+# unqualified meta expression
+filter output oif eth0
+
+# incoming packet was subject to ipsec processing
+raw prerouting meta ipsec exists accept
+-----------------------
+
+SOCKET EXPRESSION
+~~~~~~~~~~~~~~~~~
+[verse]
+*socket* {*transparent* | *mark* | *wildcard*}
+*socket* *cgroupv2* *level* 'NUM'
+
+Socket expression can be used to search for an existing open TCP/UDP socket and
+its attributes that can be associated with a packet. It looks for an established
+or non-zero bound listening socket (possibly with a non-local address). You can
+also use it to match on the socket cgroupv2 at a given ancestor level, e.g. if
+the socket belongs to cgroupv2 'a/b', ancestor level 1 checks for a matching on
+cgroup 'a' and ancestor level 2 checks for a matching on cgroup 'b'.
+
+.Available socket attributes
+[options="header"]
+|==================
+|Name |Description| Type
+|transparent|
+Value of the IP_TRANSPARENT socket option in the found socket. It can be 0 or 1.|
+boolean (1 bit)
+|mark| Value of the socket mark (SOL_SOCKET, SO_MARK). | mark
+|wildcard|
+Indicates whether the socket is wildcard-bound (e.g. 0.0.0.0 or ::0). |
+boolean (1 bit)
+|cgroupv2|
+cgroup version 2 for this socket (path from /sys/fs/cgroup)|
+cgroupv2
+|==================
+
+.Using socket expression
+------------------------
+# Mark packets that correspond to a transparent socket. "socket wildcard 0"
+# means that zero-bound listener sockets are NOT matched (which is usually
+# exactly what you want).
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ socket transparent 1 socket wildcard 0 mark set 0x00000001 accept
+ }
+}
+
+# Trace packets that corresponds to a socket with a mark value of 15
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ socket mark 0x0000000f nftrace set 1
+ }
+}
+
+# Set packet mark to socket mark
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport 8080 mark set socket mark
+ }
+}
+
+# Count packets for cgroupv2 "user.slice" at level 1
+table inet x {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ socket cgroupv2 level 1 "user.slice" counter
+ }
+}
+----------------------
+
+OSF EXPRESSION
+~~~~~~~~~~~~~~
+[verse]
+*osf* [*ttl* {*loose* | *skip*}] {*name* | *version*}
+
+The osf expression does passive operating system fingerprinting. This
+expression compares some data (Window Size, MSS, options and their order, DF,
+and others) from packets with the SYN bit set.
+
+.Available osf attributes
+[options="header"]
+|==================
+|Name |Description| Type
+|ttl|
+Do TTL checks on the packet to determine the operating system.|
+string
+|version|
+Do OS version checks on the packet.|
+|name|
+Name of the OS signature to match. All signatures can be found at pf.os file.
+Use "unknown" for OS signatures that the expression could not detect.|
+string
+|==================
+
+.Available ttl values
+---------------------
+If no TTL attribute is passed, make a true IP header and fingerprint TTL true comparison. This generally works for LANs.
+
+* loose: Check if the IP header's TTL is less than the fingerprint one. Works for globally-routable addresses.
+* skip: Do not compare the TTL at all.
+---------------------
+
+.Using osf expression
+---------------------
+# Accept packets that match the "Linux" OS genre signature without comparing TTL.
+table inet x {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ osf ttl skip name "Linux"
+ }
+}
+-----------------------
+
+FIB EXPRESSIONS
+~~~~~~~~~~~~~~~
+[verse]
+*fib* {*saddr* | *daddr* | *mark* | *iif* | *oif*} [*.* ...] {*oif* | *oifname* | *type*}
+
+A fib expression queries the fib (forwarding information base) to obtain
+information such as the output interface index a particular address would use.
+The input is a tuple of elements that is used as input to the fib lookup
+functions.
+
+.fib expression specific types
+[options="header"]
+|==================
+|Keyword| Description| Type
+|oif|
+Output interface index|
+integer (32 bit)
+|oifname|
+Output interface name|
+string
+|type|
+Address type |
+fib_addrtype
+|=======================
+
+Use *nft* *describe* *fib_addrtype* to get a list of all address types.
+
+.Using fib expressions
+----------------------
+# drop packets without a reverse path
+filter prerouting fib saddr . iif oif missing drop
+
+In this example, 'saddr . iif' looks up routing information based on the source address and the input interface.
+oif picks the output interface index from the routing information.
+If no route was found for the source address/input interface combination, the output interface index is zero.
+In case the input interface is specified as part of the input key, the output interface index is always the same as the input interface index or zero.
+If only 'saddr oif' is given, then oif can be any interface index or zero.
+
+# drop packets to address not configured on incoming interface
+filter prerouting fib daddr . iif type != { local, broadcast, multicast } drop
+
+# perform lookup in a specific 'blackhole' table (0xdead, needs ip appropriate ip rule)
+filter prerouting meta mark set 0xdead fib daddr . mark type vmap { blackhole : drop, prohibit : jump prohibited, unreachable : drop }
+----------------------
+
+ROUTING EXPRESSIONS
+~~~~~~~~~~~~~~~~~~~
+[verse]
+*rt* [*ip* | *ip6*] {*classid* | *nexthop* | *mtu* | *ipsec*}
+
+A routing expression refers to routing data associated with a packet.
+
+.Routing expression types
+[options="header"]
+|=======================
+|Keyword| Description| Type
+|classid|
+Routing realm|
+realm
+|nexthop|
+Routing nexthop|
+ipv4_addr/ipv6_addr
+|mtu|
+TCP maximum segment size of route |
+integer (16 bit)
+|ipsec|
+route via ipsec tunnel or transport |
+boolean
+|=================================
+
+.Routing expression specific types
+[options="header"]
+|=======================
+|Type| Description
+|realm|
+Routing Realm (32 bit number). Can be specified numerically or as symbolic name defined in /etc/iproute2/rt_realms.
+|========================
+
+.Using routing expressions
+--------------------------
+# IP family independent rt expression
+filter output rt classid 10
+
+# IP family dependent rt expressions
+ip filter output rt nexthop 192.168.0.1
+ip6 filter output rt nexthop fd00::1
+inet filter output rt ip nexthop 192.168.0.1
+inet filter output rt ip6 nexthop fd00::1
+
+# outgoing packet will be encapsulated/encrypted by ipsec
+filter output rt ipsec exists
+--------------------------
+
+IPSEC EXPRESSIONS
+~~~~~~~~~~~~~~~~~
+
+[verse]
+*ipsec* {*in* | *out*} [ *spnum* 'NUM' ] {*reqid* | *spi*}
+*ipsec* {*in* | *out*} [ *spnum* 'NUM' ] {*ip* | *ip6*} {*saddr* | *daddr*}
+
+An ipsec expression refers to ipsec data associated with a packet.
+
+The 'in' or 'out' keyword needs to be used to specify if the expression should
+examine inbound or outbound policies. The 'in' keyword can be used in the
+prerouting, input and forward hooks. The 'out' keyword applies to forward,
+output and postrouting hooks.
+The optional keyword spnum can be used to match a specific state in a chain,
+it defaults to 0.
+
+.Ipsec expression types
+[options="header"]
+|=======================
+|Keyword| Description| Type
+|reqid|
+Request ID|
+integer (32 bit)
+|spi|
+Security Parameter Index|
+integer (32 bit)
+|saddr|
+Source address of the tunnel|
+ipv4_addr/ipv6_addr
+|daddr|
+Destination address of the tunnel|
+ipv4_addr/ipv6_addr
+|=================================
+
+*Note:* When using xfrm_interface, this expression is not useable in output
+hook as the plain packet does not traverse it with IPsec info attached - use a
+chain in postrouting hook instead.
+
+NUMGEN EXPRESSION
+~~~~~~~~~~~~~~~~~
+
+[verse]
+*numgen* {*inc* | *random*} *mod* 'NUM' [ *offset* 'NUM' ]
+
+Create a number generator. The *inc* or *random* keywords control its
+operation mode: In *inc* mode, the last returned value is simply incremented.
+In *random* mode, a new random number is returned. The value after *mod*
+keyword specifies an upper boundary (read: modulus) which is not reached by
+returned numbers. The optional *offset* allows one to increment the returned value
+by a fixed offset.
+
+A typical use-case for *numgen* is load-balancing:
+
+.Using numgen expression
+------------------------
+# round-robin between 192.168.10.100 and 192.168.20.200:
+add rule nat prerouting dnat to numgen inc mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+
+# probability-based with odd bias using intervals:
+add rule nat prerouting dnat to numgen random mod 10 map \
+ { 0-2 : 192.168.10.100, 3-9 : 192.168.20.200 }
+------------------------
+
+HASH EXPRESSIONS
+~~~~~~~~~~~~~~~~
+
+[verse]
+*jhash* {*ip saddr* | *ip6 daddr* | *tcp dport* | *udp sport* | *ether saddr*} [*.* ...] *mod* 'NUM' [ *seed* 'NUM' ] [ *offset* 'NUM' ]
+*symhash* *mod* 'NUM' [ *offset* 'NUM' ]
+
+Use a hashing function to generate a number. The functions available are
+*jhash*, known as Jenkins Hash, and *symhash*, for Symmetric Hash. The
+*jhash* requires an expression to determine the parameters of the packet
+header to apply the hashing, concatenations are possible as well. The value
+after *mod* keyword specifies an upper boundary (read: modulus) which is
+not reached by returned numbers. The optional *seed* is used to specify an
+init value used as seed in the hashing function. The optional *offset*
+allows one to increment the returned value by a fixed offset.
+
+A typical use-case for *jhash* and *symhash* is load-balancing:
+
+.Using hash expressions
+------------------------
+# load balance based on source ip between 2 ip addresses:
+add rule nat prerouting dnat to jhash ip saddr mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+
+# symmetric load balancing between 2 ip addresses:
+add rule nat prerouting dnat to symhash mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+------------------------
diff --git a/doc/stateful-objects.txt b/doc/stateful-objects.txt
new file mode 100644
index 0000000..00d3c5f
--- /dev/null
+++ b/doc/stateful-objects.txt
@@ -0,0 +1,243 @@
+CT HELPER
+~~~~~~~~~
+[verse]
+*add* *ct helper* ['family'] 'table' 'name' *{ type* 'type' *protocol* 'protocol' *;* [*l3proto* 'family' *;*] *}*
+*delete* *ct helper* ['family'] 'table' 'name'
+*list* *ct helpers*
+
+Ct helper is used to define connection tracking helpers that can then be used in
+combination with the *ct helper set* statement. 'type' and 'protocol' are
+mandatory, l3proto is derived from the table family by default, i.e. in the inet
+table the kernel will try to load both the ipv4 and ipv6 helper backends, if
+they are supported by the kernel.
+
+.conntrack helper specifications
+[options="header"]
+|=================
+|Keyword | Description | Type
+| type |
+name of helper type |
+quoted string (e.g. "ftp")
+|protocol |
+layer 4 protocol of the helper |
+string (e.g. ip)
+|l3proto |
+layer 3 protocol of the helper |
+address family (e.g. ip)
+|comment |
+per ct helper comment field |
+string
+|=================
+
+.defining and assigning ftp helper
+----------------------------------
+Unlike iptables, helper assignment needs to be performed after the conntrack
+lookup has completed, for example with the default 0 hook priority.
+
+table inet myhelpers {
+ ct helper ftp-standard {
+ type "ftp" protocol tcp
+ }
+ chain prerouting {
+ type filter hook prerouting priority filter;
+ tcp dport 21 ct helper set "ftp-standard"
+ }
+}
+----------------------------------
+
+CT TIMEOUT
+~~~~~~~~~~
+[verse]
+*add* *ct timeout* ['family'] 'table' 'name' *{ protocol* 'protocol' *; policy = {* 'state'*:* 'value' [*,* ...] *} ;* [*l3proto* 'family' *;*] *}*
+*delete* *ct timeout* ['family'] 'table' 'name'
+*list* *ct timeouts*
+
+Ct timeout is used to update connection tracking timeout values.Timeout policies are assigned
+with the *ct timeout set* statement. 'protocol' and 'policy' are
+ mandatory, l3proto is derived from the table family by default.
+
+.conntrack timeout specifications
+[options="header"]
+|=================
+|Keyword | Description | Type
+| protocol |
+layer 4 protocol of the timeout object |
+string (e.g. ip)
+|state |
+connection state name |
+string (e.g. "established")
+|value |
+timeout value for connection state |
+unsigned integer
+|l3proto |
+layer 3 protocol of the timeout object |
+address family (e.g. ip)
+|comment |
+per ct timeout comment field |
+string
+|=================
+
+tcp connection state names that can have a specific timeout value are:
+
+'close', 'close_wait', 'established', 'fin_wait', 'last_ack', 'retrans', 'syn_recv', 'syn_sent', 'time_wait' and 'unack'.
+
+You can use 'sysctl -a |grep net.netfilter.nf_conntrack_tcp_timeout_' to view and change the system-wide defaults.
+'ct timeout' allows for flow-specific settings, without changing the global timeouts.
+
+For example, tcp port 53 could have much lower settings than other traffic.
+
+udp state names that can have a specific timeout value are 'replied' and 'unreplied'.
+
+.defining and assigning ct timeout policy
+----------------------------------
+table ip filter {
+ ct timeout customtimeout {
+ protocol tcp;
+ l3proto ip
+ policy = { established: 2m, close: 20s }
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ ct timeout set "customtimeout"
+ }
+}
+----------------------------------
+
+.testing the updated timeout policy
+----------------------------------
+
+% conntrack -E
+
+It should display:
+
+[UPDATE] tcp 6 120 ESTABLISHED src=172.16.19.128 dst=172.16.19.1
+sport=22 dport=41360 [UNREPLIED] src=172.16.19.1 dst=172.16.19.128
+sport=41360 dport=22
+----------------------------------
+
+CT EXPECTATION
+~~~~~~~~~~~~~~
+[verse]
+*add* *ct expectation* ['family'] 'table' 'name' *{ protocol* 'protocol' *; dport* 'dport' *; timeout* 'timeout' *; size* 'size' *; [*l3proto* 'family' *;*] *}*
+*delete* *ct expectation* ['family'] 'table' 'name'
+*list* *ct expectations*
+
+Ct expectation is used to create connection expectations. Expectations are
+assigned with the *ct expectation set* statement. 'protocol', 'dport',
+'timeout' and 'size' are mandatory, l3proto is derived from the table family
+by default.
+
+.conntrack expectation specifications
+[options="header"]
+|=================
+|Keyword | Description | Type
+|protocol |
+layer 4 protocol of the expectation object |
+string (e.g. ip)
+|dport |
+destination port of expected connection |
+unsigned integer
+|timeout |
+timeout value for expectation |
+unsigned integer
+|size |
+size value for expectation |
+unsigned integer
+|l3proto |
+layer 3 protocol of the expectation object |
+address family (e.g. ip)
+|comment |
+per ct expectation comment field |
+string
+|=================
+
+.defining and assigning ct expectation policy
+---------------------------------------------
+table ip filter {
+ ct expectation expect {
+ protocol udp
+ dport 9876
+ timeout 2m
+ size 8
+ l3proto ip
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ct expectation set "expect"
+ }
+}
+----------------------------------
+
+COUNTER
+~~~~~~~
+[verse]
+*add* *counter* ['family'] 'table' 'name' [*{* [ *packets* 'packets' *bytes* 'bytes' ';' ] [ *comment* 'comment' ';' *}*]
+*delete* *counter* ['family'] 'table' 'name'
+*list* *counters*
+
+.Counter specifications
+[options="header"]
+|=================
+|Keyword | Description | Type
+|packets |
+initial count of packets |
+unsigned integer (64 bit)
+|bytes |
+initial count of bytes |
+unsigned integer (64 bit)
+|comment |
+per counter comment field |
+string
+|=================
+
+.*Using named counters*
+------------------
+nft add counter filter http
+nft add rule filter input tcp dport 80 counter name \"http\"
+------------------
+
+.*Using named counters with maps*
+------------------
+nft add counter filter http
+nft add counter filter https
+nft add rule filter input counter name tcp dport map { 80 : \"http\", 443 : \"https\" }
+------------------
+
+QUOTA
+~~~~~
+[verse]
+*add* *quota* ['family'] 'table' 'name' *{* [*over*|*until*] 'bytes' 'BYTE_UNIT' [ *used* 'bytes' 'BYTE_UNIT' ] ';' [ *comment* 'comment' ';' ] *}*
+BYTE_UNIT := bytes | kbytes | mbytes
+*delete* *quota* ['family'] 'table' 'name'
+*list* *quotas*
+
+.Quota specifications
+[options="header"]
+|=================
+|Keyword | Description | Type
+|quota |
+quota limit, used as the quota name |
+Two arguments, unsigned integer (64 bit) and string: bytes, kbytes, mbytes.
+"over" and "until" go before these arguments
+|used |
+initial value of used quota |
+Two arguments, unsigned integer (64 bit) and string: bytes, kbytes, mbytes
+|comment |
+per quota comment field |
+string
+|=================
+
+.*Using named quotas*
+------------------
+nft add quota filter user123 { over 20 mbytes }
+nft add rule filter input ip saddr 192.168.10.123 quota name \"user123\"
+------------------
+
+.*Using named quotas with maps*
+------------------
+nft add quota filter user123 { over 20 mbytes }
+nft add quota filter user124 { over 20 mbytes }
+nft add rule filter input quota name ip saddr map { 192.168.10.123 : \"user123\", 192.168.10.124 : \"user124\" }
+------------------
diff --git a/doc/statements.txt b/doc/statements.txt
new file mode 100644
index 0000000..1967280
--- /dev/null
+++ b/doc/statements.txt
@@ -0,0 +1,875 @@
+VERDICT STATEMENT
+~~~~~~~~~~~~~~~~~
+The verdict statement alters control flow in the ruleset and issues policy decisions for packets.
+
+[verse]
+{*accept* | *drop* | *queue* | *continue* | *return*}
+{*jump* | *goto*} 'chain'
+
+*accept* and *drop* are absolute verdicts -- they terminate ruleset evaluation immediately.
+
+[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 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.
+The drop occurs instantly, no further chains or hooks are evaluated.
+It is not possible to accept the packet in a later chain again, as those
+are not evaluated anymore for the packet.
+*queue*:: Terminate ruleset evaluation and queue the packet to userspace.
+Userspace must provide a drop or accept verdict. In case of accept, processing
+resumes with the next base chain hook, not the rule following the queue verdict.
+*continue*:: Continue ruleset evaluation with the next rule. This
+ is the default behaviour in case a rule issues no verdict.
+*return*:: Return from the current chain and continue evaluation at the
+ next rule in the last chain. If issued in a base chain, it is equivalent to the
+ base chain policy.
+*jump* 'chain':: Continue evaluation at the first rule in 'chain'. The current
+ position in the ruleset is pushed to a call stack and evaluation will continue
+ there when the new chain is entirely evaluated or a *return* verdict is issued.
+ In case an absolute verdict is issued by a rule in the chain, ruleset evaluation
+ terminates immediately and the specific action is taken.
+*goto* 'chain':: Similar to *jump*, but the current position is not pushed to the
+ call stack, meaning that after the new chain evaluation will continue at the last
+ chain instead of the one containing the goto statement.
+
+.Using verdict statements
+-------------------
+# process packets from eth0 and the internal network in from_lan
+# chain, drop all packets from eth0 with different source addresses.
+
+filter input iif eth0 ip saddr 192.168.0.0/24 jump from_lan
+filter input iif eth0 drop
+-------------------
+
+PAYLOAD STATEMENT
+~~~~~~~~~~~~~~~~~
+[verse]
+'payload_expression' *set* 'value'
+
+The payload statement alters packet content. It can be used for example to
+set ip DSCP (diffserv) header field or ipv6 flow labels.
+
+.route some packets instead of bridging
+---------------------------------------
+# redirect tcp:http from 192.160.0.0/16 to local machine for routing instead of bridging
+# assumes 00:11:22:33:44:55 is local MAC address.
+bridge input meta iif eth0 ip saddr 192.168.0.0/16 tcp dport 80 meta pkttype set unicast ether daddr set 00:11:22:33:44:55
+-------------------------------------------
+
+.Set IPv4 DSCP header field
+---------------------------
+ip forward ip dscp set 42
+---------------------------
+
+EXTENSION HEADER STATEMENT
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+'extension_header_expression' *set* 'value'
+
+The extension header statement alters packet content in variable-sized headers.
+This can currently be used to alter the TCP Maximum segment size of packets,
+similar to the TCPMSS target in iptables.
+
+.change tcp mss
+---------------
+tcp flags syn tcp option maxseg size set 1360
+# set a size based on route information:
+tcp flags syn tcp option maxseg size set rt mtu
+---------------
+
+You can also remove tcp options via reset keyword.
+
+.remove tcp option
+---------------
+tcp flags syn reset tcp option sack-perm
+---------------
+
+LOG STATEMENT
+~~~~~~~~~~~~~
+[verse]
+*log* [*prefix* 'quoted_string'] [*level* 'syslog-level'] [*flags* 'log-flags']
+*log* *group* 'nflog_group' [*prefix* 'quoted_string'] [*queue-threshold* 'value'] [*snaplen* 'size']
+*log level audit*
+
+The log statement enables logging of matching packets. When this statement is
+used from a rule, the Linux kernel will print some information on all matching
+packets, such as header fields, via the kernel log (where it can be read with
+dmesg(1) or read in the syslog).
+
+In the second form of invocation (if 'nflog_group' is specified), the Linux
+kernel will pass the packet to nfnetlink_log which will send the log through a
+netlink socket to the specified group. One userspace process may subscribe to
+the group to receive the logs, see man(8) ulogd for the Netfilter userspace log
+daemon and libnetfilter_log documentation for details in case you would like to
+develop a custom program to digest your logs.
+
+In the third form of invocation (if level audit is specified), the Linux
+kernel writes a message into the audit buffer suitably formatted for reading
+with auditd. Therefore no further formatting options (such as prefix or flags)
+are allowed in this mode.
+
+This is a non-terminating statement, so the rule evaluation continues after
+the packet is logged.
+
+.log statement options
+[options="header"]
+|==================
+|Keyword | Description | Type
+|prefix|
+Log message prefix|
+quoted string
+|level|
+Syslog level of logging |
+string: emerg, alert, crit, err, warn [default], notice, info, debug, audit
+|group|
+NFLOG group to send messages to|
+unsigned integer (16 bit)
+|snaplen|
+Length of packet payload to include in netlink message |
+unsigned integer (32 bit)
+|queue-threshold|
+Number of packets to queue inside the kernel before sending them to userspace |
+unsigned integer (32 bit)
+|==================================
+
+.log-flags
+[options="header"]
+|==================
+| Flag | Description
+|tcp sequence|
+Log TCP sequence numbers.
+|tcp options|
+Log options from the TCP packet header.
+|ip options|
+Log options from the IP/IPv6 packet header.
+|skuid|
+Log the userid of the process which generated the packet.
+|ether|
+Decode MAC addresses and protocol.
+|all|
+Enable all log flags listed above.
+|==============================
+
+.Using log statement
+--------------------
+# log the UID which generated the packet and ip options
+ip filter output log flags skuid flags ip options
+
+# log the tcp sequence numbers and tcp options from the TCP packet
+ip filter output log flags tcp sequence,options
+
+# enable all supported log flags
+ip6 filter output log flags all
+-----------------------
+
+REJECT STATEMENT
+~~~~~~~~~~~~~~~~
+[verse]
+____
+*reject* [ *with* 'REJECT_WITH' ]
+
+'REJECT_WITH' := *icmp* 'icmp_code' |
+ *icmpv6* 'icmpv6_code' |
+ *icmpx* 'icmpx_code' |
+ *tcp reset*
+____
+
+A reject statement is used to send back an error packet in response to the
+matched packet otherwise it is equivalent to drop so it is a terminating
+statement, ending rule traversal. This statement is only valid in base chains
+using the *input*,
+*forward* or *output* hooks, and user-defined chains which are only called from
+those chains.
+
+.different ICMP reject variants are meant for use in different table families
+[options="header"]
+|==================
+|Variant |Family | Type
+|icmp|
+ip|
+icmp_code
+|icmpv6|
+ip6|
+icmpv6_code
+|icmpx|
+inet|
+icmpx_code
+|==================
+
+For a description of the different types and a list of supported keywords refer
+to DATA TYPES section above. The common default reject value is
+*port-unreachable*. +
+
+Note that in bridge family, reject statement is only allowed in base chains
+which hook into input or prerouting.
+
+COUNTER STATEMENT
+~~~~~~~~~~~~~~~~~
+A counter statement sets the hit count of packets along with the number of bytes.
+
+[verse]
+*counter* *packets* 'number' *bytes* 'number'
+*counter* { *packets* 'number' | *bytes* 'number' }
+
+CONNTRACK STATEMENT
+~~~~~~~~~~~~~~~~~~~
+The conntrack statement can be used to set the conntrack mark and conntrack labels.
+
+[verse]
+*ct* {*mark* | *event* | *label* | *zone*} *set* 'value'
+
+The ct statement sets meta data associated with a connection. The zone id
+has to be assigned before a conntrack lookup takes place, i.e. this has to be
+done in prerouting and possibly output (if locally generated packets need to be
+placed in a distinct zone), with a hook priority of *raw* (-300).
+
+Unlike iptables, where the helper assignment happens in the raw table,
+the helper needs to be assigned after a conntrack entry has been
+found, i.e. it will not work when used with hook priorities equal or before
+-200.
+
+.Conntrack statement types
+[options="header"]
+|==================
+|Keyword| Description| Value
+|event|
+conntrack event bits |
+bitmask, integer (32 bit)
+|helper|
+name of ct helper object to assign to the connection |
+quoted string
+|mark|
+Connection tracking mark |
+mark
+|label|
+Connection tracking label|
+label
+|zone|
+conntrack zone|
+integer (16 bit)
+|==================
+
+.save packet nfmark in conntrack
+--------------------------------
+ct mark set meta mark
+--------------------------------
+
+.set zone mapped via interface
+------------------------------
+table inet raw {
+ chain prerouting {
+ type filter hook prerouting priority raw;
+ ct zone set iif map { "eth1" : 1, "veth1" : 2 }
+ }
+ chain output {
+ type filter hook output priority raw;
+ ct zone set oif map { "eth1" : 1, "veth1" : 2 }
+ }
+}
+------------------------------------------------------
+
+.restrict events reported by ctnetlink
+--------------------------------------
+ct event set new,related,destroy
+--------------------------------------
+
+NOTRACK STATEMENT
+~~~~~~~~~~~~~~~~~
+The notrack statement allows one to disable connection tracking for certain
+packets.
+
+[verse]
+*notrack*
+
+Note that for this statement to be effective, it has to be applied to packets
+before a conntrack lookup happens. Therefore, it needs to sit in a chain with
+either prerouting or output hook and a hook priority of -300 (*raw*) or less.
+
+See SYNPROXY STATEMENT for an example usage.
+
+META STATEMENT
+~~~~~~~~~~~~~~
+A meta statement sets the value of a meta expression. The existing meta fields
+are: priority, mark, pkttype, nftrace. +
+
+[verse]
+*meta* {*mark* | *priority* | *pkttype* | *nftrace* | *broute*} *set* 'value'
+
+A meta statement sets meta data associated with a packet. +
+
+.Meta statement types
+[options="header"]
+|==================
+|Keyword| Description| Value
+|priority |
+TC packet priority|
+tc_handle
+|mark|
+Packet mark |
+mark
+|pkttype |
+packet type |
+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
+~~~~~~~~~~~~~~~
+[verse]
+____
+*limit rate* [*over*] 'packet_number' */* 'TIME_UNIT' [*burst* 'packet_number' *packets*]
+*limit rate* [*over*] 'byte_number' 'BYTE_UNIT' */* 'TIME_UNIT' [*burst* 'byte_number' 'BYTE_UNIT']
+
+'TIME_UNIT' := *second* | *minute* | *hour* | *day*
+'BYTE_UNIT' := *bytes* | *kbytes* | *mbytes*
+____
+
+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.
+
+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"]
+|==================
+|Value | Description | Type
+|packet_number |
+Number of packets |
+unsigned integer (32 bit)
+|byte_number |
+Number of bytes |
+unsigned integer (32 bit)
+|========================
+
+NAT STATEMENTS
+~~~~~~~~~~~~~~
+[verse]
+____
+*snat* [[*ip* | *ip6*] [ *prefix* ] *to*] 'ADDR_SPEC' [*:*'PORT_SPEC'] ['FLAGS']
+*dnat* [[*ip* | *ip6*] [ *prefix* ] *to*] 'ADDR_SPEC' [*:*'PORT_SPEC'] ['FLAGS']
+*masquerade* [*to :*'PORT_SPEC'] ['FLAGS']
+*redirect* [*to :*'PORT_SPEC'] ['FLAGS']
+
+'ADDR_SPEC' := 'address' | 'address' *-* 'address'
+'PORT_SPEC' := 'port' | 'port' *-* 'port'
+
+'FLAGS' := 'FLAG' [*,* 'FLAGS']
+'FLAG' := *persistent* | *random* | *fully-random*
+____
+
+The nat statements are only valid from nat chain types. +
+
+The *snat* and *masquerade* statements specify that the source address of the
+packet should be modified. While *snat* is only valid in the postrouting and
+input chains, *masquerade* makes sense only in postrouting. The dnat and
+redirect statements are only valid in the prerouting and output chains, they
+specify that the destination address of the packet should be modified. You can
+use non-base chains which are called from base chains of nat chain type too.
+All future packets in this connection will also be mangled, and rules should
+cease being examined.
+
+The *masquerade* statement is a special form of snat which always uses the
+outgoing interface's IP address to translate to. It is particularly useful on
+gateways with dynamic (public) IP addresses.
+
+The *redirect* statement is a special form of dnat which always translates the
+destination address to the local host's one. It comes in handy if one only wants
+to alter the destination port of incoming traffic on different interfaces.
+
+When used in the inet family (available with kernel 5.2), the dnat and snat
+statements require the use of the ip and ip6 keyword in case an address is
+provided, see the examples below.
+
+Before kernel 4.18 nat statements require both prerouting and postrouting base chains
+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"]
+|==================
+|Expression| Description| Type
+|address|
+Specifies that the source/destination address of the packet should be modified.
+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 port of the packet should be modified. |
+port number (16 bit)
+|===============================
+
+.NAT statement flags
+[options="header"]
+|==================
+|Flag| Description
+|persistent |
+Gives a client the same source-/destination-address for each connection.
+|random|
+In kernel 5.0 and newer this is the same as fully-random.
+In earlier kernels the port mapping will be randomized using a seeded MD5
+hash mix using source and destination address and destination port.
+
+|fully-random|
+If used then port mapping is generated based on a 32-bit pseudo-random algorithm.
+|=============================
+
+.Using NAT statements
+---------------------
+# create a suitable table/chain setup for all further examples
+add table nat
+add chain nat prerouting { type nat hook prerouting priority dstnat; }
+add chain nat postrouting { type nat hook postrouting priority srcnat; }
+
+# translate source addresses of all packets leaving via eth0 to address 1.2.3.4
+add rule nat postrouting oif eth0 snat to 1.2.3.4
+
+# redirect all traffic entering via eth0 to destination address 192.168.1.120
+add rule nat prerouting iif eth0 dnat to 192.168.1.120
+
+# translate source addresses of all packets leaving via eth0 to whatever
+# locally generated packets would use as source to reach the same destination
+add rule nat postrouting oif eth0 masquerade
+
+# redirect incoming TCP traffic for port 22 to port 2222
+add rule nat prerouting tcp dport 22 redirect to :2222
+
+# inet family:
+# handle ip dnat:
+add rule inet nat prerouting dnat ip to 10.0.2.99
+# handle ip6 dnat:
+add rule inet nat prerouting dnat ip6 to fe80::dead
+# this masquerades both ipv4 and ipv6:
+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
+in any way. If any of the arguments is missing the data of the incoming packet
+is used as parameter. Tproxy matching requires another rule that ensures the
+presence of transport protocol header is specified.
+
+[verse]
+*tproxy to* 'address'*:*'port'
+*tproxy to* {'address' | *:*'port'}
+
+This syntax can be used in *ip/ip6* tables where network layer protocol is
+obvious. Either IP address or port can be specified, but at least one of them is
+necessary.
+
+[verse]
+*tproxy* {*ip* | *ip6*} *to* 'address'[*:*'port']
+*tproxy to :*'port'
+
+This syntax can be used in *inet* tables. The *ip/ip6* parameter defines the
+family the rule will match. The *address* parameter must be of this family.
+When only *port* is defined, the address family should not be specified. In
+this case the rule will match for both families.
+
+.tproxy attributes
+[options="header"]
+|=================
+| Name | Description
+| address | IP address the listening socket with IP_TRANSPARENT option is bound to.
+| port | Port the listening socket with IP_TRANSPARENT option is bound to.
+|=================
+
+.Example ruleset for tproxy statement
+-------------------------------------
+table ip x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport ntp tproxy to 1.1.1.1
+ udp dport ssh tproxy to :2222
+ }
+}
+table ip6 x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport ntp tproxy to [dead::beef]
+ udp dport ssh tproxy to :2222
+ }
+}
+table inet x {
+ chain y {
+ type filter hook prerouting priority mangle; policy accept;
+ tcp dport 321 tproxy to :ssh
+ tcp dport 99 tproxy ip to 1.1.1.1:999
+ udp dport 155 tproxy ip6 to [dead::beef]:smux
+ }
+}
+-------------------------------------
+
+SYNPROXY STATEMENT
+~~~~~~~~~~~~~~~~~~
+This statement will process TCP three-way-handshake parallel in netfilter
+context to protect either local or backend system. This statement requires
+connection tracking because sequence numbers need to be translated.
+
+[verse]
+*synproxy* [*mss* 'mss_value'] [*wscale* 'wscale_value'] ['SYNPROXY_FLAGS']
+
+.synproxy statement attributes
+[options="header"]
+|=================
+| Name | Description
+| mss | Maximum segment size announced to clients. This must match the backend.
+| wscale | Window scale announced to clients. This must match the backend.
+|=================
+
+.synproxy statement flags
+[options="header"]
+|=================
+| Flag | Description
+| sack-perm |
+Pass client selective acknowledgement option to backend (will be disabled if
+not present).
+| timestamp |
+Pass client timestamp option to backend (will be disabled if not present, also
+needed for selective acknowledgement and window scaling).
+|=================
+
+.Example ruleset for synproxy statement
+---------------------------------------
+Determine tcp options used by backend, from an external system
+
+ tcpdump -pni eth0 -c 1 'tcp[tcpflags] == (tcp-syn|tcp-ack)'
+ port 80 &
+ telnet 192.0.2.42 80
+ 18:57:24.693307 IP 192.0.2.42.80 > 192.0.2.43.48757:
+ Flags [S.], seq 360414582, ack 788841994, win 14480,
+ options [mss 1460,sackOK,
+ TS val 1409056151 ecr 9690221,
+ nop,wscale 9],
+ length 0
+
+Switch tcp_loose mode off, so conntrack will mark out-of-flow packets as state INVALID.
+
+ echo 0 > /proc/sys/net/netfilter/nf_conntrack_tcp_loose
+
+Make SYN packets untracked.
+
+ table ip x {
+ chain y {
+ type filter hook prerouting priority raw; policy accept;
+ tcp flags syn notrack
+ }
+ }
+
+Catch UNTRACKED (SYN packets) and INVALID (3WHS ACK packets) states and send
+them to SYNPROXY. This rule will respond to SYN packets with SYN+ACK
+syncookies, create ESTABLISHED for valid client response (3WHS ACK packets) and
+drop incorrect cookies. Flags combinations not expected during 3WHS will not
+match and continue (e.g. SYN+FIN, SYN+ACK). Finally, drop invalid packets, this
+will be out-of-flow packets that were not matched by SYNPROXY.
+
+ table ip x {
+ chain z {
+ type filter hook input priority filter; policy accept;
+ ct state invalid, untracked synproxy mss 1460 wscale 9 timestamp sack-perm
+ ct state invalid drop
+ }
+ }
+---------------------------------------
+
+FLOW STATEMENT
+~~~~~~~~~~~~~~
+A flow statement allows us to select what flows you want to accelerate
+forwarding through layer 3 network stack bypass. You have to specify the
+flowtable name where you want to offload this flow.
+
+*flow add @*'flowtable'
+
+QUEUE STATEMENT
+~~~~~~~~~~~~~~~
+This statement passes the packet to userspace using the nfnetlink_queue handler.
+The packet is put into the queue identified by its 16-bit queue number.
+Userspace can inspect and modify the packet if desired. Userspace must then drop
+or re-inject the packet into the kernel. See libnetfilter_queue documentation
+for details.
+
+[verse]
+____
+*queue* [*flags* 'QUEUE_FLAGS'] [*to* 'queue_number']
+*queue* [*flags* 'QUEUE_FLAGS'] [*to* 'queue_number_from' - 'queue_number_to']
+*queue* [*flags* 'QUEUE_FLAGS'] [*to* 'QUEUE_EXPRESSION' ]
+
+'QUEUE_FLAGS' := 'QUEUE_FLAG' [*,* 'QUEUE_FLAGS']
+'QUEUE_FLAG' := *bypass* | *fanout*
+'QUEUE_EXPRESSION' := *numgen* | *hash* | *symhash* | *MAP STATEMENT*
+____
+
+QUEUE_EXPRESSION can be used to compute a queue number
+at run-time with the hash or numgen expressions. It also
+allows one to use the map statement to assign fixed queue numbers
+based on external inputs such as the source ip address or interface names.
+
+.queue statement values
+[options="header"]
+|==================
+|Value | Description | Type
+|queue_number |
+Sets queue number, default is 0. |
+unsigned integer (16 bit)
+|queue_number_from |
+Sets initial queue in the range, if fanout is used. |
+unsigned integer (16 bit)
+|queue_number_to |
+Sets closing queue in the range, if fanout is used. |
+unsigned integer (16 bit)
+|=====================
+
+.queue statement flags
+[options="header"]
+|==================
+|Flag | Description
+|bypass |
+Let packets go through if userspace application cannot back off. Before using
+this flag, read libnetfilter_queue documentation for performance tuning recommendations.
+|fanout |
+Distribute packets between several queues.
+|===============================
+
+DUP STATEMENT
+~~~~~~~~~~~~~
+The dup statement is used to duplicate a packet and send the copy to a different
+destination.
+
+[verse]
+*dup to* 'device'
+*dup to* 'address' *device* 'device'
+
+.Dup statement values
+[options="header"]
+|==================
+|Expression | Description | Type
+|address |
+Specifies that the copy of the packet should be sent to a new gateway.|
+ipv4_addr, ipv6_addr, e.g. abcd::1234, or you can use a mapping, e.g. ip saddr map { 192.168.1.2 : 10.1.1.1 }
+|device |
+Specifies that the copy should be transmitted via device. |
+string
+|===================
+
+
+.Using the dup statement
+------------------------
+# send to machine with ip address 10.2.3.4 on eth0
+ip filter forward dup to 10.2.3.4 device "eth0"
+
+# copy raw frame to another interface
+netdev ingress dup to "eth0"
+dup to "eth0"
+
+# combine with map dst addr to gateways
+dup to ip daddr map { 192.168.7.1 : "eth0", 192.168.7.2 : "eth1" }
+-----------------------------------
+
+FWD STATEMENT
+~~~~~~~~~~~~~
+The fwd statement is used to redirect a raw packet to another interface. It is
+only available in the netdev family ingress and egress hooks. It is similar to
+the dup statement except that no copy is made.
+
+You can also specify the address of the next hop and the device to forward the
+packet to. This updates the source and destination MAC address of the packet by
+transmitting it through the neighboring layer. This also decrements the ttl
+field of the IP packet. This provides a way to effectively bypass the classical
+forwarding path, thus skipping the fib (forwarding information base) lookup.
+
+[verse]
+*fwd to* 'device'
+*fwd* [*ip* | *ip6*] *to* 'address' *device* 'device'
+
+.Using the fwd statement
+------------------------
+# redirect raw packet to device
+netdev ingress fwd to "eth0"
+
+# forward packet to next hop 192.168.200.1 via eth0 device
+netdev ingress ether saddr set fwd ip to 192.168.200.1 device "eth0"
+-----------------------------------
+
+SET STATEMENT
+~~~~~~~~~~~~~
+The set statement is used to dynamically add or update elements in a set from
+the packet path. The set setname must already exist in the given table and must
+have been created with one or both of the dynamic and the timeout flags. The
+dynamic flag is required if the set statement expression includes a stateful
+object. The timeout flag is implied if the set is created with a timeout, and is
+required if the set statement updates elements, rather than adding them.
+Furthermore, these sets should specify both a maximum set size (to prevent
+memory exhaustion), and their elements should have a timeout (so their number
+will not grow indefinitely) either from the set definition or from the statement
+that adds or updates them. The set statement can be used to e.g. create dynamic
+blacklists.
+
+Dynamic updates are also supported with maps. In this case, the *add* or
+*update* rule needs to provide both the key and the data element (value),
+separated via ':'.
+
+[verse]
+{*add* | *update*} *@*'setname' *{* 'expression' [*timeout* 'timeout'] [*comment* 'string'] *}*
+
+.Example for simple blacklist
+-----------------------------
+# declare a set, bound to table "filter", in family "ip".
+# Timeout and size are mandatory because we will add elements from packet path.
+# Entries will timeout after one minute, after which they might be
+# re-added if limit condition persists.
+nft add set ip filter blackhole \
+ "{ type ipv4_addr; flags dynamic; timeout 1m; size 65536; }"
+
+# declare a set to store the limit per saddr.
+# This must be separate from blackhole since the timeout is different
+nft add set ip filter flood \
+ "{ type ipv4_addr; flags dynamic; timeout 10s; size 128000; }"
+
+# whitelist internal interface.
+nft add rule ip filter input meta iifname "internal" accept
+
+# drop packets coming from blacklisted ip addresses.
+nft add rule ip filter input ip saddr @blackhole counter drop
+
+# add source ip addresses to the blacklist if more than 10 tcp connection
+# requests occurred per second and ip address.
+nft add rule ip filter input tcp flags syn tcp dport ssh \
+ add @flood { ip saddr limit rate over 10/second } \
+ add @blackhole { ip saddr } \
+ drop
+
+# inspect state of the sets.
+nft list set ip filter flood
+nft list set ip filter blackhole
+
+# manually add two addresses to the blackhole.
+nft add element filter blackhole { 10.2.3.4, 10.23.1.42 }
+-----------------------------------------------
+
+MAP STATEMENT
+~~~~~~~~~~~~~
+The map statement is used to lookup data based on some specific input key.
+
+[verse]
+____
+'expression' *map* *{* 'MAP_ELEMENTS' *}*
+
+'MAP_ELEMENTS' := 'MAP_ELEMENT' [*,* 'MAP_ELEMENTS']
+'MAP_ELEMENT' := 'key' *:* 'value'
+____
+
+The 'key' is a value returned by 'expression'.
+// XXX: Write about where map statement can be used (list of statements?)
+
+.Using the map statement
+------------------------
+# select DNAT target based on TCP dport:
+# connections to port 80 are redirected to 192.168.1.100,
+# connections to port 8888 are redirected to 192.168.1.101
+nft add rule ip nat prerouting dnat tcp dport map { 80 : 192.168.1.100, 8888 : 192.168.1.101 }
+
+# source address based SNAT:
+# packets from net 192.168.1.0/24 will appear as originating from 10.0.0.1,
+# packets from net 192.168.2.0/24 will appear as originating from 10.0.0.2
+nft add rule ip nat postrouting snat to ip saddr map { 192.168.1.0/24 : 10.0.0.1, 192.168.2.0/24 : 10.0.0.2 }
+------------------------
+
+VMAP STATEMENT
+~~~~~~~~~~~~~~
+The verdict map (vmap) statement works analogous to the map statement, but
+contains verdicts as values.
+
+[verse]
+____
+'expression' *vmap* *{* 'VMAP_ELEMENTS' *}*
+
+'VMAP_ELEMENTS' := 'VMAP_ELEMENT' [*,* 'VMAP_ELEMENTS']
+'VMAP_ELEMENT' := 'key' *:* 'verdict'
+____
+
+.Using the vmap statement
+-------------------------
+# 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
new file mode 100644
index 0000000..3b8b0b6
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,6 @@
+check_PROGRAMS = nft-buffer \
+ nft-json-file
+
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+LDADD = $(top_builddir)/src/libnftables.la
diff --git a/examples/Makefile.in b/examples/Makefile.in
new file mode 100644
index 0000000..a192875
--- /dev/null
+++ b/examples/Makefile.in
@@ -0,0 +1,625 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = nft-buffer$(EXEEXT) nft-json-file$(EXEEXT)
+subdir = examples
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+nft_buffer_SOURCES = nft-buffer.c
+nft_buffer_OBJECTS = nft-buffer.$(OBJEXT)
+nft_buffer_LDADD = $(LDADD)
+nft_buffer_DEPENDENCIES = $(top_builddir)/src/libnftables.la
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+nft_json_file_SOURCES = nft-json-file.c
+nft_json_file_OBJECTS = nft-json-file.$(OBJEXT)
+nft_json_file_LDADD = $(LDADD)
+nft_json_file_DEPENDENCIES = $(top_builddir)/src/libnftables.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/nft-buffer.Po \
+ ./$(DEPDIR)/nft-json-file.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = nft-buffer.c nft-json-file.c
+DIST_SOURCES = nft-buffer.c nft-json-file.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+LDADD = $(top_builddir)/src/libnftables.la
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examples/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign examples/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+nft-buffer$(EXEEXT): $(nft_buffer_OBJECTS) $(nft_buffer_DEPENDENCIES) $(EXTRA_nft_buffer_DEPENDENCIES)
+ @rm -f nft-buffer$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(nft_buffer_OBJECTS) $(nft_buffer_LDADD) $(LIBS)
+
+nft-json-file$(EXEEXT): $(nft_json_file_OBJECTS) $(nft_json_file_DEPENDENCIES) $(EXTRA_nft_json_file_DEPENDENCIES)
+ @rm -f nft-json-file$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(nft_json_file_OBJECTS) $(nft_json_file_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nft-buffer.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nft-json-file.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/nft-buffer.Po
+ -rm -f ./$(DEPDIR)/nft-json-file.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/nft-buffer.Po
+ -rm -f ./$(DEPDIR)/nft-json-file.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/examples/nft-buffer.c b/examples/nft-buffer.c
new file mode 100644
index 0000000..1c4b1e0
--- /dev/null
+++ b/examples/nft-buffer.c
@@ -0,0 +1,34 @@
+/* gcc nft-buffer.c -o nft-buffer -lnftables */
+#include <stdlib.h>
+#include <nftables/libnftables.h>
+
+const char ruleset[] =
+ "flush ruleset;"
+ "add table x;"
+ "add chain x y { type filter hook input priority 0; };"
+ "add rule x y counter;";
+
+int main(void)
+{
+ struct nft_ctx *ctx;
+ int err;
+
+ ctx = nft_ctx_new(0);
+ if (!ctx) {
+ perror("cannot allocate nft context");
+ return EXIT_FAILURE;
+ }
+
+ /* create ruleset: all commands in the buffer are atomically applied */
+ err = nft_run_cmd_from_buffer(ctx, ruleset);
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ err = nft_run_cmd_from_buffer(ctx, "list ruleset");
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ nft_ctx_free(ctx);
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/nft-json-file.c b/examples/nft-json-file.c
new file mode 100644
index 0000000..0c832f2
--- /dev/null
+++ b/examples/nft-json-file.c
@@ -0,0 +1,30 @@
+/* gcc nft-json-file.c -o nft-json-file -lnftables */
+#include <stdlib.h>
+#include <nftables/libnftables.h>
+
+int main(void)
+{
+ struct nft_ctx *ctx;
+ int err;
+
+ ctx = nft_ctx_new(0);
+ if (!ctx) {
+ perror("cannot allocate nft context");
+ return EXIT_FAILURE;
+ }
+
+ nft_ctx_output_set_flags(ctx, NFT_CTX_OUTPUT_JSON);
+
+ /* create ruleset: all commands in the buffer are atomically applied */
+ err = nft_run_cmd_from_filename(ctx, "json-ruleset.nft");
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ err = nft_run_cmd_from_buffer(ctx, "list ruleset");
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ nft_ctx_free(ctx);
+
+ return EXIT_SUCCESS;
+}
diff --git a/files/Makefile b/files/Makefile
new file mode 100644
index 0000000..71781b1
--- /dev/null
+++ b/files/Makefile
@@ -0,0 +1,638 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# files/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/nftables
+pkgincludedir = $(includedir)/nftables
+pkglibdir = $(libdir)/nftables
+pkglibexecdir = $(libexecdir)/nftables
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = files
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+A2X = a2x
+ACLOCAL = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' aclocal-1.16
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 0
+AR = ar
+AUTOCONF = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoconf
+AUTOHEADER = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoheader
+AUTOMAKE = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS =
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DSYMUTIL =
+DUMPBIN =
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /usr/bin/grep -E
+EXEEXT =
+FGREP = /usr/bin/grep -F
+GCC_FVISIBILITY_HIDDEN = -fvisibility=hidden
+GREP = /usr/bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS =
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBMNL_CFLAGS =
+LIBMNL_LIBS = -lmnl
+LIBNFTNL_CFLAGS =
+LIBNFTNL_LIBS = -lnftnl
+LIBOBJS =
+LIBS = -ledit -lgmp
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO =
+LN_S = ln -s
+LTLIBOBJS =
+LT_SYS_LIBRARY_PATH =
+MAKEINFO = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' makeinfo
+MANIFEST_TOOL = :
+MKDIR_P = /usr/bin/mkdir -p
+NM = /usr/bin/nm -B
+NMEDIT =
+OBJDUMP = objdump
+OBJEXT = o
+OTOOL =
+OTOOL64 =
+PACKAGE = nftables
+PACKAGE_BUGREPORT = netfilter-devel@vger.kernel.org
+PACKAGE_NAME = nftables
+PACKAGE_STRING = nftables 1.0.9
+PACKAGE_TARNAME = nftables
+PACKAGE_URL =
+PACKAGE_VERSION = 1.0.9
+PATH_SEPARATOR = :
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR =
+PKG_CONFIG_PATH =
+RANLIB = ranlib
+SED = /usr/bin/sed
+SET_MAKE =
+SHELL = /bin/bash
+STRIP = strip
+VERSION = 1.0.9
+XTABLES_CFLAGS =
+XTABLES_LIBS =
+YACC = bison -y
+YFLAGS =
+abs_builddir = /home/pablo/devel/scm/git-netfilter/nftables/files
+abs_srcdir = /home/pablo/devel/scm/git-netfilter/nftables/files
+abs_top_builddir = /home/pablo/devel/scm/git-netfilter/nftables
+abs_top_srcdir = /home/pablo/devel/scm/git-netfilter/nftables
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_DUMPBIN =
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = tar --format=posix -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/pablo/devel/scm/git-netfilter/nftables/build-aux/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../
+top_builddir = ..
+top_srcdir = ..
+SUBDIRS = nftables \
+ examples \
+ osf
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/Makefile.am b/files/Makefile.am
new file mode 100644
index 0000000..7deec15
--- /dev/null
+++ b/files/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = nftables \
+ examples \
+ osf
diff --git a/files/Makefile.in b/files/Makefile.in
new file mode 100644
index 0000000..7567632
--- /dev/null
+++ b/files/Makefile.in
@@ -0,0 +1,638 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = files
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = nftables \
+ examples \
+ osf
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/examples/Makefile b/files/examples/Makefile
new file mode 100644
index 0000000..04ee889
--- /dev/null
+++ b/files/examples/Makefile
@@ -0,0 +1,530 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# files/examples/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/nftables
+pkgincludedir = $(includedir)/nftables
+pkglibdir = $(libdir)/nftables
+pkglibexecdir = $(libexecdir)/nftables
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = files/examples
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(dist_pkgdoc_SCRIPTS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgdocdir)"
+SCRIPTS = $(dist_pkgdoc_SCRIPTS)
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = a2x
+ACLOCAL = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' aclocal-1.16
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 0
+AR = ar
+AUTOCONF = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoconf
+AUTOHEADER = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoheader
+AUTOMAKE = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS =
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DSYMUTIL =
+DUMPBIN =
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /usr/bin/grep -E
+EXEEXT =
+FGREP = /usr/bin/grep -F
+GCC_FVISIBILITY_HIDDEN = -fvisibility=hidden
+GREP = /usr/bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS =
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBMNL_CFLAGS =
+LIBMNL_LIBS = -lmnl
+LIBNFTNL_CFLAGS =
+LIBNFTNL_LIBS = -lnftnl
+LIBOBJS =
+LIBS = -ledit -lgmp
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO =
+LN_S = ln -s
+LTLIBOBJS =
+LT_SYS_LIBRARY_PATH =
+MAKEINFO = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' makeinfo
+MANIFEST_TOOL = :
+MKDIR_P = /usr/bin/mkdir -p
+NM = /usr/bin/nm -B
+NMEDIT =
+OBJDUMP = objdump
+OBJEXT = o
+OTOOL =
+OTOOL64 =
+PACKAGE = nftables
+PACKAGE_BUGREPORT = netfilter-devel@vger.kernel.org
+PACKAGE_NAME = nftables
+PACKAGE_STRING = nftables 1.0.9
+PACKAGE_TARNAME = nftables
+PACKAGE_URL =
+PACKAGE_VERSION = 1.0.9
+PATH_SEPARATOR = :
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR =
+PKG_CONFIG_PATH =
+RANLIB = ranlib
+SED = /usr/bin/sed
+SET_MAKE =
+SHELL = /bin/bash
+STRIP = strip
+VERSION = 1.0.9
+XTABLES_CFLAGS =
+XTABLES_LIBS =
+YACC = bison -y
+YFLAGS =
+abs_builddir = /home/pablo/devel/scm/git-netfilter/nftables/files/examples
+abs_srcdir = /home/pablo/devel/scm/git-netfilter/nftables/files/examples
+abs_top_builddir = /home/pablo/devel/scm/git-netfilter/nftables
+abs_top_srcdir = /home/pablo/devel/scm/git-netfilter/nftables
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_DUMPBIN =
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = tar --format=posix -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/pablo/devel/scm/git-netfilter/nftables/build-aux/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+pkgdocdir = ${docdir}/examples
+dist_pkgdoc_SCRIPTS = ct_helpers.nft \
+ load_balancing.nft \
+ secmark.nft \
+ sets_and_maps.nft
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/examples/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/examples/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dist_pkgdocSCRIPTS: $(dist_pkgdoc_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_pkgdoc_SCRIPTS)'; test -n "$(pkgdocdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdocdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgdocdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pkgdocdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pkgdocdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_pkgdocSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkgdoc_SCRIPTS)'; test -n "$(pkgdocdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pkgdocdir)'; $(am__uninstall_files_from_dir)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgdocdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgdocSCRIPTS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_pkgdocSCRIPTS
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pkgdocSCRIPTS install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-dist_pkgdocSCRIPTS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/examples/Makefile.am b/files/examples/Makefile.am
new file mode 100644
index 0000000..b29e9f6
--- /dev/null
+++ b/files/examples/Makefile.am
@@ -0,0 +1,5 @@
+pkgdocdir = ${docdir}/examples
+dist_pkgdoc_SCRIPTS = ct_helpers.nft \
+ load_balancing.nft \
+ secmark.nft \
+ sets_and_maps.nft
diff --git a/files/examples/Makefile.in b/files/examples/Makefile.in
new file mode 100644
index 0000000..d35c9d6
--- /dev/null
+++ b/files/examples/Makefile.in
@@ -0,0 +1,530 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = files/examples
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(dist_pkgdoc_SCRIPTS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgdocdir)"
+SCRIPTS = $(dist_pkgdoc_SCRIPTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkgdocdir = ${docdir}/examples
+dist_pkgdoc_SCRIPTS = ct_helpers.nft \
+ load_balancing.nft \
+ secmark.nft \
+ sets_and_maps.nft
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/examples/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/examples/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-dist_pkgdocSCRIPTS: $(dist_pkgdoc_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_pkgdoc_SCRIPTS)'; test -n "$(pkgdocdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdocdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgdocdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pkgdocdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pkgdocdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_pkgdocSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkgdoc_SCRIPTS)'; test -n "$(pkgdocdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(pkgdocdir)'; $(am__uninstall_files_from_dir)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgdocdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgdocSCRIPTS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_pkgdocSCRIPTS
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pkgdocSCRIPTS install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-dist_pkgdocSCRIPTS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/examples/ct_helpers.nft b/files/examples/ct_helpers.nft
new file mode 100755
index 0000000..07ebb2a
--- /dev/null
+++ b/files/examples/ct_helpers.nft
@@ -0,0 +1,43 @@
+#!/usr/sbin/nft -f
+
+# This example file shows how to use ct helpers in the nftables framework.
+# Note that nftables includes interesting improvements compared to how this
+# was done with iptables, such as loading multiple helpers with a single rule
+# This script is meant to be loaded with `nft -f <file>`
+# You require linux kernel >= 4.12 and nft >= 0.8
+# For up-to-date information please visit https://wiki.nftables.org
+
+# Using ct helpers is an important security feature when doing stateful
+# firewalling, since it mitigate certain networking attacks.
+# More info at: https://home.regit.org/netfilter-en/secure-use-of-helpers/
+
+
+flush ruleset
+table inet filter {
+ # declare helpers of this table
+ ct helper ftp-standard {
+ type "ftp" protocol tcp;
+ l3proto inet
+ }
+ ct helper sip-5060 {
+ type "sip" protocol udp;
+ l3proto inet
+ }
+ ct helper tftp-69 {
+ type "tftp" protocol udp
+ l3proto inet
+ }
+
+ chain input {
+ type filter hook input priority 0; policy drop;
+ ct state established,related accept
+
+ # assign a single helper in a single rule
+ tcp dport 21 ct helper set "ftp-standard"
+
+ # assign multiple helpers in a single rule
+ ct helper set udp dport map {
+ 69 : "tftp-69", \
+ 5060 : "sip-5060" }
+ }
+}
diff --git a/files/examples/load_balancing.nft b/files/examples/load_balancing.nft
new file mode 100755
index 0000000..2f03d27
--- /dev/null
+++ b/files/examples/load_balancing.nft
@@ -0,0 +1,54 @@
+#!/usr/sbin/nft -f
+
+# This example file shows how to implement load balancing using the nftables
+# framework.
+# This script is meant to be loaded with `nft -f <file>`
+# You require linux kernel >= 4.12 and nft >= 0.7
+# For up-to-date information please visit https://wiki.nftables.org
+
+flush ruleset
+
+table ip nat {
+ chain prerouting {
+ type nat hook prerouting priority -300;
+ # round-robing load balancing between the 2 IPv4 addresses:
+ dnat to numgen inc mod 2 map {
+ 0 : 192.168.10.100, \
+ 1 : 192.168.20.200 }
+ # emulate flow distribution with different backend weights using intervals:
+ dnat to numgen inc mod 10 map {
+ 0-5 : 192.168.10.100, \
+ 6-9 : 192.168.20.200 }
+ # tcp port based distribution is also possible:
+ ip protocol tcp dnat to 192.168.1.100 : numgen inc mod 2 map {
+ 0 : 4040 ,\
+ 1 : 4050 }
+ # consistent hash-based distribution:
+ dnat to jhash ip saddr . tcp dport mod 2 map {
+ 0 : 192.168.20.100, \
+ 1 : 192.168.30.100 }
+ }
+}
+
+table ip raw {
+ chain prerouting {
+ type filter hook prerouting priority -300;
+ # using stateless NAT, round-robing distribution (you could use hashing too):
+ tcp dport 80 notrack ip daddr set numgen inc mod 2 map { 0 : 192.168.1.100, 1 : 192.168.1.101 }
+ }
+}
+
+table netdev mytable {
+ chain ingress {
+ # mind the NIC devices, they must exist in the system
+ type filter hook ingress device eth0 priority 0;
+ # using Direct Server Return (DSR), connectionless approach:
+ udp dport 53 ether saddr set aa:bb:cc:dd:ff:ee ether daddr set numgen inc mod 2 map {
+ 0 : aa:aa:aa:aa:aa:aa,
+ 1 : bb:bb:bb:bb:bb:bb } fwd to eth1
+ # using Direct Server Return (DSR), connection-oriented flows:
+ tcp dport 80 ether saddr set aa:bb:cc:dd:ff:ee ether daddr set jhash ip saddr . tcp sport mod 2 map {
+ 0 : aa:aa:aa:aa:aa:aa,
+ 1 : bb:bb:bb:bb:bb:bb } fwd to eth1
+ }
+}
diff --git a/files/examples/secmark.nft b/files/examples/secmark.nft
new file mode 100755
index 0000000..c923ceb
--- /dev/null
+++ b/files/examples/secmark.nft
@@ -0,0 +1,87 @@
+#!/usr/sbin/nft -f
+
+# This example file shows how to use secmark labels with the nftables framework.
+# This script is meant to be loaded with `nft -f <file>`
+# You require linux kernel >= 4.20 and nft >= 0.9.3
+# This example is SELinux based, for the secmark objects you require
+# SELinux enabled and a SELinux policy defining the stated contexts
+# For up-to-date information please visit https://wiki.nftables.org
+
+
+flush ruleset
+
+table inet x {
+ secmark ssh_server {
+ "system_u:object_r:ssh_server_packet_t:s0"
+ }
+
+ secmark dns_client {
+ "system_u:object_r:dns_client_packet_t:s0"
+ }
+
+ secmark http_client {
+ "system_u:object_r:http_client_packet_t:s0"
+ }
+
+ secmark https_client {
+ "system_u:object_r:http_client_packet_t:s0"
+ }
+
+ secmark ntp_client {
+ "system_u:object_r:ntp_client_packet_t:s0"
+ }
+
+ secmark icmp_client {
+ "system_u:object_r:icmp_client_packet_t:s0"
+ }
+
+ secmark icmp_server {
+ "system_u:object_r:icmp_server_packet_t:s0"
+ }
+
+ secmark ssh_client {
+ "system_u:object_r:ssh_client_packet_t:s0"
+ }
+
+ secmark git_client {
+ "system_u:object_r:git_client_packet_t:s0"
+ }
+
+ map secmapping_in {
+ type inet_service : secmark
+ elements = { 22 : "ssh_server" }
+ }
+
+ map secmapping_out {
+ type inet_service : secmark
+ elements = { 22 : "ssh_client", 53 : "dns_client", 80 : "http_client", 123 : "ntp_client", 443 : "http_client", 9418 : "git_client" }
+ }
+
+ chain y {
+ type filter hook input priority -225;
+
+ # label new incoming packets and add to connection
+ ct state new meta secmark set tcp dport map @secmapping_in
+ ct state new meta secmark set udp dport map @secmapping_in
+ ct state new ip protocol icmp meta secmark set "icmp_server"
+ ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_server"
+ ct state new ct secmark set meta secmark
+
+ # set label for est/rel packets from connection
+ ct state established,related meta secmark set ct secmark
+ }
+
+ chain z {
+ type filter hook output priority 225;
+
+ # label new outgoing packets and add to connection
+ ct state new meta secmark set tcp dport map @secmapping_out
+ ct state new meta secmark set udp dport map @secmapping_out
+ ct state new ip protocol icmp meta secmark set "icmp_client"
+ ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_client"
+ ct state new ct secmark set meta secmark
+
+ # set label for est/rel packets from connection
+ ct state established,related meta secmark set ct secmark
+ }
+}
diff --git a/files/examples/sets_and_maps.nft b/files/examples/sets_and_maps.nft
new file mode 100755
index 0000000..f5157b3
--- /dev/null
+++ b/files/examples/sets_and_maps.nft
@@ -0,0 +1,54 @@
+#!/usr/sbin/nft -f
+
+# This example file shows how to use sets and maps in the nftables framework.
+# This script is meant to be loaded with `nft -f <file>`
+# For up-to-date information please visit https://wiki.nftables.org
+
+# symbolic anonymous set definition built from symbolic singleton definitions
+define int_if1 = eth0
+define int_if2 = eth1
+define int_ifs = { $int_if1, $int_if2 }
+
+define ext_if1 = eth2
+define ext_if2 = eth3
+define ext_ifs = { $ext_if1, $ext_if2 }
+
+# recursive symbolic anonymous set definition
+define local_ifs = { $int_ifs, $ext_ifs }
+
+# symbolic anonymous set definition
+define tcp_ports = { ssh, domain, https, 123-125 }
+
+delete table filter
+table filter {
+ # named set of type iface_index
+ set local_ifs {
+ type iface_index
+ }
+
+ # named map of type iface_index : ipv4_addr
+ map nat_map {
+ type iface_index : ipv4_addr
+ }
+
+ map jump_map {
+ type iface_index : verdict
+ }
+
+ chain input_1 { counter; }
+ chain input_2 { counter; }
+ chain input {
+ type filter hook input priority 0
+
+ # symbolic anonymous sets
+ meta iif $local_ifs tcp dport $tcp_ports counter
+
+ # literal anonymous set
+ meta iif { eth0, eth1 } counter
+
+ meta iif @local_ifs counter
+ meta iif vmap @jump_map
+
+ #meta iif vmap { eth0 : jump input1, eth1 : jump input2 }
+ }
+}
diff --git a/files/nftables/Makefile b/files/nftables/Makefile
new file mode 100644
index 0000000..1c7442c
--- /dev/null
+++ b/files/nftables/Makefile
@@ -0,0 +1,525 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# files/nftables/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/nftables
+pkgincludedir = $(includedir)/nftables
+pkglibdir = $(libdir)/nftables
+pkglibexecdir = $(libexecdir)/nftables
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = files/nftables
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(dist_pkgdata_DATA) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgdatadir)"
+DATA = $(dist_pkgdata_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = a2x
+ACLOCAL = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' aclocal-1.16
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 0
+AR = ar
+AUTOCONF = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoconf
+AUTOHEADER = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoheader
+AUTOMAKE = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS =
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DSYMUTIL =
+DUMPBIN =
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /usr/bin/grep -E
+EXEEXT =
+FGREP = /usr/bin/grep -F
+GCC_FVISIBILITY_HIDDEN = -fvisibility=hidden
+GREP = /usr/bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS =
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBMNL_CFLAGS =
+LIBMNL_LIBS = -lmnl
+LIBNFTNL_CFLAGS =
+LIBNFTNL_LIBS = -lnftnl
+LIBOBJS =
+LIBS = -ledit -lgmp
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO =
+LN_S = ln -s
+LTLIBOBJS =
+LT_SYS_LIBRARY_PATH =
+MAKEINFO = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' makeinfo
+MANIFEST_TOOL = :
+MKDIR_P = /usr/bin/mkdir -p
+NM = /usr/bin/nm -B
+NMEDIT =
+OBJDUMP = objdump
+OBJEXT = o
+OTOOL =
+OTOOL64 =
+PACKAGE = nftables
+PACKAGE_BUGREPORT = netfilter-devel@vger.kernel.org
+PACKAGE_NAME = nftables
+PACKAGE_STRING = nftables 1.0.9
+PACKAGE_TARNAME = nftables
+PACKAGE_URL =
+PACKAGE_VERSION = 1.0.9
+PATH_SEPARATOR = :
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR =
+PKG_CONFIG_PATH =
+RANLIB = ranlib
+SED = /usr/bin/sed
+SET_MAKE =
+SHELL = /bin/bash
+STRIP = strip
+VERSION = 1.0.9
+XTABLES_CFLAGS =
+XTABLES_LIBS =
+YACC = bison -y
+YFLAGS =
+abs_builddir = /home/pablo/devel/scm/git-netfilter/nftables/files/nftables
+abs_srcdir = /home/pablo/devel/scm/git-netfilter/nftables/files/nftables
+abs_top_builddir = /home/pablo/devel/scm/git-netfilter/nftables
+abs_top_srcdir = /home/pablo/devel/scm/git-netfilter/nftables
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_DUMPBIN =
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = tar --format=posix -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/pablo/devel/scm/git-netfilter/nftables/build-aux/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+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
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/nftables/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/nftables/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_pkgdataDATA: $(dist_pkgdata_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \
+ done
+
+uninstall-dist_pkgdataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgdatadir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgdataDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_pkgdataDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pkgdataDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-dist_pkgdataDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/nftables/Makefile.am b/files/nftables/Makefile.am
new file mode 100644
index 0000000..ee88dd8
--- /dev/null
+++ b/files/nftables/Makefile.am
@@ -0,0 +1,14 @@
+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/nftables/Makefile.in b/files/nftables/Makefile.in
new file mode 100644
index 0000000..b7c383a
--- /dev/null
+++ b/files/nftables/Makefile.in
@@ -0,0 +1,525 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = files/nftables
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(dist_pkgdata_DATA) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgdatadir)"
+DATA = $(dist_pkgdata_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+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
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/nftables/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/nftables/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_pkgdataDATA: $(dist_pkgdata_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \
+ done
+
+uninstall-dist_pkgdataDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgdatadir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgdataDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_pkgdataDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pkgdataDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-dist_pkgdataDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/nftables/all-in-one.nft b/files/nftables/all-in-one.nft
new file mode 100644
index 0000000..15ac22e
--- /dev/null
+++ b/files/nftables/all-in-one.nft
@@ -0,0 +1,35 @@
+# Here is an example of different families, hooks and priorities in the
+# nftables framework, all mixed together.
+#
+# more examples are located in files/examples in nftables source.
+# For up-to-date information please visit https://wiki.nftables.org
+#
+# This script is meant to be loaded with `nft -f <file>`
+
+# clear all prior state
+flush ruleset
+
+# native dual stack IPv4 & IPv6 family
+include "./inet-filter.nft"
+include "./inet-nat.nft"
+
+# netdev family at ingress hook. Attached to a given NIC
+include "./netdev-ingress.nft"
+
+# IPv4 family, typical iptables tables/chains layout
+include "./ipv4-filter.nft"
+include "./ipv4-mangle.nft"
+include "./ipv4-nat.nft"
+include "./ipv4-raw.nft"
+
+# IPv6 family, typical ip6tables tables/chains layout
+include "./ipv6-filter.nft"
+include "./ipv6-mangle.nft"
+include "./ipv6-nat.nft"
+include "./ipv6-raw.nft"
+
+# ARP family, typical arptables tables/chain layout
+include "./arp-filter.nft"
+
+# bridge family, typical ebtables tables/chain layout
+include "./bridge-filter.nft"
diff --git a/files/nftables/arp-filter.nft b/files/nftables/arp-filter.nft
new file mode 100644
index 0000000..6e4c624
--- /dev/null
+++ b/files/nftables/arp-filter.nft
@@ -0,0 +1,4 @@
+table arp filter {
+ chain input { type filter hook input priority 0; }
+ chain output { type filter hook output priority 0; }
+}
diff --git a/files/nftables/bridge-filter.nft b/files/nftables/bridge-filter.nft
new file mode 100644
index 0000000..f071205
--- /dev/null
+++ b/files/nftables/bridge-filter.nft
@@ -0,0 +1,5 @@
+table bridge filter {
+ chain input { type filter hook input priority -200; }
+ chain forward { type filter hook forward priority -200; }
+ chain output { type filter hook output priority 200; }
+}
diff --git a/files/nftables/inet-filter.nft b/files/nftables/inet-filter.nft
new file mode 100644
index 0000000..bfe43b4
--- /dev/null
+++ b/files/nftables/inet-filter.nft
@@ -0,0 +1,5 @@
+table inet filter {
+ chain input { type filter hook input priority 0; }
+ chain forward { type filter hook forward priority 0; }
+ chain output { type filter hook output priority 0; }
+}
diff --git a/files/nftables/inet-nat.nft b/files/nftables/inet-nat.nft
new file mode 100644
index 0000000..babd7f0
--- /dev/null
+++ b/files/nftables/inet-nat.nft
@@ -0,0 +1,6 @@
+table inet nat {
+ chain prerouting { type nat hook prerouting priority -100; }
+ chain input { type nat hook input priority 100; }
+ chain output { type nat hook output priority -100; }
+ chain postrouting { type nat hook postrouting priority 100; }
+}
diff --git a/files/nftables/ipv4-filter.nft b/files/nftables/ipv4-filter.nft
new file mode 100644
index 0000000..ab62024
--- /dev/null
+++ b/files/nftables/ipv4-filter.nft
@@ -0,0 +1,5 @@
+table filter {
+ chain input { type filter hook input priority 0; }
+ chain forward { type filter hook forward priority 0; }
+ chain output { type filter hook output priority 0; }
+}
diff --git a/files/nftables/ipv4-mangle.nft b/files/nftables/ipv4-mangle.nft
new file mode 100644
index 0000000..07da5bd
--- /dev/null
+++ b/files/nftables/ipv4-mangle.nft
@@ -0,0 +1,3 @@
+table mangle {
+ chain output { type route hook output priority -150; }
+}
diff --git a/files/nftables/ipv4-nat.nft b/files/nftables/ipv4-nat.nft
new file mode 100644
index 0000000..2c9ce7c
--- /dev/null
+++ b/files/nftables/ipv4-nat.nft
@@ -0,0 +1,6 @@
+table nat {
+ chain prerouting { type nat hook prerouting priority -100; }
+ chain input { type nat hook input priority 100; }
+ chain output { type nat hook output priority -100; }
+ chain postrouting { type nat hook postrouting priority 100; }
+}
diff --git a/files/nftables/ipv4-raw.nft b/files/nftables/ipv4-raw.nft
new file mode 100644
index 0000000..2318e87
--- /dev/null
+++ b/files/nftables/ipv4-raw.nft
@@ -0,0 +1,4 @@
+table raw {
+ chain prerouting { type filter hook prerouting priority -300; }
+ chain output { type filter hook output priority -300; }
+}
diff --git a/files/nftables/ipv6-filter.nft b/files/nftables/ipv6-filter.nft
new file mode 100644
index 0000000..383d075
--- /dev/null
+++ b/files/nftables/ipv6-filter.nft
@@ -0,0 +1,5 @@
+table ip6 filter {
+ chain input { type filter hook input priority 0; }
+ chain forward { type filter hook forward priority 0; }
+ chain output { type filter hook output priority 0; }
+}
diff --git a/files/nftables/ipv6-mangle.nft b/files/nftables/ipv6-mangle.nft
new file mode 100644
index 0000000..88c51e5
--- /dev/null
+++ b/files/nftables/ipv6-mangle.nft
@@ -0,0 +1,3 @@
+table ip6 mangle {
+ chain output { type route hook output priority -150; }
+}
diff --git a/files/nftables/ipv6-nat.nft b/files/nftables/ipv6-nat.nft
new file mode 100644
index 0000000..6a356f1
--- /dev/null
+++ b/files/nftables/ipv6-nat.nft
@@ -0,0 +1,6 @@
+table ip6 nat {
+ chain prerouting { type nat hook prerouting priority -100; }
+ chain input { type nat hook input priority 100; }
+ chain output { type nat hook output priority -100; }
+ chain postrouting { type nat hook postrouting priority 100; }
+}
diff --git a/files/nftables/ipv6-raw.nft b/files/nftables/ipv6-raw.nft
new file mode 100644
index 0000000..f92668b
--- /dev/null
+++ b/files/nftables/ipv6-raw.nft
@@ -0,0 +1,4 @@
+table ip6 raw {
+ chain prerouting { type filter hook prerouting priority -300; }
+ chain output { type filter hook output priority -300; }
+}
diff --git a/files/nftables/netdev-ingress.nft b/files/nftables/netdev-ingress.nft
new file mode 100644
index 0000000..3ed881a
--- /dev/null
+++ b/files/nftables/netdev-ingress.nft
@@ -0,0 +1,5 @@
+# mind the NIC, it must exist
+table netdev filter {
+ chain loinput { type filter hook ingress device lo priority 0; }
+}
+
diff --git a/files/osf/Makefile b/files/osf/Makefile
new file mode 100644
index 0000000..f726927
--- /dev/null
+++ b/files/osf/Makefile
@@ -0,0 +1,512 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# files/osf/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/nftables
+pkgincludedir = $(includedir)/nftables
+pkglibdir = $(libdir)/nftables
+pkglibexecdir = $(libexecdir)/nftables
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = files/osf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(dist_pkgsysconf_DATA) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgsysconfdir)"
+DATA = $(dist_pkgsysconf_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = a2x
+ACLOCAL = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' aclocal-1.16
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 0
+AR = ar
+AUTOCONF = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoconf
+AUTOHEADER = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' autoheader
+AUTOMAKE = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS =
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DLLTOOL = false
+DSYMUTIL =
+DUMPBIN =
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /usr/bin/grep -E
+EXEEXT =
+FGREP = /usr/bin/grep -F
+GCC_FVISIBILITY_HIDDEN = -fvisibility=hidden
+GREP = /usr/bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LD = /usr/bin/ld -m elf_x86_64
+LDFLAGS =
+LEX = flex
+LEXLIB = -lfl
+LEX_OUTPUT_ROOT = lex.yy
+LIBMNL_CFLAGS =
+LIBMNL_LIBS = -lmnl
+LIBNFTNL_CFLAGS =
+LIBNFTNL_LIBS = -lnftnl
+LIBOBJS =
+LIBS = -ledit -lgmp
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIPO =
+LN_S = ln -s
+LTLIBOBJS =
+LT_SYS_LIBRARY_PATH =
+MAKEINFO = ${SHELL} '/home/pablo/devel/scm/git-netfilter/nftables/build-aux/missing' makeinfo
+MANIFEST_TOOL = :
+MKDIR_P = /usr/bin/mkdir -p
+NM = /usr/bin/nm -B
+NMEDIT =
+OBJDUMP = objdump
+OBJEXT = o
+OTOOL =
+OTOOL64 =
+PACKAGE = nftables
+PACKAGE_BUGREPORT = netfilter-devel@vger.kernel.org
+PACKAGE_NAME = nftables
+PACKAGE_STRING = nftables 1.0.9
+PACKAGE_TARNAME = nftables
+PACKAGE_URL =
+PACKAGE_VERSION = 1.0.9
+PATH_SEPARATOR = :
+PKG_CONFIG = /usr/bin/pkg-config
+PKG_CONFIG_LIBDIR =
+PKG_CONFIG_PATH =
+RANLIB = ranlib
+SED = /usr/bin/sed
+SET_MAKE =
+SHELL = /bin/bash
+STRIP = strip
+VERSION = 1.0.9
+XTABLES_CFLAGS =
+XTABLES_LIBS =
+YACC = bison -y
+YFLAGS =
+abs_builddir = /home/pablo/devel/scm/git-netfilter/nftables/files/osf
+abs_srcdir = /home/pablo/devel/scm/git-netfilter/nftables/files/osf
+abs_top_builddir = /home/pablo/devel/scm/git-netfilter/nftables
+abs_top_srcdir = /home/pablo/devel/scm/git-netfilter/nftables
+ac_ct_AR = ar
+ac_ct_CC = gcc
+ac_ct_DUMPBIN =
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = tar --format=posix -chf - "$$tardir"
+am__untar = tar -xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/pablo/devel/scm/git-netfilter/nftables/build-aux/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+pkgsysconfdir = ${sysconfdir}/nftables/osf
+dist_pkgsysconf_DATA = pf.os
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/osf/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/osf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_pkgsysconfDATA: $(dist_pkgsysconf_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_pkgsysconf_DATA)'; test -n "$(pkgsysconfdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgsysconfdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgsysconfdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgsysconfdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgsysconfdir)" || exit $$?; \
+ done
+
+uninstall-dist_pkgsysconfDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkgsysconf_DATA)'; test -n "$(pkgsysconfdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgsysconfdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgsysconfdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgsysconfDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_pkgsysconfDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pkgsysconfDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-dist_pkgsysconfDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/osf/Makefile.am b/files/osf/Makefile.am
new file mode 100644
index 0000000..d80196d
--- /dev/null
+++ b/files/osf/Makefile.am
@@ -0,0 +1,2 @@
+pkgsysconfdir = ${sysconfdir}/nftables/osf
+dist_pkgsysconf_DATA = pf.os
diff --git a/files/osf/Makefile.in b/files/osf/Makefile.in
new file mode 100644
index 0000000..ebf6dcb
--- /dev/null
+++ b/files/osf/Makefile.in
@@ -0,0 +1,512 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = files/osf
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(dist_pkgsysconf_DATA) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgsysconfdir)"
+DATA = $(dist_pkgsysconf_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkgsysconfdir = ${sysconfdir}/nftables/osf
+dist_pkgsysconf_DATA = pf.os
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign files/osf/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign files/osf/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_pkgsysconfDATA: $(dist_pkgsysconf_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_pkgsysconf_DATA)'; test -n "$(pkgsysconfdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgsysconfdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgsysconfdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgsysconfdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgsysconfdir)" || exit $$?; \
+ done
+
+uninstall-dist_pkgsysconfDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_pkgsysconf_DATA)'; test -n "$(pkgsysconfdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgsysconfdir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgsysconfdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_pkgsysconfDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_pkgsysconfDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-dist_pkgsysconfDATA install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+ uninstall-am uninstall-dist_pkgsysconfDATA
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/files/osf/pf.os b/files/osf/pf.os
new file mode 100644
index 0000000..35cbb47
--- /dev/null
+++ b/files/osf/pf.os
@@ -0,0 +1,703 @@
+# $FreeBSD: head/etc/pf.os 258865 2013-12-03 04:32:02Z eadler $
+# $OpenBSD: pf.os,v 1.27 2016/09/03 17:08:57 sthen Exp $
+# passive OS fingerprinting
+# -------------------------
+#
+# SYN signatures. Those signatures work for SYN packets only (duh!).
+#
+# (C) Copyright 2000-2003 by Michal Zalewski <lcamtuf@coredump.cx>
+# (C) Copyright 2003 by Mike Frantzen <frantzen@w4g.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+#
+# This fingerprint database is adapted from Michal Zalewski's p0f passive
+# operating system package. The last database sync was from a Nov 3 2003
+# p0f.fp.
+#
+#
+# Each line in this file specifies a single fingerprint. Please read the
+# information below carefully before attempting to append any signatures
+# reported as UNKNOWN to this file to avoid mistakes.
+#
+# We use the following set metrics for fingerprinting:
+#
+# - Window size (WSS) - a highly OS dependent setting used for TCP/IP
+# performance control (max. amount of data to be sent without ACK).
+# Some systems use a fixed value for initial packets. On other
+# systems, it is a multiple of MSS or MTU (MSS+40). In some rare
+# cases, the value is just arbitrary.
+#
+# NEW SIGNATURE: if p0f reported a special value of 'Snn', the number
+# appears to be a multiple of MSS (MSS*nn); a special value of 'Tnn'
+# means it is a multiple of MTU ((MSS+40)*nn). Unless you notice the
+# value of nn is not fixed (unlikely), just copy the Snn or Tnn token
+# literally. If you know this device has a simple stack and a fixed
+# MTU, you can however multiply S value by MSS, or T value by MSS+40,
+# and put it instead of Snn or Tnn.
+#
+# If WSS otherwise looks like a fixed value (for example a multiple
+# of two), or if you can confirm the value is fixed, please quote
+# it literally. If there's no apparent pattern in WSS chosen, you
+# should consider wildcarding this value.
+#
+# - Overall packet size - a function of all IP and TCP options and bugs.
+#
+# NEW SIGNATURE: Copy this value literally.
+#
+# - Initial TTL - We check the actual TTL of a received packet. It can't
+# be higher than the initial TTL, and also shouldn't be dramatically
+# lower (maximum distance is defined as 40 hops).
+#
+# NEW SIGNATURE: *Never* copy TTL from a p0f-reported signature literally.
+# You need to determine the initial TTL. The best way to do it is to
+# check the documentation for a remote system, or check its settings.
+# A fairly good method is to simply round the observed TTL up to
+# 32, 64, 128, or 255, but it should be noted that some obscure devices
+# might not use round TTLs (in particular, some shoddy appliances use
+# "original" initial TTL settings). If not sure, you can see how many
+# hops you're away from the remote party with traceroute or mtr.
+#
+# - Don't fragment flag (DF) - some modern OSes set this to implement PMTU
+# discovery. Others do not bother.
+#
+# NEW SIGNATURE: Copy this value literally.
+#
+# - Maximum segment size (MSS) - this setting is usually link-dependent. P0f
+# uses it to determine link type of the remote host.
+#
+# NEW SIGNATURE: Always wildcard this value, except for rare cases when
+# you have an appliance with a fixed value, know the system supports only
+# a very limited number of network interface types, or know the system
+# is using a value it pulled out of nowhere. Specific unique MSS
+# can be used to tell Google crawlbots from the rest of the population.
+#
+# - Window scaling (WSCALE) - this feature is used to scale WSS.
+# It extends the size of a TCP/IP window to 32 bits. Some modern
+# systems implement this feature.
+#
+# NEW SIGNATURE: Observe several signatures. Initial WSCALE is often set
+# to zero or other low value. There's usually no need to wildcard this
+# parameter.
+#
+# - Timestamp - some systems that implement timestamps set them to
+# zero in the initial SYN. This case is detected and handled appropriately.
+#
+# - Selective ACK permitted - a flag set by systems that implement
+# selective ACK functionality.
+#
+# - The sequence of TCP all options (MSS, window scaling, selective ACK
+# permitted, timestamp, NOP). Other than the options previously
+# discussed, p0f also checks for timestamp option (a silly
+# extension to broadcast your uptime ;-), NOP options (used for
+# header padding) and sackOK option (selective ACK feature).
+#
+# NEW SIGNATURE: Copy the sequence literally.
+#
+# To wildcard any value (except for initial TTL or TCP options), replace
+# it with '*'. You can also use a modulo operator to match any values
+# that divide by nnn - '%nnn'.
+#
+# Fingerprint entry format:
+#
+# wwww:ttt:D:ss:OOO...:OS:Version:Subtype:Details
+#
+# wwww - window size (can be *, %nnn, Snn or Tnn). The special values
+# "S" and "T" which are a multiple of MSS or a multiple of MTU
+# respectively.
+# ttt - initial TTL
+# D - don't fragment bit (0 - not set, 1 - set)
+# ss - overall SYN packet size
+# OOO - option value and order specification (see below)
+# OS - OS genre (Linux, Solaris, Windows)
+# Version - OS Version (2.0.27 on x86, etc)
+# Subtype - OS subtype or patchlevel (SP3, lo0)
+# details - Generic OS details
+#
+# If OS genre starts with '*', p0f will not show distance, link type
+# and timestamp data. It is useful for userland TCP/IP stacks of
+# network scanners and so on, where many settings are randomized or
+# bogus.
+#
+# If OS genre starts with @, it denotes an approximate hit for a group
+# of operating systems (signature reporting still enabled in this case).
+# Use this feature at the end of this file to catch cases for which
+# you don't have a precise match, but can tell it's Windows or FreeBSD
+# or whatnot by looking at, say, flag layout alone.
+#
+# Option block description is a list of comma or space separated
+# options in the order they appear in the packet:
+#
+# N - NOP option
+# Wnnn - window scaling option, value nnn (or * or %nnn)
+# Mnnn - maximum segment size option, value nnn (or * or %nnn)
+# S - selective ACK OK
+# T - timestamp
+# T0 - timestamp with a zero value
+#
+# To denote no TCP options, use a single '.'.
+#
+# Please report any additions to this file, or any inaccuracies or
+# problems spotted, to the maintainers: lcamtuf@coredump.cx,
+# frantzen@openbsd.org and bugs@openbsd.org with a tcpdump packet
+# capture of the relevant SYN packet(s)
+#
+# A test and submission page is available at
+# http://lcamtuf.coredump.cx/p0f-help/
+#
+#
+# WARNING WARNING WARNING
+# -----------------------
+#
+# Do not add a system X as OS Y just because NMAP says so. It is often
+# the case that X is a NAT firewall. While nmap is talking to the
+# device itself, p0f is fingerprinting the guy behind the firewall
+# instead.
+#
+# When in doubt, use common sense, don't add something that looks like
+# a completely different system as Linux or FreeBSD or LinkSys router.
+# Check DNS name, establish a connection to the remote host and look
+# at SYN+ACK - does it look similar?
+#
+# Some users tweak their TCP/IP settings - enable or disable RFC1323
+# functionality, enable or disable timestamps or selective ACK,
+# disable PMTU discovery, change MTU and so on. Always compare a new rule
+# to other fingerprints for this system, and verify the system isn't
+# "customized" before adding it. It is OK to add signature variants
+# caused by a commonly used software (personal firewalls, security
+# packages, etc), but it makes no sense to try to add every single
+# possible /proc/sys/net/ipv4 tweak on Linux or so.
+#
+# KEEP IN MIND: Some packet firewalls configured to normalize outgoing
+# traffic (OpenBSD pf with "scrub" enabled, for example) will, well,
+# normalize packets. Signatures will not correspond to the originating
+# system (and probably not quite to the firewall either).
+#
+# NOTE: Try to keep this file in some reasonable order, from most to
+# least likely systems. This will speed up operation. Also keep most
+# generic and broad rules near the end.
+#
+
+##########################
+# Standard OS signatures #
+##########################
+
+# ----------------- AIX ---------------------
+
+# AIX is first because its signatures are close to NetBSD, MacOS X and
+# Linux 2.0, but it uses a fairly rare MSSes, at least sometimes...
+# This is a shoddy hack, though.
+
+45046:64:0:44:M*: AIX:4.3::AIX 4.3
+16384:64:0:44:M512: AIX:4.3:2-3:AIX 4.3.2 and earlier
+
+16384:64:0:60:M512,N,W%2,N,N,T: AIX:4.3-5.2:3:AIX 4.3.3-5.2
+32768:64:0:60:M512,N,W%2,N,N,T: AIX:4.3-5.2:3:AIX 4.3.3-5.2
+65535:64:0:60:M512,N,W%2,N,N,T: AIX:4.3-5-2:3:AIX 4.3.3-5.2
+65535:64:0:64:M*,N,W1,N,N,T,N,N,S: AIX:5.3:ML1:AIX 5.3 ML1
+
+# ----------------- Linux -------------------
+
+# S1:64:0:44:M*:A: Linux:1.2::Linux 1.2.x (XXX quirks support)
+512:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x
+16384:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x
+
+# Endian snafu! Nelson says "ha-ha":
+2:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x (MkLinux) on Mac
+64:64:0:44:M*: Linux:2.0:3x:Linux 2.0.3x (MkLinux) on Mac
+
+
+S4:64:1:60:M1360,S,T,N,W0: Linux:google::Linux (Google crawlbot)
+
+S2:64:1:60:M*,S,T,N,W0: Linux:2.4::Linux 2.4 (big boy)
+S3:64:1:60:M*,S,T,N,W0: Linux:2.4:.18-21:Linux 2.4.18 and newer
+S4:64:1:60:M*,S,T,N,W0: Linux:2.4/2.6::Linux 2.4/2.6 <= 2.6.7
+
+S4:64:1:60:M*,S,T,N,W5: Linux:2.6::Linux 2.6 (newer, 1)
+S4:64:1:60:M*,S,T,N,W6: Linux:2.6::Linux 2.6 (newer, 2)
+S4:64:1:60:M*,S,T,N,W7: Linux:2.6::Linux 2.6 (newer, 3)
+T4:64:1:60:M*,S,T,N,W7: Linux:2.6::Linux 2.6 (newer, 4)
+
+S10:64:1:60:M*,S,T,N,W4: Linux:3.0::Linux 3.0
+S10:64:1:60:M*,S,T,N,W6: Linux:3.1::Linux 3.1
+S10:64:1:60:M*,S,T,N,W7: Linux:3.4-3.10::Linux 3.4 - 3.10
+S20:64:1:60:M*,S,T,N,W7: Linux:3.11-4.19::Linux 3.11 - 4.19
+S44:64:1:60:M*,S,T,N,W7: Linux:4.20::Linux 4.20
+
+S3:64:1:60:M*,S,T,N,W1: Linux:2.5::Linux 2.5 (sometimes 2.4)
+S4:64:1:60:M*,S,T,N,W1: Linux:2.5-2.6::Linux 2.5/2.6
+S3:64:1:60:M*,S,T,N,W2: Linux:2.5::Linux 2.5 (sometimes 2.4)
+S4:64:1:60:M*,S,T,N,W2: Linux:2.5::Linux 2.5 (sometimes 2.4)
+
+S20:64:1:60:M*,S,T,N,W0: Linux:2.2:20-25:Linux 2.2.20 and newer
+S22:64:1:60:M*,S,T,N,W0: Linux:2.2::Linux 2.2
+S11:64:1:60:M*,S,T,N,W0: Linux:2.2::Linux 2.2
+
+# Popular cluster config scripts disable timestamps and
+# selective ACK:
+S4:64:1:48:M1460,N,W0: Linux:2.4:cluster:Linux 2.4 in cluster
+
+# This needs to be investigated. On some systems, WSS
+# is selected as a multiple of MTU instead of MSS. I got
+# many submissions for this for many late versions of 2.4:
+T4:64:1:60:M1412,S,T,N,W0: Linux:2.4::Linux 2.4 (late, uncommon)
+
+# This happens only over loopback, but let's make folks happy:
+32767:64:1:60:M16396,S,T,N,W0: Linux:2.4:lo0:Linux 2.4 (local)
+S8:64:1:60:M3884,S,T,N,W0: Linux:2.2:lo0:Linux 2.2 (local)
+
+# Opera visitors:
+16384:64:1:60:M*,S,T,N,W0: Linux:2.2:Opera:Linux 2.2 (Opera?)
+32767:64:1:60:M*,S,T,N,W0: Linux:2.4:Opera:Linux 2.4 (Opera?)
+
+# Some fairly common mods:
+S4:64:1:52:M*,N,N,S,N,W0: Linux:2.4:ts:Linux 2.4 w/o timestamps
+S22:64:1:52:M*,N,N,S,N,W0: Linux:2.2:ts:Linux 2.2 w/o timestamps
+
+
+# ----------------- FreeBSD -----------------
+
+16384:64:1:44:M*: FreeBSD:2.0-4.2::FreeBSD 2.0-4.2
+16384:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.4::FreeBSD 4.4
+
+1024:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.4::FreeBSD 4.4
+
+57344:64:1:44:M*: FreeBSD:4.6-4.8:noRFC1323:FreeBSD 4.6-4.8 (no RFC1323)
+57344:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.6-4.9::FreeBSD 4.6-4.9
+
+32768:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.8-5.1::FreeBSD 4.8-5.1 (or MacOS X)
+65535:64:1:60:M*,N,W0,N,N,T: FreeBSD:4.8-5.2::FreeBSD 4.8-5.2 (or MacOS X)
+65535:64:1:60:M*,N,W1,N,N,T: FreeBSD:4.7-5.2::FreeBSD 4.7-5.2
+
+65535:64:1:60:M*,N,W6,S,T: FreeBSD:9.0-12.0::FreeBSD 9.0 - 12.0
+
+# XXX need quirks support
+# 65535:64:1:60:M*,N,W0,N,N,T:Z:FreeBSD:5.1-5.4::5.1-current (1)
+# 65535:64:1:60:M*,N,W1,N,N,T:Z:FreeBSD:5.1-5.4::5.1-current (2)
+# 65535:64:1:60:M*,N,W2,N,N,T:Z:FreeBSD:5.1-5.4::5.1-current (3)
+# 65535:64:1:44:M*:Z:FreeBSD:5.2::FreeBSD 5.2 (no RFC1323)
+
+# 16384:64:1:60:M*,N,N,N,N,N,N,T:FreeBSD:4.4:noTS:FreeBSD 4.4 (w/o timestamps)
+
+# ----------------- NetBSD ------------------
+
+16384:64:0:60:M*,N,W0,N,N,T: NetBSD:1.3::NetBSD 1.3
+65535:64:0:60:M*,N,W0,N,N,T0: NetBSD:1.6:opera:NetBSD 1.6 (Opera)
+16384:64:0:60:M*,N,W0,N,N,T0: NetBSD:1.6::NetBSD 1.6
+16384:64:1:60:M*,N,W0,N,N,T0: NetBSD:1.6:df:NetBSD 1.6 (DF)
+65535:64:1:60:M*,N,W1,N,N,T0: NetBSD:1.6::NetBSD 1.6W-current (DF)
+65535:64:1:60:M*,N,W0,N,N,T0: NetBSD:1.6::NetBSD 1.6X (DF)
+32768:64:1:60:M*,N,W0,N,N,T0: NetBSD:1.6:randomization:NetBSD 1.6ZH-current (w/ ip_id randomization)
+
+# ----------------- OpenBSD -----------------
+
+16384:64:0:60:M*,N,W0,N,N,T: OpenBSD:2.6::NetBSD 1.3 (or OpenBSD 2.6)
+16384:64:1:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.0-4.8::OpenBSD 3.0-4.8
+16384:64:0:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.0-4.8:no-df:OpenBSD 3.0-4.8 (scrub no-df)
+57344:64:1:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.3-4.0::OpenBSD 3.3-4.0
+57344:64:0:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.3-4.0:no-df:OpenBSD 3.3-4.0 (scrub no-df)
+
+65535:64:1:64:M*,N,N,S,N,W0,N,N,T: OpenBSD:3.0-4.0:opera:OpenBSD 3.0-4.0 (Opera)
+
+16384:64:1:64:M*,N,N,S,N,W3,N,N,T: OpenBSD:4.9::OpenBSD 4.9
+16384:64:0:64:M*,N,N,S,N,W3,N,N,T: OpenBSD:4.9:no-df:OpenBSD 4.9 (scrub no-df)
+
+16384:64:1:64:M*,N,N,S,N,W6,N,N,T: OpenBSD:6.1::OpenBSD 6.1
+16384:64:0:64:M*,N,N,S,N,W6,N,N,T: OpenBSD:6.1:no-df:OpenBSD 6.1 (scrub no-df)
+
+# ----------------- DragonFly BSD -----------------
+
+57344:64:1:60:M*,N,W0,N,N,T: DragonFly:1.0:A:DragonFly 1.0A
+57344:64:0:64:M*,N,W0,N,N,S,N,N,T: DragonFly:1.2-1.12::DragonFly 1.2-1.12
+5840:64:1:60:M*,S,T,N,W4: DragonFly:2.0-2.1::DragonFly 2.0-2.1
+57344:64:0:64:M*,N,W0,N,N,S,N,N,T: DragonFly:2.2-2.3::DragonFly 2.2-2.3
+57344:64:0:64:M*,N,W5,N,N,S,N,N,T: DragonFly:2.4-2.7::DragonFly 2.4-2.7
+
+# ----------------- Solaris -----------------
+
+S17:64:1:64:N,W3,N,N,T0,N,N,S,M*: Solaris:8:RFC1323:Solaris 8 RFC1323
+S17:64:1:48:N,N,S,M*: Solaris:8::Solaris 8
+S17:255:1:44:M*: Solaris:2.5-2.7::Solaris 2.5 to 7
+
+S6:255:1:44:M*: Solaris:2.6-2.7::Solaris 2.6 to 7
+S23:255:1:44:M*: Solaris:2.5:1:Solaris 2.5.1
+S34:64:1:48:M*,N,N,S: Solaris:2.9::Solaris 9
+S44:255:1:44:M*: Solaris:2.7::Solaris 7
+
+4096:64:0:44:M1460: SunOS:4.1::SunOS 4.1.x
+
+S34:64:1:52:M*,N,W0,N,N,S: Solaris:10:beta:Solaris 10 (beta)
+32850:64:1:64:M*,N,N,T,N,W1,N,N,S: Solaris:10::Solaris 10 1203
+
+# ----------------- IRIX --------------------
+
+49152:64:0:44:M*: IRIX:6.4::IRIX 6.4
+61440:64:0:44:M*: IRIX:6.2-6.5::IRIX 6.2-6.5
+49152:64:0:52:M*,N,W2,N,N,S: IRIX:6.5:RFC1323:IRIX 6.5 (RFC1323)
+49152:64:0:52:M*,N,W3,N,N,S: IRIX:6.5:RFC1323:IRIX 6.5 (RFC1323)
+
+61440:64:0:48:M*,N,N,S: IRIX:6.5:12-21:IRIX 6.5.12 - 6.5.21
+49152:64:0:48:M*,N,N,S: IRIX:6.5:15-21:IRIX 6.5.15 - 6.5.21
+
+49152:60:0:64:M*,N,W2,N,N,T,N,N,S: IRIX:6.5:IP27:IRIX 6.5 IP27
+
+
+# ----------------- Tru64 -------------------
+
+32768:64:1:48:M*,N,W0: Tru64:4.0::Tru64 4.0 (or OS/2 Warp 4)
+32768:64:0:48:M*,N,W0: Tru64:5.0::Tru64 5.0
+8192:64:0:44:M1460: Tru64:5.1:noRFC1323:Tru64 6.1 (no RFC1323) (or QNX 6)
+61440:64:0:48:M*,N,W0: Tru64:5.1a:JP4:Tru64 v5.1a JP4 (or OpenVMS 7.x on Compaq 5.x stack)
+
+# ----------------- OpenVMS -----------------
+
+6144:64:1:60:M*,N,W0,N,N,T: OpenVMS:7.2::OpenVMS 7.2 (Multinet 4.4 stack)
+
+# ----------------- MacOS -------------------
+
+# XXX Need EOL tcp opt support
+# S2:255:1:48:M*,W0,E:.:MacOS:8.6 classic
+
+# XXX some of these use EOL too
+16616:255:1:48:M*,W0: MacOS:7.3-8.6:OTTCP:MacOS 7.3-8.6 (OTTCP)
+16616:255:1:48:M*,N,N,N: MacOS:8.1-8.6:OTTCP:MacOS 8.1-8.6 (OTTCP)
+32768:255:1:48:M*,W0,N: MacOS:9.0-9.2::MacOS 9.0-9.2
+65535:255:1:48:M*,N,N,N,N: MacOS:9.1::MacOS 9.1 (OT 2.7.4)
+
+
+# ----------------- Windows -----------------
+
+# Windows TCP/IP stack is a mess. For most recent XP, 2000 and
+# even 98, the patchlevel, not the actual OS version, is more
+# relevant to the signature. They share the same code, so it would
+# seem. Luckily for us, almost all Windows 9x boxes have an
+# awkward MSS of 536, which I use to tell one from another
+# in most difficult cases.
+
+8192:32:1:44:M*: Windows:3.11::Windows 3.11 (Tucows)
+S44:64:1:64:M*,N,W0,N,N,T0,N,N,S: Windows:95::Windows 95
+8192:128:1:64:M*,N,W0,N,N,T0,N,N,S: Windows:95:b:Windows 95b
+
+# There were so many tweaking tools and so many stack versions for
+# Windows 98 it is no longer possible to tell them from each other
+# without some very serious research. Until then, there's an insane
+# number of signatures, for your amusement:
+
+S44:32:1:48:M*,N,N,S: Windows:98:lowTTL:Windows 98 (low TTL)
+8192:32:1:48:M*,N,N,S: Windows:98:lowTTL:Windows 98 (low TTL)
+%8192:64:1:48:M536,N,N,S: Windows:98::Windows 98
+%8192:128:1:48:M536,N,N,S: Windows:98::Windows 98
+S4:64:1:48:M*,N,N,S: Windows:98::Windows 98
+S6:64:1:48:M*,N,N,S: Windows:98::Windows 98
+S12:64:1:48:M*,N,N,S: Windows:98::Windows 98
+T30:64:1:64:M1460,N,W0,N,N,T0,N,N,S: Windows:98::Windows 98
+32767:64:1:48:M*,N,N,S: Windows:98::Windows 98
+37300:64:1:48:M*,N,N,S: Windows:98::Windows 98
+46080:64:1:52:M*,N,W3,N,N,S: Windows:98:RFC1323:Windows 98 (RFC1323)
+65535:64:1:44:M*: Windows:98:noSack:Windows 98 (no sack)
+S16:128:1:48:M*,N,N,S: Windows:98::Windows 98
+S16:128:1:64:M*,N,W0,N,N,T0,N,N,S: Windows:98::Windows 98
+S26:128:1:48:M*,N,N,S: Windows:98::Windows 98
+T30:128:1:48:M*,N,N,S: Windows:98::Windows 98
+32767:128:1:52:M*,N,W0,N,N,S: Windows:98::Windows 98
+60352:128:1:48:M*,N,N,S: Windows:98::Windows 98
+60352:128:1:64:M*,N,W2,N,N,T0,N,N,S: Windows:98::Windows 98
+
+# What's with 1414 on NT?
+T31:128:1:44:M1414: Windows:NT:4.0:Windows NT 4.0 SP6a
+64512:128:1:44:M1414: Windows:NT:4.0:Windows NT 4.0 SP6a
+8192:128:1:44:M*: Windows:NT:4.0:Windows NT 4.0 (older)
+
+# Windows XP and 2000. Most of the signatures that were
+# either dubious or non-specific (no service pack data)
+# were deleted and replaced with generics at the end.
+
+65535:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows 2000 SP4, XP SP1
+65535:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows 2000 SP4, XP SP1
+%8192:128:1:48:M*,N,N,S: Windows:2000:SP2+:Windows 2000 SP2, XP SP1 (seldom 98 4.10.2222)
+%8192:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows 2000 SP2, XP SP1 (seldom 98 4.10.2222)
+S20:128:1:48:M*,N,N,S: Windows:2000::Windows 2000/XP SP3
+S20:128:1:48:M*,N,N,S: Windows:XP:SP3:Windows 2000/XP SP3
+S45:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows 2000 SP4, XP SP 1
+S45:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows 2000 SP4, XP SP 1
+40320:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows 2000 SP4
+
+S6:128:1:48:M*,N,N,S: Windows:2000:SP2:Windows XP, 2000 SP2+
+S6:128:1:48:M*,N,N,S: Windows:XP::Windows XP, 2000 SP2+
+S12:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows XP SP1
+S44:128:1:48:M*,N,N,S: Windows:2000:SP3:Windows Pro SP1, 2000 SP3
+S44:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows Pro SP1, 2000 SP3
+64512:128:1:48:M*,N,N,S: Windows:2000:SP3:Windows SP1, 2000 SP3
+64512:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows SP1, 2000 SP3
+32767:128:1:48:M*,N,N,S: Windows:2000:SP4:Windows SP1, 2000 SP4
+32767:128:1:48:M*,N,N,S: Windows:XP:SP1:Windows SP1, 2000 SP4
+
+8192:128:1:52:M*,N,W2,N,N,S: Windows:Vista::Windows Vista/7
+
+# Odds, ends, mods:
+
+S52:128:1:48:M1260,N,N,S: Windows:2000:cisco:Windows XP/2000 via Cisco
+S52:128:1:48:M1260,N,N,S: Windows:XP:cisco:Windows XP/2000 via Cisco
+65520:128:1:48:M*,N,N,S: Windows:XP::Windows XP bare-bone
+16384:128:1:52:M536,N,W0,N,N,S: Windows:2000:ZoneAlarm:Windows 2000 w/ZoneAlarm?
+2048:255:0:40:.: Windows:.NET::Windows .NET Enterprise Server
+
+44620:64:0:48:M*,N,N,S: Windows:ME::Windows ME no SP (?)
+S6:255:1:48:M536,N,N,S: Windows:95:winsock2:Windows 95 winsock 2
+32768:32:1:52:M1460,N,W0,N,N,S: Windows:2003:AS:Windows 2003 AS
+
+
+# No need to be more specific, it passes:
+# *:128:1:48:M*,N,N,S:U:-Windows:XP/2000 while downloading (leak!) XXX quirk
+# there is an equiv similar generic sig w/o the quirk
+
+# ----------------- HP/UX -------------------
+
+32768:64:1:44:M*: HP-UX:B.10.20::HP-UX B.10.20
+32768:64:0:48:M*,W0,N: HP-UX:11.0::HP-UX 11.0
+32768:64:1:48:M*,W0,N: HP-UX:11.10::HP-UX 11.0 or 11.11
+32768:64:1:48:M*,W0,N: HP-UX:11.11::HP-UX 11.0 or 11.11
+
+# Whoa. Hardcore WSS.
+0:64:0:48:M*,W0,N: HP-UX:B.11.00:A:HP-UX B.11.00 A (RFC1323)
+
+# ----------------- RiscOS ------------------
+
+# We don't yet support the ?12 TCP option
+#16384:64:1:68:M1460,N,W0,N,N,T,N,N,?12: RISCOS:3.70-4.36::RISC OS 3.70-4.36
+12288:32:0:44:M536: RISC OS:3.70:4.10:RISC OS 3.70 inet 4.10
+
+# XXX quirk
+# 4096:64:1:56:M1460,N,N,T:T: RISC OS:3.70:freenet:RISC OS 3.70 freenet 2.00
+
+
+
+# ----------------- BSD/OS ------------------
+
+# Once again, power of two WSS is also shared by MacOS X with DF set
+8192:64:1:60:M1460,N,W0,N,N,T: BSD/OS:3.1::BSD/OS 3.1-4.3 (or MacOS X 10.2 w/DF)
+8192:64:1:60:M1460,N,W0,N,N,T: BSD/OS:4.0-4.3::BSD/OS 3.1-4.3 (or MacOS X 10.2)
+
+
+# ---------------- NewtonOS -----------------
+
+4096:64:0:44:M1420: NewtonOS:2.1::NewtonOS 2.1
+
+# ---------------- NeXTSTEP -----------------
+
+S4:64:0:44:M1024: NeXTSTEP:3.3::NeXTSTEP 3.3
+S8:64:0:44:M512: NeXTSTEP:3.3::NeXTSTEP 3.3
+
+# ------------------ BeOS -------------------
+
+1024:255:0:48:M*,N,W0: BeOS:5.0-5.1::BeOS 5.0-5.1
+12288:255:0:44:M1402: BeOS:5.0::BeOS 5.0.x
+
+# ------------------ OS/400 -----------------
+
+8192:64:1:60:M1440,N,W0,N,N,T: OS/400:VR4-VR5::OS/400 VR4/R5
+4096:64:1:60:M1440,N,W0,N,N,T: OS/400:V4R5:CF67032:OS/400 V4R5 + CF67032
+
+# XXX quirk
+# 28672:64:0:44:M1460:A:OS/390:?
+
+# ------------------ ULTRIX -----------------
+
+16384:64:0:40:.: ULTRIX:4.5::ULTRIX 4.5
+
+# ------------------- QNX -------------------
+
+S16:64:0:44:M512: QNX:::QNX demodisk
+
+# ------------------ Novell -----------------
+
+16384:128:1:44:M1460: Novell:NW:5.0:Novel Netware 5.0
+6144:128:1:44:M1460: Novell:IW:4.11:Novell IntranetWare 4.11
+6144:128:1:44:M1368: Novell:BM::Novell BorderManager ?
+
+6144:128:1:52:M*,W0,N,S,N,N: Novell:Netware:6:Novell Netware 6 SP3
+
+
+# ----------------- SCO ------------------
+S3:64:1:60:M1460,N,W0,N,N,T: SCO:UnixWare:7.1:SCO UnixWare 7.1
+S17:64:1:60:M1380,N,W0,N,N,T: SCO:UnixWare:7.1:SCO UnixWare 7.1.3 MP3
+S23:64:1:44:M1380: SCO:OpenServer:5.0:SCO OpenServer 5.0
+
+# ------------------- DOS -------------------
+
+2048:255:0:44:M536: DOS:WATTCP:1.05:DOS Arachne via WATTCP/1.05
+T2:255:0:44:M984: DOS:WATTCP:1.05Arachne:Arachne via WATTCP/1.05 (eepro)
+
+# ------------------ OS/2 -------------------
+
+S56:64:0:44:M512: OS/2:4::OS/2 4
+28672:64:0:44:M1460: OS/2:4::OS/2 Warp 4.0
+
+# ----------------- TOPS-20 -----------------
+
+# Another hardcore MSS, one of the ACK leakers hunted down.
+# XXX QUIRK 0:64:0:44:M1460:A:TOPS-20:version 7
+0:64:0:44:M1460: TOPS-20:7::TOPS-20 version 7
+
+# ----------------- FreeMiNT ----------------
+
+S44:255:0:44:M536: FreeMiNT:1:16A:FreeMiNT 1 patch 16A (Atari)
+
+# ------------------ AMIGA ------------------
+
+# XXX TCP option 12
+# S32:64:1:56:M*,N,N,S,N,N,?12:.:AMIGA:3.9 BB2 with Miami stack
+
+# ------------------ Plan9 ------------------
+
+65535:255:0:48:M1460,W0,N: Plan9:4::Plan9 edition 4
+
+# ----------------- AMIGAOS -----------------
+
+16384:64:1:48:M1560,N,N,S: AMIGAOS:3.9::AMIGAOS 3.9 BB2 MiamiDX
+
+###########################################
+# Appliance / embedded / other signatures #
+###########################################
+
+# ---------- Firewalls / routers ------------
+
+S12:64:1:44:M1460: @Checkpoint:::Checkpoint (unknown 1)
+S12:64:1:48:N,N,S,M1460: @Checkpoint:::Checkpoint (unknown 2)
+4096:32:0:44:M1460: ExtremeWare:4.x::ExtremeWare 4.x
+
+# XXX TCP option 12
+# S32:64:0:68:M512,N,W0,N,N,T,N,N,?12:.:Nokia:IPSO w/Checkpoint NG FP3
+# S16:64:0:68:M1024,N,W0,N,N,T,N,N,?12:.:Nokia:IPSO 3.7 build 026
+
+S4:64:1:60:W0,N,S,T,M1460: FortiNet:FortiGate:50:FortiNet FortiGate 50
+
+8192:64:1:44:M1460: Eagle:::Eagle Secure Gateway
+
+S52:128:1:48:M1260,N,N,N,N: LinkSys:WRV54G::LinkSys WRV54G VPN router
+
+
+
+# ------- Switches and other stuff ----------
+
+4128:255:0:44:M*: Cisco:::Cisco Catalyst 3500, 7500 etc
+S8:255:0:44:M*: Cisco:12008::Cisco 12008
+60352:128:1:64:M1460,N,W2,N,N,T,N,N,S: Alteon:ACEswitch::Alteon ACEswitch
+64512:128:1:44:M1370: Nortel:Contivity Client::Nortel Conectivity Client
+
+
+# ---------- Caches and whatnots ------------
+
+S4:64:1:52:M1460,N,N,S,N,W0: AOL:web cache::AOL web cache
+
+32850:64:1:64:N,W1,N,N,T,N,N,S,M*: NetApp:5.x::NetApp Data OnTap 5.x
+16384:64:1:64:M1460,N,N,S,N,W0,N: NetApp:5.3:1:NetApp 5.3.1
+65535:64:0:64:M1460,N,N,S,N,W*,N,N,T: NetApp:5.3-5.5::NetApp 5.3-5.5
+65535:64:0:60:M1460,N,W0,N,N,T: NetApp:CacheFlow::NetApp CacheFlow
+8192:64:1:64:M1460,N,N,S,N,W0,N,N,T: NetApp:5.2:1:NetApp NetCache 5.2.1
+20480:64:1:64:M1460,N,N,S,N,W0,N,N,T: NetApp:4.1::NetApp NetCache4.1
+
+65535:64:0:60:M1460,N,W0,N,N,T: CacheFlow:4.1::CacheFlow CacheOS 4.1
+8192:64:0:60:M1380,N,N,N,N,N,N,T: CacheFlow:1.1::CacheFlow CacheOS 1.1
+
+S4:64:0:48:M1460,N,N,S: Cisco:Content Engine::Cisco Content Engine
+
+27085:128:0:40:.: Dell:PowerApp cache::Dell PowerApp (Linux-based)
+
+65535:255:1:48:N,W1,M1460: Inktomi:crawler::Inktomi crawler
+S1:255:1:60:M1460,S,T,N,W0: LookSmart:ZyBorg::LookSmart ZyBorg
+
+16384:255:0:40:.: Proxyblocker:::Proxyblocker (what's this?)
+
+65535:255:0:48:M*,N,N,S: Redline:::Redline T|X 2200
+
+32696:128:0:40:M1460: Spirent:Avalanche::Spirent Web Avalanche HTTP benchmarking engine
+
+# ----------- Embedded systems --------------
+
+S9:255:0:44:M536: PalmOS:Tungsten:C:PalmOS Tungsten C
+S5:255:0:44:M536: PalmOS:3-4::PalmOS 3/4
+S4:255:0:44:M536: PalmOS:3:5:PalmOS 3.5
+2948:255:0:44:M536: PalmOS:3:5:PalmOS 3.5.3 (Handera)
+S29:255:0:44:M536: PalmOS:5::PalmOS 5.0
+16384:255:0:44:M1398: PalmOS:5.2:Clie:PalmOS 5.2 (Clie)
+S14:255:0:44:M1350: PalmOS:5.2:Treo:PalmOS 5.2.1 (Treo)
+
+S23:64:1:64:N,W1,N,N,T,N,N,S,M1460: SymbianOS:7::SymbianOS 7
+
+8192:255:0:44:M1460: SymbianOS:6048::Symbian OS 6048 (Nokia 7650?)
+8192:255:0:44:M536: SymbianOS:9210::Symbian OS (Nokia 9210?)
+S22:64:1:56:M1460,T,S: SymbianOS:P800::Symbian OS ? (SE P800?)
+S36:64:1:56:M1360,T,S: SymbianOS:6600::Symbian OS 60xx (Nokia 6600?)
+
+
+# Perhaps S4?
+5840:64:1:60:M1452,S,T,N,W1: Zaurus:3.10::Zaurus 3.10
+
+32768:128:1:64:M1460,N,W0,N,N,T0,N,N,S: PocketPC:2002::PocketPC 2002
+
+S1:255:0:44:M346: Contiki:1.1:rc0:Contiki 1.1-rc0
+
+4096:128:0:44:M1460: Sega:Dreamcast:3.0:Sega Dreamcast Dreamkey 3.0
+T5:64:0:44:M536: Sega:Dreamcast:HKT-3020:Sega Dreamcast HKT-3020 (browser disc 51027)
+S22:64:1:44:M1460: Sony:PS2::Sony Playstation 2 (SOCOM?)
+
+S12:64:0:44:M1452: AXIS:5600:v5.64:AXIS Printer Server 5600 v5.64
+
+3100:32:1:44:M1460: Windows:CE:2.0:Windows CE 2.0
+
+####################
+# Fancy signatures #
+####################
+
+1024:64:0:40:.: *NMAP:syn scan:1:NMAP syn scan (1)
+2048:64:0:40:.: *NMAP:syn scan:2:NMAP syn scan (2)
+3072:64:0:40:.: *NMAP:syn scan:3:NMAP syn scan (3)
+4096:64:0:40:.: *NMAP:syn scan:4:NMAP syn scan (4)
+
+# Requires quirks support
+# 1024:64:0:40:.:A:*NMAP:TCP sweep probe (1)
+# 2048:64:0:40:.:A:*NMAP:TCP sweep probe (2)
+# 3072:64:0:40:.:A:*NMAP:TCP sweep probe (3)
+# 4096:64:0:40:.:A:*NMAP:TCP sweep probe (4)
+
+1024:64:0:60:W10,N,M265,T: *NMAP:OS:1:NMAP OS detection probe (1)
+2048:64:0:60:W10,N,M265,T: *NMAP:OS:2:NMAP OS detection probe (2)
+3072:64:0:60:W10,N,M265,T: *NMAP:OS:3:NMAP OS detection probe (3)
+4096:64:0:60:W10,N,M265,T: *NMAP:OS:4:NMAP OS detection probe (4)
+
+32767:64:0:40:.: *NAST:::NASTsyn scan
+
+# Requires quirks support
+# 12345:255:0:40:.:A:-p0f:sendsyn utility
+
+
+#####################################
+# Generic signatures - just in case #
+#####################################
+
+#*:64:1:60:M*,N,W*,N,N,T: @FreeBSD:4.0-4.9::FreeBSD 4.x/5.x
+#*:64:1:60:M*,N,W*,N,N,T: @FreeBSD:5.0-5.1::FreeBSD 4.x/5.x
+
+*:128:1:52:M*,N,W0,N,N,S: @Windows:XP:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:52:M*,N,W0,N,N,S: @Windows:2000:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:52:M*,N,W*,N,N,S: @Windows:XP:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:52:M*,N,W*,N,N,S: @Windows:2000:RFC1323:Windows XP/2000 (RFC1323 no tstamp)
+*:128:1:64:M*,N,W0,N,N,T0,N,N,S: @Windows:XP:RFC1323:Windows XP/2000 (RFC1323)
+*:128:1:64:M*,N,W0,N,N,T0,N,N,S: @Windows:2000:RFC1323:Windows XP/2000 (RFC1323)
+*:128:1:64:M*,N,W*,N,N,T0,N,N,S: @Windows:XP:RFC1323:Windows XP (RFC1323, w+)
+*:128:1:48:M536,N,N,S: @Windows:98::Windows 98
+*:128:1:48:M*,N,N,S: @Windows:XP::Windows XP/2000
+*:128:1:48:M*,N,N,S: @Windows:2000::Windows XP/2000
+
+
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..162807b
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,43 @@
+SUBDIRS = linux \
+ nftables
+
+noinst_HEADERS = cli.h \
+ cache.h \
+ cmd.h \
+ datatype.h \
+ dccpopt.h \
+ nft.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/Makefile.in b/include/Makefile.in
new file mode 100644
index 0000000..fcb9c6f
--- /dev/null
+++ b/include/Makefile.in
@@ -0,0 +1,681 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = linux \
+ nftables
+
+noinst_HEADERS = cli.h \
+ cache.h \
+ cmd.h \
+ datatype.h \
+ dccpopt.h \
+ nft.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
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/cache.h b/include/cache.h
new file mode 100644
index 0000000..8ca4a9a
--- /dev/null
+++ b/include/cache.h
@@ -0,0 +1,155 @@
+#ifndef _NFT_CACHE_H_
+#define _NFT_CACHE_H_
+
+#include <list.h>
+
+struct handle;
+
+enum cache_level_bits {
+ NFT_CACHE_TABLE_BIT = (1 << 0),
+ NFT_CACHE_CHAIN_BIT = (1 << 1),
+ NFT_CACHE_SET_BIT = (1 << 2),
+ NFT_CACHE_FLOWTABLE_BIT = (1 << 3),
+ NFT_CACHE_OBJECT_BIT = (1 << 4),
+ NFT_CACHE_SETELEM_BIT = (1 << 5),
+ NFT_CACHE_RULE_BIT = (1 << 6),
+ __NFT_CACHE_MAX_BIT = (1 << 7),
+};
+
+enum cache_level_flags {
+ NFT_CACHE_EMPTY = 0,
+ NFT_CACHE_TABLE = NFT_CACHE_TABLE_BIT,
+ NFT_CACHE_CHAIN = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_CHAIN_BIT,
+ NFT_CACHE_SET = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_SET_BIT,
+ NFT_CACHE_FLOWTABLE = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_FLOWTABLE_BIT,
+ NFT_CACHE_OBJECT = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_OBJECT_BIT,
+ NFT_CACHE_SETELEM = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_SET_BIT |
+ NFT_CACHE_SETELEM_BIT,
+ NFT_CACHE_RULE = NFT_CACHE_TABLE_BIT |
+ NFT_CACHE_CHAIN_BIT |
+ NFT_CACHE_RULE_BIT,
+ NFT_CACHE_FULL = __NFT_CACHE_MAX_BIT - 1,
+ NFT_CACHE_TERSE = (1 << 27),
+ NFT_CACHE_SETELEM_MAYBE = (1 << 28),
+ NFT_CACHE_REFRESH = (1 << 29),
+ NFT_CACHE_UPDATE = (1 << 30),
+ NFT_CACHE_FLUSHED = (1 << 31),
+};
+
+struct nft_filter_obj {
+ struct list_head list;
+ uint32_t family;
+ const char *table;
+ const char *set;
+};
+
+#define NFT_CACHE_HSIZE 8192
+
+struct nft_cache_filter {
+ struct {
+ uint32_t family;
+ const char *table;
+ const char *chain;
+ const char *set;
+ const char *ft;
+ uint64_t rule_handle;
+ } list;
+
+ struct {
+ struct list_head head;
+ } obj[NFT_CACHE_HSIZE];
+};
+
+struct nft_cache;
+struct nft_ctx;
+enum cmd_ops;
+
+int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
+ struct list_head *msgs, struct nft_cache_filter *filter,
+ unsigned int *flags);
+int nft_cache_update(struct nft_ctx *ctx, unsigned int flags,
+ struct list_head *msgs,
+ const struct nft_cache_filter *filter);
+bool nft_cache_needs_update(struct nft_cache *cache);
+void nft_cache_release(struct nft_cache *cache);
+
+static inline uint32_t djb_hash(const char *key)
+{
+ uint32_t i, hash = 5381;
+
+ for (i = 0; i < strlen(key); i++)
+ hash = ((hash << 5) + hash) + key[i];
+
+ return hash;
+}
+
+struct nft_cache_filter *nft_cache_filter_init(void);
+void nft_cache_filter_fini(struct nft_cache_filter *filter);
+
+struct table;
+struct chain;
+
+void chain_cache_add(struct chain *chain, struct table *table);
+void chain_cache_del(struct chain *chain);
+struct chain *chain_cache_find(const struct table *table, const char *name);
+
+struct set;
+
+void set_cache_add(struct set *set, struct table *table);
+void set_cache_del(struct set *set);
+struct set *set_cache_find(const struct table *table, const char *name);
+
+struct cache {
+ struct list_head *ht;
+ struct list_head list;
+};
+
+struct cache_item {
+ struct list_head hlist;
+ struct list_head list;
+};
+
+void cache_init(struct cache *cache);
+void cache_free(struct cache *cache);
+void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash);
+void cache_del(struct cache_item *item);
+
+void table_cache_add(struct table *table, struct nft_cache *cache);
+void table_cache_del(struct table *table);
+struct table *table_cache_find(const struct cache *cache, const char *name,
+ uint32_t family);
+
+struct obj;
+
+void obj_cache_add(struct obj *obj, struct table *table);
+void obj_cache_del(struct obj *obj);
+struct obj *obj_cache_find(const struct table *table, const char *name,
+ uint32_t obj_type);
+
+struct flowtable;
+void ft_cache_add(struct flowtable *ft, struct table *table);
+void ft_cache_del(struct flowtable *ft);
+struct flowtable *ft_cache_find(const struct table *table, const char *name);
+
+struct nft_cache {
+ uint32_t genid;
+ struct cache table_cache;
+ uint32_t seqnum;
+ uint32_t flags;
+};
+
+struct netlink_ctx;
+
+void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
+ const char *chain);
+
+int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter,
+ bool dump, bool reset);
+
+#endif /* _NFT_CACHE_H_ */
diff --git a/include/cli.h b/include/cli.h
new file mode 100644
index 0000000..f0a0d47
--- /dev/null
+++ b/include/cli.h
@@ -0,0 +1,16 @@
+#ifndef _NFT_CLI_H_
+#define _NFT_CLI_H_
+
+#include <nftables/libnftables.h>
+
+#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) || defined(HAVE_LIBLINENOISE)
+extern int cli_init(struct nft_ctx *nft);
+#else
+static inline int cli_init(struct nft_ctx *nft)
+{
+ return -1;
+}
+#endif
+extern void cli_exit(int rc);
+
+#endif
diff --git a/include/cmd.h b/include/cmd.h
new file mode 100644
index 0000000..92a4152
--- /dev/null
+++ b/include/cmd.h
@@ -0,0 +1,13 @@
+#ifndef _NFT_CMD_H_
+#define _NFT_CMD_H_
+
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc);
+void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err);
+
+void nft_cmd_expand(struct cmd *cmd);
+void nft_cmd_post_expand(struct cmd *cmd);
+bool nft_cmd_collapse(struct list_head *cmds);
+void nft_cmd_uncollapse(struct list_head *cmds);
+
+#endif
diff --git a/include/ct.h b/include/ct.h
new file mode 100644
index 0000000..0a705fd
--- /dev/null
+++ b/include/ct.h
@@ -0,0 +1,45 @@
+#ifndef NFTABLES_CT_H
+#define NFTABLES_CT_H
+
+/**
+ * struct ct_template
+ *
+ * @token: parser token for the expression
+ * @dtype: data type of the expression
+ * @len: length of the expression
+ * @byteorder: byteorder
+ */
+struct ct_template {
+ const char *token;
+ const struct datatype *dtype;
+ enum byteorder byteorder;
+ unsigned int len;
+};
+
+extern const struct ct_template ct_templates[__NFT_CT_MAX];
+
+#define CT_TEMPLATE(__token, __dtype, __byteorder, __len) { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .byteorder = (__byteorder), \
+ .len = (__len), \
+}
+
+extern struct expr *ct_expr_alloc(const struct location *loc,
+ enum nft_ct_keys key, int8_t direction);
+extern void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
+
+extern struct stmt *notrack_stmt_alloc(const struct location *loc);
+extern struct stmt *flow_offload_stmt_alloc(const struct location *loc,
+ const char *table_name);
+extern const char *ct_dir2str(int dir);
+extern const char *ct_label2str(const struct symbol_table *tbl,
+ unsigned long value);
+
+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
new file mode 100644
index 0000000..09a7894
--- /dev/null
+++ b/include/datatype.h
@@ -0,0 +1,323 @@
+#ifndef NFTABLES_DATATYPE_H
+#define NFTABLES_DATATYPE_H
+
+#include <json.h>
+
+/**
+ * enum datatypes
+ *
+ * @TYPE_INVALID: uninitialized
+ * @TYPE_VERDICT: nftables verdict
+ * @TYPE_NFPROTO: netfilter protocol (integer subtype)
+ * @TYPE_BITMASK: bitmask
+ * @TYPE_INTEGER: integer
+ * @TYPE_STRING: string
+ * @TYPE_LLADDR: link layer address (integer subtype)
+ * @TYPE_IPADDR: IPv4 address (integer subtype)
+ * @TYPE_IP6ADDR: IPv6 address (integer subtype)
+ * @TYPE_ETHERADDR: Ethernet address (lladdr subtype)
+ * @TYPE_ETHERTYPE: EtherType (integer subtype)
+ * @TYPE_ARPOP: ARP operation (integer subtype)
+ * @TYPE_INET_PROTOCOL: internet protocol (integer subtype)
+ * @TYPE_INET_SERVICE: internet service (integer subtype)
+ * @TYPE_ICMP_TYPE: ICMP type codes (integer subtype)
+ * @TYPE_TCP_FLAG: TCP flag (bitmask 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)
+ * @TYPE_IFINDEX: interface index (integer subtype)
+ * @TYPE_ARPHRD: interface type (integer subtype)
+ * @TYPE_REALM: routing realm (integer subtype)
+ * @TYPE_CLASSID: TC classid (integer subtype)
+ * @TYPE_UID: user ID (integer subtype)
+ * @TYPE_GID: group ID (integer subtype)
+ * @TYPE_CT_STATE: conntrack state (bitmask subtype)
+ * @TYPE_CT_DIR: conntrack direction
+ * @TYPE_CT_STATUS: conntrack status (bitmask subtype)
+ * @TYPE_ICMP6_TYPE: ICMPv6 type codes (integer subtype)
+ * @TYPE_CT_LABEL: Conntrack Label (bitmask subtype)
+ * @TYPE_PKTTYPE: packet type (integer subtype)
+ * @TYPE_ICMP_CODE: icmp code (integer subtype)
+ * @TYPE_ICMPV6_CODE: icmpv6 code (integer subtype)
+ * @TYPE_ICMPX_CODE: icmpx code (integer subtype)
+ * @TYPE_DEVGROUP: devgroup code (integer subtype)
+ * @TYPE_DSCP: Differentiated Services Code Point (integer subtype)
+ * @TYPE_IFNAME: interface name (string subtype)
+ * @TYPE_IGMP: IGMP type (integer subtype)
+ * @TYPE_TIME_DATA Date type (integer subtype)
+ * @TYPE_TIME_HOUR Hour type (integer subtype)
+ * @TYPE_TIME_DAY Day type (integer subtype)
+ * @TYPE_CGROUPV2 cgroups v2 (integer subtype)
+ */
+enum datatypes {
+ TYPE_INVALID,
+ TYPE_VERDICT,
+ TYPE_NFPROTO,
+ TYPE_BITMASK,
+ TYPE_INTEGER,
+ TYPE_STRING,
+ TYPE_LLADDR,
+ TYPE_IPADDR,
+ TYPE_IP6ADDR,
+ TYPE_ETHERADDR,
+ TYPE_ETHERTYPE,
+ TYPE_ARPOP,
+ TYPE_INET_PROTOCOL,
+ TYPE_INET_SERVICE,
+ TYPE_ICMP_TYPE,
+ TYPE_TCP_FLAG,
+ TYPE_DCCP_PKTTYPE,
+ TYPE_MH_TYPE,
+ TYPE_TIME,
+ TYPE_MARK,
+ TYPE_IFINDEX,
+ TYPE_ARPHRD,
+ TYPE_REALM,
+ TYPE_CLASSID,
+ TYPE_UID,
+ TYPE_GID,
+ TYPE_CT_STATE,
+ TYPE_CT_DIR,
+ TYPE_CT_STATUS,
+ TYPE_ICMP6_TYPE,
+ TYPE_CT_LABEL,
+ TYPE_PKTTYPE,
+ TYPE_ICMP_CODE,
+ TYPE_ICMPV6_CODE,
+ TYPE_ICMPX_CODE,
+ TYPE_DEVGROUP,
+ TYPE_DSCP,
+ TYPE_ECN,
+ TYPE_FIB_ADDR,
+ TYPE_BOOLEAN,
+ TYPE_CT_EVENTBIT,
+ TYPE_IFNAME,
+ TYPE_IGMP_TYPE,
+ TYPE_TIME_DATE,
+ TYPE_TIME_HOUR,
+ TYPE_TIME_DAY,
+ TYPE_CGROUPV2,
+ __TYPE_MAX
+};
+#define TYPE_MAX (__TYPE_MAX - 1)
+
+#define TYPE_BITS 6
+#define TYPE_MASK ((1 << TYPE_BITS) - 1)
+
+/**
+ * enum byteorder
+ *
+ * @BYTEORDER_INVALID: uninitialized/unknown
+ * @BYTEORDER_HOST_ENDIAN: host endian
+ * @BYTEORDER_BIG_ENDIAN: big endian
+ */
+enum byteorder {
+ BYTEORDER_INVALID,
+ BYTEORDER_HOST_ENDIAN,
+ BYTEORDER_BIG_ENDIAN,
+};
+
+struct expr;
+
+/**
+ * enum datatype_flags
+ *
+ * @DTYPE_F_ALLOC: datatype is dynamically allocated
+ * @DTYPE_F_PREFIX: preferred representation for ranges is a prefix
+ */
+enum datatype_flags {
+ DTYPE_F_ALLOC = (1 << 0),
+ DTYPE_F_PREFIX = (1 << 1),
+};
+
+struct parse_ctx;
+/**
+ * struct datatype
+ *
+ * @type: numeric identifier
+ * @byteorder: byteorder of type (non-basetypes only)
+ * @flags: flags
+ * @size: type size (fixed sized non-basetypes only)
+ * @subtypes: number of subtypes (concat type)
+ * @name: type name
+ * @desc: type description
+ * @basetype: basetype for subtypes, determines type compatibility
+ * @basefmt: format string for basetype
+ * @print: function to print a constant of this type
+ * @parse: function to parse a symbol and return an expression
+ * @sym_tbl: symbol table for this type
+ * @refcnt: reference counter (only for DTYPE_F_ALLOC)
+ */
+struct datatype {
+ uint32_t type;
+ enum byteorder byteorder;
+ unsigned int flags;
+ unsigned int size;
+ unsigned int subtypes;
+ const char *name;
+ const char *desc;
+ const struct datatype *basetype;
+ const char *basefmt;
+ void (*print)(const struct expr *expr,
+ struct output_ctx *octx);
+ json_t *(*json)(const struct expr *expr,
+ struct output_ctx *octx);
+ struct error_record *(*parse)(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res);
+ struct error_record *(*err)(const struct expr *sym);
+ void (*describe)(struct output_ctx *octx);
+ const struct symbol_table *sym_tbl;
+ unsigned int refcnt;
+};
+
+extern const struct datatype *datatype_lookup(enum datatypes type);
+extern const struct datatype *datatype_lookup_byname(const char *name);
+extern const struct datatype *datatype_get(const struct datatype *dtype);
+extern void datatype_set(struct expr *expr, const struct datatype *dtype);
+extern void __datatype_set(struct expr *expr, const struct datatype *dtype);
+extern void datatype_free(const struct datatype *dtype);
+struct datatype *datatype_clone(const struct datatype *orig_dtype);
+
+struct parse_ctx {
+ struct symbol_tables *tbl;
+ const struct input_ctx *input;
+};
+
+extern struct error_record *symbol_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res);
+extern void datatype_print(const struct expr *expr, struct output_ctx *octx);
+
+static inline bool datatype_equal(const struct datatype *d1,
+ const struct datatype *d2)
+{
+ return d1->type == d2->type;
+}
+
+static inline const struct datatype *
+datatype_basetype(const struct datatype *dtype)
+{
+ return dtype->basetype ? dtype->basetype : dtype;
+}
+
+/**
+ * struct symbolic_constant - symbol <-> constant mapping
+ *
+ * @identifier: symbol
+ * @value: symbolic value
+ */
+struct symbolic_constant {
+ const char *identifier;
+ uint64_t value;
+};
+
+#define SYMBOL(id, v) { .identifier = (id), .value = (v) }
+#define SYMBOL_LIST_END (struct symbolic_constant) { }
+
+/**
+ * enum base - indicate how to display symbol table values
+ *
+ * @BASE_HEXADECIMAL: hexadecimal
+ * @BASE_DECIMAL: decimal
+ */
+enum base {
+ BASE_HEXADECIMAL,
+ BASE_DECIMAL,
+};
+
+/**
+ * struct symbol_table - type construction from symbolic values
+ *
+ * @base: base of symbols representation
+ * @symbols: the symbols
+ */
+struct symbol_table {
+ enum base base;
+ struct symbolic_constant symbols[];
+};
+
+extern struct error_record *symbolic_constant_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ const struct symbol_table *tbl,
+ struct expr **res);
+extern void symbolic_constant_print(const struct symbol_table *tbl,
+ const struct expr *expr, bool quotes,
+ struct output_ctx *octx);
+extern void symbol_table_print(const struct symbol_table *tbl,
+ const struct datatype *dtype,
+ enum byteorder byteorder,
+ struct output_ctx *octx);
+
+extern struct symbol_table *rt_symbol_table_init(const char *filename);
+extern void rt_symbol_table_free(const struct symbol_table *tbl);
+
+extern const struct datatype invalid_type;
+extern const struct datatype verdict_type;
+extern const struct datatype nfproto_type;
+extern const struct datatype bitmask_type;
+extern const struct datatype integer_type;
+extern const struct datatype xinteger_type;
+extern const struct datatype string_type;
+extern const struct datatype lladdr_type;
+extern const struct datatype ipaddr_type;
+extern const struct datatype ip6addr_type;
+extern const struct datatype etheraddr_type;
+extern const struct datatype ethertype_type;
+extern const struct datatype arphrd_type;
+extern const struct datatype inet_protocol_type;
+extern const struct datatype inet_service_type;
+extern const struct datatype mark_type;
+extern const struct datatype icmp_type_type;
+extern const struct datatype icmp_code_type;
+extern const struct datatype icmpv6_code_type;
+extern const struct datatype icmpx_code_type;
+extern const struct datatype igmp_type_type;
+extern const struct datatype time_type;
+extern const struct datatype boolean_type;
+extern const struct datatype priority_type;
+extern const struct datatype policy_type;
+extern const struct datatype cgroupv2_type;
+
+void inet_service_type_print(const struct expr *expr, struct output_ctx *octx);
+
+extern const struct datatype *concat_type_alloc(uint32_t type);
+
+static inline uint32_t concat_subtype_add(uint32_t type, uint32_t subtype)
+{
+ return type << TYPE_BITS | subtype;
+}
+
+static inline uint32_t concat_subtype_id(uint32_t type, unsigned int n)
+{
+ return (type >> TYPE_BITS * n) & TYPE_MASK;
+}
+
+static inline const struct datatype *
+concat_subtype_lookup(uint32_t type, unsigned int n)
+{
+ return datatype_lookup(concat_subtype_id(type, n));
+}
+
+extern const struct datatype *
+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,
+ const char *c, uint64_t *res);
+
+extern struct error_record *rate_parse(const struct location *loc,
+ const char *str, uint64_t *rate,
+ uint64_t *unit);
+
+extern struct error_record *data_unit_parse(const struct location *loc,
+ const char *str, uint64_t *rate);
+
+struct limit_rate {
+ uint64_t rate, unit;
+};
+
+extern void expr_chain_export(const struct expr *e, char *chain);
+
+#endif /* NFTABLES_DATATYPE_H */
diff --git a/include/dccpopt.h b/include/dccpopt.h
new file mode 100644
index 0000000..3617fc1
--- /dev/null
+++ b/include/dccpopt.h
@@ -0,0 +1,41 @@
+#ifndef NFTABLES_DCCPOPT_H
+#define NFTABLES_DCCPOPT_H
+
+#include <nftables.h>
+
+#define DCCPOPT_TYPE_MIN 0
+#define DCCPOPT_TYPE_MAX UINT8_MAX
+
+enum dccpopt_fields {
+ DCCPOPT_FIELD_INVALID,
+ DCCPOPT_FIELD_TYPE,
+};
+
+enum dccpopt_types {
+ DCCPOPT_PADDING = 0,
+ DCCPOPT_MANDATORY = 1,
+ DCCPOPT_SLOW_RECEIVER = 2,
+ DCCPOPT_RESERVED_SHORT = 3,
+ DCCPOPT_CHANGE_L = 32,
+ DCCPOPT_CONFIRM_L = 33,
+ DCCPOPT_CHANGE_R = 34,
+ DCCPOPT_CONFIRM_R = 35,
+ DCCPOPT_INIT_COOKIE = 36,
+ DCCPOPT_NDP_COUNT = 37,
+ DCCPOPT_ACK_VECTOR_NONCE_0 = 38,
+ DCCPOPT_ACK_VECTOR_NONCE_1 = 39,
+ DCCPOPT_DATA_DROPPED = 40,
+ DCCPOPT_TIMESTAMP = 41,
+ DCCPOPT_TIMESTAMP_ECHO = 42,
+ DCCPOPT_ELAPSED_TIME = 43,
+ DCCPOPT_DATA_CHECKSUM = 44,
+ DCCPOPT_RESERVED_LONG = 45,
+ DCCPOPT_CCID_SPECIFIC = 128,
+};
+
+const struct exthdr_desc *dccpopt_find_desc(uint8_t type);
+struct expr *dccpopt_expr_alloc(const struct location *loc, uint8_t type);
+void dccpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+ unsigned int len);
+
+#endif /* NFTABLES_DCCPOPT_H */
diff --git a/include/erec.h b/include/erec.h
new file mode 100644
index 0000000..c17f5de
--- /dev/null
+++ b/include/erec.h
@@ -0,0 +1,84 @@
+#ifndef NFTABLES_EREC_H
+#define NFTABLES_EREC_H
+
+#include <nftables.h>
+#include <utils.h>
+
+/**
+ * enum error_record_types
+ *
+ * @EREC_INFORMATIONAL: informational message
+ * @EREC_WARNING: warning message
+ * @EREC_ERROR: error message
+ */
+enum error_record_types {
+ EREC_INFORMATIONAL,
+ EREC_WARNING,
+ EREC_ERROR,
+};
+
+#define EREC_MSGBUFSIZE 1024
+#define EREC_LOCATIONS_MAX 3
+
+/**
+ * struct error_record
+ *
+ * @list: message queue node
+ * @type: error record type
+ * @num_locations: number of locations
+ * @locations: location(s) of error
+ * @msg: message
+ */
+struct error_record {
+ struct list_head list;
+ enum error_record_types type;
+ unsigned int num_locations;
+ struct location locations[EREC_LOCATIONS_MAX];
+ char *msg;
+};
+
+extern struct error_record *erec_vcreate(enum error_record_types type,
+ const struct location *loc,
+ const char *fmt, va_list ap)
+ __gmp_fmtstring(3, 0);
+extern struct error_record *erec_create(enum error_record_types type,
+ const struct location *loc,
+ const char *fmt, ...) __gmp_fmtstring(3, 4);
+extern void erec_add_location(struct error_record *erec,
+ const struct location *loc);
+extern void erec_destroy(struct error_record *erec);
+
+#define error(loc, fmt, args...) \
+ erec_create(EREC_ERROR, (loc), (fmt), ## args)
+#define warning(loc, fmt, args...) \
+ erec_create(EREC_WARNING, (loc), (fmt), ## args)
+
+static inline void erec_queue(struct error_record *erec,
+ struct list_head *queue)
+{
+ list_add_tail(&erec->list, queue);
+}
+
+extern void erec_print(struct output_ctx *octx, const struct error_record *erec,
+ unsigned int debug_mask);
+extern void erec_print_list(struct output_ctx *octx, struct list_head *list,
+ unsigned int debug_mask);
+
+struct eval_ctx;
+
+extern int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
+ const struct location *l1,
+ const struct location *l2,
+ const char *fmt, ...);
+
+#define stmt_error(ctx, s1, fmt, args...) \
+ __stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args)
+#define stmt_binary_error(ctx, s1, s2, fmt, args...) \
+ __stmt_binary_error(ctx, &(s1)->location, &(s2)->location, fmt, ## args)
+
+void print_location(FILE *f, const struct input_descriptor *indesc,
+ const struct location *loc);
+const char *line_location(const struct input_descriptor *indesc,
+ const struct location *loc, char *buf, size_t bufsiz);
+
+#endif /* NFTABLES_EREC_H */
diff --git a/include/expression.h b/include/expression.h
new file mode 100644
index 0000000..aede223
--- /dev/null
+++ b/include/expression.h
@@ -0,0 +1,530 @@
+#ifndef NFTABLES_EXPRESSION_H
+#define NFTABLES_EXPRESSION_H
+
+#include <gmputil.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <nftables.h>
+#include <datatype.h>
+#include <utils.h>
+#include <list.h>
+#include <json.h>
+#include <libnftnl/udata.h>
+
+/**
+ * enum expr_types
+ *
+ * @EXPR_INVALID: uninitialized type, should not happen
+ * @EXPR_VERDICT: nftables verdict expression
+ * @EXPR_SYMBOL: unparsed symbol
+ * @EXPR_VARIABLE: variable
+ * @EXPR_VALUE: literal numeric or string expression
+ * @EXPR_PREFIX: prefixed expression
+ * @EXPR_RANGE: literal range
+ * @EXPR_PAYLOAD: payload expression
+ * @EXPR_EXTHDR: exthdr expression
+ * @EXPR_META: meta expression
+ * @EXPR_SOCKET: socket expression
+ * @EXPR_OSF: osf expression
+ * @EXPR_CT: conntrack expression
+ * @EXPR_CONCAT: concatenation
+ * @EXPR_LIST: list of expressions
+ * @EXPR_SET: literal set
+ * @EXPR_SET_REF: set reference
+ * @EXPR_SET_ELEM: set element
+ * @EXPR_MAPPING: a single mapping (key : value)
+ * @EXPR_MAP: map operation (expr map { EXPR_MAPPING, ... })
+ * @EXPR_UNARY: byteorder conversion, generated during evaluation
+ * @EXPR_BINOP: binary operations (bitwise, shifts)
+ * @EXPR_RELATIONAL: equality and relational expressions
+ * @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,
+ EXPR_VERDICT,
+ EXPR_SYMBOL,
+ EXPR_VARIABLE,
+ EXPR_VALUE,
+ EXPR_PREFIX,
+ EXPR_RANGE,
+ EXPR_PAYLOAD,
+ EXPR_EXTHDR,
+ EXPR_META,
+ EXPR_SOCKET,
+ EXPR_OSF,
+ EXPR_CT,
+ EXPR_CONCAT,
+ EXPR_LIST,
+ EXPR_SET,
+ EXPR_SET_REF,
+ EXPR_SET_ELEM,
+ EXPR_MAPPING,
+ EXPR_MAP,
+ EXPR_UNARY,
+ EXPR_BINOP,
+ EXPR_RELATIONAL,
+ EXPR_NUMGEN,
+ EXPR_HASH,
+ EXPR_RT,
+ EXPR_FIB,
+ EXPR_XFRM,
+ EXPR_SET_ELEM_CATCHALL,
+ EXPR_FLAGCMP,
+
+ EXPR_MAX = EXPR_FLAGCMP
+};
+
+enum ops {
+ OP_INVALID,
+ OP_IMPLICIT,
+ /* Unary operations */
+ OP_HTON,
+ OP_NTOH,
+ /* Binary operations */
+ OP_LSHIFT,
+ OP_RSHIFT,
+ OP_AND,
+ OP_XOR,
+ OP_OR,
+ /* Relational operations */
+ OP_EQ,
+ OP_NEQ,
+ OP_LT,
+ OP_GT,
+ OP_LTE,
+ OP_GTE,
+ OP_NEG,
+ __OP_MAX
+};
+#define OP_MAX (__OP_MAX - 1)
+
+extern const char *expr_op_symbols[];
+
+enum symbol_types {
+ SYMBOL_VALUE,
+ SYMBOL_SET,
+};
+
+/**
+ * struct expr_ctx - type context for symbol parsing during evaluation
+ *
+ * @dtype: expected datatype
+ * @byteorder: expected byteorder
+ * @len: expected len
+ * @maxval: expected maximum value
+ */
+struct expr_ctx {
+ /* expr_ctx does not own the reference to dtype. The caller must ensure
+ * the valid lifetime.
+ */
+ const struct datatype *dtype;
+
+ enum byteorder byteorder;
+ unsigned int len;
+ unsigned int maxval;
+ const struct expr *key;
+};
+
+static inline void __expr_set_context(struct expr_ctx *ctx,
+ const struct datatype *dtype,
+ enum byteorder byteorder,
+ unsigned int len, unsigned int maxval)
+{
+ ctx->dtype = dtype;
+ ctx->byteorder = byteorder;
+ ctx->len = len;
+ ctx->maxval = maxval;
+ ctx->key = NULL;
+}
+
+static inline void expr_set_context(struct expr_ctx *ctx,
+ const struct datatype *dtype,
+ unsigned int len)
+{
+ __expr_set_context(ctx, dtype,
+ dtype ? dtype->byteorder : BYTEORDER_INVALID,
+ len, 0);
+}
+
+/**
+ * struct expr_ops
+ *
+ * @type: expression type
+ * @name: expression name for diagnostics
+ * @clone: function to clone type specific data
+ * @destroy: destructor, must release inner expressions
+ * @set_type: function to promote type and byteorder of inner types
+ * @print: function to print the expression
+ * @cmp: function to compare two expressions of the same types
+ * @pctx_update:update protocol context
+ */
+struct proto_ctx;
+struct expr_ops {
+ enum expr_types type;
+ const char *name;
+ void (*clone)(struct expr *new, const struct expr *expr);
+ void (*destroy)(struct expr *expr);
+ void (*set_type)(const struct expr *expr,
+ const struct datatype *dtype,
+ enum byteorder byteorder);
+ void (*print)(const struct expr *expr,
+ struct output_ctx *octx);
+ json_t *(*json)(const struct expr *expr,
+ struct output_ctx *octx);
+ bool (*cmp)(const struct expr *e1,
+ const struct expr *e2);
+ void (*pctx_update)(struct proto_ctx *ctx,
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right);
+ int (*build_udata)(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr);
+ struct expr * (*parse_udata)(const struct nftnl_udata *ud);
+};
+
+const struct expr_ops *expr_ops(const struct expr *e);
+const struct expr_ops *expr_ops_by_type_u32(uint32_t value);
+
+/**
+ * enum expr_flags
+ *
+ * @EXPR_F_CONSTANT: constant expression
+ * @EXPR_F_SINGLETON: singleton (implies primary and constant)
+ * @EXPR_F_PROTOCOL: expressions describes upper layer protocol
+ * @EXPR_F_INTERVAL_END: set member ends an open interval
+ * @EXPR_F_BOOLEAN: expression is boolean (set by relational expr on LHS)
+ * @EXPR_F_INTERVAL: expression describes a interval
+ * @EXPR_F_KERNEL: expression resides in the kernel
+ */
+enum expr_flags {
+ EXPR_F_CONSTANT = 0x1,
+ EXPR_F_SINGLETON = 0x2,
+ EXPR_F_PROTOCOL = 0x4,
+ EXPR_F_INTERVAL_END = 0x8,
+ EXPR_F_BOOLEAN = 0x10,
+ EXPR_F_INTERVAL = 0x20,
+ EXPR_F_KERNEL = 0x40,
+ EXPR_F_REMOVE = 0x80,
+};
+
+#include <payload.h>
+#include <exthdr.h>
+#include <fib.h>
+#include <numgen.h>
+#include <meta.h>
+#include <rt.h>
+#include <hash.h>
+#include <ct.h>
+#include <socket.h>
+#include <osf.h>
+#include <xfrm.h>
+
+/**
+ * struct expr
+ *
+ * @list: list node
+ * @location: location from parser
+ * @refcnt: reference count
+ * @flags: mask of enum expr_flags
+ * @dtype: data type of expression
+ * @byteorder: byteorder of expression
+ * @etype: expression type
+ * @op: operation for unary, binary and relational expressions
+ * @len: length of expression
+ * @union: type specific data
+ */
+struct expr {
+ struct list_head list;
+ struct location location;
+
+ unsigned int refcnt;
+ unsigned int flags;
+
+ const struct datatype *dtype;
+ enum byteorder byteorder:8;
+ enum expr_types etype:8;
+ enum ops op:8;
+ unsigned int len;
+ struct cmd *cmd;
+
+ union {
+ struct {
+ /* EXPR_SYMBOL */
+ const struct scope *scope;
+ const char *identifier;
+ enum symbol_types symtype;
+ };
+ struct {
+ /* EXPR_VARIABLE */
+ struct symbol *sym;
+ };
+ struct {
+ /* EXPR_VERDICT */
+ int verdict;
+ struct expr *chain;
+ uint32_t chain_id;
+ };
+ struct {
+ /* EXPR_VALUE */
+ mpz_t value;
+ };
+ struct {
+ /* EXPR_PREFIX */
+ struct expr *prefix;
+ unsigned int prefix_len;
+ };
+ struct {
+ /* EXPR_CONCAT, EXPR_LIST, EXPR_SET */
+ struct list_head expressions;
+ unsigned int size;
+ uint32_t set_flags;
+ uint8_t field_len[NFT_REG32_COUNT];
+ uint8_t field_count;
+ };
+ struct {
+ /* EXPR_SET_REF */
+ struct set *set;
+ };
+ struct {
+ /* EXPR_SET_ELEM */
+ struct expr *key;
+ uint64_t timeout;
+ uint64_t expiration;
+ const char *comment;
+ struct list_head stmt_list;
+ uint32_t elem_flags;
+ };
+ struct {
+ /* EXPR_UNARY */
+ struct expr *arg;
+ };
+ struct {
+ /* EXPR_RANGE, EXPR_BINOP, EXPR_MAPPING, EXPR_RELATIONAL */
+ struct expr *left;
+ struct expr *right;
+ };
+ struct {
+ /* EXPR_MAP */
+ struct expr *map;
+ struct expr *mappings;
+ };
+
+ struct {
+ /* EXPR_PAYLOAD */
+ const struct proto_desc *desc;
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *inner_desc;
+ enum proto_bases base;
+ unsigned int offset;
+ bool is_raw;
+ bool evaluated;
+ } payload;
+ struct {
+ /* EXPR_EXTHDR */
+ const struct exthdr_desc *desc;
+ const struct proto_hdr_template *tmpl;
+ uint16_t offset;
+ uint8_t raw_type;
+ enum nft_exthdr_op op;
+ unsigned int flags;
+ } exthdr;
+ struct {
+ /* EXPR_META */
+ enum nft_meta_keys key;
+ enum proto_bases base;
+ const struct proto_desc *inner_desc;
+ } meta;
+ struct {
+ /* SOCKET */
+ enum nft_socket_keys key;
+ uint32_t level;
+ } socket;
+ struct {
+ /* EXPR_RT */
+ enum nft_rt_keys key;
+ } rt;
+ struct {
+ /* EXPR_CT */
+ enum nft_ct_keys key;
+ enum proto_bases base;
+ int8_t direction;
+ uint8_t nfproto;
+ } ct;
+ struct {
+ /* EXPR_NUMGEN */
+ enum nft_ng_types type;
+ uint32_t mod;
+ uint32_t offset;
+ } numgen;
+ struct {
+ /* EXPR_HASH */
+ struct expr *expr;
+ uint32_t mod;
+ bool seed_set;
+ uint32_t seed;
+ uint32_t offset;
+ enum nft_hash_types type;
+ } hash;
+ struct {
+ /* EXPR_FIB */
+ uint32_t flags;
+ uint32_t result;
+ } fib;
+ struct {
+ /* EXPR_XFRM */
+ enum nft_xfrm_keys key;
+ uint8_t direction;
+ uint8_t spnum;
+ } xfrm;
+ struct {
+ /* EXPR_OSF */
+ uint8_t ttl;
+ uint32_t flags;
+ } osf;
+ struct {
+ /* EXPR_FLAGCMP */
+ struct expr *expr;
+ struct expr *mask;
+ struct expr *value;
+ } flagcmp;
+ };
+};
+
+extern struct expr *expr_alloc(const struct location *loc,
+ enum expr_types etype,
+ const struct datatype *dtype,
+ enum byteorder byteorder, unsigned int len);
+extern struct expr *expr_clone(const struct expr *expr);
+extern struct expr *expr_get(struct expr *expr);
+extern void expr_free(struct expr *expr);
+extern void expr_print(const struct expr *expr, struct output_ctx *octx);
+extern bool expr_cmp(const struct expr *e1, const struct expr *e2);
+extern void expr_describe(const struct expr *expr, struct output_ctx *octx);
+
+extern const struct datatype *expr_basetype(const struct expr *expr);
+extern void expr_set_type(struct expr *expr, const struct datatype *dtype,
+ enum byteorder byteorder);
+
+void expr_to_string(const struct expr *expr, char *string);
+
+struct eval_ctx;
+extern int expr_binary_error(struct list_head *msgs,
+ const struct expr *e1, const struct expr *e2,
+ const char *fmt, ...) __gmp_fmtstring(4, 5);
+
+#define expr_error(msgs, expr, fmt, args...) \
+ expr_binary_error(msgs, expr, NULL, fmt, ## args)
+
+static inline bool expr_is_constant(const struct expr *expr)
+{
+ return expr->flags & EXPR_F_CONSTANT ? true : false;
+}
+
+static inline bool expr_is_singleton(const struct expr *expr)
+{
+ return expr->flags & EXPR_F_SINGLETON ? true : false;
+}
+
+extern struct expr *unary_expr_alloc(const struct location *loc,
+ enum ops op, struct expr *arg);
+
+extern struct expr *binop_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *left, struct expr *right);
+
+extern bool must_print_eq_op(const struct expr *expr);
+
+extern struct expr *relational_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *left, struct expr *right);
+
+extern void relational_expr_pctx_update(struct proto_ctx *ctx,
+ const struct expr *expr);
+
+extern struct expr *verdict_expr_alloc(const struct location *loc,
+ int verdict, struct expr *chain);
+
+extern struct expr *symbol_expr_alloc(const struct location *loc,
+ enum symbol_types type, struct scope *scope,
+ const char *identifier);
+
+const char *expr_name(const struct expr *e);
+
+static inline void symbol_expr_set_type(struct expr *expr,
+ const struct datatype *dtype)
+{
+ if (expr->etype == EXPR_SYMBOL)
+ datatype_set(expr, dtype);
+}
+
+struct expr *variable_expr_alloc(const struct location *loc,
+ struct scope *scope, struct symbol *sym);
+
+extern struct expr *constant_expr_alloc(const struct location *loc,
+ const struct datatype *dtype,
+ enum byteorder byteorder,
+ unsigned int len, const void *data);
+extern struct expr *constant_expr_join(const struct expr *e1,
+ const struct expr *e2);
+extern struct expr *constant_expr_splice(struct expr *expr, unsigned int len);
+
+extern struct expr *flag_expr_alloc(const struct location *loc,
+ const struct datatype *dtype,
+ enum byteorder byteorder,
+ unsigned int len, unsigned long n);
+extern struct expr *bitmask_expr_to_binops(struct expr *expr);
+
+extern struct expr *prefix_expr_alloc(const struct location *loc,
+ struct expr *expr,
+ unsigned int prefix_len);
+
+extern struct expr *range_expr_alloc(const struct location *loc,
+ struct expr *low, struct expr *high);
+struct expr *range_expr_to_prefix(struct expr *range);
+
+extern struct expr *compound_expr_alloc(const struct location *loc,
+ enum expr_types etypes);
+extern void compound_expr_add(struct expr *compound, struct expr *expr);
+extern void compound_expr_remove(struct expr *compound, struct expr *expr);
+extern void list_expr_sort(struct list_head *head);
+extern void list_splice_sorted(struct list_head *list, struct list_head *head);
+
+extern struct expr *concat_expr_alloc(const struct location *loc);
+
+extern struct expr *list_expr_alloc(const struct location *loc);
+
+extern struct expr *set_expr_alloc(const struct location *loc,
+ const struct set *set);
+extern void concat_range_aggregate(struct expr *set);
+extern void interval_map_decompose(struct expr *set);
+
+extern struct expr *get_set_intervals(const struct set *set,
+ const struct expr *init);
+struct table;
+extern int get_set_decompose(struct set *cache_set, struct set *set);
+
+extern struct expr *mapping_expr_alloc(const struct location *loc,
+ struct expr *from, struct expr *to);
+extern struct expr *map_expr_alloc(const struct location *loc,
+ struct expr *arg, struct expr *list);
+
+extern struct expr *set_ref_expr_alloc(const struct location *loc,
+ struct set *set);
+
+extern struct expr *set_elem_expr_alloc(const struct location *loc,
+ struct expr *key);
+
+struct expr *set_elem_catchall_expr_alloc(const struct location *loc);
+
+struct expr *flagcmp_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *expr, struct expr *mask,
+ struct expr *value);
+
+extern void range_expr_value_low(mpz_t rop, const struct expr *expr);
+extern void range_expr_value_high(mpz_t rop, const struct expr *expr);
+
+#endif /* NFTABLES_EXPRESSION_H */
diff --git a/include/exthdr.h b/include/exthdr.h
new file mode 100644
index 0000000..084daba
--- /dev/null
+++ b/include/exthdr.h
@@ -0,0 +1,120 @@
+#ifndef NFTABLES_EXTHDR_H
+#define NFTABLES_EXTHDR_H
+
+#include <proto.h>
+#include <tcpopt.h>
+#include <ipopt.h>
+#include <dccpopt.h>
+
+enum exthdr_desc_id {
+ EXTHDR_DESC_UNKNOWN = 0,
+ EXTHDR_DESC_HBH,
+ EXTHDR_DESC_RT,
+ EXTHDR_DESC_RT0,
+ EXTHDR_DESC_RT2,
+ EXTHDR_DESC_SRH,
+ EXTHDR_DESC_FRAG,
+ EXTHDR_DESC_DST,
+ EXTHDR_DESC_MH,
+ __EXTHDR_DESC_MAX
+};
+#define EXTHDR_DESC_MAX (__EXTHDR_DESC_MAX - 1)
+
+/**
+ * struct exthdr_desc - extension header description
+ *
+ * @name: extension header name
+ * @type: extension header protocol value
+ * @templates: header field templates
+ */
+struct exthdr_desc {
+ const char *name;
+ enum exthdr_desc_id id;
+ uint8_t type;
+ struct proto_hdr_template templates[10];
+};
+
+extern struct expr *exthdr_expr_alloc(const struct location *loc,
+ const struct exthdr_desc *desc,
+ uint8_t type);
+
+extern const struct exthdr_desc *exthdr_find_proto(uint8_t proto);
+
+extern void exthdr_init_raw(struct expr *expr, uint8_t type,
+ unsigned int offset, unsigned int len,
+ enum nft_exthdr_op op, uint32_t flags);
+
+extern bool exthdr_find_template(struct expr *expr, const struct expr *mask,
+ unsigned int *shift);
+
+enum hbh_hdr_fields {
+ HBHHDR_INVALID,
+ HBHHDR_NEXTHDR,
+ HBHHDR_HDRLENGTH,
+};
+
+enum rt_hdr_fields {
+ RTHDR_INVALID,
+ RTHDR_NEXTHDR,
+ RTHDR_HDRLENGTH,
+ RTHDR_TYPE,
+ RTHDR_SEG_LEFT,
+};
+
+enum rt0_hdr_fields {
+ RT0HDR_INVALID,
+ RT0HDR_RESERVED,
+ RT0HDR_ADDR_1,
+};
+
+enum rt2_hdr_fields {
+ RT2HDR_INVALID,
+ RT2HDR_RESERVED,
+ RT2HDR_ADDR,
+};
+
+enum rt4_hdr_fields {
+ RT4HDR_INVALID,
+ RT4HDR_LASTENT,
+ RT4HDR_FLAGS,
+ RT4HDR_TAG,
+ RT4HDR_SID_1,
+};
+
+enum frag_hdr_fields {
+ FRAGHDR_INVALID,
+ FRAGHDR_NEXTHDR,
+ FRAGHDR_RESERVED,
+ FRAGHDR_FRAG_OFF,
+ FRAGHDR_RESERVED2,
+ FRAGHDR_MFRAGS,
+ FRAGHDR_ID,
+};
+
+enum dst_hdr_fields {
+ DSTHDR_INVALID,
+ DSTHDR_NEXTHDR,
+ DSTHDR_HDRLENGTH,
+};
+
+enum mh_hdr_fields {
+ MHHDR_INVALID,
+ MHHDR_NEXTHDR,
+ MHHDR_HDRLENGTH,
+ MHHDR_TYPE,
+ MHHDR_RESERVED,
+ MHHDR_CHECKSUM,
+};
+
+extern const struct expr_ops exthdr_expr_ops;
+extern const struct exthdr_desc exthdr_hbh;
+extern const struct exthdr_desc exthdr_rt;
+extern const struct exthdr_desc exthdr_rt0;
+extern const struct exthdr_desc exthdr_rt2;
+extern const struct exthdr_desc exthdr_rt4;
+extern const struct exthdr_desc exthdr_frag;
+extern const struct exthdr_desc exthdr_dst;
+extern const struct exthdr_desc exthdr_mh;
+extern const struct datatype mh_type_type;
+
+#endif /* NFTABLES_EXTHDR_H */
diff --git a/include/fib.h b/include/fib.h
new file mode 100644
index 0000000..67edccf
--- /dev/null
+++ b/include/fib.h
@@ -0,0 +1,12 @@
+#ifndef NFTABLES_FIB_H
+#define NFTABLES_FIB_H
+
+#include <linux/netfilter/nf_tables.h>
+
+extern const char *fib_result_str(enum nft_fib_result result);
+extern struct expr *fib_expr_alloc(const struct location *loc,
+ unsigned int flags,
+ unsigned int result);
+extern const struct datatype fib_addr_type;
+
+#endif /* NFTABLES_FIB_H */
diff --git a/include/gmputil.h b/include/gmputil.h
new file mode 100644
index 0000000..c524ace
--- /dev/null
+++ b/include/gmputil.h
@@ -0,0 +1,80 @@
+#ifndef NFTABLES_GMPUTIL_H
+#define NFTABLES_GMPUTIL_H
+
+#ifdef HAVE_LIBGMP
+#include <gmp.h>
+#else
+#include <mini-gmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+/* mini-gmp doesn't come with gmp_vfprintf, so we use our own minimal variant */
+extern int mpz_vfprintf(FILE *fp, const char *format, va_list args);
+#define gmp_vfprintf mpz_vfprintf
+#endif
+
+#include <inttypes.h>
+#include <asm/byteorder.h>
+
+enum mpz_word_order {
+ MPZ_MSWF = 1,
+ MPZ_LSWF = -1,
+};
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+#define MPZ_HWO MPZ_LSWF
+#elif defined(__BIG_ENDIAN_BITFIELD)
+#define MPZ_HWO MPZ_MSWF
+#else
+#error "byteorder undefined"
+#endif
+
+enum mpz_byte_order {
+ MPZ_BIG_ENDIAN = 1,
+ MPZ_HOST_ENDIAN = 0,
+ MPZ_LITTLE_ENDIAN = -1,
+};
+
+extern void mpz_bitmask(mpz_t rop, unsigned int width);
+extern void mpz_init_bitmask(mpz_t rop, unsigned int width);
+extern void mpz_prefixmask(mpz_t rop, unsigned int width, unsigned int prefix_len);
+
+extern void mpz_lshift_ui(mpz_t rop, unsigned int n);
+extern void mpz_rshift_ui(mpz_t rop, unsigned int n);
+
+extern uint64_t mpz_get_uint64(const mpz_t op);
+extern uint32_t mpz_get_uint32(const mpz_t op);
+extern uint16_t mpz_get_uint16(const mpz_t op);
+extern uint8_t mpz_get_uint8(const mpz_t op);
+
+extern uint32_t mpz_get_be32(const mpz_t op);
+extern uint16_t mpz_get_be16(const mpz_t op);
+
+enum byteorder;
+extern void *__mpz_export_data(void *data, const mpz_t op,
+ enum byteorder byteorder, unsigned int len);
+extern void __mpz_import_data(mpz_t rop, const void *data,
+ enum byteorder byteorder, unsigned int len);
+extern void __mpz_switch_byteorder(mpz_t rop, unsigned int len);
+
+#include <assert.h>
+#include <datatype.h>
+
+#define mpz_export_data(data, op, byteorder, len) \
+{ \
+ assert(len > 0); \
+ __mpz_export_data(data, op, byteorder, len); \
+}
+
+#define mpz_import_data(rop, data, byteorder, len) \
+{ \
+ assert(len > 0); \
+ __mpz_import_data(rop, data, byteorder, len); \
+}
+
+#define mpz_switch_byteorder(rop, len) \
+{ \
+ assert(len > 0); \
+ __mpz_switch_byteorder(rop, len); \
+}
+
+#endif /* NFTABLES_GMPUTIL_H */
diff --git a/include/hash.h b/include/hash.h
new file mode 100644
index 0000000..693d08a
--- /dev/null
+++ b/include/hash.h
@@ -0,0 +1,10 @@
+#ifndef NFTABLES_HASH_H
+#define NFTABLES_HASH_H
+
+extern struct expr *hash_expr_alloc(const struct location *loc,
+ uint32_t modulus,
+ bool seed_set, uint32_t seed,
+ uint32_t offset,
+ enum nft_hash_types type);
+
+#endif /* NFTABLES_HASH_H */
diff --git a/include/headers.h b/include/headers.h
new file mode 100644
index 0000000..13324c7
--- /dev/null
+++ b/include/headers.h
@@ -0,0 +1,159 @@
+#ifndef NFTABLES_HEADERS_H
+#define NFTABLES_HEADERS_H
+
+#include <netinet/in.h>
+
+#ifndef IPPROTO_UDPLITE
+# define IPPROTO_UDPLITE 136
+#endif
+
+enum tcp_hdr_flags {
+ TCP_FLAG_FIN = 0x01,
+ TCP_FLAG_SYN = 0x02,
+ TCP_FLAG_RST = 0x04,
+ TCP_FLAG_PSH = 0x08,
+ TCP_FLAG_ACK = 0x10,
+ TCP_FLAG_URG = 0x20,
+ TCP_FLAG_ECN = 0x40,
+ TCP_FLAG_CWR = 0x80,
+};
+
+struct ip_auth_hdr {
+ uint8_t nexthdr;
+ uint8_t hdrlen;
+ uint16_t reserved;
+ uint32_t spi;
+ uint32_t seq_no;
+};
+
+struct ip_esp_hdr {
+ uint32_t spi;
+ uint32_t seq_no;
+};
+
+struct ip_comp_hdr {
+ uint8_t nexthdr;
+ uint8_t flags;
+ uint16_t cpi;
+};
+
+#ifndef IPPROTO_DCCP
+# define IPPROTO_DCCP 33
+#endif
+
+enum dccp_pkt_type {
+ DCCP_PKT_REQUEST = 0,
+ DCCP_PKT_RESPONSE,
+ DCCP_PKT_DATA,
+ DCCP_PKT_ACK,
+ DCCP_PKT_DATAACK,
+ DCCP_PKT_CLOSEREQ,
+ DCCP_PKT_CLOSE,
+ DCCP_PKT_RESET,
+ DCCP_PKT_SYNC,
+ DCCP_PKT_SYNCACK,
+ DCCP_PKT_INVALID,
+};
+
+struct dccp_hdr {
+ uint16_t dccph_sport,
+ dccph_dport;
+ uint8_t dccph_doff;
+ uint8_t dccph_ccval:4,
+ dccph_cscov:4;
+ uint16_t dccph_checksum;
+ uint8_t dccph_reserved:3,
+ dccph_type:4,
+ dccph_x:1;
+ uint8_t dccph_seq2;
+ uint16_t dccph_seq;
+};
+
+#ifndef IPPROTO_SCTP
+# define IPPROTO_SCTP 132
+#endif
+
+struct sctphdr {
+ uint16_t source;
+ uint16_t dest;
+ uint32_t vtag;
+ uint32_t checksum;
+};
+
+struct arp_hdr {
+ uint16_t htype;
+ uint16_t ptype;
+ uint8_t hlen;
+ uint8_t plen;
+ uint16_t oper;
+ uint8_t sha[6];
+ uint32_t spa;
+ uint8_t tha[6];
+ uint32_t tpa;
+} __attribute__((__packed__));
+
+struct ipv6hdr {
+ uint8_t version:4,
+ priority:4;
+ uint8_t flow_lbl[3];
+
+ uint16_t payload_len;
+ uint8_t nexthdr;
+ uint8_t hop_limit;
+
+ struct in6_addr saddr;
+ struct in6_addr daddr;
+};
+
+struct vlan_hdr {
+ uint16_t vlan_id:12,
+ vlan_cfi:1,
+ vlan_pcp:3;
+ uint16_t vlan_type;
+};
+
+#ifndef IPPROTO_MH
+# define IPPROTO_MH 135
+#endif
+
+struct ip6_mh {
+ uint8_t ip6mh_proto;
+ uint8_t ip6mh_hdrlen;
+ uint8_t ip6mh_type;
+ uint8_t ip6mh_reserved;
+ uint16_t ip6mh_cksum;
+ /* Followed by type specific messages */
+ uint8_t data[0];
+};
+
+/* Type 4 Routing header - well known as srh */
+struct ip6_rt4 {
+ uint8_t ip6r4_nxt; /* next header */
+ uint8_t ip6r4_len; /* length in units of 8 octets */
+ uint8_t ip6r4_type; /* always zero */
+ uint8_t ip6r4_segleft; /* segments left */
+ uint8_t ip6r4_last_entry; /* last entry */
+ uint8_t ip6r4_flags; /* flags */
+ uint16_t ip6r4_tag; /* tag */
+ struct in6_addr ip6r4_segments[0]; /* SID list */
+};
+
+/* RFC 3775 */
+#define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */
+#define IP6_MH_TYPE_HOTI 1 /* HOTI Message */
+#define IP6_MH_TYPE_COTI 2 /* COTI Message */
+#define IP6_MH_TYPE_HOT 3 /* HOT Message */
+#define IP6_MH_TYPE_COT 4 /* COT Message */
+#define IP6_MH_TYPE_BU 5 /* Binding Update */
+#define IP6_MH_TYPE_BACK 6 /* Binding ACK */
+#define IP6_MH_TYPE_BERROR 7 /* Binding Error */
+/* RFC 4068 */
+#define IP6_MH_TYPE_FBU 8 /* Fast Binding Update */
+#define IP6_MH_TYPE_FBACK 9 /* Fast Binding ACK */
+#define IP6_MH_TYPE_FNA 10 /* Fast Binding Advertisement */
+/* RFC 5096 */
+#define IP6_MH_TYPE_EMH 11 /* Experimental Mobility Header */
+/* RFC 5142 */
+#define IP6_MH_TYPE_HASM 12 /* Home Agent Switch Message */
+
+#endif /* NFTABLES_HEADERS_H */
diff --git a/include/iface.h b/include/iface.h
new file mode 100644
index 0000000..f41ee8b
--- /dev/null
+++ b/include/iface.h
@@ -0,0 +1,18 @@
+#ifndef _NFTABLES_IFACE_H_
+#define _NFTABLES_IFACE_H_
+
+#include <net/if.h>
+
+struct iface {
+ struct list_head list;
+ char name[IFNAMSIZ];
+ uint32_t ifindex;
+};
+
+unsigned int nft_if_nametoindex(const char *name);
+char *nft_if_indextoname(unsigned int ifindex, char *name);
+
+void iface_cache_update(void);
+void iface_cache_release(void);
+
+#endif
diff --git a/include/intervals.h b/include/intervals.h
new file mode 100644
index 0000000..964804b
--- /dev/null
+++ b/include/intervals.h
@@ -0,0 +1,12 @@
+#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,
+ struct expr *init, unsigned int debug_mask);
+int set_overlap(struct list_head *msgs, struct set *set, struct expr *init);
+int set_to_intervals(const struct set *set, struct expr *init, bool add);
+
+#endif
diff --git a/include/ipopt.h b/include/ipopt.h
new file mode 100644
index 0000000..03420dc
--- /dev/null
+++ b/include/ipopt.h
@@ -0,0 +1,29 @@
+#ifndef NFTABLES_IPOPT_H
+#define NFTABLES_IPOPT_H
+
+#include <proto.h>
+#include <exthdr.h>
+#include <statement.h>
+
+extern struct expr *ipopt_expr_alloc(const struct location *loc,
+ uint8_t type, uint8_t field);
+
+extern void ipopt_init_raw(struct expr *expr, uint8_t type,
+ unsigned int offset, unsigned int len,
+ uint32_t flags, bool set_unknown);
+
+extern bool ipopt_find_template(struct expr *expr, unsigned int offset,
+ unsigned int len);
+
+enum ipopt_fields {
+ IPOPT_FIELD_INVALID,
+ IPOPT_FIELD_TYPE,
+ IPOPT_FIELD_LENGTH,
+ IPOPT_FIELD_VALUE,
+ IPOPT_FIELD_PTR,
+ IPOPT_FIELD_ADDR_0,
+};
+
+extern const struct exthdr_desc *ipopt_protocols[UINT8_MAX];
+
+#endif /* NFTABLES_IPOPT_H */
diff --git a/include/json.h b/include/json.h
new file mode 100644
index 0000000..39be892
--- /dev/null
+++ b/include/json.h
@@ -0,0 +1,281 @@
+#ifndef NFTABLES_JSON_H
+#define NFTABLES_JSON_H
+
+#include <errno.h>
+
+struct chain;
+struct cmd;
+struct expr;
+struct netlink_ctx;
+struct nlmsghdr;
+struct rule;
+struct set;
+struct obj;
+struct stmt;
+struct symbol_table;
+struct table;
+struct netlink_mon_handler;
+struct nft_ctx;
+struct location;
+struct output_ctx;
+struct list_head;
+
+#ifdef HAVE_LIBJANSSON
+
+#define JSON_SCHEMA_VERSION 1
+
+#include <jansson.h>
+
+json_t *binop_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *relational_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *flagcmp_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *range_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *meta_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *payload_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *ct_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *concat_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *set_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *set_ref_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *set_elem_catchall_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *prefix_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *list_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *unary_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *mapping_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *rt_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *numgen_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *hash_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *fib_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *constant_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *socket_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *osf_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *xfrm_expr_json(const struct expr *expr, struct output_ctx *octx);
+
+json_t *integer_type_json(const struct expr *expr, struct output_ctx *octx);
+json_t *string_type_json(const struct expr *expr, struct output_ctx *octx);
+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);
+json_t *inet_service_type_json(const struct expr *expr,
+ struct output_ctx *octx);
+json_t *mark_type_json(const struct expr *expr, struct output_ctx *octx);
+json_t *devgroup_type_json(const struct expr *expr, struct output_ctx *octx);
+json_t *ct_label_type_json(const struct expr *expr, struct output_ctx *octx);
+json_t *time_type_json(const struct expr *expr, struct output_ctx *octx);
+json_t *uid_type_json(const struct expr *expr, struct output_ctx *octx);
+json_t *gid_type_json(const struct expr *expr, struct output_ctx *octx);
+
+json_t *expr_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *flow_offload_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *payload_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *exthdr_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *quota_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *ct_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *last_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *limit_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *fwd_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *notrack_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *dup_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *meta_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+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);
+json_t *queue_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *verdict_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *connlimit_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *optstrip_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *xt_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+
+int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd);
+
+int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf,
+ struct list_head *msgs, struct list_head *cmds);
+int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
+ struct list_head *msgs, struct list_head *cmds);
+
+void monitor_print_table_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct table *t);
+void monitor_print_chain_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct chain *c);
+void monitor_print_set_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s);
+void monitor_print_element_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s);
+void monitor_print_obj_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct obj *o);
+void monitor_print_rule_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct rule *r);
+
+int json_events_cb(const struct nlmsghdr *nlh,
+ struct netlink_mon_handler *monh);
+void json_alloc_echo(struct nft_ctx *ctx);
+void json_print_echo(struct nft_ctx *ctx);
+
+#else /* ! HAVE_LIBJANSSON */
+
+typedef void json_t;
+
+#define JSON_PRINT_STUB(name, arg1_t, arg2_t) \
+static inline json_t *name##_json(arg1_t arg1, arg2_t arg2) { return NULL; }
+
+#define EXPR_PRINT_STUB(name) \
+ JSON_PRINT_STUB(name, const struct expr *, struct output_ctx *)
+#define STMT_PRINT_STUB(name) \
+ JSON_PRINT_STUB(name##_stmt, const struct stmt *, struct output_ctx *)
+
+EXPR_PRINT_STUB(binop_expr)
+EXPR_PRINT_STUB(flagcmp_expr)
+EXPR_PRINT_STUB(relational_expr)
+EXPR_PRINT_STUB(range_expr)
+EXPR_PRINT_STUB(meta_expr)
+EXPR_PRINT_STUB(payload_expr)
+EXPR_PRINT_STUB(ct_expr)
+EXPR_PRINT_STUB(concat_expr)
+EXPR_PRINT_STUB(set_expr)
+EXPR_PRINT_STUB(set_ref_expr)
+EXPR_PRINT_STUB(set_elem_expr)
+EXPR_PRINT_STUB(prefix_expr)
+EXPR_PRINT_STUB(list_expr)
+EXPR_PRINT_STUB(unary_expr)
+EXPR_PRINT_STUB(mapping_expr)
+EXPR_PRINT_STUB(map_expr)
+EXPR_PRINT_STUB(exthdr_expr)
+EXPR_PRINT_STUB(verdict_expr)
+EXPR_PRINT_STUB(rt_expr)
+EXPR_PRINT_STUB(set_elem_catchall_expr)
+EXPR_PRINT_STUB(numgen_expr)
+EXPR_PRINT_STUB(hash_expr)
+EXPR_PRINT_STUB(fib_expr)
+EXPR_PRINT_STUB(constant_expr)
+EXPR_PRINT_STUB(socket_expr)
+EXPR_PRINT_STUB(osf_expr)
+EXPR_PRINT_STUB(xfrm_expr)
+
+EXPR_PRINT_STUB(integer_type)
+EXPR_PRINT_STUB(string_type)
+EXPR_PRINT_STUB(boolean_type)
+EXPR_PRINT_STUB(inet_protocol_type)
+EXPR_PRINT_STUB(inet_service_type)
+EXPR_PRINT_STUB(mark_type)
+EXPR_PRINT_STUB(devgroup_type)
+EXPR_PRINT_STUB(ct_label_type)
+EXPR_PRINT_STUB(time_type)
+EXPR_PRINT_STUB(uid_type)
+EXPR_PRINT_STUB(gid_type)
+
+STMT_PRINT_STUB(expr)
+STMT_PRINT_STUB(flow_offload)
+STMT_PRINT_STUB(payload)
+STMT_PRINT_STUB(exthdr)
+STMT_PRINT_STUB(quota)
+STMT_PRINT_STUB(ct)
+STMT_PRINT_STUB(last)
+STMT_PRINT_STUB(limit)
+STMT_PRINT_STUB(fwd)
+STMT_PRINT_STUB(notrack)
+STMT_PRINT_STUB(dup)
+STMT_PRINT_STUB(meta)
+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)
+STMT_PRINT_STUB(queue)
+STMT_PRINT_STUB(verdict)
+STMT_PRINT_STUB(connlimit)
+STMT_PRINT_STUB(tproxy)
+STMT_PRINT_STUB(synproxy)
+STMT_PRINT_STUB(optstrip)
+STMT_PRINT_STUB(xt)
+
+#undef STMT_PRINT_STUB
+#undef EXPR_PRINT_STUB
+#undef JSON_PRINT_STUB
+
+static inline int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ return -1;
+}
+
+static inline int
+nft_parse_json_buffer(struct nft_ctx *nft, const char *buf,
+ struct list_head *msgs, struct list_head *cmds)
+{
+ return -EINVAL;
+}
+
+static inline int
+nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
+ struct list_head *msgs, struct list_head *cmds)
+{
+ return -EINVAL;
+}
+
+static inline void monitor_print_table_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct table *t)
+{
+ /* empty */
+}
+
+static inline void monitor_print_chain_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct chain *c)
+{
+ /* empty */
+}
+
+static inline void monitor_print_set_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ /* empty */
+}
+
+static inline void monitor_print_element_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ /* empty */
+}
+
+static inline void monitor_print_obj_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct obj *o)
+{
+ /* empty */
+}
+
+static inline void monitor_print_rule_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct rule *r)
+{
+ /* empty */
+}
+
+static inline int json_events_cb(const struct nlmsghdr *nlh,
+ struct netlink_mon_handler *monh)
+{
+ return -1;
+}
+
+static inline void json_alloc_echo(struct nft_ctx *ctx)
+{
+ /* empty */
+}
+
+static inline void json_print_echo(struct nft_ctx *ctx)
+{
+ /* empty */
+}
+
+#endif /* HAVE_LIBJANSSON */
+
+#endif /* NFTABLES_JSON_H */
diff --git a/include/linux/Makefile.am b/include/linux/Makefile.am
new file mode 100644
index 0000000..eb9fc4e
--- /dev/null
+++ b/include/linux/Makefile.am
@@ -0,0 +1,12 @@
+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/Makefile.in b/include/linux/Makefile.in
new file mode 100644
index 0000000..025c321
--- /dev/null
+++ b/include/linux/Makefile.in
@@ -0,0 +1,650 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/linux
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+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
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/linux/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/linux/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
new file mode 100644
index 0000000..9e07888
--- /dev/null
+++ b/include/linux/netfilter.h
@@ -0,0 +1,81 @@
+#ifndef __LINUX_NETFILTER_H
+#define __LINUX_NETFILTER_H
+
+#include <linux/types.h>
+
+#include <linux/sysctl.h>
+
+
+/* Responses from hook functions. */
+#define NF_DROP 0
+#define NF_ACCEPT 1
+#define NF_STOLEN 2
+#define NF_QUEUE 3
+#define NF_REPEAT 4
+#define NF_STOP 5
+#define NF_MAX_VERDICT NF_STOP
+
+/* we overload the higher bits for encoding auxiliary data such as the queue
+ * number or errno values. Not nice, but better than additional function
+ * arguments. */
+#define NF_VERDICT_MASK 0x000000ff
+
+/* extra verdict flags have mask 0x0000ff00 */
+#define NF_VERDICT_FLAG_QUEUE_BYPASS 0x00008000
+
+/* queue number (NF_QUEUE) or errno (NF_DROP) */
+#define NF_VERDICT_QMASK 0xffff0000
+#define NF_VERDICT_QBITS 16
+
+#define NF_QUEUE_NR(x) ((((x) << 16) & NF_VERDICT_QMASK) | NF_QUEUE)
+
+#define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP)
+
+/* only for userspace compatibility */
+#ifndef __KERNEL__
+/* Generic cache responses from hook functions.
+ <= 0x2000 is used for protocol-flags. */
+#define NFC_UNKNOWN 0x4000
+#define NFC_ALTERED 0x8000
+
+/* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */
+#define NF_VERDICT_BITS 16
+#endif
+
+enum nf_inet_hooks {
+ NF_INET_PRE_ROUTING,
+ NF_INET_LOCAL_IN,
+ NF_INET_FORWARD,
+ NF_INET_LOCAL_OUT,
+ NF_INET_POST_ROUTING,
+ NF_INET_INGRESS,
+ NF_INET_NUMHOOKS
+};
+
+enum nf_dev_hooks {
+ NF_NETDEV_INGRESS,
+ NF_NETDEV_EGRESS,
+ NF_NETDEV_NUMHOOKS
+};
+
+enum {
+ NFPROTO_UNSPEC = 0,
+ NFPROTO_INET = 1,
+ NFPROTO_IPV4 = 2,
+ NFPROTO_ARP = 3,
+ NFPROTO_NETDEV = 5,
+ NFPROTO_BRIDGE = 7,
+ NFPROTO_IPV6 = 10,
+ NFPROTO_DECNET = 12,
+ NFPROTO_NUMPROTO,
+};
+
+union nf_inet_addr {
+ __u32 all[4];
+ __be32 ip;
+ __be32 ip6[4];
+ struct in_addr in;
+ struct in6_addr in6;
+};
+
+#endif /* __LINUX_NETFILTER_H */
diff --git a/include/linux/netfilter/Makefile.am b/include/linux/netfilter/Makefile.am
new file mode 100644
index 0000000..22f66a7
--- /dev/null
+++ b/include/linux/netfilter/Makefile.am
@@ -0,0 +1,10 @@
+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/Makefile.in b/include/linux/netfilter/Makefile.in
new file mode 100644
index 0000000..05e49f0
--- /dev/null
+++ b/include/linux/netfilter/Makefile.in
@@ -0,0 +1,533 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/linux/netfilter
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+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
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/linux/netfilter/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/linux/netfilter/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
new file mode 100644
index 0000000..768ff25
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -0,0 +1,104 @@
+#ifndef _NF_CONNTRACK_COMMON_H
+#define _NF_CONNTRACK_COMMON_H
+/* Connection state tracking for netfilter. This is separated from,
+ but required by, the NAT layer; it can also be used by an iptables
+ extension. */
+enum ip_conntrack_info
+{
+ /* Part of an established connection (either direction). */
+ IP_CT_ESTABLISHED,
+
+ /* Like NEW, but related to an existing connection, or ICMP error
+ (in either direction). */
+ IP_CT_RELATED,
+
+ /* Started a new connection to track (only
+ IP_CT_DIR_ORIGINAL); may be a retransmission. */
+ IP_CT_NEW,
+
+ /* >= this indicates reply direction */
+ IP_CT_IS_REPLY,
+
+ /* Number of distinct IP_CT types (no NEW in reply dirn). */
+ IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
+};
+
+#define NF_CT_STATE_INVALID_BIT (1 << 0)
+#define NF_CT_STATE_BIT(ctinfo) (1 << ((ctinfo) % IP_CT_IS_REPLY + 1))
+#define NF_CT_STATE_UNTRACKED_BIT (1 << (IP_CT_NUMBER + 1))
+
+/* Bitset representing status of connection. */
+enum ip_conntrack_status {
+ /* It's an expected connection: bit 0 set. This bit never changed */
+ IPS_EXPECTED_BIT = 0,
+ IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
+
+ /* We've seen packets both ways: bit 1 set. Can be set, not unset. */
+ IPS_SEEN_REPLY_BIT = 1,
+ IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
+
+ /* Conntrack should never be early-expired. */
+ IPS_ASSURED_BIT = 2,
+ IPS_ASSURED = (1 << IPS_ASSURED_BIT),
+
+ /* Connection is confirmed: originating packet has left box */
+ IPS_CONFIRMED_BIT = 3,
+ IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
+
+ /* Connection needs src nat in orig dir. This bit never changed. */
+ IPS_SRC_NAT_BIT = 4,
+ IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
+
+ /* Connection needs dst nat in orig dir. This bit never changed. */
+ IPS_DST_NAT_BIT = 5,
+ IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
+
+ /* Both together. */
+ IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
+
+ /* Connection needs TCP sequence adjusted. */
+ IPS_SEQ_ADJUST_BIT = 6,
+ IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
+
+ /* NAT initialization bits. */
+ IPS_SRC_NAT_DONE_BIT = 7,
+ IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
+
+ IPS_DST_NAT_DONE_BIT = 8,
+ IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
+
+ /* Both together */
+ IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+ /* Connection is dying (removed from lists), can not be unset. */
+ IPS_DYING_BIT = 9,
+ IPS_DYING = (1 << IPS_DYING_BIT),
+
+ /* Connection has fixed timeout. */
+ IPS_FIXED_TIMEOUT_BIT = 10,
+ IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
+};
+
+/* Connection tracking event types */
+enum ip_conntrack_events {
+ IPCT_NEW, /* new conntrack */
+ IPCT_RELATED, /* related conntrack */
+ IPCT_DESTROY, /* destroyed conntrack */
+ IPCT_REPLY, /* connection has seen two-way traffic */
+ IPCT_ASSURED, /* connection status has changed to assured */
+ IPCT_PROTOINFO, /* protocol information has changed */
+ IPCT_HELPER, /* new helper has been set */
+ IPCT_MARK, /* new mark has been set */
+ IPCT_SEQADJ, /* sequence adjustment has changed */
+ IPCT_NATSEQADJ = IPCT_SEQADJ,
+ IPCT_SECMARK, /* new security mark has been set */
+ IPCT_LABEL, /* new connlabel has been set */
+};
+
+enum ip_conntrack_expect_events {
+ IPEXP_NEW, /* new expectation */
+ IPEXP_DESTROY, /* destroyed expectation */
+};
+
+
+#endif /* _NF_CONNTRACK_COMMON_H */
diff --git a/include/linux/netfilter/nf_conntrack_tuple_common.h b/include/linux/netfilter/nf_conntrack_tuple_common.h
new file mode 100644
index 0000000..8ab3118
--- /dev/null
+++ b/include/linux/netfilter/nf_conntrack_tuple_common.h
@@ -0,0 +1,41 @@
+#ifndef _NF_CONNTRACK_TUPLE_COMMON_H
+#define _NF_CONNTRACK_TUPLE_COMMON_H
+
+#include <linux/types.h>
+
+enum ip_conntrack_dir {
+ IP_CT_DIR_ORIGINAL,
+ IP_CT_DIR_REPLY,
+ IP_CT_DIR_MAX
+};
+
+/* The protocol-specific manipulable parts of the tuple: always in
+ * network order
+ */
+union nf_conntrack_man_proto {
+ /* Add other protocols here. */
+ __be16 all;
+
+ struct {
+ __be16 port;
+ } tcp;
+ struct {
+ __be16 port;
+ } udp;
+ struct {
+ __be16 id;
+ } icmp;
+ struct {
+ __be16 port;
+ } dccp;
+ struct {
+ __be16 port;
+ } sctp;
+ struct {
+ __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */
+ } gre;
+};
+
+#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
+
+#endif /* _NF_CONNTRACK_TUPLE_COMMON_H */
diff --git a/include/linux/netfilter/nf_log.h b/include/linux/netfilter/nf_log.h
new file mode 100644
index 0000000..2ae0093
--- /dev/null
+++ b/include/linux/netfilter/nf_log.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NETFILTER_NF_LOG_H
+#define _NETFILTER_NF_LOG_H
+
+#define NF_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
+#define NF_LOG_TCPOPT 0x02 /* Log TCP options */
+#define NF_LOG_IPOPT 0x04 /* Log IP options */
+#define NF_LOG_UID 0x08 /* Log UID owning local socket */
+#define NF_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
+#define NF_LOG_MACDECODE 0x20 /* Decode MAC header */
+#define NF_LOG_MASK 0x2f
+
+#define NF_LOG_PREFIXLEN 128
+
+#endif /* _NETFILTER_NF_LOG_H */
diff --git a/include/linux/netfilter/nf_nat.h b/include/linux/netfilter/nf_nat.h
new file mode 100644
index 0000000..a64586e
--- /dev/null
+++ b/include/linux/netfilter/nf_nat.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NETFILTER_NF_NAT_H
+#define _NETFILTER_NF_NAT_H
+
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+
+#define NF_NAT_RANGE_MAP_IPS (1 << 0)
+#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
+#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
+#define NF_NAT_RANGE_PERSISTENT (1 << 3)
+#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
+#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
+#define NF_NAT_RANGE_NETMAP (1 << 6)
+
+#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
+ (NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+
+#define NF_NAT_RANGE_MASK \
+ (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
+ NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
+ NF_NAT_RANGE_NETMAP)
+
+struct nf_nat_ipv4_range {
+ unsigned int flags;
+ __be32 min_ip;
+ __be32 max_ip;
+ union nf_conntrack_man_proto min;
+ union nf_conntrack_man_proto max;
+};
+
+struct nf_nat_ipv4_multi_range_compat {
+ unsigned int rangesize;
+ struct nf_nat_ipv4_range range[1];
+};
+
+struct nf_nat_range {
+ unsigned int flags;
+ union nf_inet_addr min_addr;
+ union nf_inet_addr max_addr;
+ union nf_conntrack_man_proto min_proto;
+ union nf_conntrack_man_proto max_proto;
+};
+
+struct nf_nat_range2 {
+ unsigned int flags;
+ union nf_inet_addr min_addr;
+ union nf_inet_addr max_addr;
+ union nf_conntrack_man_proto min_proto;
+ union nf_conntrack_man_proto max_proto;
+ union nf_conntrack_man_proto base_proto;
+};
+
+#endif /* _NETFILTER_NF_NAT_H */
diff --git a/include/linux/netfilter/nf_synproxy.h b/include/linux/netfilter/nf_synproxy.h
new file mode 100644
index 0000000..0e7c391
--- /dev/null
+++ b/include/linux/netfilter/nf_synproxy.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _NF_SYNPROXY_H
+#define _NF_SYNPROXY_H
+
+#include <linux/types.h>
+
+#define NF_SYNPROXY_OPT_MSS 0x01
+#define NF_SYNPROXY_OPT_WSCALE 0x02
+#define NF_SYNPROXY_OPT_SACK_PERM 0x04
+#define NF_SYNPROXY_OPT_TIMESTAMP 0x08
+#define NF_SYNPROXY_OPT_ECN 0x10
+#define NF_SYNPROXY_FLAGMASK (NF_SYNPROXY_OPT_MSS | \
+ NF_SYNPROXY_OPT_WSCALE | \
+ NF_SYNPROXY_OPT_SACK_PERM | \
+ NF_SYNPROXY_OPT_TIMESTAMP)
+
+struct nf_synproxy_info {
+ __u8 options;
+ __u8 wscale;
+ __u16 mss;
+};
+
+#endif /* _NF_SYNPROXY_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
new file mode 100644
index 0000000..c62e6ac
--- /dev/null
+++ b/include/linux/netfilter/nf_tables.h
@@ -0,0 +1,1983 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_NF_TABLES_H
+#define _LINUX_NF_TABLES_H
+
+#define NFT_NAME_MAXLEN 256
+#define NFT_TABLE_MAXNAMELEN NFT_NAME_MAXLEN
+#define NFT_CHAIN_MAXNAMELEN NFT_NAME_MAXLEN
+#define NFT_SET_MAXNAMELEN NFT_NAME_MAXLEN
+#define NFT_OBJ_MAXNAMELEN NFT_NAME_MAXLEN
+#define NFT_USERDATA_MAXLEN 256
+#define NFT_OSF_MAXGENRELEN 16
+
+/**
+ * enum nft_registers - nf_tables registers
+ *
+ * nf_tables used to have five registers: a verdict register and four data
+ * registers of size 16. The data registers have been changed to 16 registers
+ * of size 4. For compatibility reasons, the NFT_REG_[1-4] registers still
+ * map to areas of size 16, the 4 byte registers are addressed using
+ * NFT_REG32_00 - NFT_REG32_15.
+ */
+enum nft_registers {
+ NFT_REG_VERDICT,
+ NFT_REG_1,
+ NFT_REG_2,
+ NFT_REG_3,
+ NFT_REG_4,
+ __NFT_REG_MAX,
+
+ NFT_REG32_00 = 8,
+ NFT_REG32_01,
+ NFT_REG32_02,
+ NFT_REG32_03,
+ NFT_REG32_04,
+ NFT_REG32_05,
+ NFT_REG32_06,
+ NFT_REG32_07,
+ NFT_REG32_08,
+ NFT_REG32_09,
+ NFT_REG32_10,
+ NFT_REG32_11,
+ NFT_REG32_12,
+ NFT_REG32_13,
+ NFT_REG32_14,
+ NFT_REG32_15,
+};
+#define NFT_REG_MAX (__NFT_REG_MAX - 1)
+
+#define NFT_REG_SIZE 16
+#define NFT_REG32_SIZE 4
+#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1)
+
+/**
+ * enum nft_verdicts - nf_tables internal verdicts
+ *
+ * @NFT_CONTINUE: continue evaluation of the current rule
+ * @NFT_BREAK: terminate evaluation of the current rule
+ * @NFT_JUMP: push the current chain on the jump stack and jump to a chain
+ * @NFT_GOTO: jump to a chain without pushing the current chain on the jump stack
+ * @NFT_RETURN: return to the topmost chain on the jump stack
+ *
+ * The nf_tables verdicts share their numeric space with the netfilter verdicts.
+ */
+enum nft_verdicts {
+ NFT_CONTINUE = -1,
+ NFT_BREAK = -2,
+ NFT_JUMP = -3,
+ NFT_GOTO = -4,
+ NFT_RETURN = -5,
+};
+
+/**
+ * enum nf_tables_msg_types - nf_tables netlink message types
+ *
+ * @NFT_MSG_NEWTABLE: create a new table (enum nft_table_attributes)
+ * @NFT_MSG_GETTABLE: get a table (enum nft_table_attributes)
+ * @NFT_MSG_DELTABLE: delete a table (enum nft_table_attributes)
+ * @NFT_MSG_NEWCHAIN: create a new chain (enum nft_chain_attributes)
+ * @NFT_MSG_GETCHAIN: get a chain (enum nft_chain_attributes)
+ * @NFT_MSG_DELCHAIN: delete a chain (enum nft_chain_attributes)
+ * @NFT_MSG_NEWRULE: create a new rule (enum nft_rule_attributes)
+ * @NFT_MSG_GETRULE: get a rule (enum nft_rule_attributes)
+ * @NFT_MSG_DELRULE: delete a rule (enum nft_rule_attributes)
+ * @NFT_MSG_NEWSET: create a new set (enum nft_set_attributes)
+ * @NFT_MSG_GETSET: get a set (enum nft_set_attributes)
+ * @NFT_MSG_DELSET: delete a set (enum nft_set_attributes)
+ * @NFT_MSG_NEWSETELEM: create a new set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_GETSETELEM: get a set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes)
+ * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes)
+ * @NFT_MSG_TRACE: trace event (enum nft_trace_attributes)
+ * @NFT_MSG_NEWOBJ: create a stateful object (enum nft_obj_attributes)
+ * @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes)
+ * @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes)
+ * @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes)
+ * @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,
+ NFT_MSG_GETTABLE,
+ NFT_MSG_DELTABLE,
+ NFT_MSG_NEWCHAIN,
+ NFT_MSG_GETCHAIN,
+ NFT_MSG_DELCHAIN,
+ NFT_MSG_NEWRULE,
+ NFT_MSG_GETRULE,
+ NFT_MSG_DELRULE,
+ NFT_MSG_NEWSET,
+ NFT_MSG_GETSET,
+ NFT_MSG_DELSET,
+ NFT_MSG_NEWSETELEM,
+ NFT_MSG_GETSETELEM,
+ NFT_MSG_DELSETELEM,
+ NFT_MSG_NEWGEN,
+ NFT_MSG_GETGEN,
+ NFT_MSG_TRACE,
+ NFT_MSG_NEWOBJ,
+ NFT_MSG_GETOBJ,
+ NFT_MSG_DELOBJ,
+ NFT_MSG_GETOBJ_RESET,
+ 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,
+};
+
+/**
+ * enum nft_list_attributes - nf_tables generic list netlink attributes
+ *
+ * @NFTA_LIST_ELEM: list element (NLA_NESTED)
+ */
+enum nft_list_attributes {
+ NFTA_LIST_UNSPEC,
+ NFTA_LIST_ELEM,
+ __NFTA_LIST_MAX
+};
+#define NFTA_LIST_MAX (__NFTA_LIST_MAX - 1)
+
+/**
+ * enum nft_hook_attributes - nf_tables netfilter hook netlink attributes
+ *
+ * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
+ * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ * @NFTA_HOOK_DEV: netdevice name (NLA_STRING)
+ * @NFTA_HOOK_DEVS: list of netdevices (NLA_NESTED)
+ */
+enum nft_hook_attributes {
+ NFTA_HOOK_UNSPEC,
+ NFTA_HOOK_HOOKNUM,
+ NFTA_HOOK_PRIORITY,
+ NFTA_HOOK_DEV,
+ NFTA_HOOK_DEVS,
+ __NFTA_HOOK_MAX
+};
+#define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1)
+
+/**
+ * enum nft_table_flags - nf_tables table flags
+ *
+ * @NFT_TABLE_F_DORMANT: this table is not active
+ */
+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
+ *
+ * @NFTA_TABLE_NAME: name of the table (NLA_STRING)
+ * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
+ * @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
+ * @NFTA_TABLE_USERDATA: user data (NLA_BINARY)
+ * @NFTA_TABLE_OWNER: owner of this table through netlink portID (NLA_U32)
+ */
+enum nft_table_attributes {
+ NFTA_TABLE_UNSPEC,
+ NFTA_TABLE_NAME,
+ NFTA_TABLE_FLAGS,
+ NFTA_TABLE_USE,
+ NFTA_TABLE_HANDLE,
+ NFTA_TABLE_PAD,
+ NFTA_TABLE_USERDATA,
+ NFTA_TABLE_OWNER,
+ __NFTA_TABLE_MAX
+};
+#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
+
+enum nft_chain_flags {
+ NFT_CHAIN_BASE = (1 << 0),
+ NFT_CHAIN_HW_OFFLOAD = (1 << 1),
+ NFT_CHAIN_BINDING = (1 << 2),
+};
+#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \
+ NFT_CHAIN_HW_OFFLOAD | \
+ NFT_CHAIN_BINDING)
+
+/**
+ * enum nft_chain_attributes - nf_tables chain netlink attributes
+ *
+ * @NFTA_CHAIN_TABLE: name of the table containing the chain (NLA_STRING)
+ * @NFTA_CHAIN_HANDLE: numeric handle of the chain (NLA_U64)
+ * @NFTA_CHAIN_NAME: name of the chain (NLA_STRING)
+ * @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes)
+ * @NFTA_CHAIN_POLICY: numeric policy of the chain (NLA_U32)
+ * @NFTA_CHAIN_USE: number of references to this chain (NLA_U32)
+ * @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
+ * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
+ * @NFTA_CHAIN_FLAGS: chain flags
+ * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
+ * @NFTA_CHAIN_USERDATA: user data (NLA_BINARY)
+ */
+enum nft_chain_attributes {
+ NFTA_CHAIN_UNSPEC,
+ NFTA_CHAIN_TABLE,
+ NFTA_CHAIN_HANDLE,
+ NFTA_CHAIN_NAME,
+ NFTA_CHAIN_HOOK,
+ NFTA_CHAIN_POLICY,
+ NFTA_CHAIN_USE,
+ NFTA_CHAIN_TYPE,
+ NFTA_CHAIN_COUNTERS,
+ NFTA_CHAIN_PAD,
+ NFTA_CHAIN_FLAGS,
+ NFTA_CHAIN_ID,
+ NFTA_CHAIN_USERDATA,
+ __NFTA_CHAIN_MAX
+};
+#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
+
+/**
+ * enum nft_rule_attributes - nf_tables rule netlink attributes
+ *
+ * @NFTA_RULE_TABLE: name of the table containing the rule (NLA_STRING)
+ * @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING)
+ * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U64)
+ * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes)
+ * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
+ * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
+ * @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32)
+ * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32)
+ */
+enum nft_rule_attributes {
+ NFTA_RULE_UNSPEC,
+ NFTA_RULE_TABLE,
+ NFTA_RULE_CHAIN,
+ NFTA_RULE_HANDLE,
+ NFTA_RULE_EXPRESSIONS,
+ NFTA_RULE_COMPAT,
+ NFTA_RULE_POSITION,
+ NFTA_RULE_USERDATA,
+ NFTA_RULE_PAD,
+ NFTA_RULE_ID,
+ NFTA_RULE_POSITION_ID,
+ NFTA_RULE_CHAIN_ID,
+ __NFTA_RULE_MAX
+};
+#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
+
+/**
+ * enum nft_rule_compat_flags - nf_tables rule compat flags
+ *
+ * @NFT_RULE_COMPAT_F_INV: invert the check result
+ */
+enum nft_rule_compat_flags {
+ NFT_RULE_COMPAT_F_INV = (1 << 1),
+ NFT_RULE_COMPAT_F_MASK = NFT_RULE_COMPAT_F_INV,
+};
+
+/**
+ * enum nft_rule_compat_attributes - nf_tables rule compat attributes
+ *
+ * @NFTA_RULE_COMPAT_PROTO: numeric value of handled protocol (NLA_U32)
+ * @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32)
+ */
+enum nft_rule_compat_attributes {
+ NFTA_RULE_COMPAT_UNSPEC,
+ NFTA_RULE_COMPAT_PROTO,
+ NFTA_RULE_COMPAT_FLAGS,
+ __NFTA_RULE_COMPAT_MAX
+};
+#define NFTA_RULE_COMPAT_MAX (__NFTA_RULE_COMPAT_MAX - 1)
+
+/**
+ * enum nft_set_flags - nf_tables set flags
+ *
+ * @NFT_SET_ANONYMOUS: name allocation, automatic cleanup on unlink
+ * @NFT_SET_CONSTANT: set contents may not change while bound
+ * @NFT_SET_INTERVAL: set contains intervals
+ * @NFT_SET_MAP: set is used as a dictionary
+ * @NFT_SET_TIMEOUT: set uses timeouts
+ * @NFT_SET_EVAL: set can be updated from the evaluation path
+ * @NFT_SET_OBJECT: set contains stateful objects
+ * @NFT_SET_CONCAT: set contains a concatenation
+ * @NFT_SET_EXPR: set contains expressions
+ */
+enum nft_set_flags {
+ NFT_SET_ANONYMOUS = 0x1,
+ NFT_SET_CONSTANT = 0x2,
+ NFT_SET_INTERVAL = 0x4,
+ NFT_SET_MAP = 0x8,
+ NFT_SET_TIMEOUT = 0x10,
+ NFT_SET_EVAL = 0x20,
+ NFT_SET_OBJECT = 0x40,
+ NFT_SET_CONCAT = 0x80,
+ NFT_SET_EXPR = 0x100,
+};
+
+/**
+ * enum nft_set_policies - set selection policy
+ *
+ * @NFT_SET_POL_PERFORMANCE: prefer high performance over low memory use
+ * @NFT_SET_POL_MEMORY: prefer low memory use over high performance
+ */
+enum nft_set_policies {
+ NFT_SET_POL_PERFORMANCE,
+ NFT_SET_POL_MEMORY,
+};
+
+/**
+ * enum nft_set_desc_attributes - set element description
+ *
+ * @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
+ * @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED)
+ */
+enum nft_set_desc_attributes {
+ NFTA_SET_DESC_UNSPEC,
+ NFTA_SET_DESC_SIZE,
+ NFTA_SET_DESC_CONCAT,
+ __NFTA_SET_DESC_MAX
+};
+#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1)
+
+/**
+ * enum nft_set_field_attributes - attributes of concatenated fields
+ *
+ * @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32)
+ */
+enum nft_set_field_attributes {
+ NFTA_SET_FIELD_UNSPEC,
+ NFTA_SET_FIELD_LEN,
+ __NFTA_SET_FIELD_MAX
+};
+#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1)
+
+/**
+ * enum nft_set_attributes - nf_tables set netlink attributes
+ *
+ * @NFTA_SET_TABLE: table name (NLA_STRING)
+ * @NFTA_SET_NAME: set name (NLA_STRING)
+ * @NFTA_SET_FLAGS: bitmask of enum nft_set_flags (NLA_U32)
+ * @NFTA_SET_KEY_TYPE: key data type, informational purpose only (NLA_U32)
+ * @NFTA_SET_KEY_LEN: key data length (NLA_U32)
+ * @NFTA_SET_DATA_TYPE: mapping data type (NLA_U32)
+ * @NFTA_SET_DATA_LEN: mapping data length (NLA_U32)
+ * @NFTA_SET_POLICY: selection policy (NLA_U32)
+ * @NFTA_SET_DESC: set description (NLA_NESTED)
+ * @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
+ * @NFTA_SET_TIMEOUT: default timeout value (NLA_U64)
+ * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
+ * @NFTA_SET_USERDATA: user data (NLA_BINARY)
+ * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
+ * @NFTA_SET_HANDLE: set handle (NLA_U64)
+ * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
+ */
+enum nft_set_attributes {
+ NFTA_SET_UNSPEC,
+ NFTA_SET_TABLE,
+ NFTA_SET_NAME,
+ NFTA_SET_FLAGS,
+ NFTA_SET_KEY_TYPE,
+ NFTA_SET_KEY_LEN,
+ NFTA_SET_DATA_TYPE,
+ NFTA_SET_DATA_LEN,
+ NFTA_SET_POLICY,
+ NFTA_SET_DESC,
+ NFTA_SET_ID,
+ NFTA_SET_TIMEOUT,
+ NFTA_SET_GC_INTERVAL,
+ NFTA_SET_USERDATA,
+ NFTA_SET_PAD,
+ NFTA_SET_OBJ_TYPE,
+ NFTA_SET_HANDLE,
+ NFTA_SET_EXPR,
+ NFTA_SET_EXPRESSIONS,
+ __NFTA_SET_MAX
+};
+#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
+
+/**
+ * enum nft_set_elem_flags - nf_tables set element flags
+ *
+ * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
+ * @NFT_SET_ELEM_CATCHALL: special catch-all element
+ */
+enum nft_set_elem_flags {
+ NFT_SET_ELEM_INTERVAL_END = 0x1,
+ NFT_SET_ELEM_CATCHALL = 0x2,
+};
+
+/**
+ * enum nft_set_elem_attributes - nf_tables set element netlink attributes
+ *
+ * @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
+ * @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
+ * @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
+ * @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
+ * @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
+ * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
+ * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
+ * @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data)
+ * @NFTA_SET_ELEM_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
+ */
+enum nft_set_elem_attributes {
+ NFTA_SET_ELEM_UNSPEC,
+ NFTA_SET_ELEM_KEY,
+ NFTA_SET_ELEM_DATA,
+ NFTA_SET_ELEM_FLAGS,
+ NFTA_SET_ELEM_TIMEOUT,
+ NFTA_SET_ELEM_EXPIRATION,
+ NFTA_SET_ELEM_USERDATA,
+ NFTA_SET_ELEM_EXPR,
+ NFTA_SET_ELEM_PAD,
+ NFTA_SET_ELEM_OBJREF,
+ NFTA_SET_ELEM_KEY_END,
+ NFTA_SET_ELEM_EXPRESSIONS,
+ __NFTA_SET_ELEM_MAX
+};
+#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
+
+/**
+ * enum nft_set_elem_list_attributes - nf_tables set element list netlink attributes
+ *
+ * @NFTA_SET_ELEM_LIST_TABLE: table of the set to be changed (NLA_STRING)
+ * @NFTA_SET_ELEM_LIST_SET: name of the set to be changed (NLA_STRING)
+ * @NFTA_SET_ELEM_LIST_ELEMENTS: list of set elements (NLA_NESTED: nft_set_elem_attributes)
+ * @NFTA_SET_ELEM_LIST_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
+ */
+enum nft_set_elem_list_attributes {
+ NFTA_SET_ELEM_LIST_UNSPEC,
+ NFTA_SET_ELEM_LIST_TABLE,
+ NFTA_SET_ELEM_LIST_SET,
+ NFTA_SET_ELEM_LIST_ELEMENTS,
+ NFTA_SET_ELEM_LIST_SET_ID,
+ __NFTA_SET_ELEM_LIST_MAX
+};
+#define NFTA_SET_ELEM_LIST_MAX (__NFTA_SET_ELEM_LIST_MAX - 1)
+
+/**
+ * enum nft_data_types - nf_tables data types
+ *
+ * @NFT_DATA_VALUE: generic data
+ * @NFT_DATA_VERDICT: netfilter verdict
+ *
+ * The type of data is usually determined by the kernel directly and is not
+ * explicitly specified by userspace. The only difference are sets, where
+ * userspace specifies the key and mapping data types.
+ *
+ * The values 0xffffff00-0xffffffff are reserved for internally used types.
+ * The remaining range can be freely used by userspace to encode types, all
+ * values are equivalent to NFT_DATA_VALUE.
+ */
+enum nft_data_types {
+ NFT_DATA_VALUE,
+ NFT_DATA_VERDICT = 0xffffff00U,
+};
+
+#define NFT_DATA_RESERVED_MASK 0xffffff00U
+
+/**
+ * enum nft_data_attributes - nf_tables data netlink attributes
+ *
+ * @NFTA_DATA_VALUE: generic data (NLA_BINARY)
+ * @NFTA_DATA_VERDICT: nf_tables verdict (NLA_NESTED: nft_verdict_attributes)
+ */
+enum nft_data_attributes {
+ NFTA_DATA_UNSPEC,
+ NFTA_DATA_VALUE,
+ NFTA_DATA_VERDICT,
+ __NFTA_DATA_MAX
+};
+#define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1)
+
+/* Maximum length of a value */
+#define NFT_DATA_VALUE_MAXLEN 64
+
+/**
+ * enum nft_verdict_attributes - nf_tables verdict netlink attributes
+ *
+ * @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
+ * @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
+ * @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32)
+ */
+enum nft_verdict_attributes {
+ NFTA_VERDICT_UNSPEC,
+ NFTA_VERDICT_CODE,
+ NFTA_VERDICT_CHAIN,
+ NFTA_VERDICT_CHAIN_ID,
+ __NFTA_VERDICT_MAX
+};
+#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
+
+/**
+ * enum nft_expr_attributes - nf_tables expression netlink attributes
+ *
+ * @NFTA_EXPR_NAME: name of the expression type (NLA_STRING)
+ * @NFTA_EXPR_DATA: type specific data (NLA_NESTED)
+ */
+enum nft_expr_attributes {
+ NFTA_EXPR_UNSPEC,
+ NFTA_EXPR_NAME,
+ NFTA_EXPR_DATA,
+ __NFTA_EXPR_MAX
+};
+#define NFTA_EXPR_MAX (__NFTA_EXPR_MAX - 1)
+
+/**
+ * enum nft_immediate_attributes - nf_tables immediate expression netlink attributes
+ *
+ * @NFTA_IMMEDIATE_DREG: destination register to load data into (NLA_U32)
+ * @NFTA_IMMEDIATE_DATA: data to load (NLA_NESTED: nft_data_attributes)
+ */
+enum nft_immediate_attributes {
+ NFTA_IMMEDIATE_UNSPEC,
+ NFTA_IMMEDIATE_DREG,
+ NFTA_IMMEDIATE_DATA,
+ __NFTA_IMMEDIATE_MAX
+};
+#define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1)
+
+/**
+ * enum nft_bitwise_ops - nf_tables bitwise operations
+ *
+ * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and
+ * XOR boolean operations
+ * @NFT_BITWISE_LSHIFT: left-shift operation
+ * @NFT_BITWISE_RSHIFT: right-shift operation
+ */
+enum nft_bitwise_ops {
+ NFT_BITWISE_BOOL,
+ NFT_BITWISE_LSHIFT,
+ NFT_BITWISE_RSHIFT,
+};
+
+/**
+ * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
+ *
+ * @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers)
+ * @NFTA_BITWISE_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_BITWISE_LEN: length of operands (NLA_U32)
+ * @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops)
+ * @NFTA_BITWISE_DATA: argument for non-boolean operations
+ * (NLA_NESTED: nft_data_attributes)
+ *
+ * The bitwise expression supports boolean and shift operations. It implements
+ * the boolean operations by performing the following operation:
+ *
+ * dreg = (sreg & mask) ^ xor
+ *
+ * with these mask and xor values:
+ *
+ * mask xor
+ * NOT: 1 1
+ * OR: ~x x
+ * XOR: 1 x
+ * AND: x 0
+ */
+enum nft_bitwise_attributes {
+ NFTA_BITWISE_UNSPEC,
+ NFTA_BITWISE_SREG,
+ NFTA_BITWISE_DREG,
+ NFTA_BITWISE_LEN,
+ NFTA_BITWISE_MASK,
+ NFTA_BITWISE_XOR,
+ NFTA_BITWISE_OP,
+ NFTA_BITWISE_DATA,
+ __NFTA_BITWISE_MAX
+};
+#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
+
+/**
+ * enum nft_byteorder_ops - nf_tables byteorder operators
+ *
+ * @NFT_BYTEORDER_NTOH: network to host operator
+ * @NFT_BYTEORDER_HTON: host to network operator
+ */
+enum nft_byteorder_ops {
+ NFT_BYTEORDER_NTOH,
+ NFT_BYTEORDER_HTON,
+};
+
+/**
+ * enum nft_byteorder_attributes - nf_tables byteorder expression netlink attributes
+ *
+ * @NFTA_BYTEORDER_SREG: source register (NLA_U32: nft_registers)
+ * @NFTA_BYTEORDER_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_BYTEORDER_OP: operator (NLA_U32: enum nft_byteorder_ops)
+ * @NFTA_BYTEORDER_LEN: length of the data (NLA_U32)
+ * @NFTA_BYTEORDER_SIZE: data size in bytes (NLA_U32: 2 or 4)
+ */
+enum nft_byteorder_attributes {
+ NFTA_BYTEORDER_UNSPEC,
+ NFTA_BYTEORDER_SREG,
+ NFTA_BYTEORDER_DREG,
+ NFTA_BYTEORDER_OP,
+ NFTA_BYTEORDER_LEN,
+ NFTA_BYTEORDER_SIZE,
+ __NFTA_BYTEORDER_MAX
+};
+#define NFTA_BYTEORDER_MAX (__NFTA_BYTEORDER_MAX - 1)
+
+/**
+ * enum nft_cmp_ops - nf_tables relational operator
+ *
+ * @NFT_CMP_EQ: equal
+ * @NFT_CMP_NEQ: not equal
+ * @NFT_CMP_LT: less than
+ * @NFT_CMP_LTE: less than or equal to
+ * @NFT_CMP_GT: greater than
+ * @NFT_CMP_GTE: greater than or equal to
+ */
+enum nft_cmp_ops {
+ NFT_CMP_EQ,
+ NFT_CMP_NEQ,
+ NFT_CMP_LT,
+ NFT_CMP_LTE,
+ NFT_CMP_GT,
+ NFT_CMP_GTE,
+};
+
+/**
+ * enum nft_cmp_attributes - nf_tables cmp expression netlink attributes
+ *
+ * @NFTA_CMP_SREG: source register of data to compare (NLA_U32: nft_registers)
+ * @NFTA_CMP_OP: cmp operation (NLA_U32: nft_cmp_ops)
+ * @NFTA_CMP_DATA: data to compare against (NLA_NESTED: nft_data_attributes)
+ */
+enum nft_cmp_attributes {
+ NFTA_CMP_UNSPEC,
+ NFTA_CMP_SREG,
+ NFTA_CMP_OP,
+ NFTA_CMP_DATA,
+ __NFTA_CMP_MAX
+};
+#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1)
+
+/**
+ * enum nft_range_ops - nf_tables range operator
+ *
+ * @NFT_RANGE_EQ: equal
+ * @NFT_RANGE_NEQ: not equal
+ */
+enum nft_range_ops {
+ NFT_RANGE_EQ,
+ NFT_RANGE_NEQ,
+};
+
+/**
+ * enum nft_range_attributes - nf_tables range expression netlink attributes
+ *
+ * @NFTA_RANGE_SREG: source register of data to compare (NLA_U32: nft_registers)
+ * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_cmp_ops)
+ * @NFTA_RANGE_FROM_DATA: data range from (NLA_NESTED: nft_data_attributes)
+ * @NFTA_RANGE_TO_DATA: data range to (NLA_NESTED: nft_data_attributes)
+ */
+enum nft_range_attributes {
+ NFTA_RANGE_UNSPEC,
+ NFTA_RANGE_SREG,
+ NFTA_RANGE_OP,
+ NFTA_RANGE_FROM_DATA,
+ NFTA_RANGE_TO_DATA,
+ __NFTA_RANGE_MAX
+};
+#define NFTA_RANGE_MAX (__NFTA_RANGE_MAX - 1)
+
+enum nft_lookup_flags {
+ NFT_LOOKUP_F_INV = (1 << 0),
+};
+
+/**
+ * enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes
+ *
+ * @NFTA_LOOKUP_SET: name of the set where to look for (NLA_STRING)
+ * @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers)
+ * @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_LOOKUP_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
+ * @NFTA_LOOKUP_FLAGS: flags (NLA_U32: enum nft_lookup_flags)
+ */
+enum nft_lookup_attributes {
+ NFTA_LOOKUP_UNSPEC,
+ NFTA_LOOKUP_SET,
+ NFTA_LOOKUP_SREG,
+ NFTA_LOOKUP_DREG,
+ NFTA_LOOKUP_SET_ID,
+ NFTA_LOOKUP_FLAGS,
+ __NFTA_LOOKUP_MAX
+};
+#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
+
+enum nft_dynset_ops {
+ NFT_DYNSET_OP_ADD,
+ NFT_DYNSET_OP_UPDATE,
+ NFT_DYNSET_OP_DELETE,
+};
+
+enum nft_dynset_flags {
+ NFT_DYNSET_F_INV = (1 << 0),
+ NFT_DYNSET_F_EXPR = (1 << 1),
+};
+
+/**
+ * enum nft_dynset_attributes - dynset expression attributes
+ *
+ * @NFTA_DYNSET_SET_NAME: name of set the to add data to (NLA_STRING)
+ * @NFTA_DYNSET_SET_ID: uniquely identifier of the set in the transaction (NLA_U32)
+ * @NFTA_DYNSET_OP: operation (NLA_U32)
+ * @NFTA_DYNSET_SREG_KEY: source register of the key (NLA_U32)
+ * @NFTA_DYNSET_SREG_DATA: source register of the data (NLA_U32)
+ * @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
+ * @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_DYNSET_FLAGS: flags (NLA_U32)
+ * @NFTA_DYNSET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
+ */
+enum nft_dynset_attributes {
+ NFTA_DYNSET_UNSPEC,
+ NFTA_DYNSET_SET_NAME,
+ NFTA_DYNSET_SET_ID,
+ NFTA_DYNSET_OP,
+ NFTA_DYNSET_SREG_KEY,
+ NFTA_DYNSET_SREG_DATA,
+ NFTA_DYNSET_TIMEOUT,
+ NFTA_DYNSET_EXPR,
+ NFTA_DYNSET_PAD,
+ NFTA_DYNSET_FLAGS,
+ NFTA_DYNSET_EXPRESSIONS,
+ __NFTA_DYNSET_MAX,
+};
+#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
+
+/**
+ * enum nft_payload_bases - nf_tables payload expression offset bases
+ *
+ * @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,
+};
+
+/**
+ * enum nft_payload_csum_types - nf_tables payload expression checksum types
+ *
+ * @NFT_PAYLOAD_CSUM_NONE: no checksumming
+ * @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791)
+ * @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309)
+ */
+enum nft_payload_csum_types {
+ NFT_PAYLOAD_CSUM_NONE,
+ NFT_PAYLOAD_CSUM_INET,
+ NFT_PAYLOAD_CSUM_SCTP,
+};
+
+enum nft_payload_csum_flags {
+ NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0),
+};
+
+enum nft_inner_type {
+ NFT_INNER_UNSPEC = 0,
+ NFT_INNER_VXLAN,
+ NFT_INNER_GENEVE,
+};
+
+enum nft_inner_flags {
+ NFT_INNER_HDRSIZE = (1 << 0),
+ NFT_INNER_LL = (1 << 1),
+ NFT_INNER_NH = (1 << 2),
+ NFT_INNER_TH = (1 << 3),
+};
+#define NFT_INNER_MASK (NFT_INNER_HDRSIZE | NFT_INNER_LL | \
+ NFT_INNER_NH | NFT_INNER_TH)
+
+enum nft_inner_attributes {
+ NFTA_INNER_UNSPEC,
+ NFTA_INNER_NUM,
+ NFTA_INNER_TYPE,
+ NFTA_INNER_FLAGS,
+ NFTA_INNER_HDRSIZE,
+ NFTA_INNER_EXPR,
+ __NFTA_INNER_MAX
+};
+#define NFTA_INNER_MAX (__NFTA_INNER_MAX - 1)
+
+/**
+ * enum nft_payload_attributes - nf_tables payload expression netlink attributes
+ *
+ * @NFTA_PAYLOAD_DREG: destination register to load data into (NLA_U32: nft_registers)
+ * @NFTA_PAYLOAD_BASE: payload base (NLA_U32: nft_payload_bases)
+ * @NFTA_PAYLOAD_OFFSET: payload offset relative to base (NLA_U32)
+ * @NFTA_PAYLOAD_LEN: payload length (NLA_U32)
+ * @NFTA_PAYLOAD_SREG: source register to load data from (NLA_U32: nft_registers)
+ * @NFTA_PAYLOAD_CSUM_TYPE: checksum type (NLA_U32)
+ * @NFTA_PAYLOAD_CSUM_OFFSET: checksum offset relative to base (NLA_U32)
+ * @NFTA_PAYLOAD_CSUM_FLAGS: checksum flags (NLA_U32)
+ */
+enum nft_payload_attributes {
+ NFTA_PAYLOAD_UNSPEC,
+ NFTA_PAYLOAD_DREG,
+ NFTA_PAYLOAD_BASE,
+ NFTA_PAYLOAD_OFFSET,
+ NFTA_PAYLOAD_LEN,
+ NFTA_PAYLOAD_SREG,
+ NFTA_PAYLOAD_CSUM_TYPE,
+ NFTA_PAYLOAD_CSUM_OFFSET,
+ NFTA_PAYLOAD_CSUM_FLAGS,
+ __NFTA_PAYLOAD_MAX
+};
+#define NFTA_PAYLOAD_MAX (__NFTA_PAYLOAD_MAX - 1)
+
+enum nft_exthdr_flags {
+ NFT_EXTHDR_F_PRESENT = (1 << 0),
+};
+
+/**
+ * enum nft_exthdr_op - nf_tables match options
+ *
+ * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
+ * @NFT_EXTHDR_OP_TCP: match against tcp options
+ * @NFT_EXTHDR_OP_IPV4: match against ipv4 options
+ * @NFT_EXTHDR_OP_SCTP: match against sctp chunks
+ * @NFT_EXTHDR_OP_DCCP: match against dccp options
+ */
+enum nft_exthdr_op {
+ NFT_EXTHDR_OP_IPV6,
+ NFT_EXTHDR_OP_TCPOPT,
+ NFT_EXTHDR_OP_IPV4,
+ NFT_EXTHDR_OP_SCTP,
+ NFT_EXTHDR_OP_DCCP,
+ __NFT_EXTHDR_OP_MAX
+};
+#define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1)
+
+/**
+ * enum nft_exthdr_attributes - nf_tables extension header expression netlink attributes
+ *
+ * @NFTA_EXTHDR_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_EXTHDR_TYPE: extension header type (NLA_U8)
+ * @NFTA_EXTHDR_OFFSET: extension header offset (NLA_U32)
+ * @NFTA_EXTHDR_LEN: extension header length (NLA_U32)
+ * @NFTA_EXTHDR_FLAGS: extension header flags (NLA_U32)
+ * @NFTA_EXTHDR_OP: option match type (NLA_U32)
+ * @NFTA_EXTHDR_SREG: option match type (NLA_U32)
+ */
+enum nft_exthdr_attributes {
+ NFTA_EXTHDR_UNSPEC,
+ NFTA_EXTHDR_DREG,
+ NFTA_EXTHDR_TYPE,
+ NFTA_EXTHDR_OFFSET,
+ NFTA_EXTHDR_LEN,
+ NFTA_EXTHDR_FLAGS,
+ NFTA_EXTHDR_OP,
+ NFTA_EXTHDR_SREG,
+ __NFTA_EXTHDR_MAX
+};
+#define NFTA_EXTHDR_MAX (__NFTA_EXTHDR_MAX - 1)
+
+/**
+ * enum nft_meta_keys - nf_tables meta expression keys
+ *
+ * @NFT_META_LEN: packet length (skb->len)
+ * @NFT_META_PROTOCOL: packet ethertype protocol (skb->protocol), invalid in OUTPUT
+ * @NFT_META_PRIORITY: packet priority (skb->priority)
+ * @NFT_META_MARK: packet mark (skb->mark)
+ * @NFT_META_IIF: packet input interface index (dev->ifindex)
+ * @NFT_META_OIF: packet output interface index (dev->ifindex)
+ * @NFT_META_IIFNAME: packet input interface name (dev->name)
+ * @NFT_META_OIFNAME: packet output interface name (dev->name)
+ * @NFT_META_IIFTYPE: packet input interface type (dev->type)
+ * @NFT_META_OIFTYPE: packet output interface type (dev->type)
+ * @NFT_META_SKUID: originating socket UID (fsuid)
+ * @NFT_META_SKGID: originating socket GID (fsgid)
+ * @NFT_META_NFTRACE: packet nftrace bit
+ * @NFT_META_RTCLASSID: realm value of packet's route (skb->dst->tclassid)
+ * @NFT_META_SECMARK: packet secmark (skb->secmark)
+ * @NFT_META_NFPROTO: netfilter protocol
+ * @NFT_META_L4PROTO: layer 4 protocol number
+ * @NFT_META_BRI_IIFNAME: packet input bridge interface name
+ * @NFT_META_BRI_OIFNAME: packet output bridge interface name
+ * @NFT_META_PKTTYPE: packet type (skb->pkt_type), special handling for loopback
+ * @NFT_META_CPU: cpu id through smp_processor_id()
+ * @NFT_META_IIFGROUP: packet input interface group
+ * @NFT_META_OIFGROUP: packet output interface group
+ * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid)
+ * @NFT_META_PRANDOM: a 32bit pseudo-random number
+ * @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp)
+ * @NFT_META_IIFKIND: packet input interface kind name (dev->rtnl_link_ops->kind)
+ * @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind)
+ * @NFT_META_BRI_IIFPVID: packet input bridge port pvid
+ * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto
+ * @NFT_META_TIME_NS: time since epoch (in nanoseconds)
+ * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday)
+ * @NFT_META_TIME_HOUR: hour of day (in seconds)
+ * @NFT_META_SDIF: slave device interface index
+ * @NFT_META_SDIFNAME: slave device interface name
+ * @NFT_META_BRI_BROUTE: packet br_netfilter_broute bit
+ */
+enum nft_meta_keys {
+ NFT_META_LEN,
+ NFT_META_PROTOCOL,
+ NFT_META_PRIORITY,
+ NFT_META_MARK,
+ NFT_META_IIF,
+ NFT_META_OIF,
+ NFT_META_IIFNAME,
+ NFT_META_OIFNAME,
+ NFT_META_IFTYPE,
+#define NFT_META_IIFTYPE NFT_META_IFTYPE
+ NFT_META_OIFTYPE,
+ NFT_META_SKUID,
+ NFT_META_SKGID,
+ NFT_META_NFTRACE,
+ NFT_META_RTCLASSID,
+ NFT_META_SECMARK,
+ NFT_META_NFPROTO,
+ NFT_META_L4PROTO,
+ NFT_META_BRI_IIFNAME,
+ NFT_META_BRI_OIFNAME,
+ NFT_META_PKTTYPE,
+ NFT_META_CPU,
+ NFT_META_IIFGROUP,
+ NFT_META_OIFGROUP,
+ NFT_META_CGROUP,
+ NFT_META_PRANDOM,
+ NFT_META_SECPATH,
+ NFT_META_IIFKIND,
+ NFT_META_OIFKIND,
+ NFT_META_BRI_IIFPVID,
+ NFT_META_BRI_IIFVPROTO,
+ NFT_META_TIME_NS,
+ NFT_META_TIME_DAY,
+ NFT_META_TIME_HOUR,
+ NFT_META_SDIF,
+ NFT_META_SDIFNAME,
+ NFT_META_BRI_BROUTE,
+ __NFT_META_IIFTYPE,
+};
+
+/**
+ * enum nft_rt_keys - nf_tables routing expression keys
+ *
+ * @NFT_RT_CLASSID: realm value of packet's route (skb->dst->tclassid)
+ * @NFT_RT_NEXTHOP4: routing nexthop for IPv4
+ * @NFT_RT_NEXTHOP6: routing nexthop for IPv6
+ * @NFT_RT_TCPMSS: fetch current path tcp mss
+ * @NFT_RT_XFRM: boolean, skb->dst->xfrm != NULL
+ */
+enum nft_rt_keys {
+ NFT_RT_CLASSID,
+ NFT_RT_NEXTHOP4,
+ NFT_RT_NEXTHOP6,
+ NFT_RT_TCPMSS,
+ NFT_RT_XFRM,
+ __NFT_RT_MAX
+};
+#define NFT_RT_MAX (__NFT_RT_MAX - 1)
+
+/**
+ * enum nft_hash_types - nf_tables hash expression types
+ *
+ * @NFT_HASH_JENKINS: Jenkins Hash
+ * @NFT_HASH_SYM: Symmetric Hash
+ */
+enum nft_hash_types {
+ NFT_HASH_JENKINS,
+ NFT_HASH_SYM,
+};
+
+/**
+ * enum nft_hash_attributes - nf_tables hash expression netlink attributes
+ *
+ * @NFTA_HASH_SREG: source register (NLA_U32)
+ * @NFTA_HASH_DREG: destination register (NLA_U32)
+ * @NFTA_HASH_LEN: source data length (NLA_U32)
+ * @NFTA_HASH_MODULUS: modulus value (NLA_U32)
+ * @NFTA_HASH_SEED: seed value (NLA_U32)
+ * @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
+ * @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types)
+ * @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING)
+ * @NFTA_HASH_SET_ID: id of the map (NLA_U32)
+ */
+enum nft_hash_attributes {
+ NFTA_HASH_UNSPEC,
+ NFTA_HASH_SREG,
+ NFTA_HASH_DREG,
+ NFTA_HASH_LEN,
+ NFTA_HASH_MODULUS,
+ NFTA_HASH_SEED,
+ NFTA_HASH_OFFSET,
+ NFTA_HASH_TYPE,
+ NFTA_HASH_SET_NAME, /* deprecated */
+ NFTA_HASH_SET_ID, /* deprecated */
+ __NFTA_HASH_MAX,
+};
+#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
+
+/**
+ * enum nft_meta_attributes - nf_tables meta expression netlink attributes
+ *
+ * @NFTA_META_DREG: destination register (NLA_U32)
+ * @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys)
+ * @NFTA_META_SREG: source register (NLA_U32)
+ */
+enum nft_meta_attributes {
+ NFTA_META_UNSPEC,
+ NFTA_META_DREG,
+ NFTA_META_KEY,
+ NFTA_META_SREG,
+ __NFTA_META_MAX
+};
+#define NFTA_META_MAX (__NFTA_META_MAX - 1)
+
+/**
+ * enum nft_rt_attributes - nf_tables routing expression netlink attributes
+ *
+ * @NFTA_RT_DREG: destination register (NLA_U32)
+ * @NFTA_RT_KEY: routing data item to load (NLA_U32: nft_rt_keys)
+ */
+enum nft_rt_attributes {
+ NFTA_RT_UNSPEC,
+ NFTA_RT_DREG,
+ NFTA_RT_KEY,
+ __NFTA_RT_MAX
+};
+#define NFTA_RT_MAX (__NFTA_RT_MAX - 1)
+
+/**
+ * enum nft_socket_attributes - nf_tables socket expression netlink attributes
+ *
+ * @NFTA_SOCKET_KEY: socket key to match
+ * @NFTA_SOCKET_DREG: destination register
+ * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
+ */
+enum nft_socket_attributes {
+ NFTA_SOCKET_UNSPEC,
+ NFTA_SOCKET_KEY,
+ NFTA_SOCKET_DREG,
+ NFTA_SOCKET_LEVEL,
+ __NFTA_SOCKET_MAX
+};
+#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
+
+/*
+ * enum nft_socket_keys - nf_tables socket expression keys
+ *
+ * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
+ * @NFT_SOCKET_MARK: Value of the socket mark
+ * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
+ * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
+ */
+enum nft_socket_keys {
+ NFT_SOCKET_TRANSPARENT,
+ NFT_SOCKET_MARK,
+ NFT_SOCKET_WILDCARD,
+ NFT_SOCKET_CGROUPV2,
+ __NFT_SOCKET_MAX
+};
+#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
+
+/**
+ * enum nft_ct_keys - nf_tables ct expression keys
+ *
+ * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info)
+ * @NFT_CT_DIRECTION: conntrack direction (enum ip_conntrack_dir)
+ * @NFT_CT_STATUS: conntrack status (bitmask of enum ip_conntrack_status)
+ * @NFT_CT_MARK: conntrack mark value
+ * @NFT_CT_SECMARK: conntrack secmark value
+ * @NFT_CT_EXPIRATION: relative conntrack expiration time in ms
+ * @NFT_CT_HELPER: connection tracking helper assigned to conntrack
+ * @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol
+ * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address, deprecated)
+ * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address, deprecated)
+ * @NFT_CT_PROTOCOL: conntrack layer 4 protocol
+ * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
+ * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
+ * @NFT_CT_LABELS: conntrack labels
+ * @NFT_CT_PKTS: conntrack packets
+ * @NFT_CT_BYTES: conntrack bytes
+ * @NFT_CT_AVGPKT: conntrack average bytes per packet
+ * @NFT_CT_ZONE: conntrack zone
+ * @NFT_CT_EVENTMASK: ctnetlink events to be generated for this conntrack
+ * @NFT_CT_SRC_IP: conntrack layer 3 protocol source (IPv4 address)
+ * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address)
+ * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address)
+ * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address)
+ * @NFT_CT_ID: conntrack id
+ */
+enum nft_ct_keys {
+ NFT_CT_STATE,
+ NFT_CT_DIRECTION,
+ NFT_CT_STATUS,
+ NFT_CT_MARK,
+ NFT_CT_SECMARK,
+ NFT_CT_EXPIRATION,
+ NFT_CT_HELPER,
+ NFT_CT_L3PROTOCOL,
+ NFT_CT_SRC,
+ NFT_CT_DST,
+ NFT_CT_PROTOCOL,
+ NFT_CT_PROTO_SRC,
+ NFT_CT_PROTO_DST,
+ NFT_CT_LABELS,
+ NFT_CT_PKTS,
+ NFT_CT_BYTES,
+ NFT_CT_AVGPKT,
+ NFT_CT_ZONE,
+ NFT_CT_EVENTMASK,
+ NFT_CT_SRC_IP,
+ NFT_CT_DST_IP,
+ NFT_CT_SRC_IP6,
+ NFT_CT_DST_IP6,
+ NFT_CT_ID,
+ __NFT_CT_MAX
+};
+#define NFT_CT_MAX (__NFT_CT_MAX - 1)
+
+/**
+ * enum nft_ct_attributes - nf_tables ct expression netlink attributes
+ *
+ * @NFTA_CT_DREG: destination register (NLA_U32)
+ * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys)
+ * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8)
+ * @NFTA_CT_SREG: source register (NLA_U32)
+ */
+enum nft_ct_attributes {
+ NFTA_CT_UNSPEC,
+ NFTA_CT_DREG,
+ NFTA_CT_KEY,
+ NFTA_CT_DIRECTION,
+ NFTA_CT_SREG,
+ __NFTA_CT_MAX
+};
+#define NFTA_CT_MAX (__NFTA_CT_MAX - 1)
+
+/**
+ * enum nft_flow_attributes - ct offload expression attributes
+ * @NFTA_FLOW_TABLE_NAME: flow table name (NLA_STRING)
+ */
+enum nft_offload_attributes {
+ NFTA_FLOW_UNSPEC,
+ NFTA_FLOW_TABLE_NAME,
+ __NFTA_FLOW_MAX,
+};
+#define NFTA_FLOW_MAX (__NFTA_FLOW_MAX - 1)
+
+enum nft_limit_type {
+ NFT_LIMIT_PKTS,
+ NFT_LIMIT_PKT_BYTES
+};
+
+enum nft_limit_flags {
+ NFT_LIMIT_F_INV = (1 << 0),
+};
+
+/**
+ * enum nft_limit_attributes - nf_tables limit expression netlink attributes
+ *
+ * @NFTA_LIMIT_RATE: refill rate (NLA_U64)
+ * @NFTA_LIMIT_UNIT: refill unit (NLA_U64)
+ * @NFTA_LIMIT_BURST: burst (NLA_U32)
+ * @NFTA_LIMIT_TYPE: type of limit (NLA_U32: enum nft_limit_type)
+ * @NFTA_LIMIT_FLAGS: flags (NLA_U32: enum nft_limit_flags)
+ */
+enum nft_limit_attributes {
+ NFTA_LIMIT_UNSPEC,
+ NFTA_LIMIT_RATE,
+ NFTA_LIMIT_UNIT,
+ NFTA_LIMIT_BURST,
+ NFTA_LIMIT_TYPE,
+ NFTA_LIMIT_FLAGS,
+ NFTA_LIMIT_PAD,
+ __NFTA_LIMIT_MAX
+};
+#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
+
+enum nft_connlimit_flags {
+ NFT_CONNLIMIT_F_INV = (1 << 0),
+};
+
+/**
+ * enum nft_connlimit_attributes - nf_tables connlimit expression netlink attributes
+ *
+ * @NFTA_CONNLIMIT_COUNT: number of connections (NLA_U32)
+ * @NFTA_CONNLIMIT_FLAGS: flags (NLA_U32: enum nft_connlimit_flags)
+ */
+enum nft_connlimit_attributes {
+ NFTA_CONNLIMIT_UNSPEC,
+ NFTA_CONNLIMIT_COUNT,
+ NFTA_CONNLIMIT_FLAGS,
+ __NFTA_CONNLIMIT_MAX
+};
+#define NFTA_CONNLIMIT_MAX (__NFTA_CONNLIMIT_MAX - 1)
+
+/**
+ * enum nft_counter_attributes - nf_tables counter expression netlink attributes
+ *
+ * @NFTA_COUNTER_BYTES: number of bytes (NLA_U64)
+ * @NFTA_COUNTER_PACKETS: number of packets (NLA_U64)
+ */
+enum nft_counter_attributes {
+ NFTA_COUNTER_UNSPEC,
+ NFTA_COUNTER_BYTES,
+ NFTA_COUNTER_PACKETS,
+ NFTA_COUNTER_PAD,
+ __NFTA_COUNTER_MAX
+};
+#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)
+ * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING)
+ * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32)
+ * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32)
+ * @NFTA_LOG_LEVEL: log level (NLA_U32)
+ * @NFTA_LOG_FLAGS: logging flags (NLA_U32)
+ */
+enum nft_log_attributes {
+ NFTA_LOG_UNSPEC,
+ NFTA_LOG_GROUP,
+ NFTA_LOG_PREFIX,
+ NFTA_LOG_SNAPLEN,
+ NFTA_LOG_QTHRESHOLD,
+ NFTA_LOG_LEVEL,
+ NFTA_LOG_FLAGS,
+ __NFTA_LOG_MAX
+};
+#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1)
+
+/**
+ * enum nft_log_level - nf_tables log levels
+ *
+ * @NFT_LOGLEVEL_EMERG: system is unusable
+ * @NFT_LOGLEVEL_ALERT: action must be taken immediately
+ * @NFT_LOGLEVEL_CRIT: critical conditions
+ * @NFT_LOGLEVEL_ERR: error conditions
+ * @NFT_LOGLEVEL_WARNING: warning conditions
+ * @NFT_LOGLEVEL_NOTICE: normal but significant condition
+ * @NFT_LOGLEVEL_INFO: informational
+ * @NFT_LOGLEVEL_DEBUG: debug-level messages
+ * @NFT_LOGLEVEL_AUDIT: enabling audit logging
+ */
+enum nft_log_level {
+ NFT_LOGLEVEL_EMERG,
+ NFT_LOGLEVEL_ALERT,
+ NFT_LOGLEVEL_CRIT,
+ NFT_LOGLEVEL_ERR,
+ NFT_LOGLEVEL_WARNING,
+ NFT_LOGLEVEL_NOTICE,
+ NFT_LOGLEVEL_INFO,
+ NFT_LOGLEVEL_DEBUG,
+ NFT_LOGLEVEL_AUDIT,
+ __NFT_LOGLEVEL_MAX
+};
+#define NFT_LOGLEVEL_MAX (__NFT_LOGLEVEL_MAX - 1)
+
+/**
+ * enum nft_queue_attributes - nf_tables queue expression netlink attributes
+ *
+ * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16)
+ * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16)
+ * @NFTA_QUEUE_FLAGS: various flags (NLA_U16)
+ * @NFTA_QUEUE_SREG_QNUM: source register of queue number (NLA_U32: nft_registers)
+ */
+enum nft_queue_attributes {
+ NFTA_QUEUE_UNSPEC,
+ NFTA_QUEUE_NUM,
+ NFTA_QUEUE_TOTAL,
+ NFTA_QUEUE_FLAGS,
+ NFTA_QUEUE_SREG_QNUM,
+ __NFTA_QUEUE_MAX
+};
+#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1)
+
+#define NFT_QUEUE_FLAG_BYPASS 0x01 /* for compatibility with v2 */
+#define NFT_QUEUE_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */
+#define NFT_QUEUE_FLAG_MASK 0x03
+
+enum nft_quota_flags {
+ NFT_QUOTA_F_INV = (1 << 0),
+ NFT_QUOTA_F_DEPLETED = (1 << 1),
+};
+
+/**
+ * enum nft_quota_attributes - nf_tables quota expression netlink attributes
+ *
+ * @NFTA_QUOTA_BYTES: quota in bytes (NLA_U16)
+ * @NFTA_QUOTA_FLAGS: flags (NLA_U32)
+ * @NFTA_QUOTA_CONSUMED: quota already consumed in bytes (NLA_U64)
+ */
+enum nft_quota_attributes {
+ NFTA_QUOTA_UNSPEC,
+ NFTA_QUOTA_BYTES,
+ NFTA_QUOTA_FLAGS,
+ NFTA_QUOTA_PAD,
+ NFTA_QUOTA_CONSUMED,
+ __NFTA_QUOTA_MAX
+};
+#define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1)
+
+/**
+ * enum nft_secmark_attributes - nf_tables secmark object netlink attributes
+ *
+ * @NFTA_SECMARK_CTX: security context (NLA_STRING)
+ */
+enum nft_secmark_attributes {
+ NFTA_SECMARK_UNSPEC,
+ NFTA_SECMARK_CTX,
+ __NFTA_SECMARK_MAX,
+};
+#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1)
+
+/* Max security context length */
+#define NFT_SECMARK_CTX_MAXLEN 256
+
+/**
+ * enum nft_reject_types - nf_tables reject expression reject types
+ *
+ * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable
+ * @NFT_REJECT_TCP_RST: reject using TCP RST
+ * @NFT_REJECT_ICMPX_UNREACH: abstracted ICMP unreachable for bridge and inet
+ */
+enum nft_reject_types {
+ NFT_REJECT_ICMP_UNREACH,
+ NFT_REJECT_TCP_RST,
+ NFT_REJECT_ICMPX_UNREACH,
+};
+
+/**
+ * enum nft_reject_code - Generic reject codes for IPv4/IPv6
+ *
+ * @NFT_REJECT_ICMPX_NO_ROUTE: no route to host / network unreachable
+ * @NFT_REJECT_ICMPX_PORT_UNREACH: port unreachable
+ * @NFT_REJECT_ICMPX_HOST_UNREACH: host unreachable
+ * @NFT_REJECT_ICMPX_ADMIN_PROHIBITED: administratively prohibited
+ *
+ * These codes are mapped to real ICMP and ICMPv6 codes.
+ */
+enum nft_reject_inet_code {
+ NFT_REJECT_ICMPX_NO_ROUTE = 0,
+ NFT_REJECT_ICMPX_PORT_UNREACH,
+ NFT_REJECT_ICMPX_HOST_UNREACH,
+ NFT_REJECT_ICMPX_ADMIN_PROHIBITED,
+ __NFT_REJECT_ICMPX_MAX
+};
+#define NFT_REJECT_ICMPX_MAX (__NFT_REJECT_ICMPX_MAX - 1)
+
+/**
+ * enum nft_reject_attributes - nf_tables reject expression netlink attributes
+ *
+ * @NFTA_REJECT_TYPE: packet type to use (NLA_U32: nft_reject_types)
+ * @NFTA_REJECT_ICMP_CODE: ICMP code to use (NLA_U8)
+ */
+enum nft_reject_attributes {
+ NFTA_REJECT_UNSPEC,
+ NFTA_REJECT_TYPE,
+ NFTA_REJECT_ICMP_CODE,
+ __NFTA_REJECT_MAX
+};
+#define NFTA_REJECT_MAX (__NFTA_REJECT_MAX - 1)
+
+/**
+ * enum nft_nat_types - nf_tables nat expression NAT types
+ *
+ * @NFT_NAT_SNAT: source NAT
+ * @NFT_NAT_DNAT: destination NAT
+ */
+enum nft_nat_types {
+ NFT_NAT_SNAT,
+ NFT_NAT_DNAT,
+};
+
+/**
+ * enum nft_nat_attributes - nf_tables nat expression netlink attributes
+ *
+ * @NFTA_NAT_TYPE: NAT type (NLA_U32: nft_nat_types)
+ * @NFTA_NAT_FAMILY: NAT family (NLA_U32)
+ * @NFTA_NAT_REG_ADDR_MIN: source register of address range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers)
+ * @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ * @NFTA_NAT_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
+ */
+enum nft_nat_attributes {
+ NFTA_NAT_UNSPEC,
+ NFTA_NAT_TYPE,
+ NFTA_NAT_FAMILY,
+ NFTA_NAT_REG_ADDR_MIN,
+ NFTA_NAT_REG_ADDR_MAX,
+ NFTA_NAT_REG_PROTO_MIN,
+ NFTA_NAT_REG_PROTO_MAX,
+ NFTA_NAT_FLAGS,
+ __NFTA_NAT_MAX
+};
+#define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1)
+
+/**
+ * enum nft_tproxy_attributes - nf_tables tproxy expression netlink attributes
+ *
+ * NFTA_TPROXY_FAMILY: Target address family (NLA_U32: nft_registers)
+ * NFTA_TPROXY_REG_ADDR: Target address register (NLA_U32: nft_registers)
+ * NFTA_TPROXY_REG_PORT: Target port register (NLA_U32: nft_registers)
+ */
+enum nft_tproxy_attributes {
+ NFTA_TPROXY_UNSPEC,
+ NFTA_TPROXY_FAMILY,
+ NFTA_TPROXY_REG_ADDR,
+ NFTA_TPROXY_REG_PORT,
+ __NFTA_TPROXY_MAX
+};
+#define NFTA_TPROXY_MAX (__NFTA_TPROXY_MAX - 1)
+
+/**
+ * enum nft_masq_attributes - nf_tables masquerade expression attributes
+ *
+ * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
+ * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ */
+enum nft_masq_attributes {
+ NFTA_MASQ_UNSPEC,
+ NFTA_MASQ_FLAGS,
+ NFTA_MASQ_REG_PROTO_MIN,
+ NFTA_MASQ_REG_PROTO_MAX,
+ __NFTA_MASQ_MAX
+};
+#define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1)
+
+/**
+ * enum nft_redir_attributes - nf_tables redirect expression netlink attributes
+ *
+ * @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers)
+ * @NFTA_REDIR_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers)
+ * @NFTA_REDIR_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32)
+ */
+enum nft_redir_attributes {
+ NFTA_REDIR_UNSPEC,
+ NFTA_REDIR_REG_PROTO_MIN,
+ NFTA_REDIR_REG_PROTO_MAX,
+ NFTA_REDIR_FLAGS,
+ __NFTA_REDIR_MAX
+};
+#define NFTA_REDIR_MAX (__NFTA_REDIR_MAX - 1)
+
+/**
+ * enum nft_dup_attributes - nf_tables dup expression netlink attributes
+ *
+ * @NFTA_DUP_SREG_ADDR: source register of address (NLA_U32: nft_registers)
+ * @NFTA_DUP_SREG_DEV: source register of output interface (NLA_U32: nft_register)
+ */
+enum nft_dup_attributes {
+ NFTA_DUP_UNSPEC,
+ NFTA_DUP_SREG_ADDR,
+ NFTA_DUP_SREG_DEV,
+ __NFTA_DUP_MAX
+};
+#define NFTA_DUP_MAX (__NFTA_DUP_MAX - 1)
+
+/**
+ * enum nft_fwd_attributes - nf_tables fwd expression netlink attributes
+ *
+ * @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register)
+ * @NFTA_FWD_SREG_ADDR: source register of destination address (NLA_U32: nft_register)
+ * @NFTA_FWD_NFPROTO: layer 3 family of source register address (NLA_U32: enum nfproto)
+ */
+enum nft_fwd_attributes {
+ NFTA_FWD_UNSPEC,
+ NFTA_FWD_SREG_DEV,
+ NFTA_FWD_SREG_ADDR,
+ NFTA_FWD_NFPROTO,
+ __NFTA_FWD_MAX
+};
+#define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1)
+
+/**
+ * enum nft_objref_attributes - nf_tables stateful object expression netlink attributes
+ *
+ * @NFTA_OBJREF_IMM_TYPE: object type for immediate reference (NLA_U32: nft_register)
+ * @NFTA_OBJREF_IMM_NAME: object name for immediate reference (NLA_STRING)
+ * @NFTA_OBJREF_SET_SREG: source register of the data to look for (NLA_U32: nft_registers)
+ * @NFTA_OBJREF_SET_NAME: name of the set where to look for (NLA_STRING)
+ * @NFTA_OBJREF_SET_ID: id of the set where to look for in this transaction (NLA_U32)
+ */
+enum nft_objref_attributes {
+ NFTA_OBJREF_UNSPEC,
+ NFTA_OBJREF_IMM_TYPE,
+ NFTA_OBJREF_IMM_NAME,
+ NFTA_OBJREF_SET_SREG,
+ NFTA_OBJREF_SET_NAME,
+ NFTA_OBJREF_SET_ID,
+ __NFTA_OBJREF_MAX
+};
+#define NFTA_OBJREF_MAX (__NFTA_OBJREF_MAX - 1)
+
+/**
+ * enum nft_gen_attributes - nf_tables ruleset generation attributes
+ *
+ * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32)
+ */
+enum nft_gen_attributes {
+ NFTA_GEN_UNSPEC,
+ NFTA_GEN_ID,
+ NFTA_GEN_PROC_PID,
+ NFTA_GEN_PROC_NAME,
+ __NFTA_GEN_MAX
+};
+#define NFTA_GEN_MAX (__NFTA_GEN_MAX - 1)
+
+/*
+ * enum nft_fib_attributes - nf_tables fib expression netlink attributes
+ *
+ * @NFTA_FIB_DREG: destination register (NLA_U32)
+ * @NFTA_FIB_RESULT: desired result (NLA_U32)
+ * @NFTA_FIB_FLAGS: flowi fields to initialize when querying the FIB (NLA_U32)
+ *
+ * The FIB expression performs a route lookup according
+ * to the packet data.
+ */
+enum nft_fib_attributes {
+ NFTA_FIB_UNSPEC,
+ NFTA_FIB_DREG,
+ NFTA_FIB_RESULT,
+ NFTA_FIB_FLAGS,
+ __NFTA_FIB_MAX
+};
+#define NFTA_FIB_MAX (__NFTA_FIB_MAX - 1)
+
+enum nft_fib_result {
+ NFT_FIB_RESULT_UNSPEC,
+ NFT_FIB_RESULT_OIF,
+ NFT_FIB_RESULT_OIFNAME,
+ NFT_FIB_RESULT_ADDRTYPE,
+ __NFT_FIB_RESULT_MAX
+};
+#define NFT_FIB_RESULT_MAX (__NFT_FIB_RESULT_MAX - 1)
+
+enum nft_fib_flags {
+ NFTA_FIB_F_SADDR = 1 << 0, /* look up src */
+ NFTA_FIB_F_DADDR = 1 << 1, /* look up dst */
+ NFTA_FIB_F_MARK = 1 << 2, /* use skb->mark */
+ NFTA_FIB_F_IIF = 1 << 3, /* restrict to iif */
+ NFTA_FIB_F_OIF = 1 << 4, /* restrict to oif */
+ NFTA_FIB_F_PRESENT = 1 << 5, /* check existence only */
+};
+
+enum nft_ct_helper_attributes {
+ NFTA_CT_HELPER_UNSPEC,
+ NFTA_CT_HELPER_NAME,
+ NFTA_CT_HELPER_L3PROTO,
+ NFTA_CT_HELPER_L4PROTO,
+ __NFTA_CT_HELPER_MAX,
+};
+#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1)
+
+enum nft_ct_timeout_timeout_attributes {
+ NFTA_CT_TIMEOUT_UNSPEC,
+ NFTA_CT_TIMEOUT_L3PROTO,
+ NFTA_CT_TIMEOUT_L4PROTO,
+ NFTA_CT_TIMEOUT_DATA,
+ __NFTA_CT_TIMEOUT_MAX,
+};
+#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1)
+
+enum nft_ct_expectation_attributes {
+ NFTA_CT_EXPECT_UNSPEC,
+ NFTA_CT_EXPECT_L3PROTO,
+ NFTA_CT_EXPECT_L4PROTO,
+ NFTA_CT_EXPECT_DPORT,
+ NFTA_CT_EXPECT_TIMEOUT,
+ NFTA_CT_EXPECT_SIZE,
+ __NFTA_CT_EXPECT_MAX,
+};
+#define NFTA_CT_EXPECT_MAX (__NFTA_CT_EXPECT_MAX - 1)
+
+#define NFT_OBJECT_UNSPEC 0
+#define NFT_OBJECT_COUNTER 1
+#define NFT_OBJECT_QUOTA 2
+#define NFT_OBJECT_CT_HELPER 3
+#define NFT_OBJECT_LIMIT 4
+#define NFT_OBJECT_CONNLIMIT 5
+#define NFT_OBJECT_TUNNEL 6
+#define NFT_OBJECT_CT_TIMEOUT 7
+#define NFT_OBJECT_SECMARK 8
+#define NFT_OBJECT_CT_EXPECT 9
+#define NFT_OBJECT_SYNPROXY 10
+#define __NFT_OBJECT_MAX 11
+#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
+
+/**
+ * enum nft_object_attributes - nf_tables stateful object netlink attributes
+ *
+ * @NFTA_OBJ_TABLE: name of the table containing the expression (NLA_STRING)
+ * @NFTA_OBJ_NAME: name of this expression type (NLA_STRING)
+ * @NFTA_OBJ_TYPE: stateful object type (NLA_U32)
+ * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
+ * @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
+ * @NFTA_OBJ_HANDLE: object handle (NLA_U64)
+ * @NFTA_OBJ_USERDATA: user data (NLA_BINARY)
+ */
+enum nft_object_attributes {
+ NFTA_OBJ_UNSPEC,
+ NFTA_OBJ_TABLE,
+ NFTA_OBJ_NAME,
+ NFTA_OBJ_TYPE,
+ NFTA_OBJ_DATA,
+ NFTA_OBJ_USE,
+ NFTA_OBJ_HANDLE,
+ NFTA_OBJ_PAD,
+ NFTA_OBJ_USERDATA,
+ __NFTA_OBJ_MAX
+};
+#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
+
+/**
+ * enum nft_flowtable_flags - nf_tables flowtable flags
+ *
+ * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled
+ * @NFT_FLOWTABLE_COUNTER: enable flow counters
+ */
+enum nft_flowtable_flags {
+ NFT_FLOWTABLE_HW_OFFLOAD = 0x1,
+ NFT_FLOWTABLE_COUNTER = 0x2,
+ NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD |
+ NFT_FLOWTABLE_COUNTER)
+};
+
+/**
+ * enum nft_flowtable_attributes - nf_tables flow table netlink attributes
+ *
+ * @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
+ * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
+ * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
+ * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
+ * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
+ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
+ */
+enum nft_flowtable_attributes {
+ NFTA_FLOWTABLE_UNSPEC,
+ NFTA_FLOWTABLE_TABLE,
+ NFTA_FLOWTABLE_NAME,
+ NFTA_FLOWTABLE_HOOK,
+ NFTA_FLOWTABLE_USE,
+ NFTA_FLOWTABLE_HANDLE,
+ NFTA_FLOWTABLE_PAD,
+ NFTA_FLOWTABLE_FLAGS,
+ __NFTA_FLOWTABLE_MAX
+};
+#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
+
+/**
+ * enum nft_flowtable_hook_attributes - nf_tables flow table hook netlink attributes
+ *
+ * @NFTA_FLOWTABLE_HOOK_NUM: netfilter hook number (NLA_U32)
+ * @NFTA_FLOWTABLE_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ * @NFTA_FLOWTABLE_HOOK_DEVS: input devices this flow table is bound to (NLA_NESTED)
+ */
+enum nft_flowtable_hook_attributes {
+ NFTA_FLOWTABLE_HOOK_UNSPEC,
+ NFTA_FLOWTABLE_HOOK_NUM,
+ NFTA_FLOWTABLE_HOOK_PRIORITY,
+ NFTA_FLOWTABLE_HOOK_DEVS,
+ __NFTA_FLOWTABLE_HOOK_MAX
+};
+#define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1)
+
+/**
+ * enum nft_osf_attributes - nftables osf expression netlink attributes
+ *
+ * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8)
+ * @NFTA_OSF_FLAGS: flags (NLA_U32)
+ */
+enum nft_osf_attributes {
+ NFTA_OSF_UNSPEC,
+ NFTA_OSF_DREG,
+ NFTA_OSF_TTL,
+ NFTA_OSF_FLAGS,
+ __NFTA_OSF_MAX,
+};
+#define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
+
+enum nft_osf_flags {
+ NFT_OSF_F_VERSION = (1 << 0),
+};
+
+/**
+ * enum nft_synproxy_attributes - nf_tables synproxy expression netlink attributes
+ *
+ * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
+ * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
+ * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
+ */
+enum nft_synproxy_attributes {
+ NFTA_SYNPROXY_UNSPEC,
+ NFTA_SYNPROXY_MSS,
+ NFTA_SYNPROXY_WSCALE,
+ NFTA_SYNPROXY_FLAGS,
+ __NFTA_SYNPROXY_MAX,
+};
+#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
+
+/**
+ * enum nft_device_attributes - nf_tables device netlink attributes
+ *
+ * @NFTA_DEVICE_NAME: name of this device (NLA_STRING)
+ */
+enum nft_devices_attributes {
+ NFTA_DEVICE_UNSPEC,
+ NFTA_DEVICE_NAME,
+ __NFTA_DEVICE_MAX
+};
+#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
+
+/*
+ * enum nft_xfrm_attributes - nf_tables xfrm expr netlink attributes
+ *
+ * @NFTA_XFRM_DREG: destination register (NLA_U32)
+ * @NFTA_XFRM_KEY: enum nft_xfrm_keys (NLA_U32)
+ * @NFTA_XFRM_DIR: direction (NLA_U8)
+ * @NFTA_XFRM_SPNUM: index in secpath array (NLA_U32)
+ */
+enum nft_xfrm_attributes {
+ NFTA_XFRM_UNSPEC,
+ NFTA_XFRM_DREG,
+ NFTA_XFRM_KEY,
+ NFTA_XFRM_DIR,
+ NFTA_XFRM_SPNUM,
+ __NFTA_XFRM_MAX
+};
+#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1)
+
+enum nft_xfrm_keys {
+ NFT_XFRM_KEY_UNSPEC,
+ NFT_XFRM_KEY_DADDR_IP4,
+ NFT_XFRM_KEY_DADDR_IP6,
+ NFT_XFRM_KEY_SADDR_IP4,
+ NFT_XFRM_KEY_SADDR_IP6,
+ NFT_XFRM_KEY_REQID,
+ NFT_XFRM_KEY_SPI,
+ __NFT_XFRM_KEY_MAX,
+};
+#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1)
+
+/**
+ * enum nft_trace_attributes - nf_tables trace netlink attributes
+ *
+ * @NFTA_TRACE_TABLE: name of the table (NLA_STRING)
+ * @NFTA_TRACE_CHAIN: name of the chain (NLA_STRING)
+ * @NFTA_TRACE_RULE_HANDLE: numeric handle of the rule (NLA_U64)
+ * @NFTA_TRACE_TYPE: type of the event (NLA_U32: nft_trace_types)
+ * @NFTA_TRACE_VERDICT: verdict returned by hook (NLA_NESTED: nft_verdicts)
+ * @NFTA_TRACE_ID: pseudo-id, same for each skb traced (NLA_U32)
+ * @NFTA_TRACE_LL_HEADER: linklayer header (NLA_BINARY)
+ * @NFTA_TRACE_NETWORK_HEADER: network header (NLA_BINARY)
+ * @NFTA_TRACE_TRANSPORT_HEADER: transport header (NLA_BINARY)
+ * @NFTA_TRACE_IIF: indev ifindex (NLA_U32)
+ * @NFTA_TRACE_IIFTYPE: netdev->type of indev (NLA_U16)
+ * @NFTA_TRACE_OIF: outdev ifindex (NLA_U32)
+ * @NFTA_TRACE_OIFTYPE: netdev->type of outdev (NLA_U16)
+ * @NFTA_TRACE_MARK: nfmark (NLA_U32)
+ * @NFTA_TRACE_NFPROTO: nf protocol processed (NLA_U32)
+ * @NFTA_TRACE_POLICY: policy that decided fate of packet (NLA_U32)
+ */
+enum nft_trace_attributes {
+ NFTA_TRACE_UNSPEC,
+ NFTA_TRACE_TABLE,
+ NFTA_TRACE_CHAIN,
+ NFTA_TRACE_RULE_HANDLE,
+ NFTA_TRACE_TYPE,
+ NFTA_TRACE_VERDICT,
+ NFTA_TRACE_ID,
+ NFTA_TRACE_LL_HEADER,
+ NFTA_TRACE_NETWORK_HEADER,
+ NFTA_TRACE_TRANSPORT_HEADER,
+ NFTA_TRACE_IIF,
+ NFTA_TRACE_IIFTYPE,
+ NFTA_TRACE_OIF,
+ NFTA_TRACE_OIFTYPE,
+ NFTA_TRACE_MARK,
+ NFTA_TRACE_NFPROTO,
+ NFTA_TRACE_POLICY,
+ NFTA_TRACE_PAD,
+ __NFTA_TRACE_MAX
+};
+#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1)
+
+enum nft_trace_types {
+ NFT_TRACETYPE_UNSPEC,
+ NFT_TRACETYPE_POLICY,
+ NFT_TRACETYPE_RETURN,
+ NFT_TRACETYPE_RULE,
+ __NFT_TRACETYPE_MAX
+};
+#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1)
+
+/**
+ * enum nft_ng_attributes - nf_tables number generator expression netlink attributes
+ *
+ * @NFTA_NG_DREG: destination register (NLA_U32)
+ * @NFTA_NG_MODULUS: maximum counter value (NLA_U32)
+ * @NFTA_NG_TYPE: operation type (NLA_U32)
+ * @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32)
+ * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING)
+ * @NFTA_NG_SET_ID: id of the map (NLA_U32)
+ */
+enum nft_ng_attributes {
+ NFTA_NG_UNSPEC,
+ NFTA_NG_DREG,
+ NFTA_NG_MODULUS,
+ NFTA_NG_TYPE,
+ NFTA_NG_OFFSET,
+ NFTA_NG_SET_NAME, /* deprecated */
+ NFTA_NG_SET_ID, /* deprecated */
+ __NFTA_NG_MAX
+};
+#define NFTA_NG_MAX (__NFTA_NG_MAX - 1)
+
+enum nft_ng_types {
+ NFT_NG_INCREMENTAL,
+ NFT_NG_RANDOM,
+ __NFT_NG_MAX
+};
+#define NFT_NG_MAX (__NFT_NG_MAX - 1)
+
+enum nft_tunnel_key_ip_attributes {
+ NFTA_TUNNEL_KEY_IP_UNSPEC,
+ NFTA_TUNNEL_KEY_IP_SRC,
+ NFTA_TUNNEL_KEY_IP_DST,
+ __NFTA_TUNNEL_KEY_IP_MAX
+};
+#define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1)
+
+enum nft_tunnel_ip6_attributes {
+ NFTA_TUNNEL_KEY_IP6_UNSPEC,
+ NFTA_TUNNEL_KEY_IP6_SRC,
+ NFTA_TUNNEL_KEY_IP6_DST,
+ NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
+ __NFTA_TUNNEL_KEY_IP6_MAX
+};
+#define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1)
+
+enum nft_tunnel_opts_attributes {
+ NFTA_TUNNEL_KEY_OPTS_UNSPEC,
+ NFTA_TUNNEL_KEY_OPTS_VXLAN,
+ NFTA_TUNNEL_KEY_OPTS_ERSPAN,
+ NFTA_TUNNEL_KEY_OPTS_GENEVE,
+ __NFTA_TUNNEL_KEY_OPTS_MAX
+};
+#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
+
+enum nft_tunnel_opts_vxlan_attributes {
+ NFTA_TUNNEL_KEY_VXLAN_UNSPEC,
+ NFTA_TUNNEL_KEY_VXLAN_GBP,
+ __NFTA_TUNNEL_KEY_VXLAN_MAX
+};
+#define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1)
+
+enum nft_tunnel_opts_erspan_attributes {
+ NFTA_TUNNEL_KEY_ERSPAN_UNSPEC,
+ NFTA_TUNNEL_KEY_ERSPAN_VERSION,
+ NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
+ NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
+ NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
+ __NFTA_TUNNEL_KEY_ERSPAN_MAX
+};
+#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
+
+enum nft_tunnel_opts_geneve_attributes {
+ NFTA_TUNNEL_KEY_GENEVE_UNSPEC,
+ NFTA_TUNNEL_KEY_GENEVE_CLASS,
+ NFTA_TUNNEL_KEY_GENEVE_TYPE,
+ NFTA_TUNNEL_KEY_GENEVE_DATA,
+ __NFTA_TUNNEL_KEY_GENEVE_MAX
+};
+#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1)
+
+enum nft_tunnel_flags {
+ NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0),
+ NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1),
+ NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2),
+};
+#define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \
+ NFT_TUNNEL_F_DONT_FRAGMENT | \
+ NFT_TUNNEL_F_SEQ_NUMBER)
+
+enum nft_tunnel_key_attributes {
+ NFTA_TUNNEL_KEY_UNSPEC,
+ NFTA_TUNNEL_KEY_ID,
+ NFTA_TUNNEL_KEY_IP,
+ NFTA_TUNNEL_KEY_IP6,
+ NFTA_TUNNEL_KEY_FLAGS,
+ NFTA_TUNNEL_KEY_TOS,
+ NFTA_TUNNEL_KEY_TTL,
+ NFTA_TUNNEL_KEY_SPORT,
+ NFTA_TUNNEL_KEY_DPORT,
+ NFTA_TUNNEL_KEY_OPTS,
+ __NFTA_TUNNEL_KEY_MAX
+};
+#define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1)
+
+enum nft_tunnel_keys {
+ NFT_TUNNEL_PATH,
+ NFT_TUNNEL_ID,
+ __NFT_TUNNEL_MAX
+};
+#define NFT_TUNNEL_MAX (__NFT_TUNNEL_MAX - 1)
+
+enum nft_tunnel_mode {
+ NFT_TUNNEL_MODE_NONE,
+ NFT_TUNNEL_MODE_RX,
+ NFT_TUNNEL_MODE_TX,
+ __NFT_TUNNEL_MODE_MAX
+};
+#define NFT_TUNNEL_MODE_MAX (__NFT_TUNNEL_MODE_MAX - 1)
+
+enum nft_tunnel_attributes {
+ NFTA_TUNNEL_UNSPEC,
+ NFTA_TUNNEL_KEY,
+ NFTA_TUNNEL_DREG,
+ NFTA_TUNNEL_MODE,
+ __NFTA_TUNNEL_MAX
+};
+#define NFTA_TUNNEL_MAX (__NFTA_TUNNEL_MAX - 1)
+
+#endif /* _LINUX_NF_TABLES_H */
diff --git a/include/linux/netfilter/nf_tables_compat.h b/include/linux/netfilter/nf_tables_compat.h
new file mode 100644
index 0000000..8310f5f
--- /dev/null
+++ b/include/linux/netfilter/nf_tables_compat.h
@@ -0,0 +1,38 @@
+#ifndef _NFT_COMPAT_NFNETLINK_H_
+#define _NFT_COMPAT_NFNETLINK_H_
+
+enum nft_target_attributes {
+ NFTA_TARGET_UNSPEC,
+ NFTA_TARGET_NAME,
+ NFTA_TARGET_REV,
+ NFTA_TARGET_INFO,
+ __NFTA_TARGET_MAX
+};
+#define NFTA_TARGET_MAX (__NFTA_TARGET_MAX - 1)
+
+enum nft_match_attributes {
+ NFTA_MATCH_UNSPEC,
+ NFTA_MATCH_NAME,
+ NFTA_MATCH_REV,
+ NFTA_MATCH_INFO,
+ __NFTA_MATCH_MAX
+};
+#define NFTA_MATCH_MAX (__NFTA_MATCH_MAX - 1)
+
+#define NFT_COMPAT_NAME_MAX 32
+
+enum {
+ NFNL_MSG_COMPAT_GET,
+ NFNL_MSG_COMPAT_MAX
+};
+
+enum {
+ NFTA_COMPAT_UNSPEC = 0,
+ NFTA_COMPAT_NAME,
+ NFTA_COMPAT_REV,
+ NFTA_COMPAT_TYPE,
+ __NFTA_COMPAT_MAX,
+};
+#define NFTA_COMPAT_MAX (__NFTA_COMPAT_MAX - 1)
+
+#endif
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
new file mode 100644
index 0000000..49e2b2c
--- /dev/null
+++ b/include/linux/netfilter/nfnetlink.h
@@ -0,0 +1,69 @@
+#ifndef _NFNETLINK_H
+#define _NFNETLINK_H
+#include <linux/types.h>
+#include <linux/netfilter/nfnetlink_compat.h>
+
+enum nfnetlink_groups {
+ NFNLGRP_NONE,
+#define NFNLGRP_NONE NFNLGRP_NONE
+ NFNLGRP_CONNTRACK_NEW,
+#define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW
+ NFNLGRP_CONNTRACK_UPDATE,
+#define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE
+ NFNLGRP_CONNTRACK_DESTROY,
+#define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY
+ NFNLGRP_CONNTRACK_EXP_NEW,
+#define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW
+ NFNLGRP_CONNTRACK_EXP_UPDATE,
+#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE
+ NFNLGRP_CONNTRACK_EXP_DESTROY,
+#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
+ NFNLGRP_NFTABLES,
+#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
+ NFNLGRP_ACCT_QUOTA,
+#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA
+ NFNLGRP_NFTRACE,
+#define NFNLGRP_NFTRACE NFNLGRP_NFTRACE
+ __NFNLGRP_MAX,
+};
+#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
+
+/* General form of address family dependent message.
+ */
+struct nfgenmsg {
+ __u8 nfgen_family; /* AF_xxx */
+ __u8 version; /* nfnetlink version */
+ __be16 res_id; /* resource id */
+};
+
+#define NFNETLINK_V0 0
+
+/* netfilter netlink message types are split in two pieces:
+ * 8 bit subsystem, 8bit operation.
+ */
+
+#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
+#define NFNL_MSG_TYPE(x) (x & 0x00ff)
+
+/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
+ * won't work anymore */
+#define NFNL_SUBSYS_NONE 0
+#define NFNL_SUBSYS_CTNETLINK 1
+#define NFNL_SUBSYS_CTNETLINK_EXP 2
+#define NFNL_SUBSYS_QUEUE 3
+#define NFNL_SUBSYS_ULOG 4
+#define NFNL_SUBSYS_OSF 5
+#define NFNL_SUBSYS_IPSET 6
+#define NFNL_SUBSYS_ACCT 7
+#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
+#define NFNL_SUBSYS_CTHELPER 9
+#define NFNL_SUBSYS_NFTABLES 10
+#define NFNL_SUBSYS_NFT_COMPAT 11
+#define NFNL_SUBSYS_HOOK 12
+#define NFNL_SUBSYS_COUNT 13
+
+/* Reserved control nfnetlink messages */
+#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
+#define NFNL_MSG_BATCH_END NLMSG_MIN_TYPE+1
+
+#endif /* _NFNETLINK_H */
diff --git a/include/linux/netfilter/nfnetlink_hook.h b/include/linux/netfilter/nfnetlink_hook.h
new file mode 100644
index 0000000..84a561a
--- /dev/null
+++ b/include/linux/netfilter/nfnetlink_hook.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NFNL_HOOK_H_
+#define _NFNL_HOOK_H_
+
+enum nfnl_hook_msg_types {
+ NFNL_MSG_HOOK_GET,
+ NFNL_MSG_HOOK_MAX,
+};
+
+/**
+ * enum nfnl_hook_attributes - netfilter hook netlink attributes
+ *
+ * @NFNLA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
+ * @NFNLA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ * @NFNLA_HOOK_DEV: netdevice name (NLA_STRING)
+ * @NFNLA_HOOK_FUNCTION_NAME: hook function name (NLA_STRING)
+ * @NFNLA_HOOK_MODULE_NAME: kernel module that registered this hook (NLA_STRING)
+ * @NFNLA_HOOK_CHAIN_INFO: basechain hook metadata (NLA_NESTED)
+ */
+enum nfnl_hook_attributes {
+ NFNLA_HOOK_UNSPEC,
+ NFNLA_HOOK_HOOKNUM,
+ NFNLA_HOOK_PRIORITY,
+ NFNLA_HOOK_DEV,
+ NFNLA_HOOK_FUNCTION_NAME,
+ NFNLA_HOOK_MODULE_NAME,
+ NFNLA_HOOK_CHAIN_INFO,
+ __NFNLA_HOOK_MAX
+};
+#define NFNLA_HOOK_MAX (__NFNLA_HOOK_MAX - 1)
+
+/**
+ * enum nfnl_hook_chain_info_attributes - chain description
+ *
+ * @NFNLA_HOOK_INFO_DESC: nft chain and table name (NLA_NESTED)
+ * @NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32)
+ *
+ * NFNLA_HOOK_INFO_DESC depends on NFNLA_HOOK_INFO_TYPE value:
+ * NFNL_HOOK_TYPE_NFTABLES: enum nft_table_attributes
+ * NFNL_HOOK_TYPE_BPF: enum nfnl_hook_bpf_attributes
+ */
+enum nfnl_hook_chain_info_attributes {
+ NFNLA_HOOK_INFO_UNSPEC,
+ NFNLA_HOOK_INFO_DESC,
+ NFNLA_HOOK_INFO_TYPE,
+ __NFNLA_HOOK_INFO_MAX,
+};
+#define NFNLA_HOOK_INFO_MAX (__NFNLA_HOOK_INFO_MAX - 1)
+
+enum nfnl_hook_chain_desc_attributes {
+ NFNLA_CHAIN_UNSPEC,
+ NFNLA_CHAIN_TABLE,
+ NFNLA_CHAIN_FAMILY,
+ NFNLA_CHAIN_NAME,
+ __NFNLA_CHAIN_MAX,
+};
+#define NFNLA_CHAIN_MAX (__NFNLA_CHAIN_MAX - 1)
+
+/**
+ * enum nfnl_hook_chaintype - chain type
+ *
+ * @NFNL_HOOK_TYPE_NFTABLES: nf_tables base chain
+ * @NFNL_HOOK_TYPE_BPF: bpf program
+ */
+enum nfnl_hook_chaintype {
+ NFNL_HOOK_TYPE_NFTABLES = 0x1,
+ NFNL_HOOK_TYPE_BPF,
+};
+
+/**
+ * enum nfnl_hook_bpf_attributes - bpf prog description
+ *
+ * @NFNLA_HOOK_BPF_ID: bpf program id (NLA_U32)
+ */
+enum nfnl_hook_bpf_attributes {
+ NFNLA_HOOK_BPF_UNSPEC,
+ NFNLA_HOOK_BPF_ID,
+ __NFNLA_HOOK_BPF_MAX,
+};
+#define NFNLA_HOOK_BPF_MAX (__NFNLA_HOOK_BPF_MAX - 1)
+
+#endif /* _NFNL_HOOK_H */
diff --git a/include/linux/netfilter/nfnetlink_osf.h b/include/linux/netfilter/nfnetlink_osf.h
new file mode 100644
index 0000000..15a39d2
--- /dev/null
+++ b/include/linux/netfilter/nfnetlink_osf.h
@@ -0,0 +1,119 @@
+#ifndef _NF_OSF_H
+#define _NF_OSF_H
+
+#include <linux/types.h>
+
+#define MAXGENRELEN 32
+
+#define NF_OSF_GENRE (1 << 0)
+#define NF_OSF_TTL (1 << 1)
+#define NF_OSF_LOG (1 << 2)
+#define NF_OSF_INVERT (1 << 3)
+
+#define NF_OSF_LOGLEVEL_ALL 0 /* log all matched fingerprints */
+#define NF_OSF_LOGLEVEL_FIRST 1 /* log only the first matced fingerprint */
+#define NF_OSF_LOGLEVEL_ALL_KNOWN 2 /* do not log unknown packets */
+
+#define NF_OSF_TTL_TRUE 0 /* True ip and fingerprint TTL comparison */
+
+/* Check if ip TTL is less than fingerprint one */
+#define NF_OSF_TTL_LESS 1
+
+/* Do not compare ip and fingerprint TTL at all */
+#define NF_OSF_TTL_NOCHECK 2
+
+#define NF_OSF_FLAGMASK (NF_OSF_GENRE | NF_OSF_TTL | \
+ NF_OSF_LOG | NF_OSF_INVERT)
+/* Wildcard MSS (kind of).
+ * It is used to implement a state machine for the different wildcard values
+ * of the MSS and window sizes.
+ */
+struct nf_osf_wc {
+ __u32 wc;
+ __u32 val;
+};
+
+/* This struct represents IANA options
+ * http://www.iana.org/assignments/tcp-parameters
+ */
+struct nf_osf_opt {
+ __u16 kind, length;
+ struct nf_osf_wc wc;
+};
+
+struct nf_osf_info {
+ char genre[MAXGENRELEN];
+ __u32 len;
+ __u32 flags;
+ __u32 loglevel;
+ __u32 ttl;
+};
+
+struct nf_osf_user_finger {
+ struct nf_osf_wc wss;
+
+ __u8 ttl, df;
+ __u16 ss, mss;
+ __u16 opt_num;
+
+ char genre[MAXGENRELEN];
+ char version[MAXGENRELEN];
+ char subtype[MAXGENRELEN];
+
+ /* MAX_IPOPTLEN is maximum if all options are NOPs or EOLs */
+ struct nf_osf_opt opt[MAX_IPOPTLEN];
+};
+
+struct nf_osf_nlmsg {
+ struct nf_osf_user_finger f;
+ struct iphdr ip;
+ struct tcphdr tcp;
+};
+
+/* Defines for IANA option kinds */
+enum iana_options {
+ OSFOPT_EOL = 0, /* End of options */
+ OSFOPT_NOP, /* NOP */
+ OSFOPT_MSS, /* Maximum segment size */
+ OSFOPT_WSO, /* Window scale option */
+ OSFOPT_SACKP, /* SACK permitted */
+ OSFOPT_SACK, /* SACK */
+ OSFOPT_ECHO,
+ OSFOPT_ECHOREPLY,
+ OSFOPT_TS, /* Timestamp option */
+ OSFOPT_POCP, /* Partial Order Connection Permitted */
+ OSFOPT_POSP, /* Partial Order Service Profile */
+
+ /* Others are not used in the current OSF */
+ OSFOPT_EMPTY = 255,
+};
+
+/*
+ * Initial window size option state machine: multiple of mss, mtu or
+ * plain numeric value. Can also be made as plain numeric value which
+ * is not a multiple of specified value.
+ */
+enum nf_osf_window_size_options {
+ OSF_WSS_PLAIN = 0,
+ OSF_WSS_MSS,
+ OSF_WSS_MTU,
+ OSF_WSS_MODULO,
+ OSF_WSS_MAX,
+};
+
+enum nf_osf_attr_type {
+ OSF_ATTR_UNSPEC,
+ OSF_ATTR_FINGER,
+ OSF_ATTR_MAX,
+};
+
+/*
+ * Add/remove fingerprint from the kernel.
+ */
+enum nf_osf_msg_types {
+ OSF_MSG_ADD,
+ OSF_MSG_REMOVE,
+ OSF_MSG_MAX,
+};
+
+#endif /* _NF_OSF_H */
diff --git a/include/linux/netfilter_arp.h b/include/linux/netfilter_arp.h
new file mode 100644
index 0000000..92bc6dd
--- /dev/null
+++ b/include/linux/netfilter_arp.h
@@ -0,0 +1,19 @@
+#ifndef __LINUX_ARP_NETFILTER_H
+#define __LINUX_ARP_NETFILTER_H
+
+/* ARP-specific defines for netfilter.
+ * (C)2002 Rusty Russell IBM -- This code is GPL.
+ */
+
+#include <linux/netfilter.h>
+
+/* There is no PF_ARP. */
+#define NF_ARP 0
+
+/* ARP Hooks */
+#define NF_ARP_IN 0
+#define NF_ARP_OUT 1
+#define NF_ARP_FORWARD 2
+#define NF_ARP_NUMHOOKS 3
+
+#endif /* __LINUX_ARP_NETFILTER_H */
diff --git a/include/linux/netfilter_arp/Makefile.am b/include/linux/netfilter_arp/Makefile.am
new file mode 100644
index 0000000..0a16c1a
--- /dev/null
+++ b/include/linux/netfilter_arp/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = arp_tables.h
diff --git a/include/linux/netfilter_arp/Makefile.in b/include/linux/netfilter_arp/Makefile.in
new file mode 100644
index 0000000..514df65
--- /dev/null
+++ b/include/linux/netfilter_arp/Makefile.in
@@ -0,0 +1,523 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/linux/netfilter_arp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = arp_tables.h
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/linux/netfilter_arp/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/linux/netfilter_arp/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
new file mode 100644
index 0000000..bb1ec64
--- /dev/null
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -0,0 +1,204 @@
+/*
+ * Format of an ARP firewall descriptor
+ *
+ * src, tgt, src_mask, tgt_mask, arpop, arpop_mask are always stored in
+ * network byte order.
+ * flags are stored in host byte order (of course).
+ */
+
+#ifndef _ARPTABLES_H
+#define _ARPTABLES_H
+
+#include <linux/types.h>
+
+#include <linux/netfilter_arp.h>
+
+#include <linux/netfilter/x_tables.h>
+
+#define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define arpt_entry_target xt_entry_target
+#define arpt_standard_target xt_standard_target
+#define arpt_error_target xt_error_target
+#define ARPT_CONTINUE XT_CONTINUE
+#define ARPT_RETURN XT_RETURN
+#define arpt_counters_info xt_counters_info
+#define arpt_counters xt_counters
+#define ARPT_STANDARD_TARGET XT_STANDARD_TARGET
+#define ARPT_ERROR_TARGET XT_ERROR_TARGET
+#define ARPT_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct arpt_entry, entries, size, fn, ## args)
+
+#define ARPT_DEV_ADDR_LEN_MAX 16
+
+struct arpt_devaddr_info {
+ char addr[ARPT_DEV_ADDR_LEN_MAX];
+ char mask[ARPT_DEV_ADDR_LEN_MAX];
+};
+
+/* Yes, Virginia, you have to zero the padding. */
+struct arpt_arp {
+ /* Source and target IP addr */
+ struct in_addr src, tgt;
+ /* Mask for src and target IP addr */
+ struct in_addr smsk, tmsk;
+
+ /* Device hw address length, src+target device addresses */
+ __u8 arhln, arhln_mask;
+ struct arpt_devaddr_info src_devaddr;
+ struct arpt_devaddr_info tgt_devaddr;
+
+ /* ARP operation code. */
+ __be16 arpop, arpop_mask;
+
+ /* ARP hardware address and protocol address format. */
+ __be16 arhrd, arhrd_mask;
+ __be16 arpro, arpro_mask;
+
+ /* The protocol address length is only accepted if it is 4
+ * so there is no use in offering a way to do filtering on it.
+ */
+
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+
+ /* Flags word */
+ __u8 flags;
+ /* Inverse flags */
+ __u16 invflags;
+};
+
+/* Values for "flag" field in struct arpt_ip (general arp structure).
+ * No flags defined yet.
+ */
+#define ARPT_F_MASK 0x00 /* All possible flag bits mask. */
+
+/* Values for "inv" field in struct arpt_arp. */
+#define ARPT_INV_VIA_IN 0x0001 /* Invert the sense of IN IFACE. */
+#define ARPT_INV_VIA_OUT 0x0002 /* Invert the sense of OUT IFACE */
+#define ARPT_INV_SRCIP 0x0004 /* Invert the sense of SRC IP. */
+#define ARPT_INV_TGTIP 0x0008 /* Invert the sense of TGT IP. */
+#define ARPT_INV_SRCDEVADDR 0x0010 /* Invert the sense of SRC DEV ADDR. */
+#define ARPT_INV_TGTDEVADDR 0x0020 /* Invert the sense of TGT DEV ADDR. */
+#define ARPT_INV_ARPOP 0x0040 /* Invert the sense of ARP OP. */
+#define ARPT_INV_ARPHRD 0x0080 /* Invert the sense of ARP HRD. */
+#define ARPT_INV_ARPPRO 0x0100 /* Invert the sense of ARP PRO. */
+#define ARPT_INV_ARPHLN 0x0200 /* Invert the sense of ARP HLN. */
+#define ARPT_INV_MASK 0x03FF /* All possible flag bits mask. */
+
+/* This structure defines each of the firewall rules. Consists of 3
+ parts which are 1) general ARP header stuff 2) match specific
+ stuff 3) the target to perform if the rule matches */
+struct arpt_entry
+{
+ struct arpt_arp arp;
+
+ /* Size of arpt_entry + matches */
+ __u16 target_offset;
+ /* Size of arpt_entry + matches + target */
+ __u16 next_offset;
+
+ /* Back pointer */
+ unsigned int comefrom;
+
+ /* Packet and byte counters. */
+ struct xt_counters counters;
+
+ /* The matches (if any), then the target. */
+ unsigned char elems[0];
+};
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use a raw
+ * socket for this. Instead we check rights in the calls.
+ *
+ * ATTENTION: check linux/in.h before adding new number here.
+ */
+#define ARPT_BASE_CTL 96
+
+#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
+#define ARPT_SO_SET_ADD_COUNTERS (ARPT_BASE_CTL + 1)
+#define ARPT_SO_SET_MAX ARPT_SO_SET_ADD_COUNTERS
+
+#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
+#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
+/* #define ARPT_SO_GET_REVISION_MATCH (APRT_BASE_CTL + 2) */
+#define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3)
+#define ARPT_SO_GET_MAX (ARPT_SO_GET_REVISION_TARGET)
+
+/* The argument to ARPT_SO_GET_INFO */
+struct arpt_getinfo {
+ /* Which table: caller fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Kernel fills these in. */
+ /* Which hook entry points are valid: bitmask */
+ unsigned int valid_hooks;
+
+ /* Hook entry points: one per netfilter hook. */
+ unsigned int hook_entry[NF_ARP_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_ARP_NUMHOOKS];
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Size of entries. */
+ unsigned int size;
+};
+
+/* The argument to ARPT_SO_SET_REPLACE. */
+struct arpt_replace {
+ /* Which table. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Which hook entry points are valid: bitmask. You can't
+ change this. */
+ unsigned int valid_hooks;
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Total size of new entries */
+ unsigned int size;
+
+ /* Hook entry points. */
+ unsigned int hook_entry[NF_ARP_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_ARP_NUMHOOKS];
+
+ /* Information about old entries: */
+ /* Number of counters (must be equal to current number of entries). */
+ unsigned int num_counters;
+ /* The old entries' counters. */
+ struct xt_counters *counters;
+
+ /* The entries (hang off end: not really an array). */
+ struct arpt_entry entries[0];
+};
+
+/* The argument to ARPT_SO_GET_ENTRIES. */
+struct arpt_get_entries {
+ /* Which table: user fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* User fills this in: total entry size. */
+ unsigned int size;
+
+ /* The entries. */
+ struct arpt_entry entrytable[0];
+};
+
+/* Helper functions */
+static __inline__ struct xt_entry_target *arpt_get_target(struct arpt_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+#endif /* _ARPTABLES_H */
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
new file mode 100644
index 0000000..6187a55
--- /dev/null
+++ b/include/linux/netfilter_bridge.h
@@ -0,0 +1,40 @@
+#ifndef __LINUX_BRIDGE_NETFILTER_H
+#define __LINUX_BRIDGE_NETFILTER_H
+
+/* bridge-specific defines for netfilter.
+ */
+
+#include <linux/netfilter.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/if_pppox.h>
+
+/* Bridge Hooks */
+/* After promisc drops, checksum checks. */
+#define NF_BR_PRE_ROUTING 0
+/* If the packet is destined for this box. */
+#define NF_BR_LOCAL_IN 1
+/* If the packet is destined for another interface. */
+#define NF_BR_FORWARD 2
+/* Packets coming from a local process. */
+#define NF_BR_LOCAL_OUT 3
+/* Packets about to hit the wire. */
+#define NF_BR_POST_ROUTING 4
+/* Not really a hook, but used for the ebtables broute table */
+#define NF_BR_BROUTING 5
+#define NF_BR_NUMHOOKS 6
+
+#include <limits.h> /* for INT_MIN, INT_MAX */
+
+enum nf_br_hook_priorities {
+ NF_BR_PRI_FIRST = INT_MIN,
+ NF_BR_PRI_NAT_DST_BRIDGED = -300,
+ NF_BR_PRI_FILTER_BRIDGED = -200,
+ NF_BR_PRI_BRNF = 0,
+ NF_BR_PRI_NAT_DST_OTHER = 100,
+ NF_BR_PRI_FILTER_OTHER = 200,
+ NF_BR_PRI_NAT_SRC = 300,
+ NF_BR_PRI_LAST = INT_MAX,
+};
+
+#endif
diff --git a/include/linux/netfilter_bridge/Makefile.am b/include/linux/netfilter_bridge/Makefile.am
new file mode 100644
index 0000000..d2e8b38
--- /dev/null
+++ b/include/linux/netfilter_bridge/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = ebtables.h
diff --git a/include/linux/netfilter_bridge/Makefile.in b/include/linux/netfilter_bridge/Makefile.in
new file mode 100644
index 0000000..662dd80
--- /dev/null
+++ b/include/linux/netfilter_bridge/Makefile.in
@@ -0,0 +1,523 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/linux/netfilter_bridge
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = ebtables.h
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/linux/netfilter_bridge/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/linux/netfilter_bridge/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
new file mode 100644
index 0000000..a225911
--- /dev/null
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -0,0 +1,266 @@
+/*
+ * ebtables
+ *
+ * Authors:
+ * Bart De Schuymer <bdschuym@pandora.be>
+ *
+ * ebtables.c,v 2.0, April, 2002
+ *
+ * This code is stongly inspired on the iptables code which is
+ * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ */
+
+#ifndef __LINUX_BRIDGE_EFF_H
+#define __LINUX_BRIDGE_EFF_H
+#include <linux/netfilter_bridge.h>
+
+#define EBT_TABLE_MAXNAMELEN 32
+#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+#define EBT_FUNCTION_MAXNAMELEN EBT_TABLE_MAXNAMELEN
+
+/* verdicts >0 are "branches" */
+#define EBT_ACCEPT -1
+#define EBT_DROP -2
+#define EBT_CONTINUE -3
+#define EBT_RETURN -4
+#define NUM_STANDARD_TARGETS 4
+/* ebtables target modules store the verdict inside an int. We can
+ * reclaim a part of this int for backwards compatible extensions.
+ * The 4 lsb are more than enough to store the verdict. */
+#define EBT_VERDICT_BITS 0x0000000F
+
+struct xt_match;
+struct xt_target;
+
+struct ebt_counter {
+ uint64_t pcnt;
+ uint64_t bcnt;
+};
+
+struct ebt_replace {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ /* nr of rules in the table */
+ unsigned int nentries;
+ /* total size of the entries */
+ unsigned int entries_size;
+ /* start of the chains */
+ struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
+ /* nr of counters userspace expects back */
+ unsigned int num_counters;
+ /* where the kernel will put the old counters */
+ struct ebt_counter *counters;
+ char *entries;
+};
+
+struct ebt_replace_kernel {
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ /* nr of rules in the table */
+ unsigned int nentries;
+ /* total size of the entries */
+ unsigned int entries_size;
+ /* start of the chains */
+ struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
+ /* nr of counters userspace expects back */
+ unsigned int num_counters;
+ /* where the kernel will put the old counters */
+ struct ebt_counter *counters;
+ char *entries;
+};
+
+struct ebt_entries {
+ /* this field is always set to zero
+ * See EBT_ENTRY_OR_ENTRIES.
+ * Must be same size as ebt_entry.bitmask */
+ unsigned int distinguisher;
+ /* the chain name */
+ char name[EBT_CHAIN_MAXNAMELEN];
+ /* counter offset for this chain */
+ unsigned int counter_offset;
+ /* one standard (accept, drop, return) per hook */
+ int policy;
+ /* nr. of entries */
+ unsigned int nentries;
+ /* entry list */
+ char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+/* used for the bitmask of struct ebt_entry */
+
+/* This is a hack to make a difference between an ebt_entry struct and an
+ * ebt_entries struct when traversing the entries from start to end.
+ * Using this simplifies the code a lot, while still being able to use
+ * ebt_entries.
+ * Contrary, iptables doesn't use something like ebt_entries and therefore uses
+ * different techniques for naming the policy and such. So, iptables doesn't
+ * need a hack like this.
+ */
+#define EBT_ENTRY_OR_ENTRIES 0x01
+/* these are the normal masks */
+#define EBT_NOPROTO 0x02
+#define EBT_802_3 0x04
+#define EBT_SOURCEMAC 0x08
+#define EBT_DESTMAC 0x10
+#define EBT_F_MASK (EBT_NOPROTO | EBT_802_3 | EBT_SOURCEMAC | EBT_DESTMAC \
+ | EBT_ENTRY_OR_ENTRIES)
+
+#define EBT_IPROTO 0x01
+#define EBT_IIN 0x02
+#define EBT_IOUT 0x04
+#define EBT_ISOURCE 0x8
+#define EBT_IDEST 0x10
+#define EBT_ILOGICALIN 0x20
+#define EBT_ILOGICALOUT 0x40
+#define EBT_INV_MASK (EBT_IPROTO | EBT_IIN | EBT_IOUT | EBT_ILOGICALIN \
+ | EBT_ILOGICALOUT | EBT_ISOURCE | EBT_IDEST)
+
+struct ebt_entry_match {
+ union {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ struct xt_match *match;
+ } u;
+ /* size of data */
+ unsigned int match_size;
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+struct ebt_entry_watcher {
+ union {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ struct xt_target *watcher;
+ } u;
+ /* size of data */
+ unsigned int watcher_size;
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+struct ebt_entry_target {
+ union {
+ char name[EBT_FUNCTION_MAXNAMELEN];
+ struct xt_target *target;
+ } u;
+ /* size of data */
+ unsigned int target_size;
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+#define EBT_STANDARD_TARGET "standard"
+struct ebt_standard_target {
+ struct ebt_entry_target target;
+ int verdict;
+};
+
+/* one entry */
+struct ebt_entry {
+ /* this needs to be the first field */
+ unsigned int bitmask;
+ unsigned int invflags;
+ __be16 ethproto;
+ /* the physical in-dev */
+ char in[IFNAMSIZ];
+ /* the logical in-dev */
+ char logical_in[IFNAMSIZ];
+ /* the physical out-dev */
+ char out[IFNAMSIZ];
+ /* the logical out-dev */
+ char logical_out[IFNAMSIZ];
+ unsigned char sourcemac[ETH_ALEN];
+ unsigned char sourcemsk[ETH_ALEN];
+ unsigned char destmac[ETH_ALEN];
+ unsigned char destmsk[ETH_ALEN];
+ /* sizeof ebt_entry + matches */
+ unsigned int watchers_offset;
+ /* sizeof ebt_entry + matches + watchers */
+ unsigned int target_offset;
+ /* sizeof ebt_entry + matches + watchers + target */
+ unsigned int next_offset;
+ unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
+};
+
+/* {g,s}etsockopt numbers */
+#define EBT_BASE_CTL 128
+
+#define EBT_SO_SET_ENTRIES (EBT_BASE_CTL)
+#define EBT_SO_SET_COUNTERS (EBT_SO_SET_ENTRIES+1)
+#define EBT_SO_SET_MAX (EBT_SO_SET_COUNTERS+1)
+
+#define EBT_SO_GET_INFO (EBT_BASE_CTL)
+#define EBT_SO_GET_ENTRIES (EBT_SO_GET_INFO+1)
+#define EBT_SO_GET_INIT_INFO (EBT_SO_GET_ENTRIES+1)
+#define EBT_SO_GET_INIT_ENTRIES (EBT_SO_GET_INIT_INFO+1)
+#define EBT_SO_GET_MAX (EBT_SO_GET_INIT_ENTRIES+1)
+
+
+/* blatently stolen from ip_tables.h
+ * fn returns 0 to continue iteration */
+#define EBT_MATCH_ITERATE(e, fn, args...) \
+({ \
+ unsigned int __i; \
+ int __ret = 0; \
+ struct ebt_entry_match *__match; \
+ \
+ for (__i = sizeof(struct ebt_entry); \
+ __i < (e)->watchers_offset; \
+ __i += __match->match_size + \
+ sizeof(struct ebt_entry_match)) { \
+ __match = (void *)(e) + __i; \
+ \
+ __ret = fn(__match , ## args); \
+ if (__ret != 0) \
+ break; \
+ } \
+ if (__ret == 0) { \
+ if (__i != (e)->watchers_offset) \
+ __ret = -EINVAL; \
+ } \
+ __ret; \
+})
+
+#define EBT_WATCHER_ITERATE(e, fn, args...) \
+({ \
+ unsigned int __i; \
+ int __ret = 0; \
+ struct ebt_entry_watcher *__watcher; \
+ \
+ for (__i = e->watchers_offset; \
+ __i < (e)->target_offset; \
+ __i += __watcher->watcher_size + \
+ sizeof(struct ebt_entry_watcher)) { \
+ __watcher = (void *)(e) + __i; \
+ \
+ __ret = fn(__watcher , ## args); \
+ if (__ret != 0) \
+ break; \
+ } \
+ if (__ret == 0) { \
+ if (__i != (e)->target_offset) \
+ __ret = -EINVAL; \
+ } \
+ __ret; \
+})
+
+#define EBT_ENTRY_ITERATE(entries, size, fn, args...) \
+({ \
+ unsigned int __i; \
+ int __ret = 0; \
+ struct ebt_entry *__entry; \
+ \
+ for (__i = 0; __i < (size);) { \
+ __entry = (void *)(entries) + __i; \
+ __ret = fn(__entry , ## args); \
+ if (__ret != 0) \
+ break; \
+ if (__entry->bitmask != 0) \
+ __i += __entry->next_offset; \
+ else \
+ __i += sizeof(struct ebt_entries); \
+ } \
+ if (__ret == 0) { \
+ if (__i != (size)) \
+ __ret = -EINVAL; \
+ } \
+ __ret; \
+})
+
+#endif /* __LINUX_BRIDGE_EFF_H */
diff --git a/include/linux/netfilter_decnet.h b/include/linux/netfilter_decnet.h
new file mode 100644
index 0000000..ca70c6c
--- /dev/null
+++ b/include/linux/netfilter_decnet.h
@@ -0,0 +1,72 @@
+#ifndef __LINUX_DECNET_NETFILTER_H
+#define __LINUX_DECNET_NETFILTER_H
+
+/* DECnet-specific defines for netfilter.
+ * This file (C) Steve Whitehouse 1999 derived from the
+ * ipv4 netfilter header file which is
+ * (C)1998 Rusty Russell -- This code is GPL.
+ */
+
+#include <linux/netfilter.h>
+
+/* only for userspace compatibility */
+/* IP Cache bits. */
+/* Src IP address. */
+#define NFC_DN_SRC 0x0001
+/* Dest IP address. */
+#define NFC_DN_DST 0x0002
+/* Input device. */
+#define NFC_DN_IF_IN 0x0004
+/* Output device. */
+#define NFC_DN_IF_OUT 0x0008
+
+/* DECnet Hooks */
+/* After promisc drops, checksum checks. */
+#define NF_DN_PRE_ROUTING 0
+/* If the packet is destined for this box. */
+#define NF_DN_LOCAL_IN 1
+/* If the packet is destined for another interface. */
+#define NF_DN_FORWARD 2
+/* Packets coming from a local process. */
+#define NF_DN_LOCAL_OUT 3
+/* Packets about to hit the wire. */
+#define NF_DN_POST_ROUTING 4
+/* Input Hello Packets */
+#define NF_DN_HELLO 5
+/* Input Routing Packets */
+#define NF_DN_ROUTE 6
+#define NF_DN_NUMHOOKS 7
+
+enum nf_dn_hook_priorities {
+ NF_DN_PRI_FIRST = INT_MIN,
+ NF_DN_PRI_CONNTRACK = -200,
+ NF_DN_PRI_MANGLE = -150,
+ NF_DN_PRI_NAT_DST = -100,
+ NF_DN_PRI_FILTER = 0,
+ NF_DN_PRI_NAT_SRC = 100,
+ NF_DN_PRI_DNRTMSG = 200,
+ NF_DN_PRI_LAST = INT_MAX,
+};
+
+struct nf_dn_rtmsg {
+ int nfdn_ifindex;
+};
+
+#define NFDN_RTMSG(r) ((unsigned char *)(r) + NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg)))
+
+/* backwards compatibility for userspace */
+#define DNRMG_L1_GROUP 0x01
+#define DNRMG_L2_GROUP 0x02
+
+enum {
+ DNRNG_NLGRP_NONE,
+#define DNRNG_NLGRP_NONE DNRNG_NLGRP_NONE
+ DNRNG_NLGRP_L1,
+#define DNRNG_NLGRP_L1 DNRNG_NLGRP_L1
+ DNRNG_NLGRP_L2,
+#define DNRNG_NLGRP_L2 DNRNG_NLGRP_L2
+ __DNRNG_NLGRP_MAX
+};
+#define DNRNG_NLGRP_MAX (__DNRNG_NLGRP_MAX - 1)
+
+#endif /*__LINUX_DECNET_NETFILTER_H*/
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
new file mode 100644
index 0000000..074e2c8
--- /dev/null
+++ b/include/linux/netfilter_ipv4.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* IPv4-specific defines for netfilter.
+ * (C)1998 Rusty Russell -- This code is GPL.
+ */
+#ifndef __LINUX_IP_NETFILTER_H
+#define __LINUX_IP_NETFILTER_H
+
+
+#include <linux/netfilter.h>
+
+/* only for userspace compatibility */
+
+#include <limits.h> /* for INT_MIN, INT_MAX */
+
+/* IP Cache bits. */
+/* Src IP address. */
+#define NFC_IP_SRC 0x0001
+/* Dest IP address. */
+#define NFC_IP_DST 0x0002
+/* Input device. */
+#define NFC_IP_IF_IN 0x0004
+/* Output device. */
+#define NFC_IP_IF_OUT 0x0008
+/* TOS. */
+#define NFC_IP_TOS 0x0010
+/* Protocol. */
+#define NFC_IP_PROTO 0x0020
+/* IP options. */
+#define NFC_IP_OPTIONS 0x0040
+/* Frag & flags. */
+#define NFC_IP_FRAG 0x0080
+
+/* Per-protocol information: only matters if proto match. */
+/* TCP flags. */
+#define NFC_IP_TCPFLAGS 0x0100
+/* Source port. */
+#define NFC_IP_SRC_PT 0x0200
+/* Dest port. */
+#define NFC_IP_DST_PT 0x0400
+/* Something else about the proto */
+#define NFC_IP_PROTO_UNKNOWN 0x2000
+
+/* IP Hooks */
+/* After promisc drops, checksum checks. */
+#define NF_IP_PRE_ROUTING 0
+/* If the packet is destined for this box. */
+#define NF_IP_LOCAL_IN 1
+/* If the packet is destined for another interface. */
+#define NF_IP_FORWARD 2
+/* Packets coming from a local process. */
+#define NF_IP_LOCAL_OUT 3
+/* Packets about to hit the wire. */
+#define NF_IP_POST_ROUTING 4
+#define NF_IP_NUMHOOKS 5
+
+enum nf_ip_hook_priorities {
+ NF_IP_PRI_FIRST = INT_MIN,
+ NF_IP_PRI_RAW_BEFORE_DEFRAG = -450,
+ NF_IP_PRI_CONNTRACK_DEFRAG = -400,
+ NF_IP_PRI_RAW = -300,
+ NF_IP_PRI_SELINUX_FIRST = -225,
+ NF_IP_PRI_CONNTRACK = -200,
+ NF_IP_PRI_MANGLE = -150,
+ NF_IP_PRI_NAT_DST = -100,
+ NF_IP_PRI_FILTER = 0,
+ NF_IP_PRI_SECURITY = 50,
+ NF_IP_PRI_NAT_SRC = 100,
+ NF_IP_PRI_SELINUX_LAST = 225,
+ NF_IP_PRI_CONNTRACK_HELPER = 300,
+ NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
+ NF_IP_PRI_LAST = INT_MAX,
+};
+
+/* Arguments for setsockopt SOL_IP: */
+/* 2.0 firewalling went from 64 through 71 (and +256, +512, etc). */
+/* 2.2 firewalling (+ masq) went from 64 through 76 */
+/* 2.4 firewalling went 64 through 67. */
+#define SO_ORIGINAL_DST 80
+
+
+#endif /* __LINUX_IP_NETFILTER_H */
diff --git a/include/linux/netfilter_ipv4/Makefile.am b/include/linux/netfilter_ipv4/Makefile.am
new file mode 100644
index 0000000..fec4253
--- /dev/null
+++ b/include/linux/netfilter_ipv4/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = ip_tables.h
diff --git a/include/linux/netfilter_ipv4/Makefile.in b/include/linux/netfilter_ipv4/Makefile.in
new file mode 100644
index 0000000..bf2b12e
--- /dev/null
+++ b/include/linux/netfilter_ipv4/Makefile.in
@@ -0,0 +1,523 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/linux/netfilter_ipv4
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = ip_tables.h
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/linux/netfilter_ipv4/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/linux/netfilter_ipv4/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
new file mode 100644
index 0000000..38542b4
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -0,0 +1,227 @@
+/*
+ * 25-Jul-1998 Major changes to allow for ip chain table
+ *
+ * 3-Jan-2000 Named tables to allow packet selection for different uses.
+ */
+
+/*
+ * Format of an IP firewall descriptor
+ *
+ * src, dst, src_mask, dst_mask are always stored in network byte order.
+ * flags are stored in host byte order (of course).
+ * Port numbers are stored in HOST byte order.
+ */
+
+#ifndef _IPTABLES_H
+#define _IPTABLES_H
+
+#include <linux/types.h>
+
+#include <linux/netfilter_ipv4.h>
+
+#include <linux/netfilter/x_tables.h>
+
+#define IPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define ipt_match xt_match
+#define ipt_target xt_target
+#define ipt_table xt_table
+#define ipt_get_revision xt_get_revision
+#define ipt_entry_match xt_entry_match
+#define ipt_entry_target xt_entry_target
+#define ipt_standard_target xt_standard_target
+#define ipt_error_target xt_error_target
+#define ipt_counters xt_counters
+#define IPT_CONTINUE XT_CONTINUE
+#define IPT_RETURN XT_RETURN
+
+/* This group is older than old (iptables < v1.4.0-rc1~89) */
+#include <linux/netfilter/xt_tcpudp.h>
+#define ipt_udp xt_udp
+#define ipt_tcp xt_tcp
+#define IPT_TCP_INV_SRCPT XT_TCP_INV_SRCPT
+#define IPT_TCP_INV_DSTPT XT_TCP_INV_DSTPT
+#define IPT_TCP_INV_FLAGS XT_TCP_INV_FLAGS
+#define IPT_TCP_INV_OPTION XT_TCP_INV_OPTION
+#define IPT_TCP_INV_MASK XT_TCP_INV_MASK
+#define IPT_UDP_INV_SRCPT XT_UDP_INV_SRCPT
+#define IPT_UDP_INV_DSTPT XT_UDP_INV_DSTPT
+#define IPT_UDP_INV_MASK XT_UDP_INV_MASK
+
+/* The argument to IPT_SO_ADD_COUNTERS. */
+#define ipt_counters_info xt_counters_info
+/* Standard return verdict, or do jump. */
+#define IPT_STANDARD_TARGET XT_STANDARD_TARGET
+/* Error verdict. */
+#define IPT_ERROR_TARGET XT_ERROR_TARGET
+
+/* fn returns 0 to continue iteration */
+#define IPT_MATCH_ITERATE(e, fn, args...) \
+ XT_MATCH_ITERATE(struct ipt_entry, e, fn, ## args)
+
+/* fn returns 0 to continue iteration */
+#define IPT_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct ipt_entry, entries, size, fn, ## args)
+
+/* Yes, Virginia, you have to zero the padding. */
+struct ipt_ip {
+ /* Source and destination IP addr */
+ struct in_addr src, dst;
+ /* Mask for src and dest IP addr */
+ struct in_addr smsk, dmsk;
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+
+ /* Protocol, 0 = ANY */
+ __u16 proto;
+
+ /* Flags word */
+ __u8 flags;
+ /* Inverse flags */
+ __u8 invflags;
+};
+
+/* Values for "flag" field in struct ipt_ip (general ip structure). */
+#define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
+#define IPT_F_GOTO 0x02 /* Set if jump is a goto */
+#define IPT_F_MASK 0x03 /* All possible flag bits mask. */
+
+/* Values for "inv" field in struct ipt_ip. */
+#define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
+#define IPT_INV_VIA_OUT 0x02 /* Invert the sense of OUT IFACE */
+#define IPT_INV_TOS 0x04 /* Invert the sense of TOS. */
+#define IPT_INV_SRCIP 0x08 /* Invert the sense of SRC IP. */
+#define IPT_INV_DSTIP 0x10 /* Invert the sense of DST OP. */
+#define IPT_INV_FRAG 0x20 /* Invert the sense of FRAG. */
+#define IPT_INV_PROTO XT_INV_PROTO
+#define IPT_INV_MASK 0x7F /* All possible flag bits mask. */
+
+/* This structure defines each of the firewall rules. Consists of 3
+ parts which are 1) general IP header stuff 2) match specific
+ stuff 3) the target to perform if the rule matches */
+struct ipt_entry {
+ struct ipt_ip ip;
+
+ /* Mark with fields that we care about. */
+ unsigned int nfcache;
+
+ /* Size of ipt_entry + matches */
+ __u16 target_offset;
+ /* Size of ipt_entry + matches + target */
+ __u16 next_offset;
+
+ /* Back pointer */
+ unsigned int comefrom;
+
+ /* Packet and byte counters. */
+ struct xt_counters counters;
+
+ /* The matches (if any), then the target. */
+ unsigned char elems[0];
+};
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use a raw
+ * socket for this. Instead we check rights in the calls.
+ *
+ * ATTENTION: check linux/in.h before adding new number here.
+ */
+#define IPT_BASE_CTL 64
+
+#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
+#define IPT_SO_SET_ADD_COUNTERS (IPT_BASE_CTL + 1)
+#define IPT_SO_SET_MAX IPT_SO_SET_ADD_COUNTERS
+
+#define IPT_SO_GET_INFO (IPT_BASE_CTL)
+#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
+#define IPT_SO_GET_REVISION_MATCH (IPT_BASE_CTL + 2)
+#define IPT_SO_GET_REVISION_TARGET (IPT_BASE_CTL + 3)
+#define IPT_SO_GET_MAX IPT_SO_GET_REVISION_TARGET
+
+/* ICMP matching stuff */
+struct ipt_icmp {
+ __u8 type; /* type to match */
+ __u8 code[2]; /* range of code */
+ __u8 invflags; /* Inverse flags */
+};
+
+/* Values for "inv" field for struct ipt_icmp. */
+#define IPT_ICMP_INV 0x01 /* Invert the sense of type/code test */
+
+/* The argument to IPT_SO_GET_INFO */
+struct ipt_getinfo {
+ /* Which table: caller fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Kernel fills these in. */
+ /* Which hook entry points are valid: bitmask */
+ unsigned int valid_hooks;
+
+ /* Hook entry points: one per netfilter hook. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Size of entries. */
+ unsigned int size;
+};
+
+/* The argument to IPT_SO_SET_REPLACE. */
+struct ipt_replace {
+ /* Which table. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Which hook entry points are valid: bitmask. You can't
+ change this. */
+ unsigned int valid_hooks;
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Total size of new entries */
+ unsigned int size;
+
+ /* Hook entry points. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Information about old entries: */
+ /* Number of counters (must be equal to current number of entries). */
+ unsigned int num_counters;
+ /* The old entries' counters. */
+ struct xt_counters *counters;
+
+ /* The entries (hang off end: not really an array). */
+ struct ipt_entry entries[0];
+};
+
+/* The argument to IPT_SO_GET_ENTRIES. */
+struct ipt_get_entries {
+ /* Which table: user fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* User fills this in: total entry size. */
+ unsigned int size;
+
+ /* The entries. */
+ struct ipt_entry entrytable[0];
+};
+
+/* Helper functions */
+static __inline__ struct xt_entry_target *
+ipt_get_target(struct ipt_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+#endif /* _IPTABLES_H */
diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h
new file mode 100644
index 0000000..7430b39
--- /dev/null
+++ b/include/linux/netfilter_ipv6.h
@@ -0,0 +1,72 @@
+#ifndef __LINUX_IP6_NETFILTER_H
+#define __LINUX_IP6_NETFILTER_H
+
+/* IPv6-specific defines for netfilter.
+ * (C)1998 Rusty Russell -- This code is GPL.
+ * (C)1999 David Jeffery
+ * this header was blatantly ripped from netfilter_ipv4.h
+ * it's amazing what adding a bunch of 6s can do =8^)
+ */
+
+#include <linux/netfilter.h>
+
+/* only for userspace compatibility */
+/* IP Cache bits. */
+/* Src IP address. */
+#define NFC_IP6_SRC 0x0001
+/* Dest IP address. */
+#define NFC_IP6_DST 0x0002
+/* Input device. */
+#define NFC_IP6_IF_IN 0x0004
+/* Output device. */
+#define NFC_IP6_IF_OUT 0x0008
+/* TOS. */
+#define NFC_IP6_TOS 0x0010
+/* Protocol. */
+#define NFC_IP6_PROTO 0x0020
+/* IP options. */
+#define NFC_IP6_OPTIONS 0x0040
+/* Frag & flags. */
+#define NFC_IP6_FRAG 0x0080
+
+
+/* Per-protocol information: only matters if proto match. */
+/* TCP flags. */
+#define NFC_IP6_TCPFLAGS 0x0100
+/* Source port. */
+#define NFC_IP6_SRC_PT 0x0200
+/* Dest port. */
+#define NFC_IP6_DST_PT 0x0400
+/* Something else about the proto */
+#define NFC_IP6_PROTO_UNKNOWN 0x2000
+
+/* IP6 Hooks */
+/* After promisc drops, checksum checks. */
+#define NF_IP6_PRE_ROUTING 0
+/* If the packet is destined for this box. */
+#define NF_IP6_LOCAL_IN 1
+/* If the packet is destined for another interface. */
+#define NF_IP6_FORWARD 2
+/* Packets coming from a local process. */
+#define NF_IP6_LOCAL_OUT 3
+/* Packets about to hit the wire. */
+#define NF_IP6_POST_ROUTING 4
+#define NF_IP6_NUMHOOKS 5
+
+
+enum nf_ip6_hook_priorities {
+ NF_IP6_PRI_FIRST = INT_MIN,
+ NF_IP6_PRI_CONNTRACK_DEFRAG = -400,
+ NF_IP6_PRI_SELINUX_FIRST = -225,
+ NF_IP6_PRI_CONNTRACK = -200,
+ NF_IP6_PRI_MANGLE = -150,
+ NF_IP6_PRI_NAT_DST = -100,
+ NF_IP6_PRI_FILTER = 0,
+ NF_IP6_PRI_SECURITY = 50,
+ NF_IP6_PRI_NAT_SRC = 100,
+ NF_IP6_PRI_SELINUX_LAST = 225,
+ NF_IP6_PRI_LAST = INT_MAX,
+};
+
+
+#endif /*__LINUX_IP6_NETFILTER_H*/
diff --git a/include/linux/netfilter_ipv6/Makefile.am b/include/linux/netfilter_ipv6/Makefile.am
new file mode 100644
index 0000000..bec6c3f
--- /dev/null
+++ b/include/linux/netfilter_ipv6/Makefile.am
@@ -0,0 +1 @@
+noinst_HEADERS = ip6_tables.h
diff --git a/include/linux/netfilter_ipv6/Makefile.in b/include/linux/netfilter_ipv6/Makefile.in
new file mode 100644
index 0000000..78cfde6
--- /dev/null
+++ b/include/linux/netfilter_ipv6/Makefile.in
@@ -0,0 +1,523 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/linux/netfilter_ipv6
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = ip6_tables.h
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/linux/netfilter_ipv6/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/linux/netfilter_ipv6/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
new file mode 100644
index 0000000..4432dd1
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -0,0 +1,265 @@
+/*
+ * 25-Jul-1998 Major changes to allow for ip chain table
+ *
+ * 3-Jan-2000 Named tables to allow packet selection for different uses.
+ */
+
+/*
+ * Format of an IP6 firewall descriptor
+ *
+ * src, dst, src_mask, dst_mask are always stored in network byte order.
+ * flags are stored in host byte order (of course).
+ * Port numbers are stored in HOST byte order.
+ */
+
+#ifndef _IP6_TABLES_H
+#define _IP6_TABLES_H
+
+#include <linux/types.h>
+
+#include <linux/netfilter_ipv6.h>
+
+#include <linux/netfilter/x_tables.h>
+
+#define IP6T_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN
+#define IP6T_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN
+#define ip6t_match xt_match
+#define ip6t_target xt_target
+#define ip6t_table xt_table
+#define ip6t_get_revision xt_get_revision
+#define ip6t_entry_match xt_entry_match
+#define ip6t_entry_target xt_entry_target
+#define ip6t_standard_target xt_standard_target
+#define ip6t_error_target xt_error_target
+#define ip6t_counters xt_counters
+#define IP6T_CONTINUE XT_CONTINUE
+#define IP6T_RETURN XT_RETURN
+
+/* Pre-iptables-1.4.0 */
+#include <linux/netfilter/xt_tcpudp.h>
+#define ip6t_tcp xt_tcp
+#define ip6t_udp xt_udp
+#define IP6T_TCP_INV_SRCPT XT_TCP_INV_SRCPT
+#define IP6T_TCP_INV_DSTPT XT_TCP_INV_DSTPT
+#define IP6T_TCP_INV_FLAGS XT_TCP_INV_FLAGS
+#define IP6T_TCP_INV_OPTION XT_TCP_INV_OPTION
+#define IP6T_TCP_INV_MASK XT_TCP_INV_MASK
+#define IP6T_UDP_INV_SRCPT XT_UDP_INV_SRCPT
+#define IP6T_UDP_INV_DSTPT XT_UDP_INV_DSTPT
+#define IP6T_UDP_INV_MASK XT_UDP_INV_MASK
+
+#define ip6t_counters_info xt_counters_info
+#define IP6T_STANDARD_TARGET XT_STANDARD_TARGET
+#define IP6T_ERROR_TARGET XT_ERROR_TARGET
+#define IP6T_MATCH_ITERATE(e, fn, args...) \
+ XT_MATCH_ITERATE(struct ip6t_entry, e, fn, ## args)
+#define IP6T_ENTRY_ITERATE(entries, size, fn, args...) \
+ XT_ENTRY_ITERATE(struct ip6t_entry, entries, size, fn, ## args)
+
+/* Yes, Virginia, you have to zero the padding. */
+struct ip6t_ip6 {
+ /* Source and destination IP6 addr */
+ struct in6_addr src, dst;
+ /* Mask for src and dest IP6 addr */
+ struct in6_addr smsk, dmsk;
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+
+ /* Upper protocol number
+ * - The allowed value is 0 (any) or protocol number of last parsable
+ * header, which is 50 (ESP), 59 (No Next Header), 135 (MH), or
+ * the non IPv6 extension headers.
+ * - The protocol numbers of IPv6 extension headers except of ESP and
+ * MH do not match any packets.
+ * - You also need to set IP6T_FLAGS_PROTO to "flags" to check protocol.
+ */
+ __u16 proto;
+ /* TOS to match iff flags & IP6T_F_TOS */
+ __u8 tos;
+
+ /* Flags word */
+ __u8 flags;
+ /* Inverse flags */
+ __u8 invflags;
+};
+
+/* Values for "flag" field in struct ip6t_ip6 (general ip6 structure). */
+#define IP6T_F_PROTO 0x01 /* Set if rule cares about upper
+ protocols */
+#define IP6T_F_TOS 0x02 /* Match the TOS. */
+#define IP6T_F_GOTO 0x04 /* Set if jump is a goto */
+#define IP6T_F_MASK 0x07 /* All possible flag bits mask. */
+
+/* Values for "inv" field in struct ip6t_ip6. */
+#define IP6T_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
+#define IP6T_INV_VIA_OUT 0x02 /* Invert the sense of OUT IFACE */
+#define IP6T_INV_TOS 0x04 /* Invert the sense of TOS. */
+#define IP6T_INV_SRCIP 0x08 /* Invert the sense of SRC IP. */
+#define IP6T_INV_DSTIP 0x10 /* Invert the sense of DST OP. */
+#define IP6T_INV_FRAG 0x20 /* Invert the sense of FRAG. */
+#define IP6T_INV_PROTO XT_INV_PROTO
+#define IP6T_INV_MASK 0x7F /* All possible flag bits mask. */
+
+/* This structure defines each of the firewall rules. Consists of 3
+ parts which are 1) general IP header stuff 2) match specific
+ stuff 3) the target to perform if the rule matches */
+struct ip6t_entry {
+ struct ip6t_ip6 ipv6;
+
+ /* Mark with fields that we care about. */
+ unsigned int nfcache;
+
+ /* Size of ipt_entry + matches */
+ __u16 target_offset;
+ /* Size of ipt_entry + matches + target */
+ __u16 next_offset;
+
+ /* Back pointer */
+ unsigned int comefrom;
+
+ /* Packet and byte counters. */
+ struct xt_counters counters;
+
+ /* The matches (if any), then the target. */
+ unsigned char elems[0];
+};
+
+/* Standard entry */
+struct ip6t_standard {
+ struct ip6t_entry entry;
+ struct xt_standard_target target;
+};
+
+struct ip6t_error {
+ struct ip6t_entry entry;
+ struct xt_error_target target;
+};
+
+#define IP6T_ENTRY_INIT(__size) \
+{ \
+ .target_offset = sizeof(struct ip6t_entry), \
+ .next_offset = (__size), \
+}
+
+#define IP6T_STANDARD_INIT(__verdict) \
+{ \
+ .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
+ .target = XT_TARGET_INIT(XT_STANDARD_TARGET, \
+ sizeof(struct xt_standard_target)), \
+ .target.verdict = -(__verdict) - 1, \
+}
+
+#define IP6T_ERROR_INIT \
+{ \
+ .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
+ .target = XT_TARGET_INIT(XT_ERROR_TARGET, \
+ sizeof(struct xt_error_target)), \
+ .target.errorname = "ERROR", \
+}
+
+/*
+ * New IP firewall options for [gs]etsockopt at the RAW IP level.
+ * Unlike BSD Linux inherits IP options so you don't have to use
+ * a raw socket for this. Instead we check rights in the calls.
+ *
+ * ATTENTION: check linux/in6.h before adding new number here.
+ */
+#define IP6T_BASE_CTL 64
+
+#define IP6T_SO_SET_REPLACE (IP6T_BASE_CTL)
+#define IP6T_SO_SET_ADD_COUNTERS (IP6T_BASE_CTL + 1)
+#define IP6T_SO_SET_MAX IP6T_SO_SET_ADD_COUNTERS
+
+#define IP6T_SO_GET_INFO (IP6T_BASE_CTL)
+#define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1)
+#define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 4)
+#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5)
+#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET
+
+/* ICMP matching stuff */
+struct ip6t_icmp {
+ __u8 type; /* type to match */
+ __u8 code[2]; /* range of code */
+ __u8 invflags; /* Inverse flags */
+};
+
+/* Values for "inv" field for struct ipt_icmp. */
+#define IP6T_ICMP_INV 0x01 /* Invert the sense of type/code test */
+
+/* The argument to IP6T_SO_GET_INFO */
+struct ip6t_getinfo {
+ /* Which table: caller fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Kernel fills these in. */
+ /* Which hook entry points are valid: bitmask */
+ unsigned int valid_hooks;
+
+ /* Hook entry points: one per netfilter hook. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Size of entries. */
+ unsigned int size;
+};
+
+/* The argument to IP6T_SO_SET_REPLACE. */
+struct ip6t_replace {
+ /* Which table. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* Which hook entry points are valid: bitmask. You can't
+ change this. */
+ unsigned int valid_hooks;
+
+ /* Number of entries */
+ unsigned int num_entries;
+
+ /* Total size of new entries */
+ unsigned int size;
+
+ /* Hook entry points. */
+ unsigned int hook_entry[NF_INET_NUMHOOKS];
+
+ /* Underflow points. */
+ unsigned int underflow[NF_INET_NUMHOOKS];
+
+ /* Information about old entries: */
+ /* Number of counters (must be equal to current number of entries). */
+ unsigned int num_counters;
+ /* The old entries' counters. */
+ struct xt_counters *counters;
+
+ /* The entries (hang off end: not really an array). */
+ struct ip6t_entry entries[0];
+};
+
+/* The argument to IP6T_SO_GET_ENTRIES. */
+struct ip6t_get_entries {
+ /* Which table: user fills this in. */
+ char name[XT_TABLE_MAXNAMELEN];
+
+ /* User fills this in: total entry size. */
+ unsigned int size;
+
+ /* The entries. */
+ struct ip6t_entry entrytable[0];
+};
+
+/* Helper functions */
+static __inline__ struct xt_entry_target *
+ip6t_get_target(struct ip6t_entry *e)
+{
+ return (void *)e + e->target_offset;
+}
+
+/*
+ * Main firewall chains definitions and global var's definitions.
+ */
+
+#endif /* _IP6_TABLES_H */
diff --git a/include/list.h b/include/list.h
new file mode 100644
index 0000000..857921e
--- /dev/null
+++ b/include/list.h
@@ -0,0 +1,643 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+#define prefetch(x) ((void)0)
+
+#define LIST_POISON1 ((void *)0x12345678)
+#define LIST_POISON2 ((void *)0x87654321)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void init_list_head(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/**
+ * list_is_first -- tests whether @list is the first entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->prev == head;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ init_list_head(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ init_list_head(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ struct list_head *new_first = entry->next;
+ list->next = head->next;
+ list->next->prev = list;
+ list->prev = entry;
+ entry->next = list;
+ head->next = new_first;
+ new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ * and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ *
+ */
+static inline void list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ if (list_empty(head))
+ return;
+ if (list_is_singular(head) &&
+ (head->next != entry && head != entry))
+ return;
+ if (entry == head)
+ init_list_head(list);
+ else
+ __list_cut_position(list, head, entry);
+}
+
+static inline void __list_splice(const struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+
+ first->prev = prev;
+ prev->next = first;
+
+ last->next = next;
+ next->prev = last;
+}
+
+/**
+ * list_splice - join two lists, this is designed for stacks
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head, head->next);
+ init_list_head(list);
+ }
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head->prev, head);
+ init_list_head(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_next_entry - get the next element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+
+#define init_hlist_head(ptr) ((ptr)->first = NULL)
+
+static inline void init_hlist_node(struct hlist_node *h)
+{
+ h->next = NULL;
+ h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ __hlist_del(n);
+ init_hlist_node(n);
+ }
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if(next->next)
+ next->next->pprev = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = n)
+
+#endif
diff --git a/include/meta.h b/include/meta.h
new file mode 100644
index 0000000..1478902
--- /dev/null
+++ b/include/meta.h
@@ -0,0 +1,48 @@
+#ifndef NFTABLES_META_H
+#define NFTABLES_META_H
+
+/**
+ * struct meta_template - template for meta expressions and statements
+ *
+ * @token: parser token for the expression
+ * @dtype: data type of the expression
+ * @len: length of the expression
+ * @byteorder: byteorder
+ */
+struct meta_template {
+ const char *token;
+ const struct datatype *dtype;
+ enum byteorder byteorder;
+ unsigned int len;
+};
+
+extern const struct meta_template meta_templates[];
+
+#define META_TEMPLATE(__token, __dtype, __len, __byteorder) { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .len = (__len), \
+ .byteorder = (__byteorder), \
+}
+
+extern struct expr *meta_expr_alloc(const struct location *loc,
+ enum nft_meta_keys key);
+
+struct stmt *meta_stmt_meta_iiftype(const struct location *loc, uint16_t type);
+
+struct error_record *meta_key_parse(const struct location *loc,
+ const char *name,
+ unsigned int *value);
+
+extern const struct datatype ifindex_type;
+extern const struct datatype tchandle_type;
+extern const struct datatype gid_type;
+extern const struct datatype uid_type;
+extern const struct datatype devgroup_type;
+extern const struct datatype pkttype_type;
+extern const struct datatype ifname_type;
+extern const struct datatype date_type;
+extern const struct datatype hour_type;
+extern const struct datatype day_type;
+
+#endif /* NFTABLES_META_H */
diff --git a/include/mini-gmp.h b/include/mini-gmp.h
new file mode 100644
index 0000000..27e0c06
--- /dev/null
+++ b/include/mini-gmp.h
@@ -0,0 +1,300 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+Copyright 2011-2015, 2017 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+or
+
+ * the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library. If not,
+see https://www.gnu.org/licenses/. */
+
+/* About mini-gmp: This is a minimal implementation of a subset of the
+ GMP interface. It is intended for inclusion into applications which
+ have modest bignums needs, as a fallback when the real GMP library
+ is not installed.
+
+ This file defines the public interface. */
+
+#ifndef __MINI_GMP_H__
+#define __MINI_GMP_H__
+
+/* For size_t */
+#include <stddef.h>
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+void mp_set_memory_functions (void *(*) (size_t),
+ void *(*) (void *, size_t, size_t),
+ void (*) (void *, size_t));
+
+void mp_get_memory_functions (void *(**) (size_t),
+ void *(**) (void *, size_t, size_t),
+ void (**) (void *, size_t));
+
+typedef unsigned long mp_limb_t;
+typedef long mp_size_t;
+typedef unsigned long mp_bitcnt_t;
+
+typedef mp_limb_t *mp_ptr;
+typedef const mp_limb_t *mp_srcptr;
+
+typedef struct
+{
+ int _mp_alloc; /* Number of *limbs* allocated and pointed
+ to by the _mp_d field. */
+ int _mp_size; /* abs(_mp_size) is the number of limbs the
+ last field points to. If _mp_size is
+ negative this is a negative number. */
+ mp_limb_t *_mp_d; /* Pointer to the limbs. */
+} __mpz_struct;
+
+typedef __mpz_struct mpz_t[1];
+
+typedef __mpz_struct *mpz_ptr;
+typedef const __mpz_struct *mpz_srcptr;
+
+extern const int mp_bits_per_limb;
+
+void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);
+void mpn_zero (mp_ptr, mp_size_t);
+
+int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);
+int mpn_zero_p (mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
+
+mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
+void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
+void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);
+int mpn_perfect_square_p (mp_srcptr, mp_size_t);
+mp_size_t mpn_sqrtrem (mp_ptr, mp_ptr, mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
+
+mp_bitcnt_t mpn_scan0 (mp_srcptr, mp_bitcnt_t);
+mp_bitcnt_t mpn_scan1 (mp_srcptr, mp_bitcnt_t);
+
+void mpn_com (mp_ptr, mp_srcptr, mp_size_t);
+mp_limb_t mpn_neg (mp_ptr, mp_srcptr, mp_size_t);
+
+mp_bitcnt_t mpn_popcount (mp_srcptr, mp_size_t);
+
+mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
+#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)
+
+size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
+mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);
+
+void mpz_init (mpz_t);
+void mpz_init2 (mpz_t, mp_bitcnt_t);
+void mpz_clear (mpz_t);
+
+#define mpz_odd_p(z) (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
+#define mpz_even_p(z) (! mpz_odd_p (z))
+
+int mpz_sgn (const mpz_t);
+int mpz_cmp_si (const mpz_t, long);
+int mpz_cmp_ui (const mpz_t, unsigned long);
+int mpz_cmp (const mpz_t, const mpz_t);
+int mpz_cmpabs_ui (const mpz_t, unsigned long);
+int mpz_cmpabs (const mpz_t, const mpz_t);
+int mpz_cmp_d (const mpz_t, double);
+int mpz_cmpabs_d (const mpz_t, double);
+
+void mpz_abs (mpz_t, const mpz_t);
+void mpz_neg (mpz_t, const mpz_t);
+void mpz_swap (mpz_t, mpz_t);
+
+void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_add (mpz_t, const mpz_t, const mpz_t);
+void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
+void mpz_sub (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_mul_si (mpz_t, const mpz_t, long int);
+void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_mul (mpz_t, const mpz_t, const mpz_t);
+void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_addmul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_addmul (mpz_t, const mpz_t, const mpz_t);
+void mpz_submul_ui (mpz_t, const mpz_t, unsigned long int);
+void mpz_submul (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
+void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
+void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
+
+void mpz_mod (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_divexact (mpz_t, const mpz_t, const mpz_t);
+
+int mpz_divisible_p (const mpz_t, const mpz_t);
+int mpz_congruent_p (const mpz_t, const mpz_t, const mpz_t);
+
+unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
+unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
+unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);
+
+unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);
+
+void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);
+
+int mpz_divisible_ui_p (const mpz_t, unsigned long);
+
+unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
+void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
+void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
+int mpz_invert (mpz_t, const mpz_t, const mpz_t);
+
+void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
+void mpz_sqrt (mpz_t, const mpz_t);
+int mpz_perfect_square_p (const mpz_t);
+
+void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
+void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
+void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
+void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);
+
+void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
+int mpz_root (mpz_t, const mpz_t, unsigned long);
+
+void mpz_fac_ui (mpz_t, unsigned long);
+void mpz_2fac_ui (mpz_t, unsigned long);
+void mpz_mfac_uiui (mpz_t, unsigned long, unsigned long);
+void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);
+
+int mpz_probab_prime_p (const mpz_t, int);
+
+int mpz_tstbit (const mpz_t, mp_bitcnt_t);
+void mpz_setbit (mpz_t, mp_bitcnt_t);
+void mpz_clrbit (mpz_t, mp_bitcnt_t);
+void mpz_combit (mpz_t, mp_bitcnt_t);
+
+void mpz_com (mpz_t, const mpz_t);
+void mpz_and (mpz_t, const mpz_t, const mpz_t);
+void mpz_ior (mpz_t, const mpz_t, const mpz_t);
+void mpz_xor (mpz_t, const mpz_t, const mpz_t);
+
+mp_bitcnt_t mpz_popcount (const mpz_t);
+mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
+mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
+mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);
+
+int mpz_fits_slong_p (const mpz_t);
+int mpz_fits_ulong_p (const mpz_t);
+long int mpz_get_si (const mpz_t);
+unsigned long int mpz_get_ui (const mpz_t);
+double mpz_get_d (const mpz_t);
+size_t mpz_size (const mpz_t);
+mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);
+
+void mpz_realloc2 (mpz_t, mp_bitcnt_t);
+mp_srcptr mpz_limbs_read (mpz_srcptr);
+mp_ptr mpz_limbs_modify (mpz_t, mp_size_t);
+mp_ptr mpz_limbs_write (mpz_t, mp_size_t);
+void mpz_limbs_finish (mpz_t, mp_size_t);
+mpz_srcptr mpz_roinit_n (mpz_t, mp_srcptr, mp_size_t);
+
+#define MPZ_ROINIT_N(xp, xs) {{0, (xs),(xp) }}
+
+void mpz_set_si (mpz_t, signed long int);
+void mpz_set_ui (mpz_t, unsigned long int);
+void mpz_set (mpz_t, const mpz_t);
+void mpz_set_d (mpz_t, double);
+
+void mpz_init_set_si (mpz_t, signed long int);
+void mpz_init_set_ui (mpz_t, unsigned long int);
+void mpz_init_set (mpz_t, const mpz_t);
+void mpz_init_set_d (mpz_t, double);
+
+size_t mpz_sizeinbase (const mpz_t, int);
+char *mpz_get_str (char *, int, const mpz_t);
+int mpz_set_str (mpz_t, const char *, int);
+int mpz_init_set_str (mpz_t, const char *, int);
+
+/* This long list taken from gmp.h. */
+/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4,
+ <iostream> defines EOF but not FILE. */
+#if defined (FILE) \
+ || defined (H_STDIO) \
+ || defined (_H_STDIO) /* AIX */ \
+ || defined (_STDIO_H) /* glibc, Sun, SCO */ \
+ || defined (_STDIO_H_) /* BSD, OSF */ \
+ || defined (__STDIO_H) /* Borland */ \
+ || defined (__STDIO_H__) /* IRIX */ \
+ || defined (_STDIO_INCLUDED) /* HPUX */ \
+ || defined (__dj_include_stdio_h_) /* DJGPP */ \
+ || defined (_FILE_DEFINED) /* Microsoft */ \
+ || defined (__STDIO__) /* Apple MPW MrC */ \
+ || defined (_MSL_STDIO_H) /* Metrowerks */ \
+ || defined (_STDIO_H_INCLUDED) /* QNX4 */ \
+ || defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \
+ || defined (__STDIO_LOADED) /* VMS */
+size_t mpz_out_str (FILE *, int, const mpz_t);
+#endif
+
+void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
+void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);
+
+#if defined (__cplusplus)
+}
+#endif
+#endif /* __MINI_GMP_H__ */
diff --git a/include/misspell.h b/include/misspell.h
new file mode 100644
index 0000000..ba01e74
--- /dev/null
+++ b/include/misspell.h
@@ -0,0 +1,13 @@
+#ifndef _MISSPELL_H_
+#define _MISSPELL_H_
+
+struct string_misspell_state {
+ unsigned int min_distance;
+ void *obj;
+};
+
+void string_misspell_init(struct string_misspell_state *st);
+int string_misspell_update(const char *a, const char *b,
+ void *obj, struct string_misspell_state *st);
+
+#endif
diff --git a/include/mnl.h b/include/mnl.h
new file mode 100644
index 0000000..cd5a205
--- /dev/null
+++ b/include/mnl.h
@@ -0,0 +1,105 @@
+#ifndef _NFTABLES_MNL_H_
+#define _NFTABLES_MNL_H_
+
+#include <list.h>
+#include <netlink.h>
+#include <rule.h>
+#include <libmnl/libmnl.h>
+
+struct mnl_socket *nft_mnl_socket_open(void);
+
+uint32_t mnl_seqnum_alloc(uint32_t *seqnum);
+uint32_t mnl_genid_get(struct netlink_ctx *ctx);
+
+struct mnl_err {
+ struct list_head head;
+ int err;
+ uint32_t seqnum;
+ uint32_t offset;
+};
+
+void mnl_err_list_free(struct mnl_err *err);
+
+struct nftnl_batch *mnl_batch_init(void);
+bool mnl_batch_ready(struct nftnl_batch *batch);
+void mnl_batch_reset(struct nftnl_batch *batch);
+uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t seqnum);
+void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum);
+int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
+ uint32_t num_cmds);
+
+int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags);
+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,
+ uint64_t rule_handle,
+ bool dump, bool reset);
+
+int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags);
+int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd);
+int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct chain *chain);
+
+struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
+ int family, const char *table,
+ const char *chain);
+
+int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags);
+int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd);
+
+struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
+ int family, const char *table);
+
+int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags);
+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, 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,
+ bool reset);
+struct nftnl_set *mnl_nft_setelem_get_one(struct netlink_ctx *ctx,
+ struct nftnl_set *nls,
+ bool reset);
+
+struct nftnl_obj_list *mnl_nft_obj_dump(struct netlink_ctx *ctx, int family,
+ const char *table,
+ const char *name, uint32_t type,
+ bool dump, bool reset);
+int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags);
+int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type);
+
+struct nftnl_flowtable_list *
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *ft);
+
+int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags);
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd);
+
+int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname);
+
+int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
+ struct output_ctx *octx,
+ int (*cb)(const struct nlmsghdr *nlh, void *data),
+ void *cb_data);
+
+int nft_mnl_talk(struct netlink_ctx *ctx, const void *data, unsigned int len,
+ int (*cb)(const struct nlmsghdr *nlh, void *data),
+ void *cb_data);
+
+#endif /* _NFTABLES_MNL_H_ */
diff --git a/include/netlink.h b/include/netlink.h
new file mode 100644
index 0000000..6766d7e
--- /dev/null
+++ b/include/netlink.h
@@ -0,0 +1,263 @@
+#ifndef NFTABLES_NETLINK_H
+#define NFTABLES_NETLINK_H
+
+#include <libnftnl/table.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/set.h>
+#include <libnftnl/object.h>
+#include <libnftnl/flowtable.h>
+
+#include <linux/netlink.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <rule.h>
+
+#define MAX_REGS (1 + NFT_REG32_15 - NFT_REG32_00)
+
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+#endif
+
+struct netlink_parse_ctx {
+ struct list_head *msgs;
+ struct table *table;
+ struct rule *rule;
+ struct stmt *stmt;
+ struct expr *registers[MAX_REGS + 1];
+ unsigned int debug_mask;
+ struct netlink_ctx *nlctx;
+ bool inner;
+ uint8_t inner_reg;
+};
+
+
+#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;
+};
+
+extern const struct input_descriptor indesc_netlink;
+extern const struct location netlink_location;
+
+/**
+ * struct netlink_ctx
+ *
+ * @nft: nftables context
+ * @msgs: message queue
+ * @list: list of parsed rules/chains/tables
+ * @set: current set
+ * @data: pointer to pass data to callback
+ * @seqnum: sequence number
+ */
+struct netlink_ctx {
+ struct nft_ctx *nft;
+ struct list_head *msgs;
+ struct list_head list;
+ struct set *set;
+ const void *data;
+ uint32_t seqnum;
+ struct nftnl_batch *batch;
+ int maybe_emsgsize;
+};
+
+extern struct nftnl_expr *alloc_nft_expr(const char *name);
+extern void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls);
+struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
+ const struct expr *expr);
+
+extern struct nftnl_table *netlink_table_alloc(const struct nlmsghdr *nlh);
+extern struct nftnl_chain *netlink_chain_alloc(const struct nlmsghdr *nlh);
+extern struct nftnl_set *netlink_set_alloc(const struct nlmsghdr *nlh);
+extern struct nftnl_obj *netlink_obj_alloc(const struct nlmsghdr *nlh);
+extern struct nftnl_rule *netlink_rule_alloc(const struct nlmsghdr *nlh);
+
+struct nft_data_linearize {
+ uint32_t len;
+ uint32_t value[4];
+ char chain[NFT_CHAIN_MAXNAMELEN];
+ uint32_t chain_id;
+ int verdict;
+};
+
+struct nft_data_delinearize {
+ uint32_t len;
+ const uint32_t *value;
+ const char *chain;
+ int verdict;
+};
+
+static inline unsigned int netlink_register_space(unsigned int size)
+{
+ return div_round_up(size, NFT_REG32_SIZE * BITS_PER_BYTE);
+}
+
+static inline unsigned int netlink_padded_len(unsigned int size)
+{
+ return netlink_register_space(size) * NFT_REG32_SIZE * BITS_PER_BYTE;
+}
+
+static inline unsigned int netlink_padding_len(unsigned int size)
+{
+ return netlink_padded_len(size) - size;
+}
+
+extern void netlink_gen_data(const struct expr *expr,
+ struct nft_data_linearize *data);
+extern void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
+ unsigned int len,
+ struct nft_data_linearize *data);
+extern struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt);
+
+extern struct expr *netlink_alloc_value(const struct location *loc,
+ const struct nft_data_delinearize *nld);
+extern struct expr *netlink_alloc_data(const struct location *loc,
+ const struct nft_data_delinearize *nld,
+ enum nft_registers dreg);
+
+struct netlink_linearize_ctx;
+extern void netlink_linearize_rule(struct netlink_ctx *ctx,
+ const struct rule *rule,
+ struct netlink_linearize_ctx *lctx);
+extern struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
+ struct nftnl_rule *r);
+
+extern int netlink_list_chains(struct netlink_ctx *ctx, const struct handle *h);
+extern struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
+ const struct nftnl_chain *nlc);
+
+extern int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter);
+extern struct table *netlink_delinearize_table(struct netlink_ctx *ctx,
+ const struct nftnl_table *nlt);
+
+extern struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
+ const struct nftnl_set *nls);
+
+extern struct stmt *netlink_parse_set_expr(const struct set *set,
+ const struct nft_cache *cache,
+ const struct nftnl_expr *nle);
+
+extern int netlink_list_setelems(struct netlink_ctx *ctx,
+ 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, bool reset);
+extern int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
+ struct set *set,
+ struct nft_cache *cache);
+
+extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h);
+extern int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
+ uint32_t type, bool dump);
+extern struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
+ struct nftnl_obj *nlo);
+
+extern int netlink_list_flowtables(struct netlink_ctx *ctx,
+ const struct handle *h);
+extern struct flowtable *netlink_delinearize_flowtable(struct netlink_ctx *ctx,
+ struct nftnl_flowtable *nlo);
+
+extern int netlink_reset_rules(struct netlink_ctx *ctx, const struct cmd *cmd,
+ bool dump);
+
+extern void netlink_dump_chain(const struct nftnl_chain *nlc,
+ struct netlink_ctx *ctx);
+extern void netlink_dump_rule(const struct nftnl_rule *nlr,
+ struct netlink_ctx *ctx);
+extern void netlink_dump_expr(const struct nftnl_expr *nle,
+ FILE *fp, unsigned int debug_mask);
+extern void netlink_dump_set(const struct nftnl_set *nls,
+ struct netlink_ctx *ctx);
+extern void netlink_dump_obj(struct nftnl_obj *nlo, struct netlink_ctx *ctx);
+extern void netlink_dump_flowtable(struct nftnl_flowtable *flo, struct netlink_ctx *ctx);
+
+#define netlink_abi_error() \
+ __netlink_abi_error(__FILE__, __LINE__, strerror(errno));
+extern void __noreturn __netlink_abi_error(const char *file, int line, const char *reason);
+extern int netlink_io_error(struct netlink_ctx *ctx,
+ const struct location *loc, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+#define netlink_init_error() \
+ __netlink_init_error(__FILE__, __LINE__, strerror(errno));
+extern void __noreturn __netlink_init_error(const char *file, int line, const char *reason);
+
+struct netlink_mon_handler {
+ uint32_t monitor_flags;
+ uint32_t format;
+ struct netlink_ctx *ctx;
+ const struct location *loc;
+ unsigned int debug_mask;
+ struct nft_cache *cache;
+};
+
+extern int netlink_monitor(struct netlink_mon_handler *monhandler,
+ struct mnl_socket *nf_sock);
+struct netlink_cb_data {
+ struct netlink_ctx *nl_ctx;
+ struct list_head *err_list;
+};
+int netlink_echo_callback(const struct nlmsghdr *nlh, void *data);
+
+struct ruleset_parse {
+ struct netlink_ctx *nl_ctx;
+ struct cmd *cmd;
+};
+
+struct nftnl_parse_ctx;
+
+int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh);
+
+enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype);
+
+void netlink_linearize_init(struct netlink_linearize_ctx *lctx,
+ struct nftnl_rule *nlr);
+void netlink_linearize_fini(struct netlink_linearize_ctx *lctx);
+
+struct netlink_linearize_ctx {
+ struct nftnl_rule *nlr;
+ unsigned int reg_low;
+ struct list_head *expr_loc_htable;
+};
+
+#define NFT_EXPR_LOC_HSIZE 128
+
+struct nft_expr_loc {
+ struct list_head hlist;
+ const struct nftnl_expr *nle;
+ const struct location *loc;
+};
+
+struct nft_expr_loc *nft_expr_loc_find(const struct nftnl_expr *nle,
+ struct netlink_linearize_ctx *ctx);
+
+struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx);
+
+#endif /* NFTABLES_NETLINK_H */
diff --git a/include/nft.h b/include/nft.h
new file mode 100644
index 0000000..3c894e5
--- /dev/null
+++ b/include/nft.h
@@ -0,0 +1,12 @@
+/* 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>
+
+#endif /* NFTABLES_NFT_H */
diff --git a/include/nftables.h b/include/nftables.h
new file mode 100644
index 0000000..4b7c335
--- /dev/null
+++ b/include/nftables.h
@@ -0,0 +1,244 @@
+#ifndef NFTABLES_NFTABLES_H
+#define NFTABLES_NFTABLES_H
+
+#include <stdarg.h>
+#include <limits.h>
+#include <utils.h>
+#include <cache.h>
+#include <nftables/libnftables.h>
+
+struct cookie {
+ FILE *fp;
+ FILE *orig_fp;
+ char *buf;
+ size_t buflen;
+ size_t pos;
+};
+
+struct symbol_tables {
+ const struct symbol_table *mark;
+ const struct symbol_table *devgroup;
+ const struct symbol_table *ct_label;
+ 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 {
+ FILE *output_fp;
+ struct cookie output_cookie;
+ };
+ union {
+ FILE *error_fp;
+ struct cookie error_cookie;
+ };
+ struct symbol_tables tbl;
+};
+
+static inline bool nft_output_reversedns(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_REVERSEDNS;
+}
+
+static inline bool nft_output_service(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_SERVICE;
+}
+
+static inline bool nft_output_stateless(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_STATELESS;
+}
+
+static inline bool nft_output_handle(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_HANDLE;
+}
+
+static inline bool nft_output_json(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_JSON;
+}
+
+static inline bool nft_output_echo(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_ECHO;
+}
+
+static inline bool nft_output_guid(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_GUID;
+}
+
+static inline bool nft_output_seconds(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_NUMERIC_TIME;
+}
+
+static inline bool nft_output_numeric_proto(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_NUMERIC_PROTO;
+}
+
+static inline bool nft_output_numeric_prio(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_NUMERIC_PRIO;
+}
+
+static inline bool nft_output_numeric_symbol(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_NUMERIC_SYMBOL;
+}
+
+static inline bool nft_output_terse(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_TERSE;
+}
+
+struct mnl_socket;
+struct parser_state;
+struct scope;
+
+struct nft_vars {
+ const char *key;
+ const char *value;
+};
+
+#define MAX_INCLUDE_DEPTH 16
+
+struct nft_ctx {
+ struct mnl_socket *nf_sock;
+ char **include_paths;
+ unsigned int num_include_paths;
+ struct nft_vars *vars;
+ struct {
+ const char *buf;
+ struct list_head indesc_list;
+ } vars_ctx;
+ unsigned int num_vars;
+ unsigned int parser_max_errors;
+ unsigned int debug_mask;
+ struct input_ctx input;
+ struct output_ctx output;
+ bool check;
+ struct nft_cache cache;
+ uint32_t flags;
+ uint32_t optimize_flags;
+ struct parser_state *state;
+ void *scanner;
+ struct scope *top_scope;
+ void *json_root;
+ json_t *json_echo;
+ const char *stdin_buf;
+};
+
+enum nftables_exit_codes {
+ NFT_EXIT_SUCCESS = 0,
+ NFT_EXIT_FAILURE = 1,
+ NFT_EXIT_NOMEM = 2,
+ NFT_EXIT_NONL = 3,
+};
+
+struct input_descriptor;
+struct location {
+ const struct input_descriptor *indesc;
+ union {
+ struct {
+ off_t token_offset;
+ off_t line_offset;
+
+ unsigned int first_line;
+ unsigned int last_line;
+ unsigned int first_column;
+ unsigned int last_column;
+ };
+ struct {
+ const void *nle;
+ };
+ };
+};
+
+extern const struct location internal_location;
+
+/**
+ * enum input_descriptor_types
+ *
+ * @INDESC_INVALID: invalid
+ * @INDESC_INTERNAL: dummy type for internally generated messages
+ * @INDESC_BUFFER: buffer (command line arguments)
+ * @INDESC_FILE: file
+ * @INDESC_CLI: command line interface
+ * @INDESC_NETLINK: received from netlink
+ */
+enum input_descriptor_types {
+ INDESC_INVALID,
+ INDESC_INTERNAL,
+ INDESC_BUFFER,
+ INDESC_FILE,
+ INDESC_CLI,
+ INDESC_NETLINK,
+ INDESC_STDIN,
+};
+
+/**
+ * struct input_descriptor
+ *
+ * @location: location, used for include statements
+ * @f: file descriptor
+ * @depth: include depth of the descriptor
+ * @type: input descriptor type
+ * @name: name describing the input
+ * @union: buffer or file descriptor, depending on type
+ * @lineno: current line number in the input
+ * @column: current column in the input
+ * @token_offset: offset of the current token to the beginning
+ * @line_offset: offset of the current line to the beginning
+ */
+struct input_descriptor {
+ struct list_head list;
+ FILE *f;
+ unsigned int depth;
+ struct location location;
+ enum input_descriptor_types type;
+ const char *name;
+ const char *data;
+ unsigned int lineno;
+ unsigned int column;
+ off_t token_offset;
+ off_t line_offset;
+};
+
+void ct_label_table_init(struct nft_ctx *ctx);
+void mark_table_init(struct nft_ctx *ctx);
+void realm_table_rt_init(struct nft_ctx *ctx);
+void devgroup_table_init(struct nft_ctx *ctx);
+void xt_init(void);
+
+void ct_label_table_exit(struct nft_ctx *ctx);
+void mark_table_exit(struct nft_ctx *ctx);
+void devgroup_table_exit(struct nft_ctx *ctx);
+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, ...);
+
+int nft_optimize(struct nft_ctx *nft, struct list_head *cmds);
+
+#define __NFT_OUTPUT_NOTSUPP UINT_MAX
+
+#endif /* NFTABLES_NFTABLES_H */
diff --git a/include/nftables/Makefile.am b/include/nftables/Makefile.am
new file mode 100644
index 0000000..5cfb0c6
--- /dev/null
+++ b/include/nftables/Makefile.am
@@ -0,0 +1 @@
+pkginclude_HEADERS = libnftables.h
diff --git a/include/nftables/Makefile.in b/include/nftables/Makefile.in
new file mode 100644
index 0000000..3e93397
--- /dev/null
+++ b/include/nftables/Makefile.in
@@ -0,0 +1,576 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/nftables
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkginclude_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkgincludedir)"
+HEADERS = $(pkginclude_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkginclude_HEADERS = libnftables.h
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/nftables/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/nftables/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgincludeHEADERS: $(pkginclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \
+ done
+
+uninstall-pkgincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(pkgincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkgincludeHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-pkgincludeHEADERS install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkgincludeHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/nftables/libnftables.h b/include/nftables/libnftables.h
new file mode 100644
index 0000000..c1d48d7
--- /dev/null
+++ b/include/nftables/libnftables.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ *
+ */
+#ifndef LIB_NFTABLES_H
+#define LIB_NFTABLES_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct nft_ctx;
+
+enum nft_debug_level {
+ NFT_DEBUG_SCANNER = 0x1,
+ NFT_DEBUG_PARSER = 0x2,
+ NFT_DEBUG_EVALUATION = 0x4,
+ NFT_DEBUG_NETLINK = 0x8,
+ NFT_DEBUG_MNL = 0x10,
+ NFT_DEBUG_PROTO_CTX = 0x20,
+ NFT_DEBUG_SEGTREE = 0x40,
+};
+
+/**
+ * Possible flags to pass to nft_ctx_new()
+ */
+#define NFT_CTX_DEFAULT 0
+
+struct nft_ctx *nft_ctx_new(uint32_t flags);
+void nft_ctx_free(struct nft_ctx *ctx);
+
+bool nft_ctx_get_dry_run(struct nft_ctx *ctx);
+void nft_ctx_set_dry_run(struct nft_ctx *ctx, bool dry);
+
+enum nft_optimize_flags {
+ NFT_OPTIMIZE_ENABLED = 0x1,
+};
+
+uint32_t nft_ctx_get_optimize(struct nft_ctx *ctx);
+void nft_ctx_set_optimize(struct nft_ctx *ctx, uint32_t flags);
+
+enum {
+ NFT_CTX_INPUT_NO_DNS = (1 << 0),
+ NFT_CTX_INPUT_JSON = (1 << 1),
+};
+
+unsigned int nft_ctx_input_get_flags(struct nft_ctx *ctx);
+unsigned int nft_ctx_input_set_flags(struct nft_ctx *ctx, unsigned int flags);
+
+enum {
+ NFT_CTX_OUTPUT_REVERSEDNS = (1 << 0),
+ NFT_CTX_OUTPUT_SERVICE = (1 << 1),
+ NFT_CTX_OUTPUT_STATELESS = (1 << 2),
+ NFT_CTX_OUTPUT_HANDLE = (1 << 3),
+ NFT_CTX_OUTPUT_JSON = (1 << 4),
+ NFT_CTX_OUTPUT_ECHO = (1 << 5),
+ NFT_CTX_OUTPUT_GUID = (1 << 6),
+ NFT_CTX_OUTPUT_NUMERIC_PROTO = (1 << 7),
+ NFT_CTX_OUTPUT_NUMERIC_PRIO = (1 << 8),
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL = (1 << 9),
+ NFT_CTX_OUTPUT_NUMERIC_TIME = (1 << 10),
+ NFT_CTX_OUTPUT_NUMERIC_ALL = (NFT_CTX_OUTPUT_NUMERIC_PROTO |
+ NFT_CTX_OUTPUT_NUMERIC_PRIO |
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL |
+ NFT_CTX_OUTPUT_NUMERIC_TIME),
+ NFT_CTX_OUTPUT_TERSE = (1 << 11),
+};
+
+unsigned int nft_ctx_output_get_flags(struct nft_ctx *ctx);
+void nft_ctx_output_set_flags(struct nft_ctx *ctx, unsigned int flags);
+
+unsigned int nft_ctx_output_get_debug(struct nft_ctx *ctx);
+void nft_ctx_output_set_debug(struct nft_ctx *ctx, unsigned int mask);
+
+FILE *nft_ctx_set_output(struct nft_ctx *ctx, FILE *fp);
+int nft_ctx_buffer_output(struct nft_ctx *ctx);
+int nft_ctx_unbuffer_output(struct nft_ctx *ctx);
+const char *nft_ctx_get_output_buffer(struct nft_ctx *ctx);
+
+FILE *nft_ctx_set_error(struct nft_ctx *ctx, FILE *fp);
+int nft_ctx_buffer_error(struct nft_ctx *ctx);
+int nft_ctx_unbuffer_error(struct nft_ctx *ctx);
+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);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* LIB_NFTABLES_H */
diff --git a/include/numgen.h b/include/numgen.h
new file mode 100644
index 0000000..b230620
--- /dev/null
+++ b/include/numgen.h
@@ -0,0 +1,8 @@
+#ifndef NFTABLES_NUMGEN_H
+#define NFTABLES_NUMGEN_H
+
+extern struct expr *numgen_expr_alloc(const struct location *loc,
+ enum nft_ng_types type, uint32_t until,
+ uint32_t offset);
+
+#endif /* NFTABLES_NUMGEN_H */
diff --git a/include/osf.h b/include/osf.h
new file mode 100644
index 0000000..8f6f584
--- /dev/null
+++ b/include/osf.h
@@ -0,0 +1,9 @@
+#ifndef NFTABLES_OSF_H
+#define NFTABLES_OSF_H
+
+struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl,
+ const uint32_t flags);
+
+extern int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del);
+
+#endif /* NFTABLES_OSF_H */
diff --git a/include/owner.h b/include/owner.h
new file mode 100644
index 0000000..85d821c
--- /dev/null
+++ b/include/owner.h
@@ -0,0 +1,6 @@
+#ifndef _NFT_OWNER_H_
+#define _NFT_OWNER_H_
+
+char *get_progname(uint32_t portid);
+
+#endif
diff --git a/include/parser.h b/include/parser.h
new file mode 100644
index 0000000..f79a22f
--- /dev/null
+++ b/include/parser.h
@@ -0,0 +1,115 @@
+#ifndef NFTABLES_PARSER_H
+#define NFTABLES_PARSER_H
+
+#include <list.h>
+#include <rule.h> // FIXME
+#include <nftables.h>
+
+#define TABSIZE 8
+
+#define YYLTYPE struct location
+#define YYLTYPE_IS_TRIVIAL 0
+#define YYENABLE_NLS 0
+
+#define SCOPE_NEST_MAX 4
+
+struct parser_state {
+ struct input_descriptor *indesc;
+ struct list_head indesc_list;
+
+ struct list_head *msgs;
+ unsigned int nerrs;
+
+ struct scope *scopes[SCOPE_NEST_MAX];
+ unsigned int scope;
+ bool scope_err;
+
+ unsigned int flex_state_pop;
+ unsigned int startcond_type;
+ struct list_head *cmds;
+ unsigned int *startcond_active;
+};
+
+enum startcond_type {
+ PARSER_SC_BEGIN,
+ PARSER_SC_ARP,
+ PARSER_SC_AT,
+ PARSER_SC_CT,
+ PARSER_SC_COUNTER,
+ PARSER_SC_ETH,
+ PARSER_SC_GRE,
+ PARSER_SC_ICMP,
+ PARSER_SC_IGMP,
+ PARSER_SC_IP,
+ PARSER_SC_IP6,
+ PARSER_SC_LAST,
+ PARSER_SC_LIMIT,
+ PARSER_SC_META,
+ PARSER_SC_POLICY,
+ PARSER_SC_QUOTA,
+ PARSER_SC_SCTP,
+ PARSER_SC_SECMARK,
+ PARSER_SC_TCP,
+ PARSER_SC_TYPE,
+ PARSER_SC_VLAN,
+ PARSER_SC_XT,
+ PARSER_SC_CMD_DESTROY,
+ PARSER_SC_CMD_EXPORT,
+ PARSER_SC_CMD_IMPORT,
+ PARSER_SC_CMD_LIST,
+ PARSER_SC_CMD_MONITOR,
+ PARSER_SC_CMD_RESET,
+ PARSER_SC_EXPR_AH,
+ PARSER_SC_EXPR_COMP,
+ PARSER_SC_EXPR_DCCP,
+ PARSER_SC_EXPR_DST,
+ PARSER_SC_EXPR_ESP,
+ PARSER_SC_EXPR_FIB,
+ PARSER_SC_EXPR_FRAG,
+ PARSER_SC_EXPR_HASH,
+ PARSER_SC_EXPR_HBH,
+ PARSER_SC_EXPR_IPSEC,
+ PARSER_SC_EXPR_MH,
+ PARSER_SC_EXPR_NUMGEN,
+ PARSER_SC_EXPR_OSF,
+ PARSER_SC_EXPR_QUEUE,
+ PARSER_SC_EXPR_RT,
+ PARSER_SC_EXPR_SCTP_CHUNK,
+ PARSER_SC_EXPR_SOCKET,
+ PARSER_SC_EXPR_TH,
+ PARSER_SC_EXPR_UDP,
+ PARSER_SC_EXPR_UDPLITE,
+
+ PARSER_SC_STMT_DUP,
+ PARSER_SC_STMT_FWD,
+ PARSER_SC_STMT_LOG,
+ PARSER_SC_STMT_NAT,
+ PARSER_SC_STMT_REJECT,
+ PARSER_SC_STMT_SYNPROXY,
+ PARSER_SC_STMT_TPROXY,
+
+ __SC_MAX
+};
+
+struct mnl_socket;
+
+extern void parser_init(struct nft_ctx *nft, struct parser_state *state,
+ struct list_head *msgs, struct list_head *cmds,
+ struct scope *top_scope);
+extern int nft_parse(struct nft_ctx *ctx, void *, struct parser_state *state);
+
+extern void *scanner_init(struct parser_state *state);
+extern void scanner_destroy(struct nft_ctx *nft);
+
+extern int scanner_read_file(struct nft_ctx *nft, const char *filename,
+ const struct location *loc);
+extern int scanner_include_file(struct nft_ctx *ctx, void *scanner,
+ const char *filename,
+ const struct location *loc);
+extern void scanner_push_buffer(void *scanner,
+ const struct input_descriptor *indesc,
+ const char *buffer);
+
+extern void scanner_pop_start_cond(void *scanner, enum startcond_type sc);
+
+#endif /* NFTABLES_PARSER_H */
diff --git a/include/payload.h b/include/payload.h
new file mode 100644
index 0000000..08e45f7
--- /dev/null
+++ b/include/payload.h
@@ -0,0 +1,74 @@
+#ifndef NFTABLES_PAYLOAD_H
+#define NFTABLES_PAYLOAD_H
+
+#include <nftables.h>
+#include <proto.h>
+
+extern struct expr *payload_expr_alloc(const struct location *loc,
+ const struct proto_desc *desc,
+ unsigned int type);
+extern void payload_init_raw(struct expr *expr, enum proto_bases base,
+ unsigned int offset, unsigned int len);
+extern unsigned int payload_hdr_field(const struct expr *expr);
+
+struct eval_ctx;
+struct stmt;
+extern int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res);
+int payload_gen_inner_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res);
+extern int payload_gen_icmp_dependency(struct eval_ctx *ctx,
+ const struct expr *expr,
+ struct stmt **res);
+extern int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ const struct proto_desc *dependency,
+ enum proto_bases pb, struct stmt **res);
+
+/**
+ * struct payload_dep_ctx - payload protocol dependency tracking
+ *
+ * @icmp_type: extra info for icmp(6) decoding
+ * @prev: previous statement
+ * @pdeps: last dependency match per protocol layer
+ */
+struct payload_dep_ctx {
+ uint8_t icmp_type;
+ struct stmt *prev;
+ struct stmt *pdeps[PROTO_BASE_MAX + 1];
+};
+
+extern bool payload_is_known(const struct expr *expr);
+extern bool payload_is_stacked(const struct proto_desc *desc,
+ const struct expr *expr);
+
+void payload_dependency_reset(struct payload_dep_ctx *ctx);
+extern void payload_dependency_store(struct payload_dep_ctx *ctx,
+ struct stmt *stmt,
+ enum proto_bases base);
+extern bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
+ enum proto_bases base);
+extern struct expr *payload_dependency_get(struct payload_dep_ctx *ctx,
+ enum proto_bases base);
+extern void payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base);
+extern void payload_dependency_kill(struct payload_dep_ctx *ctx,
+ struct expr *expr, unsigned int family);
+extern void exthdr_dependency_kill(struct payload_dep_ctx *ctx,
+ struct expr *expr, unsigned int family);
+
+extern bool payload_can_merge(const struct expr *e1, const struct expr *e2);
+extern struct expr *payload_expr_join(const struct expr *e1,
+ const struct expr *e2);
+
+bool payload_expr_trim(struct expr *expr, struct expr *mask,
+ const struct proto_ctx *ctx, unsigned int *shift);
+extern void payload_expr_expand(struct list_head *list, struct expr *expr,
+ const struct proto_ctx *ctx);
+extern void payload_expr_complete(struct expr *expr,
+ const struct proto_ctx *ctx);
+
+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
new file mode 100644
index 0000000..9c98a0b
--- /dev/null
+++ b/include/proto.h
@@ -0,0 +1,474 @@
+#ifndef NFTABLES_PROTO_H
+#define NFTABLES_PROTO_H
+
+#include <nftables.h>
+#include <datatype.h>
+#include <linux/netfilter/nf_tables.h>
+
+/**
+ * enum proto_bases - protocol bases
+ *
+ * @PROTO_BASE_INVALID: uninitialised, does not happen
+ * @PROTO_BASE_LL_HDR: link layer header
+ * @PROTO_BASE_NETWORK_HDR: network layer header
+ * @PROTO_BASE_TRANSPORT_HDR: transport layer header
+ */
+enum proto_bases {
+ PROTO_BASE_INVALID,
+ PROTO_BASE_LL_HDR,
+ PROTO_BASE_NETWORK_HDR,
+ PROTO_BASE_TRANSPORT_HDR,
+ PROTO_BASE_INNER_HDR,
+ __PROTO_BASE_MAX
+};
+#define PROTO_BASE_MAX (__PROTO_BASE_MAX - 1)
+
+extern const char *proto_base_names[];
+extern const char *proto_base_tokens[];
+
+enum icmp_hdr_field_type {
+ PROTO_ICMP_ANY = 0,
+ PROTO_ICMP_ECHO, /* echo and reply */
+ PROTO_ICMP_MTU, /* destination unreachable */
+ PROTO_ICMP_ADDRESS, /* redirect */
+ PROTO_ICMP6_MTU,
+ PROTO_ICMP6_PPTR,
+ PROTO_ICMP6_ECHO,
+ PROTO_ICMP6_MGMQ,
+ PROTO_ICMP6_ADDRESS, /* neighbor solicit/advert, redirect and MLD */
+ PROTO_ICMP6_REDIRECT,
+};
+
+/**
+ * struct proto_hdr_template - protocol header field description
+ *
+ * @token: parser token describing the header field
+ * @dtype: data type of the header field
+ * @offset: offset of the header field from base
+ * @len: length of header field
+ * @meta_key: special case: meta expression key
+ * @icmp_dep: special case: icmp header dependency
+ */
+struct proto_hdr_template {
+ const char *token;
+ const struct datatype *dtype;
+ uint16_t offset;
+ uint16_t len;
+ enum byteorder byteorder:8;
+ enum nft_meta_keys meta_key:8;
+ enum icmp_hdr_field_type icmp_dep:8;
+};
+
+#define PROTO_HDR_TEMPLATE(__token, __dtype, __byteorder, __offset, __len)\
+ { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .byteorder = (__byteorder), \
+ .offset = (__offset), \
+ .len = (__len), \
+ }
+
+#define PROTO_META_TEMPLATE(__token, __dtype, __key, __len) \
+ { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .meta_key = (__key), \
+ .len = (__len), \
+ }
+
+#define PROTO_UPPER_MAX 16
+#define PROTO_HDRS_MAX 20
+
+enum proto_desc_id {
+ PROTO_DESC_UNKNOWN = 0,
+ PROTO_DESC_AH,
+ PROTO_DESC_ESP,
+ PROTO_DESC_COMP,
+ PROTO_DESC_ICMP,
+ PROTO_DESC_IGMP,
+ PROTO_DESC_UDP,
+ PROTO_DESC_UDPLITE,
+ PROTO_DESC_TCP,
+ PROTO_DESC_DCCP,
+ PROTO_DESC_SCTP,
+ PROTO_DESC_TH,
+ PROTO_DESC_IP,
+ PROTO_DESC_IP6,
+ PROTO_DESC_ICMPV6,
+ PROTO_DESC_ARP,
+ PROTO_DESC_VLAN,
+ PROTO_DESC_ETHER,
+ PROTO_DESC_VXLAN,
+ PROTO_DESC_GENEVE,
+ PROTO_DESC_GRE,
+ PROTO_DESC_GRETAP,
+ __PROTO_DESC_MAX
+};
+#define PROTO_DESC_MAX (__PROTO_DESC_MAX - 1)
+
+/**
+ * struct proto_desc - protocol header description
+ *
+ * @name: protocol name
+ * @id: protocol identifier
+ * @base: header base
+ * @checksum_key: key of template containing checksum
+ * @protocol_key: key of template containing upper layer protocol description
+ * @length: total size of the header, in bits
+ * @protocols: link to upper layer protocol descriptions indexed by protocol value
+ * @templates: header templates
+ * @pseudohdr: header fields that are part of upper layer checksum pseudoheader
+ */
+struct proto_desc {
+ const char *name;
+ enum proto_desc_id id:8;
+ enum proto_bases base:8;
+ enum nft_payload_csum_types checksum_type:8;
+ uint16_t checksum_key;
+ uint16_t protocol_key;
+ unsigned int length;
+ struct {
+ unsigned int num;
+ const struct proto_desc *desc;
+ } protocols[PROTO_UPPER_MAX];
+ struct proto_hdr_template templates[PROTO_HDRS_MAX];
+ struct {
+ uint8_t order[PROTO_HDRS_MAX];
+ 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), }
+
+/**
+ * struct hook_proto_desc - description of protocol constraints imposed by hook family
+ *
+ * @base: protocol base of packets
+ * @desc: protocol description of packets
+ */
+struct hook_proto_desc {
+ enum proto_bases base;
+ const struct proto_desc *desc;
+};
+
+#define HOOK_PROTO_DESC(__base, __desc) { .base = (__base), .desc = (__desc), }
+
+extern const struct hook_proto_desc hook_proto_desc[];
+
+/**
+ * struct dev_proto_desc - description of device LL protocol
+ *
+ * @desc: protocol description
+ * @type: arphrd value
+ */
+struct dev_proto_desc {
+ const struct proto_desc *desc;
+ uint16_t type;
+};
+
+#define DEV_PROTO_DESC(__type, __desc) { .type = (__type), .desc = (__desc), }
+
+extern int proto_dev_type(const struct proto_desc *desc, uint16_t *res);
+extern const struct proto_desc *proto_dev_desc(uint16_t type);
+
+#define PROTO_CTX_NUM_PROTOS 16
+
+/**
+ * struct proto_ctx - protocol context
+ *
+ * debug_mask: display debugging information
+ * @family: hook family
+ * @location: location of the relational expression defining the context
+ * @desc: protocol description for this layer
+ * @offset: offset from the base, for stacked headers (eg 8*14 for vlan on top of ether)
+ *
+ * The location of the context is the location of the relational expression
+ * defining it, either directly through a protocol match or indirectly
+ * through a dependency.
+ */
+struct proto_ctx {
+ unsigned int debug_mask;
+ uint8_t family;
+ bool inner;
+ union {
+ struct {
+ uint8_t type;
+ } icmp;
+ } th_dep;
+ struct {
+ struct location location;
+ const struct proto_desc *desc;
+ 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, bool inner);
+extern void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
+ const struct location *loc,
+ const struct proto_desc *desc);
+bool proto_ctx_is_ambiguous(struct proto_ctx *ctx, enum proto_bases bases);
+const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx,
+ enum proto_bases base,
+ const struct proto_desc *desc);
+extern const struct proto_desc *proto_find_upper(const struct proto_desc *base,
+ unsigned int num);
+extern int proto_find_num(const struct proto_desc *base,
+ const struct proto_desc *desc);
+const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize,
+ uint32_t flags);
+
+extern const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id);
+
+enum eth_hdr_fields {
+ ETHHDR_INVALID,
+ ETHHDR_DADDR,
+ ETHHDR_SADDR,
+ ETHHDR_TYPE,
+};
+
+enum vlan_hdr_fields {
+ VLANHDR_INVALID,
+ VLANHDR_PCP,
+ VLANHDR_DEI,
+ VLANHDR_CFI,
+ VLANHDR_VID,
+ VLANHDR_TYPE,
+};
+
+enum arp_hdr_fields {
+ ARPHDR_INVALID,
+ ARPHDR_HRD,
+ ARPHDR_PRO,
+ ARPHDR_HLN,
+ ARPHDR_PLN,
+ ARPHDR_OP,
+ ARPHDR_SADDR_ETHER,
+ ARPHDR_SADDR_IP,
+ ARPHDR_DADDR_ETHER,
+ ARPHDR_DADDR_IP,
+};
+
+enum ip_hdr_fields {
+ IPHDR_INVALID,
+ IPHDR_VERSION,
+ IPHDR_HDRLENGTH,
+ IPHDR_DSCP,
+ IPHDR_ECN,
+ IPHDR_LENGTH,
+ IPHDR_ID,
+ IPHDR_FRAG_OFF,
+ IPHDR_TTL,
+ IPHDR_PROTOCOL,
+ IPHDR_CHECKSUM,
+ IPHDR_SADDR,
+ IPHDR_DADDR,
+};
+#define IPHDR_MAX IPHDR_DADDR
+
+enum icmp_hdr_fields {
+ ICMPHDR_INVALID,
+ ICMPHDR_TYPE,
+ ICMPHDR_CODE,
+ ICMPHDR_CHECKSUM,
+ ICMPHDR_ID,
+ ICMPHDR_SEQ,
+ ICMPHDR_GATEWAY,
+ ICMPHDR_MTU,
+};
+
+enum igmp_hdr_fields {
+ IGMPHDR_INVALID,
+ IGMPHDR_TYPE,
+ IGMPHDR_CHECKSUM,
+ IGMPHDR_MRT,
+ IGMPHDR_GROUP,
+};
+
+enum icmp6_hdr_fields {
+ ICMP6HDR_INVALID,
+ ICMP6HDR_TYPE,
+ ICMP6HDR_CODE,
+ ICMP6HDR_CHECKSUM,
+ ICMP6HDR_PPTR,
+ ICMP6HDR_MTU,
+ ICMP6HDR_ID,
+ ICMP6HDR_SEQ,
+ ICMP6HDR_MAXDELAY,
+ ICMP6HDR_TADDR,
+ ICMP6HDR_DADDR,
+};
+
+enum ip6_hdr_fields {
+ IP6HDR_INVALID,
+ IP6HDR_VERSION,
+ IP6HDR_DSCP,
+ IP6HDR_ECN,
+ IP6HDR_FLOWLABEL,
+ IP6HDR_LENGTH,
+ IP6HDR_NEXTHDR,
+ IP6HDR_HOPLIMIT,
+ IP6HDR_SADDR,
+ IP6HDR_DADDR,
+ IP6HDR_PROTOCOL,
+};
+
+enum ah_hdr_fields {
+ AHHDR_INVALID,
+ AHHDR_NEXTHDR,
+ AHHDR_HDRLENGTH,
+ AHHDR_RESERVED,
+ AHHDR_SPI,
+ AHHDR_SEQUENCE,
+};
+
+enum esp_hdr_fields {
+ ESPHDR_INVALID,
+ ESPHDR_SPI,
+ ESPHDR_SEQUENCE,
+};
+
+enum comp_hdr_fields {
+ COMPHDR_INVALID,
+ COMPHDR_NEXTHDR,
+ COMPHDR_FLAGS,
+ COMPHDR_CPI,
+};
+
+enum udp_hdr_fields {
+ UDPHDR_INVALID,
+ UDPHDR_SPORT,
+ UDPHDR_DPORT,
+ UDPHDR_LENGTH,
+ UDPHDR_CSUMCOV = UDPHDR_LENGTH,
+ UDPHDR_CHECKSUM,
+};
+
+enum tcp_hdr_fields {
+ TCPHDR_INVALID,
+ TCPHDR_UNSPEC = TCPHDR_INVALID,
+ TCPHDR_SPORT,
+ TCPHDR_DPORT,
+ TCPHDR_SEQ,
+ TCPHDR_ACKSEQ,
+ TCPHDR_DOFF,
+ TCPHDR_RESERVED,
+ TCPHDR_FLAGS,
+ TCPHDR_WINDOW,
+ TCPHDR_CHECKSUM,
+ TCPHDR_URGPTR,
+};
+
+enum dccp_hdr_fields {
+ DCCPHDR_INVALID,
+ DCCPHDR_SPORT,
+ DCCPHDR_DPORT,
+ DCCPHDR_TYPE,
+};
+
+enum sctp_hdr_fields {
+ SCTPHDR_INVALID,
+ SCTPHDR_SPORT,
+ SCTPHDR_DPORT,
+ SCTPHDR_VTAG,
+ SCTPHDR_CHECKSUM,
+};
+
+enum th_hdr_fields {
+ THDR_INVALID,
+ THDR_SPORT,
+ 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;
+extern const struct proto_desc proto_esp;
+extern const struct proto_desc proto_comp;
+extern const struct proto_desc proto_udp;
+extern const struct proto_desc proto_udplite;
+extern const struct proto_desc proto_tcp;
+extern const struct proto_desc proto_dccp;
+extern const struct proto_desc proto_sctp;
+extern const struct proto_desc proto_th;
+extern const struct proto_desc proto_icmp6;
+
+extern const struct proto_desc proto_ip;
+extern const struct proto_desc proto_ip6;
+
+extern const struct proto_desc proto_inet;
+extern const struct proto_desc proto_inet_service;
+
+extern const struct proto_desc proto_arp;
+
+extern const struct proto_desc proto_vlan;
+extern const struct proto_desc proto_eth;
+
+extern const struct proto_desc proto_netdev;
+
+extern const struct proto_desc proto_unknown;
+extern const struct proto_hdr_template proto_unknown_template;
+
+extern const struct datatype icmp_type_type;
+extern const struct datatype tcp_flag_type;
+extern const struct datatype dccp_pkttype_type;
+extern const struct datatype arpop_type;
+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/rt.h b/include/rt.h
new file mode 100644
index 0000000..195af94
--- /dev/null
+++ b/include/rt.h
@@ -0,0 +1,37 @@
+#ifndef NFTABLES_RT_H
+#define NFTABLES_RT_H
+
+/**
+ * struct rt_template - template for routing expressions
+ *
+ * @token: parser token for the expression
+ * @dtype: data type of the expression
+ * @len: length of the expression
+ * @byteorder: byteorder
+ * @invalid: invalidate datatype on allocation from parser
+ */
+struct rt_template {
+ const char *token;
+ const struct datatype *dtype;
+ unsigned int len;
+ enum byteorder byteorder;
+ bool invalid;
+};
+
+extern const struct rt_template rt_templates[];
+
+#define RT_TEMPLATE(__token, __dtype, __len, __byteorder, __invalid) { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .len = (__len), \
+ .byteorder = (__byteorder), \
+ .invalid = (__invalid), \
+}
+
+extern struct expr *rt_expr_alloc(const struct location *loc,
+ enum nft_rt_keys key, bool invalid);
+extern void rt_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
+
+extern const struct datatype realm_type;
+
+#endif /* NFTABLES_RT_H */
diff --git a/include/rule.h b/include/rule.h
new file mode 100644
index 0000000..6236d29
--- /dev/null
+++ b/include/rule.h
@@ -0,0 +1,791 @@
+#ifndef NFTABLES_RULE_H
+#define NFTABLES_RULE_H
+
+#include <nftables.h>
+#include <list.h>
+#include <netinet/in.h>
+#include <libnftnl/object.h> /* For NFTNL_CTTIMEOUT_ARRAY_MAX. */
+#include <linux/netfilter/nf_tables.h>
+#include <cache.h>
+
+/**
+ * struct handle_spec - handle ID
+ *
+ * @location: location this handle was defined at
+ * @id: handle ID value
+ */
+struct handle_spec {
+ struct location location;
+ uint64_t id;
+};
+
+/**
+ * struct position_spec - position ID
+ *
+ * @location: location this position was defined at
+ * @id: position ID value
+ */
+struct position_spec {
+ struct location location;
+ uint64_t id;
+};
+
+struct table_spec {
+ struct location location;
+ const char *name;
+};
+
+struct chain_spec {
+ struct location location;
+ const char *name;
+};
+
+struct set_spec {
+ struct location location;
+ const char *name;
+};
+
+struct flowtable_spec {
+ struct location location;
+ const char *name;
+};
+
+struct obj_spec {
+ struct location location;
+ const char *name;
+};
+
+/**
+ * struct handle - handle for tables, chains, rules and sets
+ *
+ * @family: protocol family
+ * @table: table name
+ * @chain: chain name (chains and rules only)
+ * @set: set name (sets only)
+ * @obj: stateful object name (stateful object only)
+ * @flowtable: flow table name (flow table only)
+ * @handle: rule handle (rules only)
+ * @position: rule position (rules only)
+ * @set_id: set ID (sets only)
+ */
+struct handle {
+ uint32_t family;
+ struct table_spec table;
+ struct chain_spec chain;
+ struct set_spec set;
+ struct obj_spec obj;
+ struct flowtable_spec flowtable;
+ struct handle_spec handle;
+ struct position_spec position;
+ struct position_spec index;
+ uint32_t set_id;
+ uint32_t chain_id;
+ uint32_t rule_id;
+ uint32_t position_id;
+};
+
+extern void handle_merge(struct handle *dst, const struct handle *src);
+extern void handle_free(struct handle *h);
+
+/**
+ * struct scope
+ *
+ * @parent: pointer to parent scope
+ * @symbols: symbols bound in the scope
+ */
+struct scope {
+ const struct scope *parent;
+ struct list_head symbols;
+};
+
+extern struct scope *scope_alloc(void);
+extern struct scope *scope_init(struct scope *scope, const struct scope *parent);
+extern void scope_release(const struct scope *scope);
+extern void scope_free(struct scope *scope);
+
+/**
+ * struct symbol
+ *
+ * @list: scope symbol list node
+ * @identifier: identifier
+ * @expr: initializer
+ * @refcnt: reference counter
+ */
+struct symbol {
+ struct list_head list;
+ const char *identifier;
+ struct expr *expr;
+ int refcnt;
+};
+
+extern void symbol_bind(struct scope *scope, const char *identifier,
+ struct expr *expr);
+extern int symbol_unbind(const struct scope *scope, const char *identifier);
+extern struct symbol *symbol_lookup(const struct scope *scope,
+ const char *identifier);
+struct symbol *symbol_lookup_fuzzy(const struct scope *scope,
+ const char *identifier);
+struct symbol *symbol_get(const struct scope *scope, const char *identifier);
+
+enum table_flags {
+ TABLE_F_DORMANT = (1 << 0),
+ TABLE_F_OWNER = (1 << 1),
+};
+#define TABLE_FLAGS_MAX 2
+
+const char *table_flag_name(uint32_t flag);
+
+/**
+ * struct table - nftables table
+ *
+ * @list: list node
+ * @handle: table handle
+ * @location: location the table was defined at
+ * @chains: chains contained in the table
+ * @sets: sets contained in the table
+ * @objs: stateful objects contained in the table
+ * @flowtables: flow tables contained in the table
+ * @flags: table flags
+ * @refcnt: table reference counter
+ */
+struct table {
+ struct list_head list;
+ struct cache_item cache;
+ struct handle handle;
+ struct location location;
+ struct scope scope;
+ struct cache chain_cache;
+ struct cache set_cache;
+ struct cache obj_cache;
+ struct cache ft_cache;
+ struct list_head chains;
+ struct list_head sets;
+ struct list_head objs;
+ struct list_head flowtables;
+ struct list_head chain_bindings;
+ enum table_flags flags;
+ unsigned int refcnt;
+ uint32_t owner;
+ const char *comment;
+ bool has_xt_stmts;
+};
+
+extern struct table *table_alloc(void);
+extern struct table *table_get(struct table *table);
+extern void table_free(struct table *table);
+extern struct table *table_lookup_fuzzy(const struct handle *h,
+ const struct nft_cache *cache);
+
+/**
+ * enum chain_flags - chain flags
+ *
+ * @CHAIN_F_BASECHAIN: chain is a base chain
+ */
+enum chain_flags {
+ CHAIN_F_BASECHAIN = 0x1,
+ CHAIN_F_HW_OFFLOAD = 0x2,
+ CHAIN_F_BINDING = 0x4,
+};
+
+/**
+ * enum flowtable_flags - flowtable flags
+ *
+ */
+enum flowtable_flags {
+ FLOWTABLE_F_HW_OFFLOAD = 0x1, /* NF_FLOWTABLE_HW_OFFLOAD in linux nf_flow_table.h */
+};
+
+/**
+ * struct prio_spec - extendend priority specification for mixed
+ * textual/numerical parsing.
+ *
+ * @expr: expr of the standard priority value
+ */
+struct prio_spec {
+ struct location loc;
+ struct expr *expr;
+};
+
+struct hook_spec {
+ struct location loc;
+ const char *name;
+ unsigned int num;
+};
+
+struct chain_type_spec {
+ struct location loc;
+ const char *str;
+};
+
+/**
+ * struct chain - nftables chain
+ *
+ * @list: list node in table list
+ * @handle: chain handle
+ * @location: location the chain was defined at
+ * @refcnt: reference counter
+ * @flags: chain flags
+ * @hookstr: unified and human readable hook name (base chains)
+ * @hooknum: hook number (base chains)
+ * @priority: hook priority (base chains)
+ * @policy: default chain policy (base chains)
+ * @type: chain type
+ * @dev: device (if any)
+ * @rules: rules contained in the chain
+ */
+struct chain {
+ struct list_head list;
+ struct cache_item cache;
+ struct handle handle;
+ struct location location;
+ unsigned int refcnt;
+ uint32_t flags;
+ const char *comment;
+ struct {
+ struct location loc;
+ struct prio_spec priority;
+ struct hook_spec hook;
+ struct expr *policy;
+ struct chain_type_spec type;
+ const char **dev_array;
+ struct expr *dev_expr;
+ int dev_array_len;
+ };
+ struct scope scope;
+ struct list_head rules;
+};
+
+#define STD_PRIO_BUFSIZE 100
+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(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,
+ const struct nft_cache *cache,
+ const struct table **table);
+extern struct chain *chain_binding_lookup(const struct table *table,
+ const char *chain_name);
+
+extern const char *family2str(unsigned int family);
+#define __NF_ARP_INGRESS 255
+extern const char *hooknum2str(unsigned int family, unsigned int hooknum);
+extern const char *chain_policy2str(uint32_t policy);
+extern void chain_print_plain(const struct chain *chain,
+ struct output_ctx *octx);
+extern void chain_rules_print(const struct chain *chain,
+ struct output_ctx *octx, const char *indent);
+
+/**
+ * struct rule - nftables rule
+ *
+ * @list: list node in chain list
+ * @handle: rule handle
+ * @location: location the rule was defined at
+ * @stmt: list of statements
+ * @num_stmts: number of statements in stmts list
+ * @comment: comment
+ * @refcnt: rule reference counter
+ */
+struct rule {
+ struct list_head list;
+ struct handle handle;
+ struct location location;
+ struct list_head stmts;
+ unsigned int num_stmts;
+ const char *comment;
+ unsigned int refcnt;
+};
+
+extern struct rule *rule_alloc(const struct location *loc,
+ const struct handle *h);
+extern struct rule *rule_get(struct rule *rule);
+extern void rule_free(struct rule *rule);
+extern void rule_print(const struct rule *rule, struct output_ctx *octx);
+extern struct rule *rule_lookup(const struct chain *chain, uint64_t handle);
+extern struct rule *rule_lookup_by_index(const struct chain *chain,
+ uint64_t index);
+void rule_stmt_append(struct rule *rule, struct stmt *stmt);
+void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
+ struct stmt *stmt);
+
+/**
+ * struct set - nftables set
+ *
+ * @list: table set list node
+ * @handle: set handle
+ * @location: location the set was defined/declared at
+ * @refcnt: reference count
+ * @flags: bitmask of set flags
+ * @gc_int: garbage collection interval
+ * @timeout: default timeout value
+ * @key: key expression (data type, length))
+ * @data: mapping data expression
+ * @objtype: mapping object type
+ * @existing_set: reference to existing set in the kernel
+ * @init: initializer
+ * @rg_cache: cached range element (left)
+ * @policy: set mechanism policy
+ * @automerge: merge adjacents and overlapping elements, if possible
+ * @comment: comment
+ * @desc.size: count of set elements
+ * @desc.field_len: length of single concatenated fields, bytes
+ * @desc.field_count: count of concatenated fields
+ */
+struct set {
+ struct list_head list;
+ struct cache_item cache;
+ struct handle handle;
+ struct location location;
+ unsigned int refcnt;
+ uint32_t flags;
+ uint32_t gc_int;
+ uint64_t timeout;
+ struct expr *key;
+ struct expr *data;
+ uint32_t objtype;
+ struct set *existing_set;
+ struct expr *init;
+ struct expr *rg_cache;
+ uint32_t policy;
+ struct list_head stmt_list;
+ bool root;
+ bool automerge;
+ bool key_typeof_valid;
+ const char *comment;
+ struct {
+ uint32_t size;
+ uint8_t field_len[NFT_REG32_COUNT];
+ uint8_t field_count;
+ } desc;
+};
+
+extern struct set *set_alloc(const struct location *loc);
+extern struct set *set_get(struct set *set);
+extern void set_free(struct set *set);
+extern struct set *set_clone(const struct set *set);
+extern struct set *set_lookup_global(uint32_t family, const char *table,
+ const char *name, struct nft_cache *cache);
+extern struct set *set_lookup_fuzzy(const char *set_name,
+ const struct nft_cache *cache,
+ const struct table **table);
+extern const char *set_policy2str(uint32_t policy);
+extern void set_print(const struct set *set, struct output_ctx *octx);
+extern void set_print_plain(const struct set *s, struct output_ctx *octx);
+
+static inline bool set_is_datamap(uint32_t set_flags)
+{
+ return set_flags & NFT_SET_MAP;
+}
+
+static inline bool set_is_objmap(uint32_t set_flags)
+{
+ return set_flags & NFT_SET_OBJECT;
+}
+
+static inline bool set_is_map(uint32_t set_flags)
+{
+ return set_is_datamap(set_flags) || set_is_objmap(set_flags);
+}
+
+static inline bool set_is_anonymous(uint32_t set_flags)
+{
+ return set_flags & NFT_SET_ANONYMOUS;
+}
+
+static inline bool set_is_literal(uint32_t set_flags)
+{
+ return !(set_is_anonymous(set_flags) || set_is_map(set_flags));
+}
+
+static inline bool map_is_literal(uint32_t set_flags)
+{
+ return !(set_is_anonymous(set_flags) || !set_is_map(set_flags));
+}
+
+static inline bool set_is_meter(uint32_t set_flags)
+{
+ return set_is_anonymous(set_flags) && (set_flags & NFT_SET_EVAL);
+}
+
+static inline bool set_is_interval(uint32_t set_flags)
+{
+ return set_flags & NFT_SET_INTERVAL;
+}
+
+static inline bool set_is_non_concat_range(struct set *s)
+{
+ return (s->flags & NFT_SET_INTERVAL) && s->desc.field_count <= 1;
+}
+
+#include <statement.h>
+
+struct counter {
+ uint64_t packets;
+ uint64_t bytes;
+};
+
+struct quota {
+ uint64_t bytes;
+ uint64_t used;
+ uint32_t flags;
+};
+
+struct ct_helper {
+ char name[16];
+ uint16_t l3proto;
+ uint8_t l4proto;
+};
+
+struct timeout_state {
+ struct list_head head;
+ struct location location;
+ uint8_t timeout_index;
+ const char *timeout_str;
+ unsigned int timeout_value;
+};
+
+struct ct_timeout {
+ uint16_t l3proto;
+ uint8_t l4proto;
+ uint32_t timeout[NFTNL_CTTIMEOUT_ARRAY_MAX];
+ struct list_head timeout_list;
+};
+
+struct ct_expect {
+ uint16_t l3proto;
+ uint8_t l4proto;
+ uint16_t dport;
+ uint32_t timeout;
+ uint8_t size;
+};
+
+struct limit {
+ uint64_t rate;
+ uint64_t unit;
+ uint32_t burst;
+ uint32_t type;
+ uint32_t flags;
+};
+
+struct synproxy {
+ uint16_t mss;
+ uint8_t wscale;
+ uint32_t flags;
+};
+
+struct secmark {
+ char ctx[NFT_SECMARK_CTX_MAXLEN];
+};
+
+/**
+ * struct obj - nftables stateful object statement
+ *
+ * @list: table set list node
+ * @location: location the stateful object was defined/declared at
+ * @handle: counter handle
+ * @type: type of stateful object
+ * @refcnt: object reference counter
+ */
+struct obj {
+ struct list_head list;
+ struct cache_item cache;
+ struct location location;
+ struct handle handle;
+ uint32_t type;
+ unsigned int refcnt;
+ const char *comment;
+ union {
+ struct counter counter;
+ struct quota quota;
+ struct ct_helper ct_helper;
+ struct limit limit;
+ struct ct_timeout ct_timeout;
+ struct secmark secmark;
+ struct ct_expect ct_expect;
+ struct synproxy synproxy;
+ };
+};
+
+struct obj *obj_alloc(const struct location *loc);
+extern struct obj *obj_get(struct obj *obj);
+void obj_free(struct obj *obj);
+struct obj *obj_lookup_fuzzy(const char *obj_name,
+ const struct nft_cache *cache,
+ const struct table **t);
+void obj_print(const struct obj *n, struct output_ctx *octx);
+void obj_print_plain(const struct obj *obj, struct output_ctx *octx);
+const char *obj_type_name(uint32_t type);
+enum cmd_obj obj_type_to_cmd(uint32_t type);
+
+struct flowtable {
+ struct list_head list;
+ struct cache_item cache;
+ struct handle handle;
+ struct scope scope;
+ struct location location;
+ struct hook_spec hook;
+ struct prio_spec priority;
+ const char **dev_array;
+ struct expr *dev_expr;
+ int dev_array_len;
+ uint32_t flags;
+ unsigned int refcnt;
+};
+
+extern struct flowtable *flowtable_alloc(const struct location *loc);
+extern struct flowtable *flowtable_get(struct flowtable *flowtable);
+extern void flowtable_free(struct flowtable *flowtable);
+extern struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
+ const struct nft_cache *cache,
+ const struct table **table);
+
+void flowtable_print(const struct flowtable *n, struct output_ctx *octx);
+
+/**
+ * enum cmd_ops - command operations
+ *
+ * @CMD_INVALID: invalid
+ * @CMD_ADD: add object (non-exclusive)
+ * @CMD_REPLACE, replace object
+ * @CMD_CREATE: create object (exclusive)
+ * @CMD_INSERT: insert object
+ * @CMD_DELETE: delete object
+ * @CMD_GET: get object
+ * @CMD_LIST: list container
+ * @CMD_RESET: reset container
+ * @CMD_FLUSH: flush container
+ * @CMD_RENAME: rename object
+ * @CMD_IMPORT: import a ruleset in a given format
+ * @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,
+ CMD_ADD,
+ CMD_REPLACE,
+ CMD_CREATE,
+ CMD_INSERT,
+ CMD_DELETE,
+ CMD_GET,
+ CMD_LIST,
+ CMD_RESET,
+ CMD_FLUSH,
+ CMD_RENAME,
+ CMD_IMPORT,
+ CMD_EXPORT,
+ CMD_MONITOR,
+ CMD_DESCRIBE,
+ CMD_DESTROY,
+};
+
+/**
+ * enum cmd_obj - command objects
+ *
+ * @CMD_OBJ_INVALID: invalid
+ * @CMD_OBJ_ELEMENTS: set element(s)
+ * @CMD_OBJ_SET: set
+ * @CMD_OBJ_SETS: multiple sets
+ * @CMD_OBJ_SETELEMS: set elements
+ * @CMD_OBJ_RULE: rule
+ * @CMD_OBJ_CHAIN: chain
+ * @CMD_OBJ_CHAINS: multiple chains
+ * @CMD_OBJ_TABLE: table
+ * @CMD_OBJ_FLOWTABLE: flowtable
+ * @CMD_OBJ_FLOWTABLES: flowtables
+ * @CMD_OBJ_RULESET: ruleset
+ * @CMD_OBJ_EXPR: expression
+ * @CMD_OBJ_MONITOR: monitor
+ * @CMD_OBJ_MARKUP: import/export
+ * @CMD_OBJ_METER: meter
+ * @CMD_OBJ_METERS: meters
+ * @CMD_OBJ_COUNTER: counter
+ * @CMD_OBJ_COUNTERS: multiple counters
+ * @CMD_OBJ_QUOTA: quota
+ * @CMD_OBJ_QUOTAS: multiple quotas
+ * @CMD_OBJ_LIMIT: limit
+ * @CMD_OBJ_LIMITS: multiple limits
+ * @CMD_OBJ_SECMARK: secmark
+ * @CMD_OBJ_SECMARKS: multiple secmarks
+ * @CMD_OBJ_SYNPROXY: synproxy
+ * @CMD_OBJ_SYNPROXYS: multiple synproxys
+ */
+enum cmd_obj {
+ CMD_OBJ_INVALID,
+ CMD_OBJ_ELEMENTS,
+ CMD_OBJ_SET,
+ CMD_OBJ_SETELEMS,
+ CMD_OBJ_SETS,
+ CMD_OBJ_RULE,
+ CMD_OBJ_RULES,
+ CMD_OBJ_CHAIN,
+ CMD_OBJ_CHAINS,
+ CMD_OBJ_TABLE,
+ CMD_OBJ_RULESET,
+ CMD_OBJ_EXPR,
+ CMD_OBJ_MONITOR,
+ CMD_OBJ_MARKUP,
+ CMD_OBJ_METER,
+ CMD_OBJ_METERS,
+ CMD_OBJ_MAP,
+ CMD_OBJ_MAPS,
+ CMD_OBJ_COUNTER,
+ CMD_OBJ_COUNTERS,
+ CMD_OBJ_QUOTA,
+ CMD_OBJ_QUOTAS,
+ CMD_OBJ_CT_HELPER,
+ CMD_OBJ_CT_HELPERS,
+ CMD_OBJ_LIMIT,
+ CMD_OBJ_LIMITS,
+ CMD_OBJ_FLOWTABLE,
+ CMD_OBJ_FLOWTABLES,
+ CMD_OBJ_CT_TIMEOUT,
+ CMD_OBJ_CT_TIMEOUTS,
+ CMD_OBJ_SECMARK,
+ CMD_OBJ_SECMARKS,
+ CMD_OBJ_CT_EXPECT,
+ CMD_OBJ_CT_EXPECTATIONS,
+ CMD_OBJ_SYNPROXY,
+ CMD_OBJ_SYNPROXYS,
+ CMD_OBJ_HOOKS,
+};
+
+struct markup {
+ uint32_t format;
+};
+
+struct markup *markup_alloc(uint32_t format);
+void markup_free(struct markup *m);
+
+enum {
+ CMD_MONITOR_OBJ_ANY,
+ CMD_MONITOR_OBJ_TABLES,
+ CMD_MONITOR_OBJ_CHAINS,
+ CMD_MONITOR_OBJ_RULES,
+ CMD_MONITOR_OBJ_SETS,
+ CMD_MONITOR_OBJ_ELEMS,
+ CMD_MONITOR_OBJ_RULESET,
+ CMD_MONITOR_OBJ_TRACE,
+ CMD_MONITOR_OBJ_MAX
+};
+
+struct monitor {
+ struct location location;
+ uint32_t format;
+ uint32_t flags;
+ uint32_t type;
+ const char *event;
+};
+
+struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event);
+void monitor_free(struct monitor *m);
+
+#define NFT_NLATTR_LOC_MAX 32
+
+struct nlerr_loc {
+ uint16_t offset;
+ const struct location *location;
+};
+
+/**
+ * struct cmd - command statement
+ *
+ * @list: list node
+ * @location: location of the statement
+ * @op: operation
+ * @obj: object type to perform operation on
+ * @handle: handle for operations working without full objects
+ * @seqnum: sequence number to match netlink errors
+ * @union: object
+ * @arg: argument data
+ */
+struct cmd {
+ struct list_head list;
+ struct location location;
+ enum cmd_ops op;
+ enum cmd_obj obj;
+ struct handle handle;
+ uint32_t seqnum;
+ struct list_head collapse_list;
+ union {
+ void *data;
+ struct expr *expr;
+ struct set *set;
+ struct {
+ struct expr *expr; /* same offset as cmd->expr */
+ struct set *set;
+ } elem;
+ struct rule *rule;
+ struct chain *chain;
+ struct table *table;
+ struct flowtable *flowtable;
+ struct monitor *monitor;
+ struct markup *markup;
+ struct obj *object;
+ };
+ struct nlerr_loc *attr;
+ uint32_t attr_array_len;
+ uint32_t num_attrs;
+ const void *arg;
+};
+
+extern struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
+ const struct handle *h, const struct location *loc,
+ void *data);
+extern 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);
+
+#include <payload.h>
+#include <expression.h>
+
+/**
+ * struct eval_ctx - evaluation context
+ *
+ * @nft: nftables context
+ * @msgs: message queue
+ * @cmd: current command
+ * @table: current table
+ * @rule: current rule
+ * @set: current set
+ * @stmt: current statement
+ * @cache: cache context
+ * @debug_mask: debugging bitmask
+ * @ectx: expression context
+ * @pctx: payload context
+ */
+struct eval_ctx {
+ struct nft_ctx *nft;
+ struct list_head *msgs;
+ struct cmd *cmd;
+ struct table *table;
+ struct rule *rule;
+ struct set *set;
+ struct stmt *stmt;
+ uint32_t stmt_len;
+ struct expr_ctx ectx;
+ struct proto_ctx _pctx[2];
+ const struct proto_desc *inner_desc;
+};
+
+extern int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd);
+
+extern struct error_record *rule_postprocess(struct rule *rule);
+
+struct netlink_ctx;
+extern int do_command(struct netlink_ctx *ctx, struct cmd *cmd);
+
+struct timeout_protocol {
+ uint32_t array_size;
+ const char *const *state_to_name;
+ uint32_t *dflt_timeout;
+};
+
+extern struct timeout_protocol timeout_protocol[UINT8_MAX + 1];
+extern int timeout_str2num(uint16_t l4proto, struct timeout_state *ts);
+
+#endif /* NFTABLES_RULE_H */
diff --git a/include/sctp_chunk.h b/include/sctp_chunk.h
new file mode 100644
index 0000000..3819200
--- /dev/null
+++ b/include/sctp_chunk.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright Red Hat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#ifndef NFTABLES_SCTP_CHUNK_H
+#define NFTABLES_SCTP_CHUNK_H
+
+/* SCTP chunk types used on wire */
+enum sctp_hdr_chunk_types {
+ SCTP_CHUNK_TYPE_DATA = 0,
+ SCTP_CHUNK_TYPE_INIT = 1,
+ SCTP_CHUNK_TYPE_INIT_ACK = 2,
+ SCTP_CHUNK_TYPE_SACK = 3,
+ SCTP_CHUNK_TYPE_HEARTBEAT = 4,
+ SCTP_CHUNK_TYPE_HEARTBEAT_ACK = 5,
+ SCTP_CHUNK_TYPE_ABORT = 6,
+ SCTP_CHUNK_TYPE_SHUTDOWN = 7,
+ SCTP_CHUNK_TYPE_SHUTDOWN_ACK = 8,
+ SCTP_CHUNK_TYPE_ERROR = 9,
+ SCTP_CHUNK_TYPE_COOKIE_ECHO = 10,
+ SCTP_CHUNK_TYPE_COOKIE_ACK = 11,
+ SCTP_CHUNK_TYPE_ECNE = 12,
+ SCTP_CHUNK_TYPE_CWR = 13,
+ SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE = 14,
+ SCTP_CHUNK_TYPE_ASCONF_ACK = 128,
+ SCTP_CHUNK_TYPE_FORWARD_TSN = 192,
+ SCTP_CHUNK_TYPE_ASCONF = 193,
+};
+
+enum sctp_hdr_chunk_common_fields {
+ SCTP_CHUNK_COMMON_TYPE,
+ SCTP_CHUNK_COMMON_FLAGS,
+ SCTP_CHUNK_COMMON_LENGTH,
+ __SCTP_CHUNK_COMMON_MAX,
+};
+
+#define SCTP_CHUNK_START_INDEX __SCTP_CHUNK_COMMON_MAX
+
+enum sctp_hdr_chunk_data_fields {
+ SCTP_CHUNK_DATA_TSN = SCTP_CHUNK_START_INDEX,
+ SCTP_CHUNK_DATA_STREAM,
+ SCTP_CHUNK_DATA_SSN,
+ SCTP_CHUNK_DATA_PPID,
+};
+
+enum sctp_hdr_chunk_init_fields {
+ SCTP_CHUNK_INIT_TAG = SCTP_CHUNK_START_INDEX,
+ SCTP_CHUNK_INIT_RWND,
+ SCTP_CHUNK_INIT_OSTREAMS,
+ SCTP_CHUNK_INIT_ISTREAMS,
+ SCTP_CHUNK_INIT_TSN,
+};
+
+enum sctp_hdr_chunk_sack_fields {
+ SCTP_CHUNK_SACK_CTSN_ACK = SCTP_CHUNK_START_INDEX,
+ SCTP_CHUNK_SACK_RWND,
+ SCTP_CHUNK_SACK_GACK_BLOCKS,
+ SCTP_CHUNK_SACK_DUP_TSNS,
+};
+
+enum sctp_hdr_chunk_shutdown_fields {
+ SCTP_CHUNK_SHUTDOWN_CTSN_ACK = SCTP_CHUNK_START_INDEX,
+};
+
+enum sctp_hdr_chunk_ecne_cwr_fields {
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN = SCTP_CHUNK_START_INDEX,
+};
+
+enum sctp_hdr_chunk_asconf_fields {
+ SCTP_CHUNK_ASCONF_SEQNO = SCTP_CHUNK_START_INDEX,
+};
+
+enum sctp_hdr_chunk_fwd_tsn_fields {
+ SCTP_CHUNK_FORWARD_TSN_NCTSN = SCTP_CHUNK_START_INDEX,
+};
+
+struct expr *sctp_chunk_expr_alloc(const struct location *loc,
+ unsigned int type, unsigned int field);
+void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off,
+ unsigned int len, uint32_t flags);
+const struct exthdr_desc *sctp_chunk_protocol_find(const char *name);
+
+#endif /* NFTABLES_SCTP_CHUNK_H */
diff --git a/include/socket.h b/include/socket.h
new file mode 100644
index 0000000..79938cc
--- /dev/null
+++ b/include/socket.h
@@ -0,0 +1,24 @@
+#ifndef NFTABLES_SOCKET_H
+#define NFTABLES_SOCKET_H
+
+/**
+ * struct socket_template - template for routing expressions
+ *
+ * @token: parser token for the expression
+ * @dtype: data type of the expression
+ * @len: length of the expression
+ * @byteorder: byteorder
+ */
+struct socket_template {
+ const char *token;
+ const struct datatype *dtype;
+ unsigned int len;
+ enum byteorder byteorder;
+};
+
+extern const struct socket_template socket_templates[];
+
+extern struct expr *socket_expr_alloc(const struct location *loc,
+ enum nft_socket_keys key, uint32_t level);
+
+#endif /* NFTABLES_SOCKET_H */
diff --git a/include/statement.h b/include/statement.h
new file mode 100644
index 0000000..720a6ac
--- /dev/null
+++ b/include/statement.h
@@ -0,0 +1,426 @@
+#ifndef NFTABLES_STATEMENT_H
+#define NFTABLES_STATEMENT_H
+
+#include <list.h>
+#include <expression.h>
+#include <json.h>
+
+extern struct stmt *expr_stmt_alloc(const struct location *loc,
+ struct expr *expr);
+
+extern struct stmt *verdict_stmt_alloc(const struct location *loc,
+ struct expr *expr);
+
+struct chain_stmt {
+ struct chain *chain;
+ struct expr *expr;
+};
+
+struct stmt *chain_stmt_alloc(const struct location *loc, struct chain *chain,
+ enum nft_verdicts verdict);
+
+struct flow_stmt {
+ const char *table_name;
+};
+
+struct stmt *flow_stmt_alloc(const struct location *loc, const char *name);
+
+struct objref_stmt {
+ uint32_t type;
+ struct expr *expr;
+};
+
+const char *objref_type_name(uint32_t type);
+struct stmt *objref_stmt_alloc(const struct location *loc);
+
+struct connlimit_stmt {
+ uint32_t count;
+ uint32_t flags;
+};
+
+extern struct stmt *connlimit_stmt_alloc(const struct location *loc);
+
+struct counter_stmt {
+ uint64_t packets;
+ uint64_t bytes;
+};
+
+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;
+};
+
+extern struct stmt *exthdr_stmt_alloc(const struct location *loc,
+ struct expr *payload, struct expr *expr);
+
+struct payload_stmt {
+ struct expr *expr;
+ struct expr *val;
+};
+
+extern struct stmt *payload_stmt_alloc(const struct location *loc,
+ struct expr *payload, struct expr *expr);
+
+#include <meta.h>
+struct meta_stmt {
+ enum nft_meta_keys key;
+ const struct meta_template *tmpl;
+ struct expr *expr;
+};
+
+extern struct stmt *meta_stmt_alloc(const struct location *loc,
+ enum nft_meta_keys key,
+ struct expr *expr);
+
+enum {
+ STMT_LOG_PREFIX = (1 << 0),
+ STMT_LOG_SNAPLEN = (1 << 1),
+ STMT_LOG_GROUP = (1 << 2),
+ STMT_LOG_QTHRESHOLD = (1 << 3),
+ STMT_LOG_LEVEL = (1 << 4),
+};
+
+struct log_stmt {
+ struct expr *prefix;
+ unsigned int snaplen;
+ uint16_t group;
+ uint16_t qthreshold;
+ uint32_t level;
+ uint32_t logflags;
+ uint32_t flags;
+};
+
+extern const char *log_level(uint32_t level);
+extern int log_level_parse(const char *level);
+extern struct stmt *log_stmt_alloc(const struct location *loc);
+
+
+struct limit_stmt {
+ uint64_t rate;
+ uint64_t unit;
+ enum nft_limit_type type;
+ uint32_t burst;
+ uint32_t flags;
+};
+
+extern struct stmt *limit_stmt_alloc(const struct location *loc);
+extern void __limit_stmt_print(const struct limit_stmt *limit);
+
+struct reject_stmt {
+ struct expr *expr;
+ enum nft_reject_types type:8;
+ int8_t icmp_code;
+ uint8_t verbose_print:1;
+ unsigned int family;
+};
+
+extern struct stmt *reject_stmt_alloc(const struct location *loc);
+
+enum nft_nat_etypes {
+ __NFT_NAT_SNAT = NFT_NAT_SNAT,
+ __NFT_NAT_DNAT = NFT_NAT_DNAT,
+ NFT_NAT_MASQ,
+ NFT_NAT_REDIR,
+};
+
+extern const char *nat_etype2str(enum nft_nat_etypes type);
+
+enum {
+ STMT_NAT_F_INTERVAL = (1 << 0),
+ STMT_NAT_F_PREFIX = (1 << 1),
+ STMT_NAT_F_CONCAT = (1 << 2),
+};
+
+struct nat_stmt {
+ enum nft_nat_etypes type;
+ struct expr *addr;
+ struct expr *proto;
+ uint32_t flags;
+ uint8_t family;
+ uint32_t type_flags;
+};
+
+extern struct stmt *nat_stmt_alloc(const struct location *loc,
+ enum nft_nat_etypes type);
+
+struct optstrip_stmt {
+ struct expr *expr;
+};
+
+extern struct stmt *optstrip_stmt_alloc(const struct location *loc, struct expr *e);
+
+struct tproxy_stmt {
+ struct expr *addr;
+ struct expr *port;
+ uint8_t family;
+ uint8_t table_family; /* only used for printing the rule */
+};
+
+extern struct stmt *tproxy_stmt_alloc(const struct location *loc);
+
+struct queue_stmt {
+ struct expr *queue;
+ uint16_t flags;
+};
+
+extern struct stmt *queue_stmt_alloc(const struct location *loc,
+ struct expr *e, uint16_t flags);
+
+struct quota_stmt {
+ uint64_t bytes;
+ uint64_t used;
+ uint32_t flags;
+};
+
+struct stmt *quota_stmt_alloc(const struct location *loc);
+
+#include <ct.h>
+struct ct_stmt {
+ enum nft_ct_keys key;
+ const struct ct_template *tmpl;
+ struct expr *expr;
+ int8_t direction;
+};
+
+extern struct stmt *ct_stmt_alloc(const struct location *loc,
+ enum nft_ct_keys key,
+ int8_t direction,
+ struct expr *expr);
+struct dup_stmt {
+ struct expr *to;
+ struct expr *dev;
+};
+
+struct stmt *dup_stmt_alloc(const struct location *loc);
+uint32_t dup_stmt_type(const char *type);
+
+struct fwd_stmt {
+ uint8_t family;
+ struct expr *addr;
+ struct expr *dev;
+};
+
+struct stmt *fwd_stmt_alloc(const struct location *loc);
+uint32_t fwd_stmt_type(const char *type);
+
+struct set_stmt {
+ struct expr *set;
+ struct expr *key;
+ struct list_head stmt_list;
+ enum nft_dynset_ops op;
+};
+
+extern const char * const set_stmt_op_names[];
+
+extern struct stmt *set_stmt_alloc(const struct location *loc);
+
+struct map_stmt {
+ struct expr *set;
+ struct expr *key;
+ struct expr *data;
+ struct list_head stmt_list;
+ enum nft_dynset_ops op;
+};
+
+extern struct stmt *map_stmt_alloc(const struct location *loc);
+
+struct synproxy_stmt {
+ uint16_t mss;
+ uint8_t wscale;
+ uint32_t flags;
+};
+
+extern struct stmt *synproxy_stmt_alloc(const struct location *loc);
+
+struct meter_stmt {
+ struct expr *set;
+ struct expr *key;
+ struct stmt *stmt;
+ const char *name;
+ uint32_t size;
+};
+
+extern struct stmt *meter_stmt_alloc(const struct location *loc);
+
+/**
+ * enum nft_xt_type - xtables statement types
+ *
+ * @NFT_XT_MATCH: match
+ * @NFT_XT_TARGET: target
+ * @NFT_XT_WATCHER: watcher (only for the bridge family)
+ */
+enum nft_xt_type {
+ NFT_XT_MATCH = 0,
+ NFT_XT_TARGET,
+ NFT_XT_WATCHER,
+};
+#define NFT_XT_MAX (NFT_XT_WATCHER + 1)
+
+struct xtables_match;
+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;
+};
+
+extern struct stmt *xt_stmt_alloc(const struct location *loc);
+
+/**
+ * enum stmt_types - statement types
+ *
+ * @STMT_INVALID: uninitialised
+ * @STMT_EXPRESSION: expression statement (relational)
+ * @STMT_VERDICT: verdict statement
+ * @STMT_METER: meter statement
+ * @STMT_COUNTER: counters
+ * @STMT_PAYLOAD: payload statement
+ * @STMT_META: meta statement
+ * @STMT_LIMIT: limit statement
+ * @STMT_LOG: log statement
+ * @STMT_REJECT: REJECT statement
+ * @STMT_NAT: NAT statement
+ * @STMT_QUEUE: QUEUE statement
+ * @STMT_CT: conntrack statement
+ * @STMT_SET: set statement
+ * @STMT_DUP: dup statement
+ * @STMT_FWD: forward statement
+ * @STMT_XT: XT statement
+ * @STMT_QUOTA: quota statement
+ * @STMT_NOTRACK: notrack statement
+ * @STMT_OBJREF: stateful object reference statement
+ * @STMT_EXTHDR: extension header statement
+ * @STMT_FLOW_OFFLOAD: flow offload statement
+ * @STMT_CONNLIMIT: connection limit statement
+ * @STMT_MAP: map statement
+ * @STMT_SYNPROXY: synproxy statement
+ * @STMT_CHAIN: chain statement
+ * @STMT_OPTSTRIP: optstrip statement
+ * @STMT_LAST: last statement
+ */
+enum stmt_types {
+ STMT_INVALID,
+ STMT_EXPRESSION,
+ STMT_VERDICT,
+ STMT_METER,
+ STMT_COUNTER,
+ STMT_PAYLOAD,
+ STMT_META,
+ STMT_LIMIT,
+ STMT_LOG,
+ STMT_REJECT,
+ STMT_NAT,
+ STMT_TPROXY,
+ STMT_QUEUE,
+ STMT_CT,
+ STMT_SET,
+ STMT_DUP,
+ STMT_FWD,
+ STMT_XT,
+ STMT_QUOTA,
+ STMT_NOTRACK,
+ STMT_OBJREF,
+ STMT_EXTHDR,
+ STMT_FLOW_OFFLOAD,
+ STMT_CONNLIMIT,
+ STMT_MAP,
+ STMT_SYNPROXY,
+ STMT_CHAIN,
+ STMT_OPTSTRIP,
+ STMT_LAST,
+};
+
+/**
+ * struct stmt_ops
+ *
+ * @type: statement type
+ * @name: name
+ * @destroy: destructor
+ * @print: function to print statement
+ */
+struct stmt;
+struct stmt_ops {
+ enum stmt_types type;
+ const char *name;
+ void (*destroy)(struct stmt *stmt);
+ void (*print)(const struct stmt *stmt,
+ struct output_ctx *octx);
+ json_t *(*json)(const struct stmt *stmt,
+ struct output_ctx *octx);
+};
+
+enum stmt_flags {
+ STMT_F_TERMINAL = 0x1,
+ STMT_F_STATEFUL = 0x2,
+};
+
+/**
+ * struct stmt
+ *
+ * @list: rule list node
+ * @ops: statement ops
+ * @location: location where the statement was defined
+ * @flags: statement flags
+ * @union: type specific data
+ */
+struct stmt {
+ struct list_head list;
+ const struct stmt_ops *ops;
+ struct location location;
+ enum stmt_flags flags;
+
+ union {
+ struct expr *expr;
+ struct exthdr_stmt exthdr;
+ struct meter_stmt meter;
+ struct connlimit_stmt connlimit;
+ struct counter_stmt counter;
+ struct payload_stmt payload;
+ struct meta_stmt meta;
+ struct last_stmt last;
+ struct log_stmt log;
+ struct limit_stmt limit;
+ struct reject_stmt reject;
+ struct nat_stmt nat;
+ struct tproxy_stmt tproxy;
+ struct optstrip_stmt optstrip;
+ struct queue_stmt queue;
+ struct quota_stmt quota;
+ struct ct_stmt ct;
+ struct set_stmt set;
+ struct dup_stmt dup;
+ struct fwd_stmt fwd;
+ struct xt_stmt xt;
+ struct objref_stmt objref;
+ struct flow_stmt flow;
+ struct map_stmt map;
+ struct synproxy_stmt synproxy;
+ struct chain_stmt chain;
+ };
+};
+
+extern struct stmt *stmt_alloc(const struct location *loc,
+ const struct stmt_ops *ops);
+int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt);
+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);
+
+const char *get_rate(uint64_t byte_rate, uint64_t *rate);
+const char *get_unit(uint64_t u);
+
+#endif /* NFTABLES_STATEMENT_H */
diff --git a/include/tcpopt.h b/include/tcpopt.h
new file mode 100644
index 0000000..3a0b842
--- /dev/null
+++ b/include/tcpopt.h
@@ -0,0 +1,85 @@
+#ifndef NFTABLES_TCPOPT_H
+#define NFTABLES_TCPOPT_H
+
+#include <proto.h>
+#include <exthdr.h>
+#include <statement.h>
+
+extern struct expr *tcpopt_expr_alloc(const struct location *loc,
+ unsigned int kind, unsigned int field);
+
+extern void tcpopt_init_raw(struct expr *expr, uint8_t type,
+ unsigned int offset, unsigned int len,
+ uint32_t flags);
+
+extern bool tcpopt_find_template(struct expr *expr, unsigned int offset,
+ unsigned int len);
+
+/* TCP option numbers used on wire */
+enum tcpopt_kind {
+ TCPOPT_KIND_EOL = 0,
+ TCPOPT_KIND_NOP = 1,
+ TCPOPT_KIND_MAXSEG = 2,
+ TCPOPT_KIND_WINDOW = 3,
+ TCPOPT_KIND_SACK_PERMITTED = 4,
+ TCPOPT_KIND_SACK = 5,
+ TCPOPT_KIND_TIMESTAMP = 8,
+ TCPOPT_KIND_ECHO = 8,
+ TCPOPT_KIND_MD5SIG = 19,
+ TCPOPT_KIND_MPTCP = 30,
+ TCPOPT_KIND_FASTOPEN = 34,
+ __TCPOPT_KIND_MAX,
+
+ /* extra oob info, internal to nft */
+ TCPOPT_KIND_SACK1 = 256,
+ TCPOPT_KIND_SACK2 = 257,
+ TCPOPT_KIND_SACK3 = 258,
+};
+
+/* Internal identifiers */
+enum tcpopt_common {
+ TCPOPT_COMMON_KIND,
+ TCPOPT_COMMON_LENGTH,
+};
+
+enum tcpopt_maxseg {
+ TCPOPT_MAXSEG_KIND,
+ TCPOPT_MAXSEG_LENGTH,
+ TCPOPT_MAXSEG_SIZE,
+};
+
+enum tcpopt_timestamp {
+ TCPOPT_TS_KIND,
+ TCPOPT_TS_LENGTH,
+ TCPOPT_TS_TSVAL,
+ TCPOPT_TS_TSECR,
+};
+
+enum tcpopt_windowscale {
+ TCPOPT_WINDOW_KIND,
+ TCPOPT_WINDOW_LENGTH,
+ TCPOPT_WINDOW_COUNT,
+};
+
+enum tcpopt_hdr_field_sack {
+ TCPOPT_SACK_KIND,
+ TCPOPT_SACK_LENGTH,
+ TCPOPT_SACK_LEFT,
+ TCPOPT_SACK_RIGHT,
+ TCPOPT_SACK_LEFT1,
+ TCPOPT_SACK_RIGHT1,
+ TCPOPT_SACK_LEFT2,
+ TCPOPT_SACK_RIGHT2,
+ TCPOPT_SACK_LEFT3,
+ TCPOPT_SACK_RIGHT3,
+};
+
+enum tcpopt_hdr_mptcp_common {
+ TCPOPT_MPTCP_KIND,
+ TCPOPT_MPTCP_LENGTH,
+ TCPOPT_MPTCP_SUBTYPE,
+};
+
+extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX];
+
+#endif /* NFTABLES_TCPOPT_H */
diff --git a/include/utils.h b/include/utils.h
new file mode 100644
index 0000000..36a28f8
--- /dev/null
+++ b/include/utils.h
@@ -0,0 +1,155 @@
+#ifndef NFTABLES_UTILS_H
+#define NFTABLES_UTILS_H
+
+#include <asm/byteorder.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <list.h>
+#include <gmputil.h>
+
+#ifdef HAVE_VISIBILITY_HIDDEN
+# define __visible __attribute__((visibility("default")))
+# define EXPORT_SYMBOL(x) typeof(x) (x) __visible;
+#else
+# define EXPORT_SYMBOL
+#endif
+
+#define BITS_PER_BYTE 8
+
+#define pr_debug(fmt, arg...) printf(fmt, ##arg)
+
+#if defined(HAVE_LIBGMP)
+#define pr_gmp_debug(fmt, arg...) gmp_printf(fmt, ##arg)
+#else
+#define pr_gmp_debug(fmt, arg...) ({ if (false) {}; 0; })
+#endif
+
+#define __fmtstring(x, y) __attribute__((format(printf, x, y)))
+#if 0
+#define __gmp_fmtstring(x, y) __fmtstring(x, y)
+#else
+#define __gmp_fmtstring(x, y)
+#endif
+
+#define __must_check __attribute__((warn_unused_result))
+#define __noreturn __attribute__((__noreturn__))
+
+#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)
+
+#define __must_be_array(a) \
+ BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
+
+#define container_of(ptr, type, member) ({ \
+ typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (void *)__mptr - offsetof(type,member) );})
+
+/**
+ * Return a pointer to a constant variable of a size smaller than the variable.
+ */
+#ifdef __LITTLE_ENDIAN_BITFIELD
+#define constant_data_ptr(val, len) \
+ ((void *)&(val))
+#elif defined(__BIG_ENDIAN_BITFIELD)
+#define constant_data_ptr(val, len) \
+ ((void *)&(val) + sizeof(val) - div_round_up(len, BITS_PER_BYTE))
+#else
+#error "byteorder undefined"
+#endif
+
+#define field_sizeof(t, f) (sizeof(((t *)NULL)->f))
+#define array_size(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+#define div_round_up(n, d) (((n) + (d) - 1) / (d))
+#define round_up(n, b) (div_round_up(n, b) * b)
+
+#define min(_x, _y) ({ \
+ _x < _y ? _x : _y; })
+
+#define max(_x, _y) ({ \
+ _x > _y ? _x : _y; })
+
+#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
+
+/**
+ * fls - find last (most-significant) bit set
+ * @x: the word to search
+ *
+ * This is defined the same way as ffs.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static inline int fls(uint32_t x)
+{
+ int r = 32;
+
+ if (!x)
+ return 0;
+ if (!(x & 0xffff0000u)) {
+ x <<= 16;
+ r -= 16;
+ }
+ if (!(x & 0xff000000u)) {
+ x <<= 8;
+ r -= 8;
+ }
+ if (!(x & 0xf0000000u)) {
+ x <<= 4;
+ r -= 4;
+ }
+ if (!(x & 0xc0000000u)) {
+ x <<= 2;
+ r -= 2;
+ }
+ if (!(x & 0x80000000u)) {
+ x <<= 1;
+ r -= 1;
+ }
+ return r;
+}
+
+extern void __memory_allocation_error(const char *filename, uint32_t line) __noreturn;
+
+#define memory_allocation_error() \
+ __memory_allocation_error(__FILE__, __LINE__);
+
+extern void xfree(const void *ptr);
+extern void *xmalloc(size_t size);
+extern void *xmalloc_array(size_t nmemb, size_t size);
+extern void *xrealloc(void *ptr, size_t size);
+extern void *xzalloc(size_t size);
+extern void *xzalloc_array(size_t nmemb, size_t size);
+extern char *xstrdup(const char *s);
+extern void xstrunescape(const char *in, char *out);
+extern int round_pow_2(unsigned int value);
+
+#endif /* NFTABLES_UTILS_H */
diff --git a/include/xfrm.h b/include/xfrm.h
new file mode 100644
index 0000000..ea7d322
--- /dev/null
+++ b/include/xfrm.h
@@ -0,0 +1,16 @@
+#ifndef NFTABLES_XFRM_H
+#define NFTABLES_XFRM_H
+
+struct xfrm_template {
+ const char *token;
+ const struct datatype *dtype;
+ unsigned int len;
+ enum byteorder byteorder;
+};
+
+extern const struct xfrm_template xfrm_templates[__NFT_XFRM_KEY_MAX];
+
+extern struct expr *xfrm_expr_alloc(const struct location *loc,
+ uint8_t direction, uint8_t spnum,
+ enum nft_xfrm_keys key);
+#endif
diff --git a/include/xt.h b/include/xt.h
new file mode 100644
index 0000000..9fc5150
--- /dev/null
+++ b/include/xt.h
@@ -0,0 +1,29 @@
+#ifndef _NFT_XT_H_
+#define _NFT_XT_H_
+
+struct netlink_linearize_ctx;
+struct netlink_parse_ctx;
+struct nftnl_expr;
+struct rule_pp_ctx;
+struct rule;
+struct output_ctx;
+
+void xt_stmt_xlate(const struct stmt *stmt, struct output_ctx *octx);
+void xt_stmt_destroy(struct stmt *stmt);
+
+void netlink_parse_target(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle);
+void netlink_parse_match(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle);
+#ifdef HAVE_LIBXTABLES
+void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt,
+ struct rule *rule);
+#else
+static inline void stmt_xt_postprocess(struct rule_pp_ctx *rctx,
+ struct stmt *stmt, struct rule *rule) {}
+
+#endif
+
+#endif /* _NFT_XT_H_ */
diff --git a/libnftables.pc.in b/libnftables.pc.in
new file mode 100644
index 0000000..6431d48
--- /dev/null
+++ b/libnftables.pc.in
@@ -0,0 +1,15 @@
+# libnftables pkg-config file
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnftables
+Description: Netfilter nf_tables user library
+URL: http://netfilter.org/projects/nftables/
+Version: @VERSION@
+Requires:
+Conflicts:
+Libs: -L${libdir} -lnftables
+Cflags: -I${includedir}
diff --git a/m4/gcc4_visibility.m4 b/m4/gcc4_visibility.m4
new file mode 100644
index 0000000..214d3f3
--- /dev/null
+++ b/m4/gcc4_visibility.m4
@@ -0,0 +1,21 @@
+
+# GCC 4.x -fvisibility=hidden
+
+AC_DEFUN([CHECK_GCC_FVISIBILITY], [
+ AC_LANG_PUSH([C])
+ saved_CFLAGS="$CFLAGS"
+ CFLAGS="$saved_CFLAGS -fvisibility=hidden"
+ AC_CACHE_CHECK([whether compiler accepts -fvisibility=hidden],
+ [ac_cv_fvisibility_hidden], AC_COMPILE_IFELSE(
+ [AC_LANG_SOURCE()],
+ [ac_cv_fvisibility_hidden=yes],
+ [ac_cv_fvisibility_hidden=no]
+ ))
+ if test "$ac_cv_fvisibility_hidden" = "yes"; then
+ AC_DEFINE([HAVE_VISIBILITY_HIDDEN], [1],
+ [True if compiler supports -fvisibility=hidden])
+ AC_SUBST([GCC_FVISIBILITY_HIDDEN], [-fvisibility=hidden])
+ fi
+ CFLAGS="$saved_CFLAGS"
+ AC_LANG_POP([C])
+])
diff --git a/m4/libtool.m4 b/m4/libtool.m4
new file mode 100644
index 0000000..c4c0294
--- /dev/null
+++ b/m4/libtool.m4
@@ -0,0 +1,8394 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program or library that is built
+# using GNU Libtool, you may include this file under the same
+# distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+])
+
+# serial 58 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.62])dnl We use AC_PATH_PROGS_FEATURE_CHECK
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS=$ltmain
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_PREPARE_CC_BASENAME
+# -----------------------
+m4_defun([_LT_PREPARE_CC_BASENAME], [
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+func_cc_basename ()
+{
+ for cc_temp in @S|@*""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+ done
+ func_cc_basename_result=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+}
+])# _LT_PREPARE_CC_BASENAME
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# It would be clearer to call AC_REQUIREs from _LT_PREPARE_CC_BASENAME,
+# but that macro is also expanded into generated libtool script, which
+# arranges for $SED and $ECHO to be set by different means.
+m4_defun([_LT_CC_BASENAME],
+[m4_require([_LT_PREPARE_CC_BASENAME])dnl
+AC_REQUIRE([_LT_DECL_SED])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+func_cc_basename $1
+cc_basename=$func_cc_basename_result
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after 'm4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+m4_require([_LT_CMD_TRUNCATE])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options that allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+old_CC=$CC
+old_CFLAGS=$CFLAGS
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from 'configure', and 'config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# 'config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain=$ac_aux_dir/ltmain.sh
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the 'libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to 'config.status' so that its
+# declaration there will have the same value as in 'configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags='_LT_TAGS'dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the 'libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into 'config.status', and then the shell code to quote escape them in
+# for loops in 'config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ## exclude from sc_prohibit_nested_quotes
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# '#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test 0 = "$lt_write_fail" && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+'$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test 0 != $[#]
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try '$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try '$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test yes = "$silent" &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options that allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}"; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile=${ofile}T
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+# Generated automatically by $as_me ($PACKAGE) $VERSION
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+
+# Provide generalized library-building support services.
+# Written by Gordon Matzigkeit, 1996
+
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# Configured defaults for sys_lib_dlsearch_path munging.
+: \${LT_SYS_LIBRARY_PATH="$configure_time_lt_sys_library_path"}
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ cat <<'_LT_EOF' >> "$cfgfile"
+
+# ### BEGIN FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_PREPARE_MUNGE_PATH_LIST
+_LT_PREPARE_CC_BASENAME
+
+# ### END FUNCTIONS SHARED WITH CONFIGURE
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test set != "${COLLECT_NAMES+set}"; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Go], [_LT_LANG(GO)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_GO. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC], [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+ fi
+fi
+if test -z "$GOC"; then
+ AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+ [LT_LANG(GO)],
+ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "$LT_MULTI_MODULE"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test 0 = "$_lt_result"; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS=$save_LDFLAGS
+ ])
+
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ elif test -f conftest && test 0 = "$_lt_result" && $GREP forced_load conftest >/dev/null 2>&1; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[912]]*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]][[,.]]*)
+ _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
+ 10.*|11.*)
+ _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test yes = "$lt_cv_apple_cc_single_mod"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test yes = "$lt_cv_ld_exported_symbols_list"; then
+ _lt_dar_export_syms=' $wl-exported_symbols_list,$output_objdir/$libname-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/$libname-symbols.expsym $lib'
+ fi
+ if test : != "$DSYMUTIL" && test no = "$lt_cv_ld_force_load"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test yes = "$lt_cv_ld_force_load"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience $wl-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+ [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=$_lt_dar_allow_undefined
+ case $cc_basename in
+ ifort*|nagfor*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test yes = "$_lt_dar_can_shared"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dsymutil"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod$_lt_dar_export_syms$_lt_dsymutil"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags$_lt_dar_export_syms$_lt_dsymutil"
+ m4_if([$1], [CXX],
+[ if test yes != "$lt_cv_apple_cc_single_mod"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dsymutil"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's|^|_|' < \$export_symbols > \$output_objdir/\$libname-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \$lib-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$lib-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring$_lt_dar_export_syms$_lt_dsymutil"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test set = "${lt_cv_aix_libpath+set}"; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+ lt_aix_libpath_sed='[
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }]'
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi],[])
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=/usr/lib:/lib
+ fi
+ ])
+ aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script that will find a shell with a builtin
+# printf (that we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case $ECHO in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[AS_HELP_STRING([--with-sysroot@<:@=DIR@:>@],
+ [Search for dependent libraries within DIR (or the compiler's sysroot
+ if not specified).])],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted. We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case $with_sysroot in #(
+ yes)
+ if test yes = "$GCC"; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ AC_MSG_RESULT([$with_sysroot])
+ AC_MSG_ERROR([The sysroot must be an absolute path.])
+ ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and where our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test no = "$enable_libtool_lock" || enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out what ABI is being produced by ac_compile, and set mode
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE=32
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE=64
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+mips64*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ emul=elf
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ emul="${emul}32"
+ ;;
+ *64-bit*)
+ emul="${emul}64"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *MSB*)
+ emul="${emul}btsmip"
+ ;;
+ *LSB*)
+ emul="${emul}ltsmip"
+ ;;
+ esac
+ case `/usr/bin/file conftest.$ac_objext` in
+ *N32*)
+ emul="${emul}n32"
+ ;;
+ esac
+ LD="${LD-ld} -m $emul"
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly. Note that the listed cases only cover the
+ # situations where additional linker options are needed (such as when
+ # doing 32-bit compilation for a host where ld defaults to 64-bit, or
+ # vice versa); the common cases where no linker options are needed do
+ # not appear in the list.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*linux*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*linux*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test yes != "$lt_cv_cc_needs_belf"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS=$SAVE_CFLAGS
+ fi
+ ;;
+*-*solaris*)
+ # Find out what ABI is being produced by ac_compile, and set linker
+ # options accordingly.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*|x86_64-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD=${LD-ld}_sol2
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks=$enable_libtool_lock
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cr}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+ [lt_cv_ar_at_file=no
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+ [echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([lt_ar_try])
+ if test 0 -eq "$ac_status"; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ AC_TRY_EVAL([lt_ar_try])
+ if test 0 -ne "$ac_status"; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+ ])
+ ])
+
+if test no = "$lt_cv_ar_at_file"; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+ [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ bitrig* | openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3" ## exclude from sc_useless_quotes_in_assignment
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test yes = "[$]$2"; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS=$save_LDFLAGS
+])
+
+if test yes = "[$]$2"; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring=ABCD
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ bitrig* | darwin* | dragonfly* | freebsd* | netbsd* | openbsd*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test X`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test 17 != "$i" # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n "$lt_cv_sys_max_cmd_len"; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes = "$cross_compiling"; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisibility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s "conftest$ac_exeext" 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test yes != "$enable_dlopen"; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen=load_add_on
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen=LoadLibrary
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],[
+ lt_cv_dlopen=dyld
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ tpf*)
+ # Don't try to run any link tests for TPF. We know it's impossible
+ # because TPF is a cross-compiler, and we know how we open DSOs.
+ lt_cv_dlopen=dlopen
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=no
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen=shl_load],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen=shl_load lt_cv_dlopen_libs=-ldld],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen=dlopen],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-ldl],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen=dlopen lt_cv_dlopen_libs=-lsvld],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen=dld_link lt_cv_dlopen_libs=-ldld])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test no = "$lt_cv_dlopen"; then
+ enable_dlopen=no
+ else
+ enable_dlopen=yes
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS=$CPPFLAGS
+ test yes = "$ac_cv_header_dlfcn_h" && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS=$LDFLAGS
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS=$LIBS
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test yes = "$lt_cv_dlopen_self"; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS=$save_CPPFLAGS
+ LDFLAGS=$save_LDFLAGS
+ LIBS=$save_LIBS
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links=nottested
+if test no = "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" && test no != "$need_locks"; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test no = "$hard_links"; then
+ AC_MSG_WARN(['$CC' does not support '-c -o', so 'make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED([LT_OBJDIR], "$lt_cv_objdir/",
+ [Define to the sub-directory where libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test yes = "$_LT_TAGVAR(hardcode_automatic, $1)"; then
+
+ # We can hardcode non-existent directories.
+ if test no != "$_LT_TAGVAR(hardcode_direct, $1)" &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test no != "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" &&
+ test no != "$_LT_TAGVAR(hardcode_minus_L, $1)"; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test relink = "$_LT_TAGVAR(hardcode_action, $1)" ||
+ test yes = "$_LT_TAGVAR(inherit_rpath, $1)"; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test yes = "$shlibpath_overrides_runpath" ||
+ test no = "$enable_shared"; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP"; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_PREPARE_MUNGE_PATH_LIST
+# ---------------------------
+# Make sure func_munge_path_list() is defined correctly.
+m4_defun([_LT_PREPARE_MUNGE_PATH_LIST],
+[[# func_munge_path_list VARIABLE PATH
+# -----------------------------------
+# VARIABLE is name of variable containing _space_ separated list of
+# directories to be munged by the contents of PATH, which is string
+# having a format:
+# "DIR[:DIR]:"
+# string "DIR[ DIR]" will be prepended to VARIABLE
+# ":DIR[:DIR]"
+# string "DIR[ DIR]" will be appended to VARIABLE
+# "DIRP[:DIRP]::[DIRA:]DIRA"
+# string "DIRP[ DIRP]" will be prepended to VARIABLE and string
+# "DIRA[ DIRA]" will be appended to VARIABLE
+# "DIR[:DIR]"
+# VARIABLE will be replaced by "DIR[ DIR]"
+func_munge_path_list ()
+{
+ case x@S|@2 in
+ x)
+ ;;
+ *:)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'` \@S|@@S|@1\"
+ ;;
+ x:*)
+ eval @S|@1=\"\@S|@@S|@1 `$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ *::*)
+ eval @S|@1=\"\@S|@@S|@1\ `$ECHO @S|@2 | $SED -e 's/.*:://' -e 's/:/ /g'`\"
+ eval @S|@1=\"`$ECHO @S|@2 | $SED -e 's/::.*//' -e 's/:/ /g'`\ \@S|@@S|@1\"
+ ;;
+ *)
+ eval @S|@1=\"`$ECHO @S|@2 | $SED 's/:/ /g'`\"
+ ;;
+ esac
+}
+]])# _LT_PREPARE_PATH_LIST
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PREPARE_MUNGE_PATH_LIST])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test yes = "$GCC"; then
+ case $host_os in
+ darwin*) lt_awk_arg='/^libraries:/,/LR/' ;;
+ *) lt_awk_arg='/^libraries:/' ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+ *) lt_sed_strip_eq='s|=/|/|g' ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary...
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=/`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ # ...but if some path component already ends with the multilib dir we assume
+ # that all is fine and trust -print-search-dirs as is (GCC 4.2? or newer).
+ case "$lt_multi_os_dir; $lt_search_path_spec " in
+ "/; "* | "/.; "* | "/./; "* | *"$lt_multi_os_dir "* | *"$lt_multi_os_dir/ "*)
+ lt_multi_os_dir=
+ ;;
+ esac
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path$lt_multi_os_dir"
+ elif test -n "$lt_multi_os_dir"; then
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS = " "; FS = "/|\n";} {
+ lt_foo = "";
+ lt_count = 0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo = "/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=.so
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+AC_ARG_VAR([LT_SYS_LIBRARY_PATH],
+[User-defined run-time library search path.])
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 supports IA64
+ library_names_spec='$libname$release$shared_ext$major $libname$release$shared_ext$versuffix $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line '#! .'. This would cause the generated library to
+ # depend on '.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | $CC -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # Using Import Files as archive members, it is possible to support
+ # filename-based versioning of shared library archives on AIX. While
+ # this would work for both with and without runtime linking, it will
+ # prevent static linking of such archives. So we do filename-based
+ # shared library versioning with .so extension only, which is used
+ # when both runtime linking and shared linking is enabled.
+ # Unfortunately, runtime linking may impact performance, so we do
+ # not want this to be the default eventually. Also, we use the
+ # versioned .so libs for executables only if there is the -brtl
+ # linker flag in LDFLAGS as well, or --with-aix-soname=svr4 only.
+ # To allow for filename-based versioning support, we need to create
+ # libNAME.so.V as an archive file, containing:
+ # *) an Import File, referring to the versioned filename of the
+ # archive as well as the shared archive member, telling the
+ # bitwidth (32 or 64) of that shared object, and providing the
+ # list of exported symbols of that shared object, eventually
+ # decorated with the 'weak' keyword
+ # *) the shared object with the F_LOADONLY flag set, to really avoid
+ # it being seen by the linker.
+ # At run time we better use the real file rather than another symlink,
+ # but for link time we create the symlink libNAME.so -> libNAME.so.V
+
+ case $with_aix_soname,$aix_use_runtimelinking in
+ # AIX (on Power*) has no versioning support, so currently we cannot hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ aix,yes) # traditional libtool
+ dynamic_linker='AIX unversionable lib.so'
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ aix,no) # traditional AIX only
+ dynamic_linker='AIX lib.a[(]lib.so.V[)]'
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ svr4,*) # full svr4 only
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,yes) # both, prefer svr4
+ dynamic_linker="AIX lib.so.V[(]$shared_archive_member_spec.o[)], lib.a[(]lib.so.V[)]"
+ library_names_spec='$libname$release$shared_ext$major $libname$shared_ext'
+ # unpreferred sharedlib libNAME.a needs extra handling
+ postinstall_cmds='test -n "$linkname" || linkname="$realname"~func_stripname "" ".so" "$linkname"~$install_shared_prog "$dir/$func_stripname_result.$libext" "$destdir/$func_stripname_result.$libext"~test -z "$tstripme" || test -z "$striplib" || $striplib "$destdir/$func_stripname_result.$libext"'
+ postuninstall_cmds='for n in $library_names $old_library; do :; done~func_stripname "" ".so" "$n"~test "$func_stripname_result" = "$n" || func_append rmfiles " $odir/$func_stripname_result.$libext"'
+ # We do not specify a path in Import Files, so LIBPATH fires.
+ shlibpath_overrides_runpath=yes
+ ;;
+ *,no) # both, prefer aix
+ dynamic_linker="AIX lib.a[(]lib.so.V[)], lib.so.V[(]$shared_archive_member_spec.o[)]"
+ library_names_spec='$libname$release.a $libname.a'
+ soname_spec='$libname$release$shared_ext$major'
+ # unpreferred sharedlib libNAME.so.V and symlink libNAME.so need extra handling
+ postinstall_cmds='test -z "$dlname" || $install_shared_prog $dir/$dlname $destdir/$dlname~test -z "$tstripme" || test -z "$striplib" || $striplib $destdir/$dlname~test -n "$linkname" || linkname=$realname~func_stripname "" ".a" "$linkname"~(cd "$destdir" && $LN_S -f $dlname $func_stripname_result.so)'
+ postuninstall_cmds='test -z "$dlname" || func_append rmfiles " $odir/$dlname"~for n in $old_library $library_names; do :; done~func_stripname "" ".a" "$n"~func_append rmfiles " $odir/$func_stripname_result.so"'
+ ;;
+ esac
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='$libname$shared_ext'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo $libname | sed -e 's/^lib/pw/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
+ library_names_spec='$libname.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec=$LIB
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$major$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$major$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[23]].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ if test 32 = "$HPUX_IA64_MODE"; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux32
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ sys_lib_dlsearch_path_spec=/usr/lib/hpux64
+ fi
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test yes = "$lt_cv_prog_gnu_ld"; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$release$shared_ext $libname$shared_ext'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib$libsuff /lib$libsuff /usr/local/lib$libsuff"
+ sys_lib_dlsearch_path_spec="/usr/lib$libsuff /lib$libsuff"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+linux*android*)
+ version_type=none # Android doesn't support versioned libraries.
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext'
+ soname_spec='$libname$release$shared_ext'
+ finish_cmds=
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ dynamic_linker='Android linker'
+ # Don't embed -rpath directories since the linker doesn't support them.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Ideally, we could use ldconfig to report *all* directores which are
+ # searched for libraries, however this is still not possible. Aside from not
+ # being certain /sbin/ldconfig is available, command
+ # 'ldconfig -N -X -v | grep ^/' on 64bit Fedora does not report /usr/lib64,
+ # even though it is searched at run-time. Try to do the best guess by
+ # appending ld.so.conf contents (and includes) to the search path.
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd* | bitrig*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec=/usr/lib
+ need_lib_prefix=no
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ need_version=no
+ else
+ need_version=yes
+ fi
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+os2*)
+ libname_spec='$name'
+ version_type=windows
+ shrext_cmds=.dll
+ need_version=no
+ need_lib_prefix=no
+ # OS/2 can only load a DLL with a base name of 8 characters or less.
+ soname_spec='`test -n "$os2dllname" && libname="$os2dllname";
+ v=$($ECHO $release$versuffix | tr -d .-);
+ n=$($ECHO $libname | cut -b -$((8 - ${#v})) | tr . _);
+ $ECHO $n$v`$shared_ext'
+ library_names_spec='${libname}_dll.$libext'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=BEGINLIBPATH
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ postinstall_cmds='base_file=`basename \$file`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\$base_file'\''i; $ECHO \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; $ECHO \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='$libname$release$shared_ext$major'
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$shared_ext$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test yes = "$with_gnu_ld"; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$shared_ext.$versuffix $libname$shared_ext.$major $libname$shared_ext'
+ soname_spec='$libname$shared_ext.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=sco
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test yes = "$with_gnu_ld"; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
+ soname_spec='$libname$release$shared_ext$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test no = "$dynamic_linker" && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test yes = "$GCC"; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test set = "${lt_cv_sys_lib_search_path_spec+set}"; then
+ sys_lib_search_path_spec=$lt_cv_sys_lib_search_path_spec
+fi
+
+if test set = "${lt_cv_sys_lib_dlsearch_path_spec+set}"; then
+ sys_lib_dlsearch_path_spec=$lt_cv_sys_lib_dlsearch_path_spec
+fi
+
+# remember unaugmented sys_lib_dlsearch_path content for libtool script decls...
+configure_time_dlsearch_path=$sys_lib_dlsearch_path_spec
+
+# ... but it needs LT_SYS_LIBRARY_PATH munging for other configure-time code
+func_munge_path_list sys_lib_dlsearch_path_spec "$LT_SYS_LIBRARY_PATH"
+
+# to be used as default LT_SYS_LIBRARY_PATH value in generated libtool
+configure_time_lt_sys_library_path=$LT_SYS_LIBRARY_PATH
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([sys_lib_dlsearch_path_spec], [configure_time_dlsearch_path], [2],
+ [Detected run-time system search path for libraries])
+_LT_DECL([], [configure_time_lt_sys_library_path], [2],
+ [Explicit LT_SYS_LIBRARY_PATH set during ./configure time])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program that can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD=$MAGIC_CMD # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD=$MAGIC_CMD
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$1"; then
+ lt_cv_path_MAGIC_CMD=$ac_dir/"$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS=$lt_save_ifs
+ MAGIC_CMD=$lt_save_MAGIC_CMD
+ ;;
+esac])
+MAGIC_CMD=$lt_cv_path_MAGIC_CMD
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program that can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test no = "$withval" || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test yes = "$GCC"; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return, which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD=$ac_prog
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test yes = "$with_gnu_ld"; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD=$ac_dir/$ac_prog
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test no != "$with_gnu_ld" && break
+ ;;
+ *)
+ test yes != "$with_gnu_ld" && break
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+else
+ lt_cv_path_LD=$LD # Let the user override the test with a path.
+fi])
+LD=$lt_cv_path_LD
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test yes != "$GCC"; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test yes = "$GCC"; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib $wl-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_PATH_DD
+# -----------
+# find a working dd
+m4_defun([_LT_PATH_DD],
+[AC_CACHE_CHECK([for a working dd], [ac_cv_path_lt_DD],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+: ${lt_DD:=$DD}
+AC_PATH_PROGS_FEATURE_CHECK([lt_DD], [dd],
+[if "$ac_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && ac_cv_path_lt_DD="$ac_path_lt_DD" ac_path_lt_DD_found=:
+fi])
+rm -f conftest.i conftest2.i conftest.out])
+])# _LT_PATH_DD
+
+
+# _LT_CMD_TRUNCATE
+# ----------------
+# find command to truncate a binary pipe
+m4_defun([_LT_CMD_TRUNCATE],
+[m4_require([_LT_PATH_DD])
+AC_CACHE_CHECK([how to truncate binary pipes], [lt_cv_truncate_bin],
+[printf 0123456789abcdef0123456789abcdef >conftest.i
+cat conftest.i conftest.i >conftest2.i
+lt_cv_truncate_bin=
+if "$ac_cv_path_lt_DD" bs=32 count=1 <conftest2.i >conftest.out 2>/dev/null; then
+ cmp -s conftest.i conftest.out \
+ && lt_cv_truncate_bin="$ac_cv_path_lt_DD bs=4096 count=1"
+fi
+rm -f conftest.i conftest2.i conftest.out
+test -z "$lt_cv_truncate_bin" && lt_cv_truncate_bin="$SED -e 4q"])
+_LT_DECL([lt_truncate_bin], [lt_cv_truncate_bin], [1],
+ [Command to truncate a binary pipe])
+])# _LT_CMD_TRUNCATE
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# 'unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# that responds to the $file_magic_cmd with a given extended regex.
+# If you have 'file' or equivalent on your system and you're not sure
+# whether 'pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ if ( file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd* | bitrig*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+os2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+ [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+ [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM=$NM
+else
+ lt_nm_to_check=${ac_tool_prefix}nm
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs=$IFS; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS=$lt_save_ifs
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm=$ac_dir/$lt_tmp_nm
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext"; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the 'sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ # MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
+ case $build_os in
+ mingw*) lt_bad_file=conftest.nm/nofile ;;
+ *) lt_bad_file=/dev/null ;;
+ esac
+ case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
+ *$lt_bad_file* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break 2
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break 2
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS=$lt_save_ifs
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test no != "$lt_cv_path_NM"; then
+ NM=$lt_cv_path_NM
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols -headers /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols -headers"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test : != "$DUMPBIN"; then
+ NM=$DUMPBIN
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh;
+ # decide which one to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd=$ECHO
+ ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+ [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+ [lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*])
+if test yes != "$lt_cv_path_mainfest_tool"; then
+ MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# _LT_DLL_DEF_P([FILE])
+# ---------------------
+# True iff FILE is a Windows DLL '.def' file.
+# Keep in sync with func_dll_def_p in the libtool script
+AC_DEFUN([_LT_DLL_DEF_P],
+[dnl
+ test DEF = "`$SED -n dnl
+ -e '\''s/^[[ ]]*//'\'' dnl Strip leading whitespace
+ -e '\''/^\(;.*\)*$/d'\'' dnl Delete empty lines and comments
+ -e '\''s/^\(EXPORTS\|LIBRARY\)\([[ ]].*\)*$/DEF/p'\'' dnl
+ -e q dnl Only consider the first "real" line
+ $1`" dnl
+])# _LT_DLL_DEF_P
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM=-lmw)
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM=-lm)
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test yes = "$GCC"; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test ia64 = "$host_cpu"; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Gets list of data symbols to import.
+ lt_cv_sys_global_symbol_to_import="sed -n -e 's/^I .* \(.*\)$/\1/p'"
+ # Adjust the below global symbol transforms to fixup imported variables.
+ lt_cdecl_hook=" -e 's/^I .* \(.*\)$/extern __declspec(dllimport) char \1;/p'"
+ lt_c_name_hook=" -e 's/^I .* \(.*\)$/ {\"\1\", (void *) 0},/p'"
+ lt_c_name_lib_hook="\
+ -e 's/^I .* \(lib.*\)$/ {\"\1\", (void *) 0},/p'\
+ -e 's/^I .* \(.*\)$/ {\"lib\1\", (void *) 0},/p'"
+else
+ # Disable hooks by default.
+ lt_cv_sys_global_symbol_to_import=
+ lt_cdecl_hook=
+ lt_c_name_hook=
+ lt_c_name_lib_hook=
+fi
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n"\
+$lt_cdecl_hook\
+" -e 's/^T .* \(.*\)$/extern int \1();/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n"\
+$lt_c_name_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/p'"
+
+# Transform an extracted symbol line into symbol name with lib prefix and
+# symbol address.
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n"\
+$lt_c_name_lib_hook\
+" -e 's/^: \(.*\) .*$/ {\"\1\", (void *) 0},/p'"\
+" -e 's/^$symcode$symcode* .* \(lib.*\)$/ {\"\1\", (void *) \&\1},/p'"\
+" -e 's/^$symcode$symcode* .* \(.*\)$/ {\"lib\1\", (void *) \&\1},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function,
+ # D for any global variable and I for any imported variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" /^ *Symbol name *: /{split(\$ 0,sn,\":\"); si=substr(sn[2],2)};"\
+" /^ *Type *: code/{print \"T\",si,substr(si,length(prfx))};"\
+" /^ *Type *: data/{print \"I\",si,substr(si,length(prfx))};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=\"D\"}; \$ 0~/\(\).*\|/{f=\"T\"};"\
+" {split(\$ 0,a,/\||\r/); split(a[2],s)};"\
+" s[1]~/^[@?]/{print f,s[1],s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print f,t[1],substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD
+ if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined _WIN32 || defined __CYGWIN__ || defined _WIN32_WCE
+/* DATA imports from DLLs on WIN32 can't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT@&t@_DLSYM_CONST
+#elif defined __osf__
+/* This system does not cope well with relocations in const data. */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT@&t@_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* .* \(.*\)$/ {\"\1\", (void *) \&\1},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS=conftstm.$ac_objext
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test yes = "$pipe_works"; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_import], [lt_cv_sys_global_symbol_to_import], [1],
+ [Transform the output of nm into a list of symbols to manually relocate])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([nm_interface], [lt_cv_nm_interface], [1],
+ [The name lister interface])
+_LT_DECL([], [nm_file_list_spec], [1],
+ [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ if test ia64 != "$host_cpu"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64, which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd* | netbsdelf*-gnu)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the '-m68020' flag to GCC prevents building anything better,
+ # like '-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test ia64 = "$host_cpu"; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ case $cc_basename in
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ case $host_os in
+ os2*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-static'
+ ;;
+ esac
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='$wl-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64, which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # flang / f18. f95 an alias for gfortran or flang on Debian
+ flang* | f18* | f95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Intel*\ [[CF]]*Compiler*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ *Portland\ Group*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms that do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
+ ;;
+ cygwin* | mingw* | cegcc*)
+ case $cc_basename in
+ cl*)
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ' (' and ')$', so one must not match beginning or
+ # end of line. Example: 'a|bc|.*d.*' will exclude the symbols 'a' and 'bc',
+ # as well as any symbol that contains 'd'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test yes != "$GCC"; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd* | bitrig*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test yes = "$with_gnu_ld"; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test yes = "$lt_use_gnu_ld_interface"; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='$wl'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v | $SED -e 's/([^)]\+)\s\+//' 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test ia64 != "$host_cpu"; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test linux-dietlibc = "$host_os"; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test no = "$tmp_diet"
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ nagfor*) # NAGFOR 5.3
+ tmp_sharedflag='-Wl,-shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ tcc*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-rdynamic'
+ ;;
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 cannot
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test no = "$_LT_TAGVAR(ld_shlibs, $1)"; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test yes = "$GCC" && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to GNU nm, but means don't demangle to AIX nm.
+ # Without the "-l" option, or with the "-B" option, AIX nm treats
+ # weak defined symbols like other global defined symbols, whereas
+ # GNU nm marks them as "W".
+ # While the 'weak' keyword is ignored in the Export File, we need
+ # it in the Import File for the 'aix-soname' feature, so we have
+ # to replace the "-B" option with "-P" for AIX nm.
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test x-brtl = "x$ld_flag" || test x-Wl,-brtl = "x$ld_flag"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # traditional, no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
+
+ if test yes = "$GCC"; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag="$shared_flag "'$wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ ;;
+
+ hpux10*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test yes,no = "$GCC,$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+ [lt_cv_irix_exported_symbol],
+ [save_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -shared $wl-exported_symbol ${wl}foo $wl-update_registry $wl/dev/null"
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE(
+ [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+ [C++], [[int foo (void) { return 0; }]],
+ [Fortran 77], [[
+ subroutine foo
+ end]],
+ [Fortran], [[
+ subroutine foo
+ end]])])],
+ [lt_cv_irix_exported_symbol=yes],
+ [lt_cv_irix_exported_symbol=no])
+ LDFLAGS=$save_LDFLAGS])
+ if test yes = "$lt_cv_irix_exported_symbol"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ linux*)
+ case $cc_basename in
+ tcc*)
+ # Fabrice Bellard et al's Tiny C Compiler
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags $wl-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ osf3*)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $pic_flag $libobjs $deplibs $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $wl-input $wl$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test yes = "$GCC"; then
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $wl-z ${wl}text $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag $wl-z ${wl}text $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='$wl'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'. GCC discards it without '$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test sequent = "$host_vendor"; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test yes = "$GCC"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test sni = "$host_vendor"; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test yes,yes = "$GCC,$enable_shared"; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME$shared_ext during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting $shlibpath_var if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+ [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC=$CC
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report what library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC=$lt_save_CC
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test no != "$CXX" &&
+ ( (test g++ = "$CXX" && `g++ -v >/dev/null 2>&1` ) ||
+ (test g++ != "$CXX"))); then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_caught_CXX_error"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_CFLAGS=$CFLAGS
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ CFLAGS=$CXXFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test yes = "$GXX"; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test yes = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='$wl'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test ia64 = "$host_cpu"; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # have runtime linking enabled, and use it for executables.
+ # For shared libraries, we enable/disable runtime linking
+ # depending on the kind of the shared library created -
+ # when "with_aix_soname,aix_use_runtimelinking" is:
+ # "aix,no" lib.a(lib.so.V) shared, rtl:no, for executables
+ # "aix,yes" lib.so shared, rtl:yes, for executables
+ # lib.a static archive
+ # "both,no" lib.so.V(shr.o) shared, rtl:yes
+ # lib.a(lib.so.V) shared, rtl:no, for executables
+ # "both,yes" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a(lib.so.V) shared, rtl:no
+ # "svr4,*" lib.so.V(shr.o) shared, rtl:yes, for executables
+ # lib.a static archive
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ if test svr4,no = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # With aix-soname=svr4, we create the lib.so.V shared archives only,
+ # so we don't have lib.a shared libs to link our executables.
+ # We have to force runtime linking in this case.
+ aix_use_runtimelinking=yes
+ LDFLAGS="$LDFLAGS -Wl,-brtl"
+ fi
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='$wl-f,'
+ case $with_aix_soname,$aix_use_runtimelinking in
+ aix,*) ;; # no import file
+ svr4,* | *,yes) # use import file
+ # The Import File defines what to hardcode.
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ ;;
+ esac
+
+ if test yes = "$GXX"; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`$CC -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag=$shared_flag' $wl-G'
+ fi
+ # Need to ensure runtime linking is disabled for the traditional
+ # shared library, or the linker may eventually find shared libraries
+ # /with/ Import File - we do not want to mix them.
+ shared_flag_aix='-shared'
+ shared_flag_svr4='-shared $wl-G'
+ else
+ # not using gcc
+ if test ia64 = "$host_cpu"; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test yes = "$aix_use_runtimelinking"; then
+ shared_flag='$wl-G'
+ else
+ shared_flag='$wl-bM:SRE'
+ fi
+ shared_flag_aix='$wl-bM:SRE'
+ shared_flag_svr4='$wl-G'
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test aix,yes = "$with_aix_soname,$aix_use_runtimelinking"; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ # The "-G" linker flag allows undefined symbols.
+ _LT_TAGVAR(no_undefined_flag, $1)='-bernotok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs $wl'$no_entry_flag' $compiler_flags `if test -n "$allow_undefined_flag"; then func_echo_all "$wl$allow_undefined_flag"; else :; fi` $wl'$exp_sym_flag:\$export_symbols' '$shared_flag
+ else
+ if test ia64 = "$host_cpu"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\$wl$no_entry_flag"' $compiler_flags $wl$allow_undefined_flag '"\$wl$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-berok'
+ if test yes = "$with_gnu_ld"; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$RM -r $output_objdir/$realname.d~$MKDIR $output_objdir/$realname.d'
+ # -brtl affects multiple linker settings, -berok does not and is overridden later
+ compiler_flags_filtered='`func_echo_all "$compiler_flags " | $SED -e "s%-brtl\\([[, ]]\\)%-berok\\1%g"`'
+ if test svr4 != "$with_aix_soname"; then
+ # This is similar to how AIX traditionally builds its shared
+ # libraries. Need -bnortl late, we may have -brtl in LDFLAGS.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_aix' -o $output_objdir/$realname.d/$soname $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$realname.d/$soname'
+ fi
+ if test aix != "$with_aix_soname"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$CC '$shared_flag_svr4' -o $output_objdir/$realname.d/$shared_archive_member_spec.o $libobjs $deplibs $wl-bnoentry '$compiler_flags_filtered'$wl-bE:$export_symbols$allow_undefined_flag~$STRIP -e $output_objdir/$realname.d/$shared_archive_member_spec.o~( func_echo_all "#! $soname($shared_archive_member_spec.o)"; if test shr_64 = "$shared_archive_member_spec"; then func_echo_all "# 64"; else func_echo_all "# 32"; fi; cat $export_symbols ) > $output_objdir/$realname.d/$shared_archive_member_spec.imp~$AR $AR_FLAGS $output_objdir/$soname $output_objdir/$realname.d/$shared_archive_member_spec.o $output_objdir/$realname.d/$shared_archive_member_spec.imp'
+ else
+ # used by -dlpreopen to get the symbols
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$MV $output_objdir/$realname.d/$soname $output_objdir'
+ fi
+ _LT_TAGVAR(archive_expsym_cmds, $1)="$_LT_TAGVAR(archive_expsym_cmds, $1)"'~$RM -r $output_objdir/$realname.d'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $GXX,$cc_basename in
+ ,cl* | no,cl*)
+ # Native MSVC
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=.dll
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp "$export_symbols" "$output_objdir/$soname.def";
+ echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
+ else
+ $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile=$lt_outputfile.exe
+ lt_tool_outputfile=$lt_tool_outputfile.exe
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test : != "$MANIFEST_TOOL" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # g++
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file, use it as
+ # is; otherwise, prepend EXPORTS...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname $wl--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ shrext_cmds=.dll
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ emxexp $libobjs | $SED /"_DLL_InitTerm"/d >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$ECHO "LIBRARY ${soname%$shared_ext} INITINSTANCE TERMINSTANCE" > $output_objdir/$libname.def~
+ $ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~
+ $ECHO "DATA MULTIPLE NONSHARED" >> $output_objdir/$libname.def~
+ $ECHO EXPORTS >> $output_objdir/$libname.def~
+ prefix_cmds="$SED"~
+ if test EXPORTS = "`$SED 1q $export_symbols`"; then
+ prefix_cmds="$prefix_cmds -e 1d";
+ fi~
+ prefix_cmds="$prefix_cmds -e \"s/^\(.*\)$/_\1/g\""~
+ cat $export_symbols | $prefix_cmds >> $output_objdir/$libname.def~
+ $CC -Zdll -Zcrtdll -o $output_objdir/$soname $libobjs $deplibs $compiler_flags $output_objdir/$libname.def~
+ emximp -o $lib $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag $wl+b $wl$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test "x$output_objdir/$soname" = "x$lib" || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl+b $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC $wl+h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag $wl+h $wl$soname $wl+b $wl$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s|^|_|" $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-h,$soname $wl--retain-symbols-file,$output_objdir/$soname.expsym $wl--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test yes = "$GXX"; then
+ if test no = "$with_gnu_ld"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib $wl-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive$convenience $wl--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname $wl-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl--rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname -o $lib $wl-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname -o $lib'
+ if test yes = "$supports_anon_versioning"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags $wl-soname $wl$soname $wl-version-script $wl$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file $wl$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` $wl--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd* | bitrig*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=$wlarc'--whole-archive$convenience '$wlarc'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\$tempext\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $soname `test -n "$verstring" && func_echo_all "$wl-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname $wl-input $wl$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' $wl-expect_unresolved $wl\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-msym $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-rpath $wl$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G$allow_undefined_flag -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G$allow_undefined_flag $wl-M $wl$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands '-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test yes,no = "$GXX,$with_gnu_ld"; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' $wl-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+ else
+ # g++ 2.7 appears to require '-G' NOT '-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags $wl-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib $wl-M $wl$lib.exp $wl-h $wl$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$wl-z ${wl}allextract$convenience $wl-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We CANNOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='$wl-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='$wl-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='$wl-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $wl-Bexport:$export_symbols $wl-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test no = "$_LT_TAGVAR(ld_shlibs, $1)" && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)=$GXX
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test yes != "$_lt_caught_CXX_error"
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+ case @S|@2 in
+ .*) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%\\\\@S|@2\$%%"`;;
+ *) func_stripname_result=`$ECHO "@S|@3" | $SED "s%^@S|@1%%; s%@S|@2\$%%"`;;
+ esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $prev$p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test x-L = "$p" ||
+ test x-R = "$p"; then
+ prev=$p
+ continue
+ fi
+
+ # Expand the sysroot to ease extracting the directories later.
+ if test -z "$prev"; then
+ case $p in
+ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+ esac
+ fi
+ case $p in
+ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+ esac
+ if test no = "$pre_test_object_deps_done"; then
+ case $prev in
+ -L | -R)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)=$prev$p
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} $prev$p"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)=$prev$p
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} $prev$p"
+ fi
+ fi
+ prev=
+ ;;
+
+ *.lto.$objext) ;; # Ignore GCC LTO objects
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test no = "$pre_test_object_deps_done"; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)=$p
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)=$p
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | $SED -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test no = "$F77"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_F77"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${F77-"f77"}
+ CFLAGS=$FFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)=$G77
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_F77"
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test no = "$FC"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test yes != "$_lt_disable_FC"; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${FC-"f95"}
+ CFLAGS=$FCFLAGS
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test no = "$can_build_shared" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test yes = "$enable_shared" && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test ia64 != "$host_cpu"; then
+ case $enable_shared,$with_aix_soname,$aix_use_runtimelinking in
+ yes,aix,yes) ;; # shared object as lib.so file only
+ yes,svr4,*) ;; # shared object as lib.so archive member only
+ yes,*) enable_static=no ;; # shared object in lib.a archive as well
+ esac
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test yes = "$enable_shared" || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)=$ac_cv_fc_compiler_gnu
+ _LT_TAGVAR(LD, $1)=$LD
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test yes != "$_lt_disable_FC"
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)=$LD
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to 'libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code=$lt_simple_compile_test_code
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test set = "${GCJFLAGS+set}" || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f "$lt_ac_sed" && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test 10 -lt "$lt_ac_count" && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test "$lt_ac_count" -gt "$lt_ac_max"; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine what file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+ [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+ [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
new file mode 100644
index 0000000..94b0829
--- /dev/null
+++ b/m4/ltoptions.m4
@@ -0,0 +1,437 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 8 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option '$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ _LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
+ [_LT_WITH_AIX_SONAME([aix])])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the 'shared' and
+# 'disable-shared' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the 'static' and
+# 'disable-static' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the 'fast-install'
+# and 'disable-fast-install' LT_INIT options.
+# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for pkg in $enableval; do
+ IFS=$lt_save_ifs
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the 'disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_AIX_SONAME([DEFAULT])
+# ----------------------------------
+# implement the --with-aix-soname flag, and support the `aix-soname=aix'
+# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
+# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
+m4_define([_LT_WITH_AIX_SONAME],
+[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
+shared_archive_member_spec=
+case $host,$enable_shared in
+power*-*-aix[[5-9]]*,yes)
+ AC_MSG_CHECKING([which variant of shared library versioning to provide])
+ AC_ARG_WITH([aix-soname],
+ [AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
+ [shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
+ [case $withval in
+ aix|svr4|both)
+ ;;
+ *)
+ AC_MSG_ERROR([Unknown argument to --with-aix-soname])
+ ;;
+ esac
+ lt_cv_with_aix_soname=$with_aix_soname],
+ [AC_CACHE_VAL([lt_cv_with_aix_soname],
+ [lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
+ with_aix_soname=$lt_cv_with_aix_soname])
+ AC_MSG_RESULT([$with_aix_soname])
+ if test aix != "$with_aix_soname"; then
+ # For the AIX way of multilib, we name the shared archive member
+ # based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
+ # and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
+ # Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
+ # the AIX toolchain works better with OBJECT_MODE set (default 32).
+ if test 64 = "${OBJECT_MODE-32}"; then
+ shared_archive_member_spec=shr_64
+ else
+ shared_archive_member_spec=shr
+ fi
+ fi
+ ;;
+*)
+ with_aix_soname=aix
+ ;;
+esac
+
+_LT_DECL([], [shared_archive_member_spec], [0],
+ [Shared archive member basename, for filename based shared library versioning on AIX])dnl
+])# _LT_WITH_AIX_SONAME
+
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
+LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
+# LT_INIT options.
+# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
+ for lt_pkg in $withval; do
+ IFS=$lt_save_ifs
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS=$lt_save_ifs
+ ;;
+ esac],
+ [pic_mode=m4_default([$1], [default])])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the 'pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
new file mode 100644
index 0000000..48bc934
--- /dev/null
+++ b/m4/ltsugar.m4
@@ -0,0 +1,124 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59, which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus 'SEPARATOR''STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
new file mode 100644
index 0000000..fa04b52
--- /dev/null
+++ b/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 4179 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.6'
+macro_revision='2.4.6'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c6b26f8
--- /dev/null
+++ b/m4/lt~obsolete.m4
@@ -0,0 +1,99 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
+# Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN),
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/py/Makefile.am b/py/Makefile.am
new file mode 100644
index 0000000..76aa082
--- /dev/null
+++ b/py/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = pyproject.toml setup.cfg setup.py src
diff --git a/py/Makefile.in b/py/Makefile.in
new file mode 100644
index 0000000..3f7ea9e
--- /dev/null
+++ b/py/Makefile.in
@@ -0,0 +1,455 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = py
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = pyproject.toml setup.cfg setup.py src
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign py/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign py/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/py/pyproject.toml b/py/pyproject.toml
new file mode 100644
index 0000000..fed528d
--- /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 0000000..953b7f4
--- /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
new file mode 100755
index 0000000..beda28e
--- /dev/null
+++ b/py/setup.py
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+from setuptools import setup
+
+setup()
diff --git a/py/src/__init__.py b/py/src/__init__.py
new file mode 100644
index 0000000..7567f09
--- /dev/null
+++ b/py/src/__init__.py
@@ -0,0 +1 @@
+from .nftables import *
diff --git a/py/src/nftables.py b/py/src/nftables.py
new file mode 100644
index 0000000..f1e43ad
--- /dev/null
+++ b/py/src/nftables.py
@@ -0,0 +1,604 @@
+#!/usr/bin/python
+# Copyright(C) 2018 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 as published by
+# the Free Software Foundation, version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+import json
+from ctypes import *
+import sys
+import os
+
+NFTABLES_VERSION = "0.1"
+
+class SchemaValidator:
+ """Libnftables JSON validator using jsonschema"""
+
+ def __init__(self):
+ schema_path = os.path.join(os.path.dirname(__file__), "schema.json")
+ with open(schema_path, 'r') as schema_file:
+ self.schema = json.load(schema_file)
+ import jsonschema
+ self.jsonschema = jsonschema
+
+ def validate(self, json):
+ self.jsonschema.validate(instance=json, schema=self.schema)
+
+class Nftables:
+ """A class representing libnftables interface"""
+
+ input_flags = {
+ "no-dns": 0x1,
+ "json": 0x2,
+ }
+
+ debug_flags = {
+ "scanner": 0x1,
+ "parser": 0x2,
+ "eval": 0x4,
+ "netlink": 0x8,
+ "mnl": 0x10,
+ "proto-ctx": 0x20,
+ "segtree": 0x40,
+ }
+
+ output_flags = {
+ "reversedns": (1 << 0),
+ "service": (1 << 1),
+ "stateless": (1 << 2),
+ "handle": (1 << 3),
+ "json": (1 << 4),
+ "echo": (1 << 5),
+ "guid": (1 << 6),
+ "numeric_proto": (1 << 7),
+ "numeric_prio": (1 << 8),
+ "numeric_symbol": (1 << 9),
+ "numeric_time": (1 << 10),
+ "terse": (1 << 11),
+ }
+
+ validator = None
+
+ def __init__(self, sofile="libnftables.so.1"):
+ """Instantiate a new Nftables class object.
+
+ Accepts a shared object file to open, by default standard search path
+ is searched for a file named 'libnftables.so'.
+
+ After loading the library using ctypes module, a new nftables context
+ 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
+
+ self.nft_ctx_new = lib.nft_ctx_new
+ 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]
+
+ self.nft_ctx_output_set_flags = lib.nft_ctx_output_set_flags
+ self.nft_ctx_output_set_flags.argtypes = [c_void_p, c_uint]
+
+ self.nft_ctx_output_get_debug = lib.nft_ctx_output_get_debug
+ self.nft_ctx_output_get_debug.restype = c_int
+ self.nft_ctx_output_get_debug.argtypes = [c_void_p]
+
+ self.nft_ctx_output_set_debug = lib.nft_ctx_output_set_debug
+ self.nft_ctx_output_set_debug.argtypes = [c_void_p, c_int]
+
+ self.nft_ctx_buffer_output = lib.nft_ctx_buffer_output
+ self.nft_ctx_buffer_output.restype = c_int
+ self.nft_ctx_buffer_output.argtypes = [c_void_p]
+
+ self.nft_ctx_get_output_buffer = lib.nft_ctx_get_output_buffer
+ self.nft_ctx_get_output_buffer.restype = c_char_p
+ self.nft_ctx_get_output_buffer.argtypes = [c_void_p]
+
+ self.nft_ctx_buffer_error = lib.nft_ctx_buffer_error
+ self.nft_ctx_buffer_error.restype = c_int
+ self.nft_ctx_buffer_error.argtypes = [c_void_p]
+
+ self.nft_ctx_get_error_buffer = lib.nft_ctx_get_error_buffer
+ self.nft_ctx_get_error_buffer.restype = c_char_p
+ self.nft_ctx_get_error_buffer.argtypes = [c_void_p]
+
+ self.nft_run_cmd_from_buffer = lib.nft_run_cmd_from_buffer
+ 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]
+
+ # initialize libnftables context
+ self.__ctx = self.nft_ctx_new(0)
+ self.nft_ctx_buffer_output(self.__ctx)
+ self.nft_ctx_buffer_error(self.__ctx)
+
+ def __del__(self):
+ 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) != 0
+
+ def __set_output_flag(self, name, val):
+ flag = self.output_flags[name]
+ flags = self.nft_ctx_output_get_flags(self.__ctx)
+ if val:
+ new_flags = flags | flag
+ else:
+ new_flags = flags & ~flag
+ self.nft_ctx_output_set_flags(self.__ctx, new_flags)
+ return (flags & flag) != 0
+
+ def get_reversedns_output(self):
+ """Get the current state of reverse DNS output.
+
+ Returns a boolean indicating whether reverse DNS lookups are performed
+ for IP addresses in output.
+ """
+ return self.__get_output_flag("reversedns")
+
+ def set_reversedns_output(self, val):
+ """Enable or disable reverse DNS output.
+
+ Accepts a boolean turning reverse DNS lookups in output on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("reversedns", val)
+
+ def get_service_output(self):
+ """Get the current state of service name output.
+
+ Returns a boolean indicating whether service names are used for port
+ numbers in output or not.
+ """
+ return self.__get_output_flag("service")
+
+ def set_service_output(self, val):
+ """Enable or disable service name output.
+
+ Accepts a boolean turning service names for port numbers in output on
+ or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("service", val)
+
+ def get_stateless_output(self):
+ """Get the current state of stateless output.
+
+ Returns a boolean indicating whether stateless output is active or not.
+ """
+ return self.__get_output_flag("stateless")
+
+ def set_stateless_output(self, val):
+ """Enable or disable stateless output.
+
+ Accepts a boolean turning stateless output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("stateless", val)
+
+ def get_handle_output(self):
+ """Get the current state of handle output.
+
+ Returns a boolean indicating whether handle output is active or not.
+ """
+ return self.__get_output_flag("handle")
+
+ def set_handle_output(self, val):
+ """Enable or disable handle output.
+
+ Accepts a boolean turning handle output on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("handle", val)
+
+ def get_json_output(self):
+ """Get the current state of JSON output.
+
+ Returns a boolean indicating whether JSON output is active or not.
+ """
+ return self.__get_output_flag("json")
+
+ def set_json_output(self, val):
+ """Enable or disable JSON output.
+
+ Accepts a boolean turning JSON output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("json", val)
+
+ def get_echo_output(self):
+ """Get the current state of echo output.
+
+ Returns a boolean indicating whether echo output is active or not.
+ """
+ return self.__get_output_flag("echo")
+
+ def set_echo_output(self, val):
+ """Enable or disable echo output.
+
+ Accepts a boolean turning echo output on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("echo", val)
+
+ def get_guid_output(self):
+ """Get the current state of GID/UID output.
+
+ Returns a boolean indicating whether names for group/user IDs are used
+ in output or not.
+ """
+ return self.__get_output_flag("guid")
+
+ def set_guid_output(self, val):
+ """Enable or disable GID/UID output.
+
+ Accepts a boolean turning names for group/user IDs on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("guid", val)
+
+ def get_numeric_proto_output(self):
+ """Get current status of numeric protocol output flag.
+
+ Returns a boolean value indicating the status.
+ """
+ return self.__get_output_flag("numeric_proto")
+
+ def set_numeric_proto_output(self, val):
+ """Set numeric protocol output flag.
+
+ Accepts a boolean turning numeric protocol output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("numeric_proto", val)
+
+ def get_numeric_prio_output(self):
+ """Get current status of numeric chain priority output flag.
+
+ Returns a boolean value indicating the status.
+ """
+ return self.__get_output_flag("numeric_prio")
+
+ def set_numeric_prio_output(self, val):
+ """Set numeric chain priority output flag.
+
+ Accepts a boolean turning numeric chain priority output either on or
+ off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("numeric_prio", val)
+
+ def get_numeric_symbol_output(self):
+ """Get current status of numeric symbols output flag.
+
+ Returns a boolean value indicating the status.
+ """
+ return self.__get_output_flag("numeric_symbol")
+
+ def set_numeric_symbol_output(self, val):
+ """Set numeric symbols output flag.
+
+ Accepts a boolean turning numeric representation of symbolic constants
+ in output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("numeric_symbol", val)
+
+ def get_numeric_time_output(self):
+ """Get current status of numeric times output flag.
+
+ Returns a boolean value indicating the status.
+ """
+ return self.__get_output_flag("numeric_time")
+
+ def set_numeric_time_output(self, val):
+ """Set numeric times output flag.
+
+ Accepts a boolean turning numeric representation of time values
+ in output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("numeric_time", val)
+
+ def get_terse_output(self):
+ """Get the current state of terse output.
+
+ Returns a boolean indicating whether terse output is active or not.
+ """
+ return self.__get_output_flag("terse")
+
+ def set_terse_output(self, val):
+ """Enable or disable terse output.
+
+ Accepts a boolean turning terse output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("terse", val)
+
+ def get_debug(self):
+ """Get currently active debug flags.
+
+ Returns a set of flag names. See set_debug() for details.
+ """
+ val = self.nft_ctx_output_get_debug(self.__ctx)
+ return self._flags_from_numeric(self.debug_flags, val)
+
+ def set_debug(self, values):
+ """Set debug output flags.
+
+ Accepts either a single flag or a set of flags. Each flag might be
+ given either as string or integer value as shown in the following
+ table:
+
+ Name | Value (hex)
+ -----------------------
+ scanner | 0x1
+ parser | 0x2
+ eval | 0x4
+ netlink | 0x8
+ mnl | 0x10
+ proto-ctx | 0x20
+ segtree | 0x40
+
+ 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()
+ self.nft_ctx_output_set_debug(self.__ctx, val)
+ return old
+
+ def cmd(self, cmdline):
+ """Run a simple nftables command via libnftables.
+
+ Accepts a string containing an nftables command just like what one
+ would enter into an interactive nftables (nft -i) session.
+
+ Returns a tuple (rc, output, error):
+ rc -- return code as returned by nft_run_cmd_from_buffer() fuction
+ output -- a string containing output written to stdout
+ error -- a string containing output written to stderr
+ """
+ cmdline_is_unicode = False
+ if not isinstance(cmdline, bytes):
+ cmdline_is_unicode = True
+ cmdline = cmdline.encode("utf-8")
+ rc = self.nft_run_cmd_from_buffer(self.__ctx, cmdline)
+ output = self.nft_ctx_get_output_buffer(self.__ctx)
+ error = self.nft_ctx_get_error_buffer(self.__ctx)
+ if cmdline_is_unicode:
+ output = output.decode("utf-8")
+ error = error.decode("utf-8")
+
+ return (rc, output, error)
+
+ def json_cmd(self, json_root):
+ """Run an nftables command in JSON syntax via libnftables.
+
+ Accepts a hash object as input.
+
+ Returns a tuple (rc, output, error):
+ rc -- return code as returned by nft_run_cmd_from_buffer() function
+ output -- a hash object containing library standard output
+ error -- a string containing output written to stderr
+ """
+ json_out_old = self.set_json_output(True)
+ rc, output, error = self.cmd(json.dumps(json_root))
+ if not json_out_old:
+ self.set_json_output(json_out_old)
+ if len(output):
+ output = json.loads(output)
+ return (rc, output, error)
+
+ def json_validate(self, json_root):
+ """Validate JSON object against libnftables schema.
+
+ Accepts a hash object as input.
+
+ Returns True if JSON is valid, raises an exception otherwise.
+ """
+ if not self.validator:
+ self.validator = SchemaValidator()
+
+ 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/src/schema.json b/py/src/schema.json
new file mode 100644
index 0000000..460e215
--- /dev/null
+++ b/py/src/schema.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "http://json-schema.org/schema#",
+ "description": "libnftables JSON API schema",
+
+ "type": "object",
+ "properties": {
+ "nftables": {
+ "type": "array",
+ "minitems": 0,
+ "items": {
+ "type": "object"
+ }
+ }
+ },
+ "required": [ "nftables" ]
+}
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..63a4ef4
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,123 @@
+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 \
+ nftutils.c \
+ nftutils.h \
+ erec.c \
+ mnl.c \
+ iface.c \
+ mergesort.c \
+ optimize.c \
+ osf.c \
+ nfnl_osf.c \
+ tcpopt.c \
+ socket.c \
+ print.c \
+ sctp_chunk.c \
+ dccpopt.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-unused-but-set-variable \
+ -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/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..580945e
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,1097 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+sbin_PROGRAMS = nft$(EXEEXT)
+@BUILD_DEBUG_TRUE@am__append_1 = -g -DDEBUG
+@BUILD_XTABLES_TRUE@am__append_2 = ${XTABLES_CFLAGS}
+@BUILD_MINIGMP_TRUE@am__append_3 = -DHAVE_MINIGMP
+@BUILD_JSON_TRUE@am__append_4 = -DHAVE_JSON
+@BUILD_XTABLES_TRUE@am__append_5 = -DHAVE_XTABLES
+@BUILD_MINIGMP_TRUE@am__append_6 = libminigmp.la
+@BUILD_MINIGMP_TRUE@am__append_7 = libminigmp.la
+@BUILD_XTABLES_TRUE@am__append_8 = ${XTABLES_LIBS}
+@BUILD_CLI_TRUE@am__append_9 = cli.c
+@BUILD_JSON_TRUE@am__append_10 = json.c parser_json.c
+@BUILD_JSON_TRUE@am__append_11 = ${JANSSON_LIBS}
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/gcc4_visibility.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(libdir)"
+PROGRAMS = $(sbin_PROGRAMS)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+libminigmp_la_LIBADD =
+am__libminigmp_la_SOURCES_DIST = mini-gmp.c
+@BUILD_MINIGMP_TRUE@am_libminigmp_la_OBJECTS = \
+@BUILD_MINIGMP_TRUE@ libminigmp_la-mini-gmp.lo
+libminigmp_la_OBJECTS = $(am_libminigmp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libminigmp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libminigmp_la_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_MINIGMP_TRUE@am_libminigmp_la_rpath =
+am__DEPENDENCIES_1 =
+@BUILD_XTABLES_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+libnftables_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) libparser.la $(am__append_7) \
+ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1)
+am__libnftables_la_SOURCES_DIST = 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 \
+ nftutils.c nftutils.h erec.c mnl.c iface.c mergesort.c \
+ optimize.c osf.c nfnl_osf.c tcpopt.c socket.c print.c \
+ sctp_chunk.c dccpopt.c libnftables.c libnftables.map xt.c \
+ json.c parser_json.c
+@BUILD_JSON_TRUE@am__objects_1 = json.lo parser_json.lo
+am_libnftables_la_OBJECTS = rule.lo statement.lo cache.lo cmd.lo \
+ datatype.lo expression.lo evaluate.lo proto.lo payload.lo \
+ exthdr.lo fib.lo hash.lo intervals.lo ipopt.lo meta.lo rt.lo \
+ numgen.lo ct.lo xfrm.lo netlink.lo netlink_linearize.lo \
+ netlink_delinearize.lo misspell.lo monitor.lo owner.lo \
+ segtree.lo gmputil.lo utils.lo nftutils.lo erec.lo mnl.lo \
+ iface.lo mergesort.lo optimize.lo osf.lo nfnl_osf.lo tcpopt.lo \
+ socket.lo print.lo sctp_chunk.lo dccpopt.lo libnftables.lo \
+ xt.lo $(am__objects_1)
+libnftables_la_OBJECTS = $(am_libnftables_la_OBJECTS)
+libnftables_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libnftables_la_LDFLAGS) $(LDFLAGS) -o \
+ $@
+libparser_la_LIBADD =
+am_libparser_la_OBJECTS = libparser_la-parser_bison.lo \
+ libparser_la-scanner.lo
+libparser_la_OBJECTS = $(am_libparser_la_OBJECTS)
+libparser_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libparser_la_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am__nft_SOURCES_DIST = main.c cli.c
+@BUILD_CLI_TRUE@am__objects_2 = cli.$(OBJEXT)
+am_nft_OBJECTS = main.$(OBJEXT) $(am__objects_2)
+nft_OBJECTS = $(am_nft_OBJECTS)
+nft_DEPENDENCIES = libnftables.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/cache.Plo ./$(DEPDIR)/cli.Po \
+ ./$(DEPDIR)/cmd.Plo ./$(DEPDIR)/ct.Plo \
+ ./$(DEPDIR)/datatype.Plo ./$(DEPDIR)/dccpopt.Plo \
+ ./$(DEPDIR)/erec.Plo ./$(DEPDIR)/evaluate.Plo \
+ ./$(DEPDIR)/expression.Plo ./$(DEPDIR)/exthdr.Plo \
+ ./$(DEPDIR)/fib.Plo ./$(DEPDIR)/gmputil.Plo \
+ ./$(DEPDIR)/hash.Plo ./$(DEPDIR)/iface.Plo \
+ ./$(DEPDIR)/intervals.Plo ./$(DEPDIR)/ipopt.Plo \
+ ./$(DEPDIR)/json.Plo ./$(DEPDIR)/libminigmp_la-mini-gmp.Plo \
+ ./$(DEPDIR)/libnftables.Plo \
+ ./$(DEPDIR)/libparser_la-parser_bison.Plo \
+ ./$(DEPDIR)/libparser_la-scanner.Plo ./$(DEPDIR)/main.Po \
+ ./$(DEPDIR)/mergesort.Plo ./$(DEPDIR)/meta.Plo \
+ ./$(DEPDIR)/misspell.Plo ./$(DEPDIR)/mnl.Plo \
+ ./$(DEPDIR)/monitor.Plo ./$(DEPDIR)/netlink.Plo \
+ ./$(DEPDIR)/netlink_delinearize.Plo \
+ ./$(DEPDIR)/netlink_linearize.Plo ./$(DEPDIR)/nfnl_osf.Plo \
+ ./$(DEPDIR)/nftutils.Plo ./$(DEPDIR)/numgen.Plo \
+ ./$(DEPDIR)/optimize.Plo ./$(DEPDIR)/osf.Plo \
+ ./$(DEPDIR)/owner.Plo ./$(DEPDIR)/parser_json.Plo \
+ ./$(DEPDIR)/payload.Plo ./$(DEPDIR)/print.Plo \
+ ./$(DEPDIR)/proto.Plo ./$(DEPDIR)/rt.Plo ./$(DEPDIR)/rule.Plo \
+ ./$(DEPDIR)/sctp_chunk.Plo ./$(DEPDIR)/segtree.Plo \
+ ./$(DEPDIR)/socket.Plo ./$(DEPDIR)/statement.Plo \
+ ./$(DEPDIR)/tcpopt.Plo ./$(DEPDIR)/utils.Plo \
+ ./$(DEPDIR)/xfrm.Plo ./$(DEPDIR)/xt.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+AM_V_LEX = $(am__v_LEX_@AM_V@)
+am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@)
+am__v_LEX_0 = @echo " LEX " $@;
+am__v_LEX_1 =
+YLWRAP = $(top_srcdir)/build-aux/ylwrap
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+ -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+AM_V_YACC = $(am__v_YACC_@AM_V@)
+am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
+am__v_YACC_0 = @echo " YACC " $@;
+am__v_YACC_1 =
+SOURCES = $(libminigmp_la_SOURCES) $(libnftables_la_SOURCES) \
+ $(libparser_la_SOURCES) $(nft_SOURCES)
+DIST_SOURCES = $(am__libminigmp_la_SOURCES_DIST) \
+ $(am__libnftables_la_SOURCES_DIST) $(libparser_la_SOURCES) \
+ $(am__nft_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/Make_global.am \
+ $(top_srcdir)/build-aux/depcomp $(top_srcdir)/build-aux/ylwrap \
+ parser_bison.c parser_bison.h scanner.c
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+A2X = @A2X@
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GCC_FVISIBILITY_HIDDEN = @GCC_FVISIBILITY_HIDDEN@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBMNL_CFLAGS = @LIBMNL_CFLAGS@
+LIBMNL_LIBS = @LIBMNL_LIBS@
+LIBNFTNL_CFLAGS = @LIBNFTNL_CFLAGS@
+LIBNFTNL_LIBS = @LIBNFTNL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XTABLES_CFLAGS = @XTABLES_CFLAGS@
+XTABLES_LIBS = @XTABLES_LIBS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# 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
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ -DDEFAULT_INCLUDE_PATH="\"${sysconfdir}\"" ${LIBMNL_CFLAGS} \
+ ${LIBNFTNL_CFLAGS} $(am__append_1) $(am__append_2) \
+ $(am__append_3) $(am__append_4) $(am__append_5)
+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 nftutils.c \
+ nftutils.h erec.c mnl.c iface.c mergesort.c optimize.c osf.c \
+ nfnl_osf.c tcpopt.c socket.c print.c sctp_chunk.c dccpopt.c \
+ libnftables.c libnftables.map xt.c $(am__append_10)
+
+# yacc and lex generate dirty code
+noinst_LTLIBRARIES = libparser.la $(am__append_6)
+libparser_la_SOURCES = parser_bison.y scanner.l
+libparser_la_CFLAGS = ${AM_CFLAGS} \
+ -Wno-missing-prototypes \
+ -Wno-missing-declarations \
+ -Wno-implicit-function-declaration \
+ -Wno-unused-but-set-variable \
+ -Wno-nested-externs \
+ -Wno-undef \
+ -Wno-redundant-decls
+
+libnftables_la_LIBADD = ${LIBMNL_LIBS} ${LIBNFTNL_LIBS} libparser.la \
+ $(am__append_7) $(am__append_8) $(am__append_11)
+libnftables_la_LDFLAGS = -version-info ${libnftables_LIBVERSION} \
+ -Wl,--version-script=$(srcdir)/libnftables.map
+
+@BUILD_MINIGMP_TRUE@libminigmp_la_SOURCES = mini-gmp.c
+@BUILD_MINIGMP_TRUE@libminigmp_la_CFLAGS = ${AM_CFLAGS} -Wno-sign-compare
+nft_SOURCES = main.c $(am__append_9)
+nft_LDADD = libnftables.la
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(top_srcdir)/Make_global.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+$(top_srcdir)/Make_global.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libminigmp.la: $(libminigmp_la_OBJECTS) $(libminigmp_la_DEPENDENCIES) $(EXTRA_libminigmp_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libminigmp_la_LINK) $(am_libminigmp_la_rpath) $(libminigmp_la_OBJECTS) $(libminigmp_la_LIBADD) $(LIBS)
+
+libnftables.la: $(libnftables_la_OBJECTS) $(libnftables_la_DEPENDENCIES) $(EXTRA_libnftables_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libnftables_la_LINK) -rpath $(libdir) $(libnftables_la_OBJECTS) $(libnftables_la_LIBADD) $(LIBS)
+parser_bison.h: parser_bison.c
+ @if test ! -f $@; then rm -f parser_bison.c; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) parser_bison.c; else :; fi
+
+libparser.la: $(libparser_la_OBJECTS) $(libparser_la_DEPENDENCIES) $(EXTRA_libparser_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libparser_la_LINK) $(libparser_la_OBJECTS) $(libparser_la_LIBADD) $(LIBS)
+
+nft$(EXEEXT): $(nft_OBJECTS) $(nft_DEPENDENCIES) $(EXTRA_nft_DEPENDENCIES)
+ @rm -f nft$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(nft_OBJECTS) $(nft_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cache.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cli.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ct.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datatype.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dccpopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/erec.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/evaluate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expression.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/exthdr.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fib.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gmputil.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iface.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/intervals.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libminigmp_la-mini-gmp.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnftables.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libparser_la-parser_bison.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libparser_la-scanner.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mergesort.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/meta.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misspell.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mnl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/monitor.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlink.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlink_delinearize.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netlink_linearize.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfnl_osf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nftutils.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/numgen.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optimize.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/osf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/owner.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser_json.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/payload.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proto.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rule.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sctp_chunk.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/segtree.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statement.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpopt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfrm.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xt.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libminigmp_la-mini-gmp.lo: mini-gmp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libminigmp_la_CFLAGS) $(CFLAGS) -MT libminigmp_la-mini-gmp.lo -MD -MP -MF $(DEPDIR)/libminigmp_la-mini-gmp.Tpo -c -o libminigmp_la-mini-gmp.lo `test -f 'mini-gmp.c' || echo '$(srcdir)/'`mini-gmp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libminigmp_la-mini-gmp.Tpo $(DEPDIR)/libminigmp_la-mini-gmp.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mini-gmp.c' object='libminigmp_la-mini-gmp.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libminigmp_la_CFLAGS) $(CFLAGS) -c -o libminigmp_la-mini-gmp.lo `test -f 'mini-gmp.c' || echo '$(srcdir)/'`mini-gmp.c
+
+libparser_la-parser_bison.lo: parser_bison.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libparser_la_CFLAGS) $(CFLAGS) -MT libparser_la-parser_bison.lo -MD -MP -MF $(DEPDIR)/libparser_la-parser_bison.Tpo -c -o libparser_la-parser_bison.lo `test -f 'parser_bison.c' || echo '$(srcdir)/'`parser_bison.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libparser_la-parser_bison.Tpo $(DEPDIR)/libparser_la-parser_bison.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='parser_bison.c' object='libparser_la-parser_bison.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libparser_la_CFLAGS) $(CFLAGS) -c -o libparser_la-parser_bison.lo `test -f 'parser_bison.c' || echo '$(srcdir)/'`parser_bison.c
+
+libparser_la-scanner.lo: scanner.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libparser_la_CFLAGS) $(CFLAGS) -MT libparser_la-scanner.lo -MD -MP -MF $(DEPDIR)/libparser_la-scanner.Tpo -c -o libparser_la-scanner.lo `test -f 'scanner.c' || echo '$(srcdir)/'`scanner.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libparser_la-scanner.Tpo $(DEPDIR)/libparser_la-scanner.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scanner.c' object='libparser_la-scanner.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libparser_la_CFLAGS) $(CFLAGS) -c -o libparser_la-scanner.lo `test -f 'scanner.c' || echo '$(srcdir)/'`scanner.c
+
+.l.c:
+ $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.y.c:
+ $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f parser_bison.c
+ -rm -f parser_bison.h
+ -rm -f scanner.c
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/cache.Plo
+ -rm -f ./$(DEPDIR)/cli.Po
+ -rm -f ./$(DEPDIR)/cmd.Plo
+ -rm -f ./$(DEPDIR)/ct.Plo
+ -rm -f ./$(DEPDIR)/datatype.Plo
+ -rm -f ./$(DEPDIR)/dccpopt.Plo
+ -rm -f ./$(DEPDIR)/erec.Plo
+ -rm -f ./$(DEPDIR)/evaluate.Plo
+ -rm -f ./$(DEPDIR)/expression.Plo
+ -rm -f ./$(DEPDIR)/exthdr.Plo
+ -rm -f ./$(DEPDIR)/fib.Plo
+ -rm -f ./$(DEPDIR)/gmputil.Plo
+ -rm -f ./$(DEPDIR)/hash.Plo
+ -rm -f ./$(DEPDIR)/iface.Plo
+ -rm -f ./$(DEPDIR)/intervals.Plo
+ -rm -f ./$(DEPDIR)/ipopt.Plo
+ -rm -f ./$(DEPDIR)/json.Plo
+ -rm -f ./$(DEPDIR)/libminigmp_la-mini-gmp.Plo
+ -rm -f ./$(DEPDIR)/libnftables.Plo
+ -rm -f ./$(DEPDIR)/libparser_la-parser_bison.Plo
+ -rm -f ./$(DEPDIR)/libparser_la-scanner.Plo
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/mergesort.Plo
+ -rm -f ./$(DEPDIR)/meta.Plo
+ -rm -f ./$(DEPDIR)/misspell.Plo
+ -rm -f ./$(DEPDIR)/mnl.Plo
+ -rm -f ./$(DEPDIR)/monitor.Plo
+ -rm -f ./$(DEPDIR)/netlink.Plo
+ -rm -f ./$(DEPDIR)/netlink_delinearize.Plo
+ -rm -f ./$(DEPDIR)/netlink_linearize.Plo
+ -rm -f ./$(DEPDIR)/nfnl_osf.Plo
+ -rm -f ./$(DEPDIR)/nftutils.Plo
+ -rm -f ./$(DEPDIR)/numgen.Plo
+ -rm -f ./$(DEPDIR)/optimize.Plo
+ -rm -f ./$(DEPDIR)/osf.Plo
+ -rm -f ./$(DEPDIR)/owner.Plo
+ -rm -f ./$(DEPDIR)/parser_json.Plo
+ -rm -f ./$(DEPDIR)/payload.Plo
+ -rm -f ./$(DEPDIR)/print.Plo
+ -rm -f ./$(DEPDIR)/proto.Plo
+ -rm -f ./$(DEPDIR)/rt.Plo
+ -rm -f ./$(DEPDIR)/rule.Plo
+ -rm -f ./$(DEPDIR)/sctp_chunk.Plo
+ -rm -f ./$(DEPDIR)/segtree.Plo
+ -rm -f ./$(DEPDIR)/socket.Plo
+ -rm -f ./$(DEPDIR)/statement.Plo
+ -rm -f ./$(DEPDIR)/tcpopt.Plo
+ -rm -f ./$(DEPDIR)/utils.Plo
+ -rm -f ./$(DEPDIR)/xfrm.Plo
+ -rm -f ./$(DEPDIR)/xt.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/cache.Plo
+ -rm -f ./$(DEPDIR)/cli.Po
+ -rm -f ./$(DEPDIR)/cmd.Plo
+ -rm -f ./$(DEPDIR)/ct.Plo
+ -rm -f ./$(DEPDIR)/datatype.Plo
+ -rm -f ./$(DEPDIR)/dccpopt.Plo
+ -rm -f ./$(DEPDIR)/erec.Plo
+ -rm -f ./$(DEPDIR)/evaluate.Plo
+ -rm -f ./$(DEPDIR)/expression.Plo
+ -rm -f ./$(DEPDIR)/exthdr.Plo
+ -rm -f ./$(DEPDIR)/fib.Plo
+ -rm -f ./$(DEPDIR)/gmputil.Plo
+ -rm -f ./$(DEPDIR)/hash.Plo
+ -rm -f ./$(DEPDIR)/iface.Plo
+ -rm -f ./$(DEPDIR)/intervals.Plo
+ -rm -f ./$(DEPDIR)/ipopt.Plo
+ -rm -f ./$(DEPDIR)/json.Plo
+ -rm -f ./$(DEPDIR)/libminigmp_la-mini-gmp.Plo
+ -rm -f ./$(DEPDIR)/libnftables.Plo
+ -rm -f ./$(DEPDIR)/libparser_la-parser_bison.Plo
+ -rm -f ./$(DEPDIR)/libparser_la-scanner.Plo
+ -rm -f ./$(DEPDIR)/main.Po
+ -rm -f ./$(DEPDIR)/mergesort.Plo
+ -rm -f ./$(DEPDIR)/meta.Plo
+ -rm -f ./$(DEPDIR)/misspell.Plo
+ -rm -f ./$(DEPDIR)/mnl.Plo
+ -rm -f ./$(DEPDIR)/monitor.Plo
+ -rm -f ./$(DEPDIR)/netlink.Plo
+ -rm -f ./$(DEPDIR)/netlink_delinearize.Plo
+ -rm -f ./$(DEPDIR)/netlink_linearize.Plo
+ -rm -f ./$(DEPDIR)/nfnl_osf.Plo
+ -rm -f ./$(DEPDIR)/nftutils.Plo
+ -rm -f ./$(DEPDIR)/numgen.Plo
+ -rm -f ./$(DEPDIR)/optimize.Plo
+ -rm -f ./$(DEPDIR)/osf.Plo
+ -rm -f ./$(DEPDIR)/owner.Plo
+ -rm -f ./$(DEPDIR)/parser_json.Plo
+ -rm -f ./$(DEPDIR)/payload.Plo
+ -rm -f ./$(DEPDIR)/print.Plo
+ -rm -f ./$(DEPDIR)/proto.Plo
+ -rm -f ./$(DEPDIR)/rt.Plo
+ -rm -f ./$(DEPDIR)/rule.Plo
+ -rm -f ./$(DEPDIR)/sctp_chunk.Plo
+ -rm -f ./$(DEPDIR)/segtree.Plo
+ -rm -f ./$(DEPDIR)/socket.Plo
+ -rm -f ./$(DEPDIR)/statement.Plo
+ -rm -f ./$(DEPDIR)/tcpopt.Plo
+ -rm -f ./$(DEPDIR)/utils.Plo
+ -rm -f ./$(DEPDIR)/xfrm.Plo
+ -rm -f ./$(DEPDIR)/xt.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS
+
+.MAKE: all check install install-am install-exec install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES clean-sbinPROGRAMS cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/cache.c b/src/cache.c
new file mode 100644
index 0000000..4e89fe1
--- /dev/null
+++ b/src/cache.c
@@ -0,0 +1,1295 @@
+/*
+ * Copyright (c) 2019 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 <expression.h>
+#include <statement.h>
+#include <rule.h>
+#include <erec.h>
+#include <utils.h>
+#include <cache.h>
+#include <netlink.h>
+#include <mnl.h>
+#include <libnftnl/chain.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+
+static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
+{
+ struct set *set;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (!cmd->table)
+ break;
+
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN |
+ NFT_CACHE_SET |
+ NFT_CACHE_OBJECT |
+ NFT_CACHE_FLOWTABLE;
+ list_for_each_entry(set, &cmd->table->sets, list) {
+ if (set->automerge)
+ flags |= NFT_CACHE_SETELEM_MAYBE;
+ }
+ break;
+ case CMD_OBJ_CHAIN:
+ case CMD_OBJ_SET:
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_FLOWTABLE:
+ flags |= NFT_CACHE_TABLE;
+ break;
+ case CMD_OBJ_ELEMENTS:
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN |
+ NFT_CACHE_SET |
+ NFT_CACHE_OBJECT |
+ NFT_CACHE_SETELEM_MAYBE;
+ break;
+ case CMD_OBJ_RULE:
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN |
+ NFT_CACHE_SET |
+ NFT_CACHE_OBJECT |
+ NFT_CACHE_FLOWTABLE;
+
+ if (cmd->handle.index.id ||
+ cmd->handle.position.id)
+ flags |= NFT_CACHE_RULE | NFT_CACHE_UPDATE;
+ break;
+ default:
+ break;
+ }
+
+ return flags;
+}
+
+static unsigned int evaluate_cache_del(struct cmd *cmd, unsigned int flags)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_ELEMENTS:
+ flags |= NFT_CACHE_SETELEM_MAYBE;
+ break;
+ default:
+ break;
+ }
+
+ return flags;
+}
+
+static unsigned int evaluate_cache_get(struct cmd *cmd, unsigned int flags)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_ELEMENTS:
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_SET |
+ NFT_CACHE_SETELEM;
+ break;
+ default:
+ break;
+ }
+
+ return flags;
+}
+
+struct nft_cache_filter *nft_cache_filter_init(void)
+{
+ struct nft_cache_filter *filter;
+ int i;
+
+ filter = xzalloc(sizeof(struct nft_cache_filter));
+ memset(&filter->list, 0, sizeof(filter->list));
+ for (i = 0; i < NFT_CACHE_HSIZE; i++)
+ init_list_head(&filter->obj[i].head);
+
+ return filter;
+}
+
+void nft_cache_filter_fini(struct nft_cache_filter *filter)
+{
+ int i;
+
+ for (i = 0; i < NFT_CACHE_HSIZE; i++) {
+ struct nft_filter_obj *obj, *next;
+
+ list_for_each_entry_safe(obj, next, &filter->obj[i].head, list)
+ xfree(obj);
+ }
+ xfree(filter);
+}
+
+static void cache_filter_add(struct nft_cache_filter *filter,
+ const struct cmd *cmd)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ obj = xmalloc(sizeof(struct nft_filter_obj));
+ obj->family = cmd->handle.family;
+ obj->table = cmd->handle.table.name;
+ obj->set = cmd->handle.set.name;
+
+ hash = djb_hash(cmd->handle.set.name) % NFT_CACHE_HSIZE;
+ list_add_tail(&obj->list, &filter->obj[hash].head);
+}
+
+static bool cache_filter_find(const struct nft_cache_filter *filter,
+ const struct handle *handle)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ hash = djb_hash(handle->set.name) % NFT_CACHE_HSIZE;
+
+ list_for_each_entry(obj, &filter->obj[hash].head, list) {
+ if (obj->family == handle->family &&
+ !strcmp(obj->table, handle->table.name) &&
+ !strcmp(obj->set, handle->set.name))
+ return true;
+ }
+
+ return false;
+}
+
+static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_METER:
+ flags |= NFT_CACHE_SET;
+ cache_filter_add(filter, cmd);
+ break;
+ case CMD_OBJ_RULESET:
+ flags |= NFT_CACHE_FLUSHED;
+ break;
+ default:
+ break;
+ }
+
+ return flags;
+}
+
+static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_CHAIN:
+ flags |= NFT_CACHE_CHAIN;
+ break;
+ default:
+ break;
+ }
+
+ return flags;
+}
+
+static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
+ unsigned int flags,
+ struct nft_cache_filter *filter)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (filter && cmd->handle.table.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ }
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_OBJ_CHAIN:
+ if (filter && cmd->handle.chain.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.chain = cmd->handle.chain.name;
+ /* implicit terse listing to fetch content of anonymous
+ * sets only when chain name is specified.
+ */
+ flags |= NFT_CACHE_TERSE;
+ }
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ if (filter && cmd->handle.table.name && cmd->handle.set.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.set = cmd->handle.set.name;
+ }
+ if (filter->list.table && filter->list.set)
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_SET | NFT_CACHE_SETELEM;
+ else if (nft_output_terse(&nft->output))
+ flags |= NFT_CACHE_FULL | NFT_CACHE_TERSE;
+ else
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_OBJ_CHAINS:
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_CHAIN;
+ break;
+ case CMD_OBJ_SETS:
+ case CMD_OBJ_MAPS:
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_SET;
+ if (!nft_output_terse(&nft->output))
+ flags |= NFT_CACHE_SETELEM;
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ if (filter &&
+ cmd->handle.table.name &&
+ cmd->handle.flowtable.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.ft = cmd->handle.flowtable.name;
+ }
+ /* fall through */
+ case CMD_OBJ_FLOWTABLES:
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_FLOWTABLE;
+ break;
+ case CMD_OBJ_RULESET:
+ 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;
+
+ return flags;
+}
+
+static unsigned int evaluate_cache_reset(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
+ if (filter) {
+ if (cmd->handle.table.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ }
+ if (cmd->handle.chain.name)
+ filter->list.chain = cmd->handle.chain.name;
+ }
+ flags |= NFT_CACHE_SET | NFT_CACHE_FLOWTABLE |
+ NFT_CACHE_OBJECT | NFT_CACHE_CHAIN;
+ break;
+ case CMD_OBJ_ELEMENTS:
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ flags |= NFT_CACHE_SET;
+ break;
+ default:
+ flags |= NFT_CACHE_TABLE;
+ break;
+ }
+
+ return flags;
+}
+
+static int nft_handle_validate(const struct cmd *cmd, struct list_head *msgs)
+{
+ const struct handle *h = &cmd->handle;
+ const struct location *loc;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_RULE:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_CHAIN:
+ case CMD_OBJ_CHAINS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->chain.name &&
+ strlen(h->chain.name) > NFT_NAME_MAXLEN) {
+ loc = &h->chain.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_ELEMENTS:
+ case CMD_OBJ_SET:
+ case CMD_OBJ_SETS:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_MAPS:
+ case CMD_OBJ_METER:
+ case CMD_OBJ_METERS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->set.name &&
+ strlen(h->set.name) > NFT_NAME_MAXLEN) {
+ loc = &h->set.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ case CMD_OBJ_FLOWTABLES:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->flowtable.name &&
+ strlen(h->flowtable.name) > NFT_NAME_MAXLEN) {
+ loc = &h->flowtable.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_INVALID:
+ case CMD_OBJ_EXPR:
+ case CMD_OBJ_RULESET:
+ case CMD_OBJ_MARKUP:
+ case CMD_OBJ_MONITOR:
+ case CMD_OBJ_SETELEMS:
+ case CMD_OBJ_HOOKS:
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_COUNTERS:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_QUOTAS:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_LIMITS:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_SECMARKS:
+ case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_SYNPROXYS:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_HELPERS:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_TIMEOUTS:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_CT_EXPECTATIONS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->obj.name &&
+ strlen(h->obj.name) > NFT_NAME_MAXLEN) {
+ loc = &h->obj.location;
+ goto err_name_too_long;
+ }
+ break;
+ }
+
+ return 0;
+
+err_name_too_long:
+ erec_queue(error(loc, "name too long, %d characters maximum allowed",
+ NFT_NAME_MAXLEN),
+ msgs);
+ return -1;
+}
+
+int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
+ struct list_head *msgs, struct nft_cache_filter *filter,
+ unsigned int *pflags)
+{
+ unsigned int flags = NFT_CACHE_EMPTY;
+ struct cmd *cmd;
+
+ list_for_each_entry(cmd, cmds, list) {
+ if (nft_handle_validate(cmd, msgs) < 0)
+ return -1;
+
+ if (filter->list.table && cmd->op != CMD_LIST)
+ memset(&filter->list, 0, sizeof(filter->list));
+
+ switch (cmd->op) {
+ case CMD_ADD:
+ case CMD_INSERT:
+ case CMD_CREATE:
+ flags = evaluate_cache_add(cmd, flags);
+ if (nft_output_echo(&nft->output))
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_REPLACE:
+ flags = NFT_CACHE_FULL;
+ break;
+ case CMD_DELETE:
+ case CMD_DESTROY:
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN |
+ NFT_CACHE_SET |
+ NFT_CACHE_FLOWTABLE |
+ NFT_CACHE_OBJECT;
+
+ flags = evaluate_cache_del(cmd, flags);
+ break;
+ case CMD_GET:
+ flags = evaluate_cache_get(cmd, flags);
+ break;
+ case CMD_RESET:
+ flags |= evaluate_cache_reset(cmd, flags, filter);
+ break;
+ case CMD_LIST:
+ flags |= evaluate_cache_list(nft, cmd, flags, filter);
+ break;
+ case CMD_MONITOR:
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_FLUSH:
+ flags = evaluate_cache_flush(cmd, flags, filter);
+ break;
+ case CMD_RENAME:
+ flags = evaluate_cache_rename(cmd, flags);
+ break;
+ case CMD_DESCRIBE:
+ case CMD_IMPORT:
+ case CMD_EXPORT:
+ break;
+ default:
+ break;
+ }
+ }
+ *pflags = flags;
+
+ return 0;
+}
+
+void table_cache_add(struct table *table, struct nft_cache *cache)
+{
+ uint32_t hash;
+
+ hash = djb_hash(table->handle.table.name) % NFT_CACHE_HSIZE;
+ cache_add(&table->cache, &cache->table_cache, hash);
+}
+
+void table_cache_del(struct table *table)
+{
+ cache_del(&table->cache);
+}
+
+struct table *table_cache_find(const struct cache *cache,
+ const char *name, uint32_t family)
+{
+ struct table *table;
+ uint32_t hash;
+
+ if (!name)
+ return NULL;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(table, &cache->ht[hash], cache.hlist) {
+ if (table->handle.family == family &&
+ !strcmp(table->handle.table.name, name))
+ return table;
+ }
+
+ return NULL;
+}
+
+struct chain_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
+{
+ struct chain_cache_dump_ctx *ctx = arg;
+ const char *chain_name, *table_name;
+ uint32_t hash, family;
+ struct chain *chain;
+
+ table_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE);
+ family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
+
+ if (family != ctx->table->handle.family ||
+ strcmp(table_name, ctx->table->handle.table.name))
+ return 0;
+
+ chain_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
+ hash = djb_hash(chain_name) % NFT_CACHE_HSIZE;
+ chain = netlink_delinearize_chain(ctx->nlctx, nlc);
+
+ if (chain->flags & CHAIN_F_BINDING) {
+ list_add_tail(&chain->cache.list, &ctx->table->chain_bindings);
+ } else {
+ cache_add(&chain->cache, &ctx->table->chain_cache, hash);
+ }
+
+ nftnl_chain_list_del(nlc);
+ nftnl_chain_free(nlc);
+
+ return 0;
+}
+
+static int chain_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_chain_list *chain_list)
+{
+ struct chain_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_chain_list_foreach(chain_list, chain_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_chain_list *
+chain_cache_dump(struct netlink_ctx *ctx,
+ const struct nft_cache_filter *filter, int *err)
+{
+ struct nftnl_chain_list *chain_list;
+ const char *table = NULL;
+ const char *chain = NULL;
+ int family = NFPROTO_UNSPEC;
+
+ if (filter && filter->list.table && filter->list.chain) {
+ family = filter->list.family;
+ table = filter->list.table;
+ chain = filter->list.chain;
+ }
+
+ chain_list = mnl_nft_chain_dump(ctx, family, table, chain);
+ if (chain_list == NULL) {
+ if (errno == EINTR) {
+ *err = -1;
+ return NULL;
+ }
+ *err = 0;
+ return NULL;
+ }
+
+ return chain_list;
+}
+
+void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
+ const char *chain)
+{
+ struct nftnl_chain_list *chain_list;
+
+ chain_list = mnl_nft_chain_dump(ctx, table->handle.family,
+ table->handle.table.name, chain);
+ if (!chain_list)
+ return;
+
+ chain_cache_init(ctx, table, chain_list);
+
+ nftnl_chain_list_free(chain_list);
+}
+
+void chain_cache_add(struct chain *chain, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(chain->handle.chain.name) % NFT_CACHE_HSIZE;
+ cache_add(&chain->cache, &table->chain_cache, hash);
+}
+
+void chain_cache_del(struct chain *chain)
+{
+ cache_del(&chain->cache);
+}
+
+struct chain *chain_cache_find(const struct table *table, const char *name)
+{
+ struct chain *chain;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(chain, &table->chain_cache.ht[hash], cache.hlist) {
+ if (!strcmp(chain->handle.chain.name, name))
+ return chain;
+ }
+
+ return NULL;
+}
+
+static int list_rule_cb(struct nftnl_rule *nlr, void *data)
+{
+ struct netlink_ctx *ctx = data;
+ const struct handle *h = ctx->data;
+ const char *table, *chain;
+ struct rule *rule;
+ uint32_t family;
+
+ family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
+ table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
+ chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
+
+ if ((h->family != NFPROTO_UNSPEC && h->family != family) ||
+ (h->table.name && strcmp(table, h->table.name) != 0) ||
+ (h->chain.name && strcmp(chain, h->chain.name) != 0))
+ return 0;
+
+ netlink_dump_rule(nlr, ctx);
+ rule = netlink_delinearize_rule(ctx, nlr);
+ assert(rule);
+ list_add_tail(&rule->list, &ctx->list);
+
+ return 0;
+}
+
+int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter,
+ bool dump, bool reset)
+{
+ struct nftnl_rule_list *rule_cache;
+ const char *table = NULL;
+ const char *chain = NULL;
+ uint64_t rule_handle = 0;
+
+ if (filter) {
+ table = filter->list.table;
+ chain = filter->list.chain;
+ rule_handle = filter->list.rule_handle;
+ }
+
+ rule_cache = mnl_nft_rule_dump(ctx, h->family,
+ table, chain, rule_handle, dump, reset);
+ if (rule_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return 0;
+ }
+
+ ctx->data = h;
+ nftnl_rule_list_foreach(rule_cache, list_rule_cb, ctx);
+ nftnl_rule_list_free(rule_cache);
+ return 0;
+}
+
+struct set_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int set_cache_cb(struct nftnl_set *nls, void *arg)
+{
+ struct set_cache_dump_ctx *ctx = arg;
+ const char *set_table;
+ const char *set_name;
+ uint32_t set_family;
+ struct set *set;
+ uint32_t hash;
+
+ set_table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
+ set_family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
+
+ if (set_family != ctx->table->handle.family ||
+ strcmp(set_table, ctx->table->handle.table.name))
+ return 0;
+
+ set = netlink_delinearize_set(ctx->nlctx, nls);
+ if (!set)
+ return -1;
+
+ set_name = nftnl_set_get_str(nls, NFTNL_SET_NAME);
+ hash = djb_hash(set_name) % NFT_CACHE_HSIZE;
+ cache_add(&set->cache, &ctx->table->set_cache, hash);
+
+ nftnl_set_list_del(nls);
+ nftnl_set_free(nls);
+ return 0;
+}
+
+static int set_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_set_list *set_list)
+{
+ struct set_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+
+ nftnl_set_list_foreach(set_list, set_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_set_list *
+set_cache_dump(struct netlink_ctx *ctx,
+ const struct nft_cache_filter *filter, int *err)
+{
+ struct nftnl_set_list *set_list;
+ int family = NFPROTO_UNSPEC;
+ const char *table = NULL;
+ const char *set = NULL;
+
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ set = filter->list.set;
+ }
+
+ set_list = mnl_nft_set_dump(ctx, family, table, set);
+ if (!set_list) {
+ if (errno == EINTR) {
+ *err = -1;
+ return NULL;
+ }
+ *err = 0;
+ return NULL;
+ }
+
+ return set_list;
+}
+
+void set_cache_add(struct set *set, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(set->handle.set.name) % NFT_CACHE_HSIZE;
+ cache_add(&set->cache, &table->set_cache, hash);
+}
+
+void set_cache_del(struct set *set)
+{
+ cache_del(&set->cache);
+}
+
+struct set *set_cache_find(const struct table *table, const char *name)
+{
+ struct set *set;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(set, &table->set_cache.ht[hash], cache.hlist) {
+ if (!strcmp(set->handle.set.name, name))
+ return set;
+ }
+
+ return NULL;
+}
+
+struct obj_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int obj_cache_cb(struct nftnl_obj *nlo, void *arg)
+{
+ struct obj_cache_dump_ctx *ctx = arg;
+ const char *obj_name;
+ struct obj *obj;
+ uint32_t hash;
+
+ obj = netlink_delinearize_obj(ctx->nlctx, nlo);
+ if (!obj)
+ return -1;
+
+ obj_name = nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME);
+ hash = djb_hash(obj_name) % NFT_CACHE_HSIZE;
+ cache_add(&obj->cache, &ctx->table->obj_cache, hash);
+
+ return 0;
+}
+
+static int obj_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_obj_list *obj_list)
+{
+ struct obj_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_obj_list_foreach(obj_list, obj_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_obj_list *obj_cache_dump(struct netlink_ctx *ctx,
+ const struct table *table)
+{
+ struct nftnl_obj_list *obj_list;
+
+ obj_list = mnl_nft_obj_dump(ctx, table->handle.family,
+ table->handle.table.name, NULL,
+ 0, true, false);
+ if (!obj_list) {
+ if (errno == EINTR)
+ return NULL;
+
+ /* old kernels do not support this, provide an empty list. */
+ obj_list = nftnl_obj_list_alloc();
+ if (!obj_list)
+ memory_allocation_error();
+
+ return obj_list;
+ }
+
+ return obj_list;
+}
+
+void obj_cache_add(struct obj *obj, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(obj->handle.obj.name) % NFT_CACHE_HSIZE;
+ cache_add(&obj->cache, &table->obj_cache, hash);
+}
+
+void obj_cache_del(struct obj *obj)
+{
+ cache_del(&obj->cache);
+}
+
+struct obj *obj_cache_find(const struct table *table, const char *name,
+ uint32_t obj_type)
+{
+ struct obj *obj;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(obj, &table->obj_cache.ht[hash], cache.hlist) {
+ if (!strcmp(obj->handle.obj.name, name) &&
+ obj->type == obj_type)
+ return obj;
+ }
+
+ return NULL;
+}
+
+struct ft_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int ft_cache_cb(struct nftnl_flowtable *nlf, void *arg)
+{
+ struct ft_cache_dump_ctx *ctx = arg;
+ struct flowtable *ft;
+ const char *ft_table;
+ const char *ft_name;
+ uint32_t ft_family;
+ uint32_t hash;
+
+ ft_family = nftnl_flowtable_get_u32(nlf, NFTNL_FLOWTABLE_FAMILY);
+ ft_table = nftnl_flowtable_get_str(nlf, NFTNL_FLOWTABLE_TABLE);
+
+ if (ft_family != ctx->table->handle.family ||
+ strcmp(ft_table, ctx->table->handle.table.name))
+ return 0;
+
+ ft = netlink_delinearize_flowtable(ctx->nlctx, nlf);
+ if (!ft)
+ return -1;
+
+ ft_name = nftnl_flowtable_get_str(nlf, NFTNL_FLOWTABLE_NAME);
+ hash = djb_hash(ft_name) % NFT_CACHE_HSIZE;
+ cache_add(&ft->cache, &ctx->table->ft_cache, hash);
+
+ nftnl_flowtable_list_del(nlf);
+ nftnl_flowtable_free(nlf);
+ return 0;
+}
+
+static int ft_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_flowtable_list *ft_list)
+{
+ struct ft_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_flowtable_list_foreach(ft_list, ft_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_flowtable_list *
+ft_cache_dump(struct netlink_ctx *ctx, const struct nft_cache_filter *filter)
+{
+ struct nftnl_flowtable_list *ft_list;
+ int family = NFPROTO_UNSPEC;
+ const char *table = NULL;
+ const char *ft = NULL;
+
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ ft = filter->list.ft;
+ }
+
+ ft_list = mnl_nft_flowtable_dump(ctx, family, table, ft);
+ if (!ft_list) {
+ if (errno == EINTR)
+ return NULL;
+
+ /* old kernels do not support this, provide an empty list. */
+ ft_list = nftnl_flowtable_list_alloc();
+ if (!ft_list)
+ memory_allocation_error();
+
+ return ft_list;
+ }
+
+ return ft_list;
+}
+
+void ft_cache_add(struct flowtable *ft, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(ft->handle.flowtable.name) % NFT_CACHE_HSIZE;
+ cache_add(&ft->cache, &table->ft_cache, hash);
+}
+
+void ft_cache_del(struct flowtable *ft)
+{
+ cache_del(&ft->cache);
+}
+
+struct flowtable *ft_cache_find(const struct table *table, const char *name)
+{
+ struct flowtable *ft;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(ft, &table->ft_cache.ht[hash], cache.hlist) {
+ if (!strcmp(ft->handle.flowtable.name, name))
+ return ft;
+ }
+
+ return NULL;
+}
+
+static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
+ struct nft_cache *cache,
+ const struct nft_cache_filter *filter)
+{
+ struct table *table, *next;
+ int ret;
+
+ ret = netlink_list_tables(ctx, h, filter);
+ if (ret < 0)
+ return -1;
+
+ list_for_each_entry_safe(table, next, &ctx->list, list) {
+ list_del(&table->list);
+ table_cache_add(table, cache);
+ }
+
+ return 0;
+}
+
+static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
+ const struct nft_cache_filter *filter)
+{
+ struct rule *rule, *nrule;
+ struct chain *chain;
+ int ret;
+
+ ret = rule_cache_dump(ctx, &table->handle, filter, true, false);
+
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+ chain = chain_cache_find(table, rule->handle.chain.name);
+ if (!chain)
+ chain = chain_binding_lookup(table,
+ rule->handle.chain.name);
+ if (!chain)
+ goto err_ctx_list;
+
+ list_move_tail(&rule->list, &chain->rules);
+ }
+
+ return ret;
+
+err_ctx_list:
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+ list_del(&rule->list);
+ rule_free(rule);
+ }
+ errno = EINTR;
+
+ return -1;
+}
+
+static int implicit_chain_cache(struct netlink_ctx *ctx, struct table *table,
+ const char *chain_name)
+{
+ struct nft_cache_filter filter;
+ struct chain *chain;
+ int ret = 0;
+
+ list_for_each_entry(chain, &table->chain_bindings, cache.list) {
+ filter.list = (typeof(filter.list)) {
+ .table = table->handle.table.name,
+ .chain = chain->handle.chain.name,
+ };
+ ret = rule_init_cache(ctx, table, &filter);
+ }
+
+ return ret;
+}
+
+static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
+ const struct nft_cache_filter *filter)
+{
+ struct nftnl_flowtable_list *ft_list = NULL;
+ struct nftnl_chain_list *chain_list = NULL;
+ struct nftnl_set_list *set_list = NULL;
+ struct nftnl_obj_list *obj_list;
+ struct table *table;
+ struct set *set;
+ int ret = 0;
+
+ if (flags & NFT_CACHE_CHAIN_BIT) {
+ chain_list = chain_cache_dump(ctx, filter, &ret);
+ if (!chain_list)
+ return -1;
+ }
+ if (flags & NFT_CACHE_SET_BIT) {
+ set_list = set_cache_dump(ctx, filter, &ret);
+ if (!set_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ }
+ if (flags & NFT_CACHE_FLOWTABLE_BIT) {
+ ft_list = ft_cache_dump(ctx, filter);
+ if (!ft_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ }
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (flags & NFT_CACHE_SET_BIT) {
+ ret = set_cache_init(ctx, table, set_list);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ if (flags & NFT_CACHE_SETELEM_BIT) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+ if (!set_is_anonymous(set->flags) &&
+ flags & NFT_CACHE_TERSE)
+ continue;
+
+ ret = netlink_list_setelems(ctx, &set->handle,
+ set, false);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ } else if (flags & NFT_CACHE_SETELEM_MAYBE) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+
+ if (!set_is_non_concat_range(set))
+ continue;
+
+ ret = netlink_list_setelems(ctx, &set->handle,
+ set, false);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ }
+ if (flags & NFT_CACHE_CHAIN_BIT) {
+ ret = chain_cache_init(ctx, table, chain_list);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ if (flags & NFT_CACHE_FLOWTABLE_BIT) {
+ ret = ft_cache_init(ctx, table, ft_list);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ if (flags & NFT_CACHE_OBJECT_BIT) {
+ obj_list = obj_cache_dump(ctx, table);
+ if (!obj_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ ret = obj_cache_init(ctx, table, obj_list);
+
+ nftnl_obj_list_free(obj_list);
+
+ if (ret < 0)
+ goto cache_fails;
+ }
+
+ if (flags & NFT_CACHE_RULE_BIT) {
+ ret = rule_init_cache(ctx, table, filter);
+ if (ret < 0)
+ goto cache_fails;
+
+ if (filter && filter->list.table && filter->list.chain) {
+ ret = implicit_chain_cache(ctx, table, filter->list.chain);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ }
+ }
+
+cache_fails:
+ if (set_list)
+ nftnl_set_list_free(set_list);
+ if (ft_list)
+ nftnl_flowtable_list_free(ft_list);
+
+ if (flags & NFT_CACHE_CHAIN_BIT)
+ nftnl_chain_list_free(chain_list);
+
+ return ret;
+}
+
+static int nft_cache_init(struct netlink_ctx *ctx, unsigned int flags,
+ const struct nft_cache_filter *filter)
+{
+ struct handle handle = {
+ .family = NFPROTO_UNSPEC,
+ };
+ int ret;
+
+ if (flags == NFT_CACHE_EMPTY)
+ return 0;
+
+ /* assume NFT_CACHE_TABLE is always set. */
+ ret = cache_init_tables(ctx, &handle, &ctx->nft->cache, filter);
+ if (ret < 0)
+ return ret;
+ ret = cache_init_objects(ctx, flags, filter);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static bool nft_cache_is_complete(struct nft_cache *cache, unsigned int flags)
+{
+ return (cache->flags & flags) == flags;
+}
+
+static bool nft_cache_needs_refresh(struct nft_cache *cache)
+{
+ return cache->flags & NFT_CACHE_REFRESH;
+}
+
+static bool nft_cache_is_updated(struct nft_cache *cache, uint16_t genid)
+{
+ return genid && genid == cache->genid;
+}
+
+bool nft_cache_needs_update(struct nft_cache *cache)
+{
+ return cache->flags & NFT_CACHE_UPDATE;
+}
+
+int nft_cache_update(struct nft_ctx *nft, unsigned int flags,
+ struct list_head *msgs,
+ const struct nft_cache_filter *filter)
+{
+ struct netlink_ctx ctx = {
+ .list = LIST_HEAD_INIT(ctx.list),
+ .nft = nft,
+ .msgs = msgs,
+ };
+ struct nft_cache *cache = &nft->cache;
+ uint32_t genid, genid_stop, oldflags;
+ int ret;
+replay:
+ ctx.seqnum = cache->seqnum++;
+ genid = mnl_genid_get(&ctx);
+ if (!nft_cache_needs_refresh(cache) &&
+ nft_cache_is_complete(cache, flags) &&
+ nft_cache_is_updated(cache, genid))
+ return 0;
+
+ if (cache->genid)
+ nft_cache_release(cache);
+
+ if (flags & NFT_CACHE_FLUSHED) {
+ oldflags = flags;
+ flags = NFT_CACHE_EMPTY;
+ if (oldflags & NFT_CACHE_UPDATE)
+ flags |= NFT_CACHE_UPDATE;
+ goto skip;
+ }
+
+ ret = nft_cache_init(&ctx, flags, filter);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ nft_cache_release(cache);
+ goto replay;
+ }
+
+ erec_queue(error(&netlink_location, "cache initialization failed: %s",
+ strerror(errno)),
+ msgs);
+ nft_cache_release(cache);
+
+ return -1;
+ }
+
+ genid_stop = mnl_genid_get(&ctx);
+ if (genid != genid_stop) {
+ nft_cache_release(cache);
+ goto replay;
+ }
+skip:
+ cache->genid = genid;
+ cache->flags = flags;
+ return 0;
+}
+
+static void nft_cache_flush(struct cache *table_cache)
+{
+ struct table *table, *next;
+
+ list_for_each_entry_safe(table, next, &table_cache->list, cache.list) {
+ table_cache_del(table);
+ table_free(table);
+ }
+}
+
+void nft_cache_release(struct nft_cache *cache)
+{
+ nft_cache_flush(&cache->table_cache);
+ cache->genid = 0;
+ cache->flags = NFT_CACHE_EMPTY;
+}
+
+void cache_init(struct cache *cache)
+{
+ int i;
+
+ cache->ht = xmalloc(sizeof(struct list_head) * NFT_CACHE_HSIZE);
+ for (i = 0; i < NFT_CACHE_HSIZE; i++)
+ init_list_head(&cache->ht[i]);
+
+ init_list_head(&cache->list);
+}
+
+void cache_free(struct cache *cache)
+{
+ xfree(cache->ht);
+}
+
+void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash)
+{
+ list_add_tail(&item->hlist, &cache->ht[hash]);
+ list_add_tail(&item->list, &cache->list);
+}
+
+void cache_del(struct cache_item *item)
+{
+ list_del(&item->hlist);
+ list_del(&item->list);
+}
diff --git a/src/cli.c b/src/cli.c
new file mode 100644
index 0000000..448c25c
--- /dev/null
+++ b/src/cli.c
@@ -0,0 +1,275 @@
+/*
+ * Asynchronous readline-based interactive interface
+ *
+ * Actually not asynchronous so far, but intended to be.
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <limits.h>
+#ifdef HAVE_LIBREADLINE
+#include <readline/readline.h>
+#include <readline/history.h>
+#elif defined(HAVE_LIBEDIT)
+#include <editline/readline.h>
+#else
+#include <linenoise.h>
+#endif
+
+#include <cli.h>
+#include <list.h>
+
+#define CMDLINE_HISTFILE ".nft.history"
+#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
+init_histfile(void)
+{
+ const char *home;
+
+ home = getenv("HOME");
+ if (home == NULL)
+ home = "";
+ snprintf(histfile, sizeof(histfile), "%s/%s", home, CMDLINE_HISTFILE);
+}
+
+#if defined(HAVE_LIBREADLINE)
+static void nft_rl_prompt_save(void)
+{
+ rl_save_prompt();
+ rl_clear_message();
+ rl_set_prompt(".... ");
+}
+#define nft_rl_prompt_restore rl_restore_prompt
+#elif defined(HAVE_LIBEDIT)
+static void nft_rl_prompt_save(void)
+{
+ rl_set_prompt(".... ");
+}
+static void nft_rl_prompt_restore(void)
+{
+ rl_set_prompt("nft> ");
+}
+#endif
+
+#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
+
+static struct nft_ctx *cli_nft;
+static char *multiline;
+
+static char *cli_append_multiline(char *line)
+{
+ size_t len = strlen(line);
+ bool complete = false;
+ char *s;
+
+ if (len == 0)
+ return NULL;
+
+ if (line[len - 1] == '\\') {
+ line[len - 1] = '\0';
+ len--;
+ } else if (multiline == NULL)
+ return line;
+ else
+ complete = 1;
+
+ if (multiline == NULL) {
+ multiline = line;
+ nft_rl_prompt_save();
+ } else {
+ len += strlen(multiline);
+ s = malloc(len + 1);
+ if (!s) {
+ fprintf(stderr, "%s:%u: Memory allocation failure\n",
+ __FILE__, __LINE__);
+ cli_exit(EXIT_FAILURE);
+ return NULL;
+ }
+ snprintf(s, len + 1, "%s%s", multiline, line);
+ free(multiline);
+ multiline = s;
+ }
+ line = NULL;
+
+ if (complete) {
+ line = multiline;
+ multiline = NULL;
+ nft_rl_prompt_restore();
+ }
+ return line;
+}
+
+static void cli_complete(char *line)
+{
+ const HIST_ENTRY *hist;
+ const char *c;
+ LIST_HEAD(msgs);
+
+ if (line == NULL) {
+ printf("\n");
+ return cli_exit(0);
+ }
+
+ line = cli_append_multiline(line);
+ if (line == NULL)
+ return;
+
+ for (c = line; *c != '\0'; c++)
+ if (!isspace(*c))
+ break;
+ if (*c == '\0')
+ return;
+
+ if (!strcmp(line, CMDLINE_QUIT))
+ return cli_exit(0);
+
+ /* avoid duplicate history entries */
+ hist = history_get(history_length);
+ if (hist == NULL || strcmp(hist->line, line))
+ add_history(line);
+
+ nft_run_cmd_from_buffer(cli_nft, line);
+ free(line);
+}
+#endif
+
+#if defined(HAVE_LIBREADLINE)
+
+static char **cli_completion(const char *text, int start, int end)
+{
+ return NULL;
+}
+
+int cli_init(struct nft_ctx *nft)
+{
+ cli_nft = nft;
+ rl_readline_name = (char *)"nft";
+ rl_instream = stdin;
+ rl_outstream = stdout;
+
+ rl_callback_handler_install(CMDLINE_PROMPT, cli_complete);
+ rl_attempted_completion_function = cli_completion;
+
+ init_histfile();
+
+ read_history(histfile);
+ history_set_pos(history_length);
+
+ while (!cli_quit)
+ rl_callback_read_char();
+
+ return cli_rc;
+}
+
+void cli_exit(int rc)
+{
+ rl_callback_handler_remove();
+ rl_deprep_terminal();
+ write_history(histfile);
+
+ __cli_exit(rc);
+}
+
+#elif defined(HAVE_LIBEDIT)
+
+int cli_init(struct nft_ctx *nft)
+{
+ char *line;
+
+ cli_nft = nft;
+ rl_readline_name = (char *)"nft";
+ rl_instream = stdin;
+ rl_outstream = stdout;
+
+ init_histfile();
+
+ read_history(histfile);
+ history_set_pos(history_length);
+
+ rl_set_prompt(CMDLINE_PROMPT);
+ while (!cli_quit) {
+ line = readline(rl_prompt);
+ if (!line) {
+ cli_exit(0);
+ break;
+ }
+ line = cli_append_multiline(line);
+ if (!line)
+ continue;
+
+ cli_complete(line);
+ }
+
+ return cli_rc;
+}
+
+void cli_exit(int rc)
+{
+ rl_deprep_terminal();
+ write_history(histfile);
+
+ __cli_exit(rc);
+}
+
+#else /* HAVE_LINENOISE */
+
+int cli_init(struct nft_ctx *nft)
+{
+ char *line;
+
+ init_histfile();
+ linenoiseHistoryLoad(histfile);
+ linenoiseSetMultiLine(1);
+
+ while (!cli_quit) {
+ line = linenoise(CMDLINE_PROMPT);
+ if (!line) {
+ cli_exit(0);
+ break;
+ }
+ if (strcmp(line, CMDLINE_QUIT) == 0) {
+ cli_exit(0);
+ } else if (line[0] != '\0') {
+ linenoiseHistoryAdd(line);
+ nft_run_cmd_from_buffer(nft, line);
+ }
+ linenoiseFree(line);
+ }
+
+ return cli_rc;
+}
+
+void cli_exit(int rc)
+{
+ linenoiseHistorySave(histfile);
+
+ __cli_exit(rc);
+}
+
+#endif /* HAVE_LINENOISE */
diff --git a/src/cmd.c b/src/cmd.c
new file mode 100644
index 0000000..68c476c
--- /dev/null
+++ b/src/cmd.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 2020 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <erec.h>
+#include <mnl.h>
+#include <cmd.h>
+#include <parser.h>
+#include <utils.h>
+#include <iface.h>
+#include <errno.h>
+#include <cache.h>
+
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc)
+{
+ if (cmd->num_attrs >= cmd->attr_array_len) {
+ cmd->attr_array_len *= 2;
+ cmd->attr = xrealloc(cmd->attr, sizeof(struct nlerr_loc) * cmd->attr_array_len);
+ }
+
+ cmd->attr[cmd->num_attrs].offset = offset;
+ cmd->attr[cmd->num_attrs].location = loc;
+ cmd->num_attrs++;
+}
+
+static int nft_cmd_enoent_table(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ struct table *table;
+
+ if (!cmd->handle.table.name)
+ return 0;
+
+ table = table_lookup_fuzzy(&cmd->handle, &ctx->nft->cache);
+ if (!table)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean table ‘%s’ in family %s?",
+ strerror(ENOENT), table->handle.table.name,
+ family2str(table->handle.family));
+ return 1;
+}
+
+static int table_fuzzy_check(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct table *table)
+{
+ if (table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name, cmd->handle.family))
+ return 0;
+
+ if (strcmp(cmd->handle.table.name, table->handle.table.name) ||
+ cmd->handle.family != table->handle.family) {
+ netlink_io_error(ctx, &cmd->handle.table.location,
+ "%s; did you mean table ‘%s’ in family %s?",
+ strerror(ENOENT), table->handle.table.name,
+ family2str(table->handle.family));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int nft_cmd_enoent_chain(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct chain *chain;
+
+ if (!cmd->handle.chain.name)
+ return 0;
+
+ chain = chain_lookup_fuzzy(&cmd->handle, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!chain)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean chain ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT), chain->handle.chain.name,
+ family2str(table->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_rule(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ unsigned int flags = NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN;
+ const struct table *table = NULL;
+ struct chain *chain;
+
+ if (nft_cache_update(ctx->nft, flags, ctx->msgs, NULL) < 0)
+ return 0;
+
+ chain = chain_lookup_fuzzy(&cmd->handle, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!chain)
+ return 0;
+
+ if (strcmp(cmd->handle.chain.name, chain->handle.chain.name)) {
+ netlink_io_error(ctx, loc, "%s; did you mean chain ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT),
+ chain->handle.chain.name,
+ family2str(table->handle.family),
+ table->handle.table.name);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int nft_cmd_enoent_set(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct set *set;
+
+ if (!cmd->handle.set.name)
+ return 0;
+
+ set = set_lookup_fuzzy(cmd->handle.set.name, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!set)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean %s ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT),
+ set_is_map(set->flags) ? "map" : "set",
+ set->handle.set.name,
+ family2str(set->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_obj(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct obj *obj;
+
+ if (!cmd->handle.obj.name)
+ return 0;
+
+ obj = obj_lookup_fuzzy(cmd->handle.obj.name, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!obj)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean obj ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT), obj->handle.obj.name,
+ family2str(obj->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_flowtable(struct netlink_ctx *ctx,
+ const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct flowtable *ft;
+
+ if (!cmd->handle.flowtable.name)
+ return 0;
+
+ ft = flowtable_lookup_fuzzy(cmd->handle.flowtable.name,
+ &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!ft)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean flowtable ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT), ft->handle.flowtable.name,
+ family2str(ft->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static void nft_cmd_enoent(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc, int err)
+{
+ int ret = 0;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ ret = nft_cmd_enoent_table(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_CHAIN:
+ ret = nft_cmd_enoent_chain(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_SET:
+ ret = nft_cmd_enoent_set(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_RULE:
+ ret = nft_cmd_enoent_rule(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_SYNPROXY:
+ ret = nft_cmd_enoent_obj(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ ret = nft_cmd_enoent_flowtable(ctx, cmd, loc);
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ return;
+
+ netlink_io_error(ctx, loc, "Could not process rule: %s", strerror(err));
+}
+
+static int nft_cmd_chain_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err)
+{
+ struct chain *chain = cmd->chain;
+ int priority;
+
+ switch (err->err) {
+ case EOPNOTSUPP:
+ if (!(chain->flags & CHAIN_F_BASECHAIN))
+ break;
+
+ mpz_export_data(&priority, chain->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ if (priority <= -200 && !strcmp(chain->type.str, "nat"))
+ return netlink_io_error(ctx, &chain->priority.loc,
+ "Chains of type \"nat\" must have a priority value above -200");
+
+ return netlink_io_error(ctx, &chain->loc,
+ "Chain of type \"%s\" is not supported, perhaps kernel support is missing?",
+ chain->type.str);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err)
+{
+ const struct location *loc = NULL;
+ uint32_t i;
+
+ for (i = 0; i < cmd->num_attrs; i++) {
+ if (!cmd->attr[i].offset)
+ break;
+ if (cmd->attr[i].offset == err->offset)
+ loc = cmd->attr[i].location;
+ }
+
+ if (loc) {
+ if (err->err == ENOENT) {
+ nft_cmd_enoent(ctx, cmd, loc, err->err);
+ return;
+ }
+ } else {
+ loc = &cmd->location;
+ }
+
+ switch (cmd->obj) {
+ case CMD_OBJ_CHAIN:
+ if (nft_cmd_chain_error(ctx, cmd, err) < 0)
+ return;
+ break;
+ default:
+ break;
+ }
+
+ 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
new file mode 100644
index 0000000..1dda799
--- /dev/null
+++ b/src/ct.c
@@ -0,0 +1,593 @@
+/*
+ * Conntrack expression related definitions and types.
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <netinet/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_conntrack_common.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+
+#include <errno.h>
+#include <erec.h>
+#include <expression.h>
+#include <datatype.h>
+#include <ct.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <statement.h>
+
+#define CONNLABEL_CONF DEFAULT_INCLUDE_PATH "/connlabel.conf"
+
+static const struct symbol_table ct_state_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("invalid", NF_CT_STATE_INVALID_BIT),
+ SYMBOL("new", NF_CT_STATE_BIT(IP_CT_NEW)),
+ SYMBOL("established", NF_CT_STATE_BIT(IP_CT_ESTABLISHED)),
+ SYMBOL("related", NF_CT_STATE_BIT(IP_CT_RELATED)),
+ SYMBOL("untracked", NF_CT_STATE_UNTRACKED_BIT),
+ SYMBOL_LIST_END
+ }
+};
+
+const struct datatype ct_state_type = {
+ .type = TYPE_CT_STATE,
+ .name = "ct_state",
+ .desc = "conntrack state",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &bitmask_type,
+ .sym_tbl = &ct_state_tbl,
+};
+
+static const struct symbol_table ct_dir_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("original", IP_CT_DIR_ORIGINAL),
+ SYMBOL("reply", IP_CT_DIR_REPLY),
+ SYMBOL_LIST_END
+ }
+};
+
+const char *ct_dir2str(int dir)
+{
+ const struct symbolic_constant *s;
+
+ for (s = ct_dir_tbl.symbols; s->identifier != NULL; s++) {
+ if (dir == (int)s->value)
+ return s->identifier;
+ }
+
+ return NULL;
+}
+
+const struct datatype ct_dir_type = {
+ .type = TYPE_CT_DIR,
+ .name = "ct_dir",
+ .desc = "conntrack direction",
+ .byteorder = BYTEORDER_INVALID,
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &ct_dir_tbl,
+};
+
+static const struct symbol_table ct_status_tbl = {
+ /*
+ * There are more, but most of them don't make sense for filtering.
+ */
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("expected", IPS_EXPECTED),
+ SYMBOL("seen-reply", IPS_SEEN_REPLY),
+ SYMBOL("assured", IPS_ASSURED),
+ SYMBOL("confirmed", IPS_CONFIRMED),
+ SYMBOL("snat", IPS_SRC_NAT),
+ SYMBOL("dnat", IPS_DST_NAT),
+ SYMBOL("dying", IPS_DYING),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype ct_status_type = {
+ .type = TYPE_CT_STATUS,
+ .name = "ct_status",
+ .desc = "conntrack status",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &bitmask_type,
+ .sym_tbl = &ct_status_tbl,
+};
+
+static const struct symbol_table ct_events_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("new", 1 << IPCT_NEW),
+ SYMBOL("related", 1 << IPCT_RELATED),
+ SYMBOL("destroy", 1 << IPCT_DESTROY),
+ SYMBOL("reply", 1 << IPCT_REPLY),
+ SYMBOL("assured", 1 << IPCT_ASSURED),
+ SYMBOL("protoinfo", 1 << IPCT_PROTOINFO),
+ SYMBOL("helper", 1 << IPCT_HELPER),
+ SYMBOL("mark", 1 << IPCT_MARK),
+ SYMBOL("seqadj", 1 << IPCT_SEQADJ),
+ SYMBOL("secmark", 1 << IPCT_SECMARK),
+ SYMBOL("label", 1 << IPCT_LABEL),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype ct_event_type = {
+ .type = TYPE_CT_EVENTBIT,
+ .name = "ct_event",
+ .desc = "conntrack event bits",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &bitmask_type,
+ .sym_tbl = &ct_events_tbl,
+};
+
+#define CT_LABEL_BIT_SIZE 128
+
+const char *ct_label2str(const struct symbol_table *ct_label_tbl,
+ unsigned long value)
+{
+ const struct symbolic_constant *s;
+
+ for (s = ct_label_tbl->symbols; s->identifier; s++) {
+ if (value == s->value)
+ return s->identifier;
+ }
+
+ return NULL;
+}
+
+static void ct_label_type_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ unsigned long bit = mpz_scan1(expr->value, 0);
+ const char *labelstr = ct_label2str(octx->tbl.ct_label, bit);
+
+ if (labelstr) {
+ nft_print(octx, "\"%s\"", labelstr);
+ return;
+ }
+ /* can happen when connlabel.conf is altered after rules were added */
+ nft_print(octx, "%lu", bit);
+}
+
+static struct error_record *ct_label_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ const struct symbolic_constant *s;
+ const struct datatype *dtype;
+ uint8_t data[CT_LABEL_BIT_SIZE / BITS_PER_BYTE];
+ uint64_t bit;
+ mpz_t value;
+
+ for (s = ctx->tbl->ct_label->symbols; s->identifier != NULL; s++) {
+ if (!strcmp(sym->identifier, s->identifier))
+ break;
+ }
+
+ dtype = sym->dtype;
+ if (s->identifier == NULL) {
+ char *ptr;
+
+ errno = 0;
+ bit = strtoull(sym->identifier, &ptr, 0);
+ if (*ptr)
+ return error(&sym->location, "%s: could not parse %s \"%s\"",
+ CONNLABEL_CONF, dtype->desc, sym->identifier);
+ if (errno)
+ return error(&sym->location, "%s: could not parse %s \"%s\": %s",
+ CONNLABEL_CONF, dtype->desc, sym->identifier, strerror(errno));
+
+ } else {
+ bit = s->value;
+ }
+
+ if (bit >= CT_LABEL_BIT_SIZE)
+ return error(&sym->location, "%s: bit %" PRIu64 " out of range (%u max)",
+ sym->identifier, bit, CT_LABEL_BIT_SIZE);
+
+ mpz_init2(value, dtype->size);
+ mpz_setbit(value, bit);
+ mpz_export_data(data, value, BYTEORDER_HOST_ENDIAN, sizeof(data));
+
+ *res = constant_expr_alloc(&sym->location, dtype,
+ dtype->byteorder, CT_LABEL_BIT_SIZE, data);
+ mpz_clear(value);
+ return NULL;
+}
+
+const struct datatype ct_label_type = {
+ .type = TYPE_CT_LABEL,
+ .name = "ct_label",
+ .desc = "conntrack label",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = CT_LABEL_BIT_SIZE,
+ .basetype = &bitmask_type,
+ .print = ct_label_type_print,
+ .json = ct_label_type_json,
+ .parse = ct_label_type_parse,
+};
+
+void ct_label_table_init(struct nft_ctx *ctx)
+{
+ ctx->output.tbl.ct_label = rt_symbol_table_init(CONNLABEL_CONF);
+}
+
+void ct_label_table_exit(struct nft_ctx *ctx)
+{
+ rt_symbol_table_free(ctx->output.tbl.ct_label);
+}
+
+#ifndef NF_CT_HELPER_NAME_LEN
+#define NF_CT_HELPER_NAME_LEN 16
+#endif
+
+const struct ct_template ct_templates[__NFT_CT_MAX] = {
+ [NFT_CT_STATE] = CT_TEMPLATE("state", &ct_state_type,
+ BYTEORDER_HOST_ENDIAN,
+ 4 * BITS_PER_BYTE),
+ [NFT_CT_DIRECTION] = CT_TEMPLATE("direction", &ct_dir_type,
+ BYTEORDER_HOST_ENDIAN,
+ BITS_PER_BYTE),
+ [NFT_CT_STATUS] = CT_TEMPLATE("status", &ct_status_type,
+ BYTEORDER_HOST_ENDIAN,
+ 4 * BITS_PER_BYTE),
+ [NFT_CT_MARK] = CT_TEMPLATE("mark", &mark_type,
+ BYTEORDER_HOST_ENDIAN,
+ 4 * BITS_PER_BYTE),
+ [NFT_CT_EXPIRATION] = CT_TEMPLATE("expiration", &time_type,
+ BYTEORDER_HOST_ENDIAN,
+ 4 * BITS_PER_BYTE),
+ [NFT_CT_HELPER] = CT_TEMPLATE("helper", &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ NF_CT_HELPER_NAME_LEN * BITS_PER_BYTE),
+ [NFT_CT_L3PROTOCOL] = CT_TEMPLATE("l3proto", &nfproto_type,
+ BYTEORDER_HOST_ENDIAN,
+ BITS_PER_BYTE),
+ [NFT_CT_SRC] = CT_TEMPLATE("saddr", &invalid_type,
+ BYTEORDER_BIG_ENDIAN, 0),
+ [NFT_CT_DST] = CT_TEMPLATE("daddr", &invalid_type,
+ BYTEORDER_BIG_ENDIAN, 0),
+ [NFT_CT_PROTOCOL] = CT_TEMPLATE("protocol", &inet_protocol_type,
+ BYTEORDER_BIG_ENDIAN,
+ BITS_PER_BYTE),
+ [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", &inet_service_type,
+ BYTEORDER_BIG_ENDIAN,
+ 2 * BITS_PER_BYTE),
+ [NFT_CT_LABELS] = CT_TEMPLATE("label", &ct_label_type,
+ BYTEORDER_HOST_ENDIAN,
+ CT_LABEL_BIT_SIZE),
+ [NFT_CT_BYTES] = CT_TEMPLATE("bytes", &integer_type,
+ BYTEORDER_HOST_ENDIAN, 64),
+ [NFT_CT_PKTS] = CT_TEMPLATE("packets", &integer_type,
+ BYTEORDER_HOST_ENDIAN, 64),
+ [NFT_CT_AVGPKT] = CT_TEMPLATE("avgpkt", &integer_type,
+ BYTEORDER_HOST_ENDIAN, 64),
+ [NFT_CT_ZONE] = CT_TEMPLATE("zone", &integer_type,
+ BYTEORDER_HOST_ENDIAN, 16),
+ [NFT_CT_EVENTMASK] = CT_TEMPLATE("event", &ct_event_type,
+ BYTEORDER_HOST_ENDIAN, 32),
+ [NFT_CT_SRC_IP] = CT_TEMPLATE("ip saddr", &ipaddr_type,
+ BYTEORDER_BIG_ENDIAN, 32),
+ [NFT_CT_DST_IP] = CT_TEMPLATE("ip daddr", &ipaddr_type,
+ BYTEORDER_BIG_ENDIAN, 32),
+ [NFT_CT_SRC_IP6] = CT_TEMPLATE("ip6 saddr", &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN, 128),
+ [NFT_CT_DST_IP6] = CT_TEMPLATE("ip6 daddr", &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN, 128),
+ [NFT_CT_SECMARK] = CT_TEMPLATE("secmark", &integer_type,
+ BYTEORDER_HOST_ENDIAN, 32),
+ [NFT_CT_ID] = CT_TEMPLATE("id", &integer_type,
+ BYTEORDER_BIG_ENDIAN, 32),
+};
+
+static void ct_print(enum nft_ct_keys key, int8_t dir, uint8_t nfproto,
+ struct output_ctx *octx)
+{
+ const char *dirstr = ct_dir2str(dir);
+ const struct proto_desc *desc;
+
+ nft_print(octx, "ct ");
+ if (dir < 0)
+ goto done;
+
+ if (dirstr)
+ nft_print(octx, "%s ", dirstr);
+
+ switch (key) {
+ case NFT_CT_SRC:
+ case NFT_CT_DST:
+ desc = proto_find_upper(&proto_inet, nfproto);
+ if (desc)
+ nft_print(octx, "%s ", desc->name);
+ break;
+ default:
+ break;
+ }
+
+ done:
+ nft_print(octx, "%s", ct_templates[key].token);
+}
+
+static void ct_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ ct_print(expr->ct.key, expr->ct.direction, expr->ct.nfproto, octx);
+}
+
+static bool ct_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ if (e1->ct.key != e2->ct.key)
+ return false;
+
+ return e1->ct.direction == e2->ct.direction;
+}
+
+static void ct_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->ct = expr->ct;
+}
+
+static void ct_expr_pctx_update(struct proto_ctx *ctx,
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
+{
+ const struct proto_desc *base = NULL, *desc;
+ uint32_t nhproto;
+
+ nhproto = mpz_get_uint32(right->value);
+
+ base = ctx->protocol[left->ct.base].desc;
+ if (!base)
+ return;
+ desc = proto_find_upper(base, nhproto);
+ if (!desc)
+ return;
+
+ proto_ctx_update(ctx, left->ct.base + 1, loc, desc);
+}
+
+#define NFTNL_UDATA_CT_KEY 0
+#define NFTNL_UDATA_CT_DIR 1
+#define NFTNL_UDATA_CT_MAX 2
+
+static int ct_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_CT_KEY, expr->ct.key);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_CT_DIR, expr->ct.direction);
+
+ return 0;
+}
+
+static int ct_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_CT_KEY:
+ case NFTNL_UDATA_CT_DIR:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *ct_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_CT_MAX + 1] = {};
+ uint32_t key, dir;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ ct_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_CT_KEY] ||
+ !ud[NFTNL_UDATA_CT_DIR])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_CT_KEY]);
+ dir = nftnl_udata_get_u32(ud[NFTNL_UDATA_CT_DIR]);
+
+ return ct_expr_alloc(&internal_location, key, dir);
+}
+
+const struct expr_ops ct_expr_ops = {
+ .type = EXPR_CT,
+ .name = "ct",
+ .print = ct_expr_print,
+ .json = ct_expr_json,
+ .cmp = ct_expr_cmp,
+ .clone = ct_expr_clone,
+ .pctx_update = ct_expr_pctx_update,
+ .parse_udata = ct_expr_parse_udata,
+ .build_udata = ct_expr_build_udata,
+};
+
+struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key,
+ int8_t direction)
+{
+ const struct ct_template *tmpl = &ct_templates[key];
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_CT, tmpl->dtype,
+ tmpl->byteorder, tmpl->len);
+ expr->ct.key = key;
+ expr->ct.direction = direction;
+
+ switch (key) {
+ case NFT_CT_SRC:
+ case NFT_CT_DST:
+ expr->ct.base = PROTO_BASE_NETWORK_HDR;
+ break;
+ case NFT_CT_PROTO_SRC:
+ case NFT_CT_PROTO_DST:
+ expr->ct.base = PROTO_BASE_TRANSPORT_HDR;
+ break;
+ case NFT_CT_PROTOCOL:
+ expr->flags = EXPR_F_PROTOCOL;
+ expr->ct.base = PROTO_BASE_NETWORK_HDR;
+ break;
+ case NFT_CT_L3PROTOCOL:
+ expr->flags = EXPR_F_PROTOCOL;
+ expr->ct.base = PROTO_BASE_LL_HDR;
+ break;
+ default:
+ break;
+ }
+
+ return expr;
+}
+
+void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
+{
+ const struct proto_desc *desc;
+
+ desc = ctx->protocol[expr->ct.base].desc;
+
+ switch (expr->ct.key) {
+ case NFT_CT_SRC:
+ case NFT_CT_DST:
+ if (desc == &proto_ip) {
+ datatype_set(expr, &ipaddr_type);
+ expr->ct.nfproto = NFPROTO_IPV4;
+ } else if (desc == &proto_ip6) {
+ datatype_set(expr, &ip6addr_type);
+ expr->ct.nfproto = NFPROTO_IPV6;
+ }
+
+ expr->len = expr->dtype->size;
+ break;
+ case NFT_CT_PROTO_SRC:
+ case NFT_CT_PROTO_DST:
+ if (desc == NULL)
+ break;
+ datatype_set(expr, &inet_service_type);
+ break;
+ case NFT_CT_SRC_IP:
+ case NFT_CT_DST_IP:
+ expr->dtype = &ipaddr_type;
+ expr->len = expr->dtype->size;
+ break;
+ case NFT_CT_SRC_IP6:
+ case NFT_CT_DST_IP6:
+ expr->dtype = &ip6addr_type;
+ expr->len = expr->dtype->size;
+ break;
+ default:
+ break;
+ }
+}
+
+static void ct_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ ct_print(stmt->ct.key, stmt->ct.direction, 0, octx);
+ nft_print(octx, " set ");
+ expr_print(stmt->ct.expr, octx);
+}
+
+static void ct_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->ct.expr);
+}
+
+static const struct stmt_ops ct_stmt_ops = {
+ .type = STMT_CT,
+ .name = "ct",
+ .print = ct_stmt_print,
+ .json = ct_stmt_json,
+ .destroy = ct_stmt_destroy,
+};
+
+struct stmt *ct_stmt_alloc(const struct location *loc, enum nft_ct_keys key,
+ int8_t direction, struct expr *expr)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &ct_stmt_ops);
+ stmt->ct.key = key;
+ stmt->ct.tmpl = &ct_templates[key];
+ stmt->ct.expr = expr;
+ stmt->ct.direction = direction;
+
+ return stmt;
+}
+
+static void notrack_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "notrack");
+}
+
+static const struct stmt_ops notrack_stmt_ops = {
+ .type = STMT_NOTRACK,
+ .name = "notrack",
+ .print = notrack_stmt_print,
+ .json = notrack_stmt_json,
+};
+
+struct stmt *notrack_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &notrack_stmt_ops);
+}
+
+static void flow_offload_stmt_print(const struct stmt *stmt,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "flow add @%s", stmt->flow.table_name);
+}
+
+static void flow_offload_stmt_destroy(struct stmt *stmt)
+{
+ xfree(stmt->flow.table_name);
+}
+
+static const struct stmt_ops flow_offload_stmt_ops = {
+ .type = STMT_FLOW_OFFLOAD,
+ .name = "flow_offload",
+ .print = flow_offload_stmt_print,
+ .destroy = flow_offload_stmt_destroy,
+ .json = flow_offload_stmt_json,
+};
+
+struct stmt *flow_offload_stmt_alloc(const struct location *loc,
+ const char *table_name)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &flow_offload_stmt_ops);
+ stmt->flow.table_name = table_name;
+
+ return stmt;
+}
diff --git a/src/datatype.c b/src/datatype.c
new file mode 100644
index 0000000..64e4647
--- /dev/null
+++ b/src/datatype.c
@@ -0,0 +1,1553 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <inttypes.h>
+#include <ctype.h> /* isdigit */
+#include <errno.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <linux/types.h>
+#include <linux/netfilter.h>
+#include <linux/icmpv6.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <nftables.h>
+#include <datatype.h>
+#include <expression.h>
+#include <gmputil.h>
+#include <erec.h>
+#include <netlink.h>
+#include <json.h>
+#include <misspell.h>
+#include "nftutils.h"
+
+#include <netinet/ip_icmp.h>
+
+static const struct datatype *datatypes[TYPE_MAX + 1] = {
+ [TYPE_INVALID] = &invalid_type,
+ [TYPE_VERDICT] = &verdict_type,
+ [TYPE_NFPROTO] = &nfproto_type,
+ [TYPE_BITMASK] = &bitmask_type,
+ [TYPE_INTEGER] = &integer_type,
+ [TYPE_STRING] = &string_type,
+ [TYPE_LLADDR] = &lladdr_type,
+ [TYPE_IPADDR] = &ipaddr_type,
+ [TYPE_IP6ADDR] = &ip6addr_type,
+ [TYPE_ETHERADDR] = &etheraddr_type,
+ [TYPE_ETHERTYPE] = &ethertype_type,
+ [TYPE_ARPOP] = &arpop_type,
+ [TYPE_INET_PROTOCOL] = &inet_protocol_type,
+ [TYPE_INET_SERVICE] = &inet_service_type,
+ [TYPE_ICMP_TYPE] = &icmp_type_type,
+ [TYPE_TCP_FLAG] = &tcp_flag_type,
+ [TYPE_DCCP_PKTTYPE] = &dccp_pkttype_type,
+ [TYPE_MH_TYPE] = &mh_type_type,
+ [TYPE_TIME] = &time_type,
+ [TYPE_MARK] = &mark_type,
+ [TYPE_IFINDEX] = &ifindex_type,
+ [TYPE_ARPHRD] = &arphrd_type,
+ [TYPE_REALM] = &realm_type,
+ [TYPE_CLASSID] = &tchandle_type,
+ [TYPE_UID] = &uid_type,
+ [TYPE_GID] = &gid_type,
+ [TYPE_CT_STATE] = &ct_state_type,
+ [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,
+ [TYPE_ICMPX_CODE] = &icmpx_code_type,
+ [TYPE_DEVGROUP] = &devgroup_type,
+ [TYPE_DSCP] = &dscp_type,
+ [TYPE_ECN] = &ecn_type,
+ [TYPE_FIB_ADDR] = &fib_addr_type,
+ [TYPE_BOOLEAN] = &boolean_type,
+ [TYPE_CT_EVENTBIT] = &ct_event_type,
+ [TYPE_IFNAME] = &ifname_type,
+ [TYPE_IGMP_TYPE] = &igmp_type_type,
+ [TYPE_TIME_DATE] = &date_type,
+ [TYPE_TIME_HOUR] = &hour_type,
+ [TYPE_TIME_DAY] = &day_type,
+ [TYPE_CGROUPV2] = &cgroupv2_type,
+};
+
+const struct datatype *datatype_lookup(enum datatypes type)
+{
+ BUILD_BUG_ON(TYPE_MAX & ~TYPE_MASK);
+
+ if (type > TYPE_MAX)
+ return NULL;
+ return datatypes[type];
+}
+
+const struct datatype *datatype_lookup_byname(const char *name)
+{
+ const struct datatype *dtype;
+ enum datatypes type;
+
+ for (type = TYPE_INVALID; type <= TYPE_MAX; type++) {
+ dtype = datatypes[type];
+ if (dtype == NULL)
+ continue;
+ if (!strcmp(dtype->name, name))
+ return dtype;
+ }
+ return NULL;
+}
+
+void datatype_print(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct datatype *dtype = expr->dtype;
+
+ do {
+ if (dtype->print != NULL)
+ return dtype->print(expr, octx);
+ if (dtype->sym_tbl != NULL)
+ return symbolic_constant_print(dtype->sym_tbl, expr,
+ false, octx);
+ } while ((dtype = dtype->basetype));
+
+ BUG("datatype %s has no print method or symbol table\n",
+ expr->dtype->name);
+}
+
+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);
+
+ if (dtype == NULL)
+ return error(&sym->location, "No symbol type information");
+ do {
+ if (dtype->parse != NULL)
+ return dtype->parse(ctx, sym, res);
+ if (dtype->sym_tbl != NULL)
+ return symbolic_constant_parse(ctx, sym, dtype->sym_tbl,
+ res);
+ } while ((dtype = dtype->basetype));
+
+ 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,
+ struct expr **res)
+{
+ const struct symbolic_constant *s;
+ const struct datatype *dtype;
+ struct error_record *erec;
+
+ for (s = tbl->symbols; s->identifier != NULL; s++) {
+ if (!strcmp(sym->identifier, s->identifier))
+ break;
+ }
+
+ if (s->identifier != NULL)
+ goto out;
+
+ dtype = sym->dtype;
+ *res = NULL;
+ do {
+ if (dtype->basetype->parse) {
+ erec = dtype->basetype->parse(ctx, sym, res);
+ 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;
+ }
+ } while ((dtype = dtype->basetype));
+
+ return error(&sym->location, "Could not parse %s", sym->dtype->desc);
+out:
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ sym->dtype->byteorder, sym->dtype->size,
+ constant_data_ptr(s->value,
+ sym->dtype->size));
+ return NULL;
+}
+
+void symbolic_constant_print(const struct symbol_table *tbl,
+ const struct expr *expr, bool quotes,
+ struct output_ctx *octx)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ const struct symbolic_constant *s;
+ uint64_t val = 0;
+
+ /* Export the data in the correct byteorder for comparison */
+ assert(expr->len / BITS_PER_BYTE <= sizeof(val));
+ mpz_export_data(constant_data_ptr(val, expr->len), expr->value,
+ expr->byteorder, len);
+
+ for (s = tbl->symbols; s->identifier != NULL; s++) {
+ if (val == s->value)
+ break;
+ }
+
+ if (s->identifier == NULL || nft_output_numeric_symbol(octx))
+ return expr_basetype(expr)->print(expr, octx);
+
+ nft_print(octx, quotes ? "\"%s\"" : "%s", s->identifier);
+}
+
+static void switch_byteorder(void *data, unsigned int len)
+{
+ mpz_t op;
+
+ mpz_init(op);
+ mpz_import_data(op, data, BYTEORDER_BIG_ENDIAN, len);
+ mpz_export_data(data, op, BYTEORDER_HOST_ENDIAN, len);
+ mpz_clear(op);
+}
+
+void symbol_table_print(const struct symbol_table *tbl,
+ const struct datatype *dtype,
+ enum byteorder byteorder,
+ struct output_ctx *octx)
+{
+ unsigned int len = div_round_up(dtype->size, BITS_PER_BYTE);
+ const struct symbolic_constant *s;
+ uint64_t value;
+
+ for (s = tbl->symbols; s->identifier != NULL; s++) {
+ value = s->value;
+
+ if (byteorder == BYTEORDER_BIG_ENDIAN)
+ switch_byteorder(&value, len);
+
+ if (tbl->base == BASE_DECIMAL)
+ nft_print(octx, "\t%-30s\t%20" PRIu64 "\n",
+ s->identifier, value);
+ else
+ nft_print(octx, "\t%-30s\t0x%.*" PRIx64 "\n",
+ s->identifier, 2 * len, value);
+ }
+}
+
+static void invalid_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_gmp_print(octx, "0x%Zx [invalid type]", expr->value);
+}
+
+const struct datatype invalid_type = {
+ .type = TYPE_INVALID,
+ .name = "invalid",
+ .desc = "invalid",
+ .print = invalid_type_print,
+};
+
+void expr_chain_export(const struct expr *e, char *chain_name)
+{
+ unsigned int len;
+
+ len = e->len / BITS_PER_BYTE;
+ if (len >= NFT_CHAIN_MAXNAMELEN)
+ BUG("verdict expression length %u is too large (%u bits max)",
+ e->len, NFT_CHAIN_MAXNAMELEN * BITS_PER_BYTE);
+
+ mpz_export_data(chain_name, e->value, BYTEORDER_HOST_ENDIAN, len);
+}
+
+static void verdict_jump_chain_print(const char *what, const struct expr *e,
+ struct output_ctx *octx)
+{
+ char chain[NFT_CHAIN_MAXNAMELEN];
+
+ memset(chain, 0, sizeof(chain));
+ expr_chain_export(e, chain);
+ nft_print(octx, "%s %s", what, chain);
+}
+
+static void verdict_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ switch (expr->verdict) {
+ case NFT_CONTINUE:
+ nft_print(octx, "continue");
+ break;
+ case NFT_BREAK:
+ nft_print(octx, "break");
+ break;
+ case NFT_JUMP:
+ if (expr->chain->etype == EXPR_VALUE) {
+ verdict_jump_chain_print("jump", expr->chain, octx);
+ } else {
+ nft_print(octx, "jump ");
+ expr_print(expr->chain, octx);
+ }
+ break;
+ case NFT_GOTO:
+ if (expr->chain->etype == EXPR_VALUE) {
+ verdict_jump_chain_print("goto", expr->chain, octx);
+ } else {
+ nft_print(octx, "goto ");
+ expr_print(expr->chain, octx);
+ }
+ break;
+ case NFT_RETURN:
+ nft_print(octx, "return");
+ break;
+ default:
+ switch (expr->verdict & NF_VERDICT_MASK) {
+ case NF_ACCEPT:
+ nft_print(octx, "accept");
+ break;
+ case NF_DROP:
+ nft_print(octx, "drop");
+ break;
+ case NF_QUEUE:
+ nft_print(octx, "queue");
+ break;
+ case NF_STOLEN:
+ nft_print(octx, "stolen");
+ break;
+ default:
+ nft_print(octx, "unknown verdict value %u", expr->verdict);
+ break;
+ }
+ }
+}
+
+static struct error_record *verdict_type_error(const struct expr *sym)
+{
+ /* 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 = {
+ .type = TYPE_VERDICT,
+ .name = "verdict",
+ .desc = "netfilter verdict",
+ .print = verdict_type_print,
+ .err = verdict_type_error,
+};
+
+static const struct symbol_table nfproto_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("ipv4", NFPROTO_IPV4),
+ SYMBOL("ipv6", NFPROTO_IPV6),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype nfproto_type = {
+ .type = TYPE_NFPROTO,
+ .name = "nf_proto",
+ .desc = "netfilter protocol",
+ .size = 1 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &nfproto_tbl,
+};
+
+const struct datatype bitmask_type = {
+ .type = TYPE_BITMASK,
+ .name = "bitmask",
+ .desc = "bitmask",
+ .basefmt = "0x%Zx",
+ .basetype = &integer_type,
+};
+
+static void integer_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct datatype *dtype = expr->dtype;
+ const char *fmt = "%Zu";
+
+ do {
+ if (dtype->basefmt != NULL) {
+ fmt = dtype->basefmt;
+ break;
+ }
+ } while ((dtype = dtype->basetype));
+
+ nft_gmp_print(octx, fmt, expr->value);
+}
+
+static struct error_record *integer_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ mpz_t v;
+
+ mpz_init(v);
+ if (mpz_set_str(v, sym->identifier, 0)) {
+ mpz_clear(v);
+ return error(&sym->location, "Could not parse %s",
+ sym->dtype->desc);
+ }
+
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ BYTEORDER_HOST_ENDIAN, 1, NULL);
+ mpz_set((*res)->value, v);
+ mpz_clear(v);
+ return NULL;
+}
+
+const struct datatype integer_type = {
+ .type = TYPE_INTEGER,
+ .name = "integer",
+ .desc = "integer",
+ .print = integer_type_print,
+ .json = integer_type_json,
+ .parse = integer_type_parse,
+};
+
+static void xinteger_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_gmp_print(octx, "0x%Zx", expr->value);
+}
+
+/* Alias of integer_type to print raw payload expressions in hexadecimal. */
+const struct datatype xinteger_type = {
+ .type = TYPE_INTEGER,
+ .name = "integer",
+ .desc = "integer",
+ .basetype = &integer_type,
+ .print = xinteger_type_print,
+ .json = integer_type_json,
+ .parse = integer_type_parse,
+};
+
+static void string_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ char data[len+1];
+
+ mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
+ data[len] = '\0';
+ nft_print(octx, "\"%s\"", data);
+}
+
+static struct error_record *string_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ *res = constant_expr_alloc(&sym->location, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(sym->identifier) + 1) * BITS_PER_BYTE,
+ sym->identifier);
+ return NULL;
+}
+
+const struct datatype string_type = {
+ .type = TYPE_STRING,
+ .name = "string",
+ .desc = "string",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .print = string_type_print,
+ .json = string_type_json,
+ .parse = string_type_parse,
+};
+
+static void lladdr_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ const char *delim = "";
+ uint8_t data[len];
+ unsigned int i;
+
+ mpz_export_data(data, expr->value, BYTEORDER_BIG_ENDIAN, len);
+
+ for (i = 0; i < len; i++) {
+ nft_print(octx, "%s%.2x", delim, data[i]);
+ delim = ":";
+ }
+}
+
+static struct error_record *lladdr_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ char buf[strlen(sym->identifier) + 1], *p;
+ const char *s = sym->identifier;
+ unsigned int len, n;
+
+ for (len = 0;;) {
+ n = strtoul(s, &p, 16);
+ if (s == p || n > 0xff)
+ return erec_create(EREC_ERROR, &sym->location,
+ "Invalid LL address");
+ buf[len++] = n;
+ if (*p == '\0')
+ break;
+ s = ++p;
+ }
+
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ BYTEORDER_BIG_ENDIAN, len * BITS_PER_BYTE,
+ buf);
+ return NULL;
+}
+
+const struct datatype lladdr_type = {
+ .type = TYPE_LLADDR,
+ .name = "ll_addr",
+ .desc = "link layer address",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .basetype = &integer_type,
+ .print = lladdr_type_print,
+ .parse = lladdr_type_parse,
+};
+
+static void ipaddr_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ struct sockaddr_in sin = { .sin_family = AF_INET, };
+ char buf[NI_MAXHOST];
+ int err;
+
+ sin.sin_addr.s_addr = mpz_get_be32(expr->value);
+ err = getnameinfo((struct sockaddr *)&sin, sizeof(sin), buf,
+ sizeof(buf), NULL, 0,
+ nft_output_reversedns(octx) ? 0 : NI_NUMERICHOST);
+ if (err != 0) {
+ getnameinfo((struct sockaddr *)&sin, sizeof(sin), buf,
+ sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ }
+ nft_print(octx, "%s", buf);
+}
+
+static struct error_record *ipaddr_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ 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));
+
+ 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);
+ }
+
+ *res = constant_expr_alloc(&sym->location, &ipaddr_type,
+ BYTEORDER_BIG_ENDIAN,
+ sizeof(addr) * BITS_PER_BYTE, &addr);
+ return NULL;
+}
+
+const struct datatype ipaddr_type = {
+ .type = TYPE_IPADDR,
+ .name = "ipv4_addr",
+ .desc = "IPv4 address",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = ipaddr_type_print,
+ .parse = ipaddr_type_parse,
+ .flags = DTYPE_F_PREFIX,
+};
+
+static void ip6addr_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
+ char buf[NI_MAXHOST];
+ int err;
+
+ mpz_export_data(&sin6.sin6_addr, expr->value, BYTEORDER_BIG_ENDIAN,
+ sizeof(sin6.sin6_addr));
+
+ err = getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), buf,
+ sizeof(buf), NULL, 0,
+ nft_output_reversedns(octx) ? 0 : NI_NUMERICHOST);
+ if (err != 0) {
+ getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), buf,
+ sizeof(buf), NULL, 0, NI_NUMERICHOST);
+ }
+ nft_print(octx, "%s", buf);
+}
+
+static struct error_record *ip6addr_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ struct in6_addr addr;
+
+ 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) {
+ 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);
+ }
+
+ *res = constant_expr_alloc(&sym->location, &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN,
+ sizeof(addr) * BITS_PER_BYTE, &addr);
+ return NULL;
+}
+
+const struct datatype ip6addr_type = {
+ .type = TYPE_IP6ADDR,
+ .name = "ipv6_addr",
+ .desc = "IPv6 address",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = 16 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = ip6addr_type_print,
+ .parse = ip6addr_type_parse,
+ .flags = DTYPE_F_PREFIX,
+};
+
+static void inet_protocol_type_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ if (!nft_output_numeric_proto(octx)) {
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name))) {
+ nft_print(octx, "%s", name);
+ return;
+ }
+ }
+ integer_type_print(expr, octx);
+}
+
+static void inet_protocol_type_describe(struct output_ctx *octx)
+{
+ uint8_t protonum;
+
+ for (protonum = 0; protonum < UINT8_MAX; protonum++) {
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (!nft_getprotobynumber(protonum, name, sizeof(name)))
+ continue;
+
+ nft_print(octx, "\t%-30s\t%u\n", name, protonum);
+ }
+}
+
+static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ uint8_t proto;
+ uintmax_t i;
+ char *end;
+
+ errno = 0;
+ i = strtoumax(sym->identifier, &end, 0);
+ if (sym->identifier != end && *end == '\0') {
+ if (errno == ERANGE || i > UINT8_MAX)
+ return error(&sym->location, "Protocol out of range");
+
+ proto = i;
+ } else {
+ int r;
+
+ r = nft_getprotobyname(sym->identifier);
+ if (r < 0)
+ return error(&sym->location, "Could not resolve protocol name");
+
+ proto = r;
+ }
+
+ *res = constant_expr_alloc(&sym->location, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN, BITS_PER_BYTE,
+ &proto);
+ return NULL;
+}
+
+const struct datatype inet_protocol_type = {
+ .type = TYPE_INET_PROTOCOL,
+ .name = "inet_proto",
+ .desc = "Internet protocol",
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = inet_protocol_type_print,
+ .json = inet_protocol_type_json,
+ .parse = inet_protocol_type_parse,
+ .describe = inet_protocol_type_describe,
+};
+
+static void inet_service_print(const struct expr *expr, struct output_ctx *octx)
+{
+ uint16_t port = mpz_get_be16(expr->value);
+ char name[NFT_SERVNAME_MAXSIZE];
+
+ if (!nft_getservbyport(port, NULL, name, sizeof(name)))
+ nft_print(octx, "%hu", ntohs(port));
+ else
+ nft_print(octx, "\"%s\"", name);
+}
+
+void inet_service_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ if (nft_output_service(octx)) {
+ inet_service_print(expr, octx);
+ return;
+ }
+ integer_type_print(expr, octx);
+}
+
+static struct error_record *inet_service_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ struct addrinfo *ai;
+ uint16_t port;
+ uintmax_t i;
+ char *end;
+ int err;
+
+ errno = 0;
+ i = strtoumax(sym->identifier, &end, 0);
+ if (sym->identifier != end && *end == '\0') {
+ if (errno == ERANGE || i > UINT16_MAX)
+ return error(&sym->location, "Service out of range");
+
+ port = htons(i);
+ } else {
+ err = getaddrinfo(NULL, sym->identifier, NULL, &ai);
+ if (err != 0)
+ return error(&sym->location, "Could not resolve service: %s",
+ gai_strerror(err));
+
+ 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);
+ }
+
+ *res = constant_expr_alloc(&sym->location, &inet_service_type,
+ BYTEORDER_BIG_ENDIAN,
+ sizeof(port) * BITS_PER_BYTE, &port);
+ return NULL;
+}
+
+const struct datatype inet_service_type = {
+ .type = TYPE_INET_SERVICE,
+ .name = "inet_service",
+ .desc = "internet network service",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = 2 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = inet_service_type_print,
+ .json = inet_service_type_json,
+ .parse = inet_service_type_parse,
+};
+
+#define RT_SYM_TAB_INITIAL_SIZE 16
+
+struct symbol_table *rt_symbol_table_init(const char *filename)
+{
+ 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));
+ nelems = 0;
+
+ f = fopen(filename, "r");
+ if (f == NULL)
+ goto out;
+
+ while (fgets(buf, sizeof(buf), f)) {
+ p = buf;
+ while (*p == ' ' || *p == '\t')
+ 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) {
+ fprintf(stderr, "iproute database '%s' corrupted\n",
+ filename);
+ break;
+ }
+
+ /* One element is reserved for list terminator */
+ if (nelems == size - 2) {
+ size *= 2;
+ tbl = xrealloc(tbl, sizeof(*tbl) + size * sizeof(s));
+ }
+
+ tbl->symbols[nelems].identifier = xstrdup(namebuf);
+ tbl->symbols[nelems].value = val;
+ nelems++;
+ }
+
+ fclose(f);
+out:
+ tbl->symbols[nelems] = SYMBOL_LIST_END;
+ return tbl;
+}
+
+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);
+}
+
+void mark_table_init(struct nft_ctx *ctx)
+{
+ ctx->output.tbl.mark = rt_symbol_table_init("/etc/iproute2/rt_marks");
+}
+
+void mark_table_exit(struct nft_ctx *ctx)
+{
+ rt_symbol_table_free(ctx->output.tbl.mark);
+}
+
+static void mark_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ return symbolic_constant_print(octx->tbl.mark, expr, true, octx);
+}
+
+static struct error_record *mark_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ return symbolic_constant_parse(ctx, sym, ctx->tbl->mark, res);
+}
+
+const struct datatype mark_type = {
+ .type = TYPE_MARK,
+ .name = "mark",
+ .desc = "packet mark",
+ .size = 4 * BITS_PER_BYTE,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .basetype = &integer_type,
+ .basefmt = "0x%.8Zx",
+ .print = mark_type_print,
+ .json = mark_type_json,
+ .parse = mark_type_parse,
+ .flags = DTYPE_F_PREFIX,
+};
+
+static const struct symbol_table icmp_code_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("net-unreachable", ICMP_NET_UNREACH),
+ SYMBOL("host-unreachable", ICMP_HOST_UNREACH),
+ SYMBOL("prot-unreachable", ICMP_PROT_UNREACH),
+ SYMBOL("port-unreachable", ICMP_PORT_UNREACH),
+ SYMBOL("net-prohibited", ICMP_NET_ANO),
+ SYMBOL("host-prohibited", ICMP_HOST_ANO),
+ SYMBOL("admin-prohibited", ICMP_PKT_FILTERED),
+ SYMBOL("frag-needed", ICMP_FRAG_NEEDED),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype icmp_code_type = {
+ .type = TYPE_ICMP_CODE,
+ .name = "icmp_code",
+ .desc = "icmp code",
+ .size = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .basetype = &integer_type,
+ .sym_tbl = &icmp_code_tbl,
+};
+
+static const struct symbol_table icmpv6_code_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("no-route", ICMPV6_NOROUTE),
+ SYMBOL("admin-prohibited", ICMPV6_ADM_PROHIBITED),
+ SYMBOL("addr-unreachable", ICMPV6_ADDR_UNREACH),
+ SYMBOL("port-unreachable", ICMPV6_PORT_UNREACH),
+ SYMBOL("policy-fail", ICMPV6_POLICY_FAIL),
+ SYMBOL("reject-route", ICMPV6_REJECT_ROUTE),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype icmpv6_code_type = {
+ .type = TYPE_ICMPV6_CODE,
+ .name = "icmpv6_code",
+ .desc = "icmpv6 code",
+ .size = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .basetype = &integer_type,
+ .sym_tbl = &icmpv6_code_tbl,
+};
+
+static const struct symbol_table icmpx_code_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("port-unreachable", NFT_REJECT_ICMPX_PORT_UNREACH),
+ SYMBOL("admin-prohibited", NFT_REJECT_ICMPX_ADMIN_PROHIBITED),
+ SYMBOL("no-route", NFT_REJECT_ICMPX_NO_ROUTE),
+ SYMBOL("host-unreachable", NFT_REJECT_ICMPX_HOST_UNREACH),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype icmpx_code_type = {
+ .type = TYPE_ICMPX_CODE,
+ .name = "icmpx_code",
+ .desc = "icmpx code",
+ .size = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .basetype = &integer_type,
+ .sym_tbl = &icmpx_code_tbl,
+};
+
+void time_print(uint64_t ms, struct output_ctx *octx)
+{
+ uint64_t days, hours, minutes, seconds;
+
+ if (nft_output_seconds(octx)) {
+ nft_print(octx, "%" PRIu64 "s", ms / 1000);
+ return;
+ }
+
+ days = ms / 86400000;
+ ms %= 86400000;
+
+ hours = ms / 3600000;
+ ms %= 3600000;
+
+ minutes = ms / 60000;
+ ms %= 60000;
+
+ seconds = ms / 1000;
+ ms %= 1000;
+
+ if (days > 0)
+ nft_print(octx, "%" PRIu64 "d", days);
+ if (hours > 0)
+ nft_print(octx, "%" PRIu64 "h", hours);
+ if (minutes > 0)
+ nft_print(octx, "%" PRIu64 "m", minutes);
+ if (seconds > 0)
+ nft_print(octx, "%" PRIu64 "s", seconds);
+ if (ms > 0)
+ nft_print(octx, "%" PRIu64 "ms", ms);
+}
+
+enum {
+ DAY = (1 << 0),
+ HOUR = (1 << 1),
+ MIN = (1 << 2),
+ SECS = (1 << 3),
+ MSECS = (1 << 4),
+};
+
+static uint32_t str2int(const char *str)
+{
+ int ret, number;
+
+ ret = sscanf(str, "%d", &number);
+ return ret == 1 ? number : 0;
+}
+
+struct error_record *time_parse(const struct location *loc, const char *str,
+ uint64_t *res)
+{
+ unsigned int max_digits = strlen("12345678");
+ int i, len;
+ unsigned int k = 0;
+ const char *c;
+ uint64_t d = 0, h = 0, m = 0, s = 0, ms = 0;
+ uint32_t mask = 0;
+
+ c = str;
+ len = strlen(c);
+ for (i = 0; i < len; i++, c++) {
+ switch (*c) {
+ case 'd':
+ if (mask & DAY)
+ return error(loc,
+ "Day has been specified twice");
+
+ d = str2int(c - k);
+ k = 0;
+ mask |= DAY;
+ break;
+ case 'h':
+ if (mask & HOUR)
+ return error(loc,
+ "Hour has been specified twice");
+
+ h = str2int(c - k);
+ k = 0;
+ mask |= HOUR;
+ break;
+ case 'm':
+ if (strcmp(c, "ms") == 0) {
+ if (mask & MSECS)
+ return error(loc,
+ "Millisecond has been specified twice");
+ ms = str2int(c - k);
+ c++;
+ i++;
+ k = 0;
+ mask |= MSECS;
+ break;
+ }
+
+ if (mask & MIN)
+ return error(loc,
+ "Minute has been specified twice");
+
+ m = str2int(c - k);
+ k = 0;
+ mask |= MIN;
+ break;
+ case 's':
+ if (mask & SECS)
+ return error(loc,
+ "Second has been specified twice");
+
+ s = str2int(c - k);
+ k = 0;
+ mask |= SECS;
+ break;
+ default:
+ if (!isdigit(*c))
+ return error(loc, "wrong time format");
+
+ if (k++ >= max_digits)
+ return error(loc, "value too large");
+ break;
+ }
+ }
+
+ /* default to seconds if no unit was specified */
+ if (!mask)
+ ms = atoi(str) * MSEC_PER_SEC;
+ else
+ ms = 24*60*60*MSEC_PER_SEC * d +
+ 60*60*MSEC_PER_SEC * h +
+ 60*MSEC_PER_SEC * m +
+ MSEC_PER_SEC * s + ms;
+
+ *res = ms;
+ return NULL;
+}
+
+
+static void time_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ time_print(mpz_get_uint64(expr->value), octx);
+}
+
+static struct error_record *time_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ struct error_record *erec;
+ uint32_t s32;
+ uint64_t s;
+
+ erec = time_parse(&sym->location, sym->identifier, &s);
+ if (erec != NULL)
+ return erec;
+
+ if (s > UINT32_MAX)
+ return error(&sym->location, "value too large");
+
+ s32 = s;
+ *res = constant_expr_alloc(&sym->location, &time_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(uint32_t) * BITS_PER_BYTE, &s32);
+ return NULL;
+}
+
+const struct datatype time_type = {
+ .type = TYPE_TIME,
+ .name = "time",
+ .desc = "relative time",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = time_type_print,
+ .json = time_type_json,
+ .parse = time_type_parse,
+};
+
+static struct error_record *concat_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ return error(&sym->location, "invalid data type, expected %s",
+ sym->dtype->desc);
+}
+
+static struct datatype *datatype_alloc(void)
+{
+ struct datatype *dtype;
+
+ dtype = xzalloc(sizeof(*dtype));
+ dtype->flags = DTYPE_F_ALLOC;
+ dtype->refcnt = 1;
+
+ return dtype;
+}
+
+const struct datatype *datatype_get(const struct datatype *ptr)
+{
+ struct datatype *dtype = (struct datatype *)ptr;
+
+ if (!dtype)
+ return NULL;
+ if (!(dtype->flags & DTYPE_F_ALLOC))
+ return dtype;
+
+ dtype->refcnt++;
+ 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)
+ __datatype_set(expr, datatype_get(dtype));
+}
+
+struct datatype *datatype_clone(const struct datatype *orig_dtype)
+{
+ struct datatype *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 = 1;
+
+ return dtype;
+}
+
+void datatype_free(const struct datatype *ptr)
+{
+ struct datatype *dtype = (struct datatype *)ptr;
+
+ if (!dtype)
+ 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);
+}
+
+const struct datatype *concat_type_alloc(uint32_t type)
+{
+ const struct datatype *i;
+ struct datatype *dtype;
+ char desc[256] = "concatenation of (";
+ char name[256] = "";
+ unsigned int size = 0, subtypes = 0, n;
+
+ n = div_round_up(fls(type), TYPE_BITS);
+ while (n > 0 && concat_subtype_id(type, --n)) {
+ i = concat_subtype_lookup(type, n);
+ if (i == NULL)
+ return NULL;
+
+ if (subtypes != 0) {
+ strncat(desc, ", ", sizeof(desc) - strlen(desc) - 1);
+ strncat(name, " . ", sizeof(name) - strlen(name) - 1);
+ }
+ strncat(desc, i->desc, sizeof(desc) - strlen(desc) - 1);
+ strncat(name, i->name, sizeof(name) - strlen(name) - 1);
+
+ size += netlink_padded_len(i->size);
+ subtypes++;
+ }
+ strncat(desc, ")", sizeof(desc) - strlen(desc) - 1);
+
+ dtype = datatype_alloc();
+ dtype->type = type;
+ dtype->size = size;
+ dtype->subtypes = subtypes;
+ dtype->name = xstrdup(name);
+ dtype->desc = xstrdup(desc);
+ dtype->parse = concat_type_parse;
+
+ return dtype;
+}
+
+const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
+ enum byteorder byteorder)
+{
+ struct datatype *dtype;
+
+ /* Restrict dynamic datatype allocation to generic integer datatype. */
+ if (orig_dtype != &integer_type)
+ return datatype_get(orig_dtype);
+
+ dtype = datatype_clone(orig_dtype);
+ dtype->byteorder = byteorder;
+
+ return dtype;
+}
+
+static struct error_record *time_unit_parse(const struct location *loc,
+ const char *str, uint64_t *unit)
+{
+ if (strcmp(str, "second") == 0)
+ *unit = 1ULL;
+ else if (strcmp(str, "minute") == 0)
+ *unit = 1ULL * 60;
+ else if (strcmp(str, "hour") == 0)
+ *unit = 1ULL * 60 * 60;
+ else if (strcmp(str, "day") == 0)
+ *unit = 1ULL * 60 * 60 * 24;
+ else if (strcmp(str, "week") == 0)
+ *unit = 1ULL * 60 * 60 * 24 * 7;
+ else
+ return error(loc, "Wrong rate format");
+
+ return NULL;
+}
+
+struct error_record *data_unit_parse(const struct location *loc,
+ const char *str, uint64_t *rate)
+{
+ if (strncmp(str, "bytes", strlen("bytes")) == 0)
+ *rate = 1ULL;
+ else if (strncmp(str, "kbytes", strlen("kbytes")) == 0)
+ *rate = 1024;
+ else if (strncmp(str, "mbytes", strlen("mbytes")) == 0)
+ *rate = 1024 * 1024;
+ else
+ return error(loc, "Wrong rate format");
+
+ return NULL;
+}
+
+struct error_record *rate_parse(const struct location *loc, const char *str,
+ uint64_t *rate, uint64_t *unit)
+{
+ struct error_record *erec;
+ const char *slash;
+
+ slash = strchr(str, '/');
+ if (!slash)
+ return error(loc, "wrong rate format");
+
+ erec = data_unit_parse(loc, str, rate);
+ if (erec != NULL)
+ return erec;
+
+ erec = time_unit_parse(loc, slash + 1, unit);
+ if (erec != NULL)
+ return erec;
+
+ return NULL;
+}
+
+static const struct symbol_table boolean_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("exists", true),
+ SYMBOL("missing", false),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype boolean_type = {
+ .type = TYPE_BOOLEAN,
+ .name = "boolean",
+ .desc = "boolean type",
+ .size = 1,
+ .basetype = &integer_type,
+ .sym_tbl = &boolean_tbl,
+ .json = boolean_type_json,
+};
+
+static struct error_record *priority_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ struct error_record *erec;
+ int num;
+
+ erec = integer_type_parse(ctx, sym, res);
+ if (!erec) {
+ num = atoi(sym->identifier);
+ expr_free(*res);
+ *res = constant_expr_alloc(&sym->location, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE, &num);
+ } else {
+ erec_destroy(erec);
+ *res = constant_expr_alloc(&sym->location, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(sym->identifier) * BITS_PER_BYTE,
+ sym->identifier);
+ }
+
+ return NULL;
+}
+
+/* This datatype is not registered via datatype_register()
+ * since this datatype should not ever be used from either
+ * rules or elements.
+ */
+const struct datatype priority_type = {
+ .type = TYPE_STRING,
+ .name = "priority",
+ .desc = "priority type",
+ .parse = priority_type_parse,
+};
+
+static struct error_record *policy_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ int policy;
+
+ if (!strcmp(sym->identifier, "accept"))
+ policy = NF_ACCEPT;
+ else if (!strcmp(sym->identifier, "drop"))
+ policy = NF_DROP;
+ else
+ return error(&sym->location, "wrong policy");
+
+ *res = constant_expr_alloc(&sym->location, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE, &policy);
+ return NULL;
+}
+
+/* This datatype is not registered via datatype_register()
+ * since this datatype should not ever be used from either
+ * rules or elements.
+ */
+const struct datatype policy_type = {
+ .type = TYPE_STRING,
+ .name = "policy",
+ .desc = "policy type",
+ .parse = policy_type_parse,
+};
+
+#define SYSFS_CGROUPSV2_PATH "/sys/fs/cgroup"
+
+static const char *cgroupv2_get_path(const char *path, uint64_t id)
+{
+ const char *cgroup_path = NULL;
+ char dent_name[PATH_MAX + 1];
+ struct dirent *dent;
+ struct stat st;
+ DIR *d;
+
+ d = opendir(path);
+ if (!d)
+ return NULL;
+
+ while ((dent = readdir(d)) != NULL) {
+ if (!strcmp(dent->d_name, ".") ||
+ !strcmp(dent->d_name, ".."))
+ continue;
+
+ snprintf(dent_name, sizeof(dent_name), "%s/%s",
+ path, dent->d_name);
+ dent_name[sizeof(dent_name) - 1] = '\0';
+
+ if (dent->d_ino == id) {
+ cgroup_path = xstrdup(dent_name);
+ break;
+ }
+
+ if (stat(dent_name, &st) >= 0 && S_ISDIR(st.st_mode)) {
+ cgroup_path = cgroupv2_get_path(dent_name, id);
+ if (cgroup_path)
+ break;
+ }
+ }
+ closedir(d);
+
+ return cgroup_path;
+}
+
+static void cgroupv2_type_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ uint64_t id = mpz_get_uint64(expr->value);
+ const char *cgroup_path;
+
+ cgroup_path = cgroupv2_get_path(SYSFS_CGROUPSV2_PATH, id);
+ if (cgroup_path)
+ nft_print(octx, "\"%s\"",
+ &cgroup_path[strlen(SYSFS_CGROUPSV2_PATH) + 1]);
+ else
+ nft_print(octx, "%" PRIu64, id);
+
+ xfree(cgroup_path);
+}
+
+static struct error_record *cgroupv2_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ char cgroupv2_path[PATH_MAX + 1];
+ struct stat st;
+ uint64_t ino;
+
+ snprintf(cgroupv2_path, sizeof(cgroupv2_path), "%s/%s",
+ SYSFS_CGROUPSV2_PATH, sym->identifier);
+ cgroupv2_path[sizeof(cgroupv2_path) - 1] = '\0';
+
+ if (stat(cgroupv2_path, &st) < 0)
+ return error(&sym->location, "cgroupv2 path fails: %s",
+ strerror(errno));
+
+ ino = st.st_ino;
+ *res = constant_expr_alloc(&sym->location, &cgroupv2_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(ino) * BITS_PER_BYTE, &ino);
+ return NULL;
+}
+
+const struct datatype cgroupv2_type = {
+ .type = TYPE_CGROUPV2,
+ .name = "cgroupsv2",
+ .desc = "cgroupsv2 path",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 8 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = cgroupv2_type_print,
+ .parse = cgroupv2_type_parse,
+};
diff --git a/src/dccpopt.c b/src/dccpopt.c
new file mode 100644
index 0000000..ebb645a
--- /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
new file mode 100644
index 0000000..cd9f62b
--- /dev/null
+++ b/src/erec.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <netlink.h>
+#include <gmputil.h>
+#include <erec.h>
+
+static const struct input_descriptor internal_indesc = {
+ .type = INDESC_INTERNAL,
+ .name = "internal",
+};
+
+const struct location internal_location = {
+ .indesc = &internal_indesc,
+};
+
+static const char * const error_record_names[] = {
+ [EREC_INFORMATIONAL] = NULL,
+ [EREC_WARNING] = "Warning",
+ [EREC_ERROR] = "Error"
+};
+
+void erec_add_location(struct error_record *erec, const struct location *loc)
+{
+ assert(erec->num_locations < EREC_LOCATIONS_MAX);
+ erec->locations[erec->num_locations] = *loc;
+ erec->locations[erec->num_locations].indesc = loc->indesc ?
+ : &internal_indesc;
+ erec->num_locations++;
+}
+
+void erec_destroy(struct error_record *erec)
+{
+ xfree(erec->msg);
+ xfree(erec);
+}
+
+__attribute__((format(printf, 3, 0)))
+struct error_record *erec_vcreate(enum error_record_types type,
+ const struct location *loc,
+ const char *fmt, va_list ap)
+{
+ struct error_record *erec;
+
+ erec = xmalloc(sizeof(*erec));
+ erec->type = type;
+ erec->num_locations = 0;
+ erec_add_location(erec, loc);
+
+ if (vasprintf(&erec->msg, fmt, ap) < 0)
+ erec->msg = NULL;
+
+ return erec;
+}
+
+__attribute__((format(printf, 3, 4)))
+struct error_record *erec_create(enum error_record_types type,
+ const struct location *loc,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(type, loc, fmt, ap);
+ va_end(ap);
+ return erec;
+}
+
+void print_location(FILE *f, const struct input_descriptor *indesc,
+ const struct location *loc)
+{
+ const struct input_descriptor *tmp;
+ const struct location *iloc;
+
+ if (indesc->location.indesc != NULL) {
+ const char *prefix = "In file included from";
+ iloc = &indesc->location;
+ for (tmp = iloc->indesc;
+ tmp != NULL && tmp->type != INDESC_INTERNAL;
+ tmp = iloc->indesc) {
+ fprintf(f, "%s %s:%u:%u-%u:\n", prefix,
+ tmp->name,
+ iloc->first_line, iloc->first_column,
+ iloc->last_column);
+ prefix = " from";
+ iloc = &tmp->location;
+ }
+ }
+ if (indesc->type != INDESC_BUFFER && indesc->name) {
+ fprintf(f, "%s:%u:%u-%u: ", indesc->name,
+ loc->first_line, loc->first_column,
+ loc->last_column);
+ }
+}
+
+const char *line_location(const struct input_descriptor *indesc,
+ const struct location *loc, char *buf, size_t bufsiz)
+{
+ const char *line = NULL;
+ FILE *f;
+
+ f = fopen(indesc->name, "r");
+ if (!f)
+ return NULL;
+
+ if (!fseek(f, loc->line_offset, SEEK_SET) &&
+ fread(buf, 1, bufsiz - 1, f) > 0) {
+ *strchrnul(buf, '\n') = '\0';
+ line = buf;
+ }
+ fclose(f);
+
+ return line;
+}
+
+void erec_print(struct output_ctx *octx, const struct error_record *erec,
+ unsigned int debug_mask)
+{
+ const struct location *loc = erec->locations;
+ const struct input_descriptor *indesc = loc->indesc;
+ const char *line = NULL;
+ char buf[1024] = {};
+ char *pbuf = NULL;
+ unsigned int i, end;
+ FILE *f;
+ int l;
+
+ switch (indesc->type) {
+ case INDESC_BUFFER:
+ case INDESC_CLI:
+ line = indesc->data;
+ *strchrnul(line, '\n') = '\0';
+ break;
+ case INDESC_STDIN:
+ line = indesc->data;
+ line += loc->line_offset;
+ *strchrnul(line, '\n') = '\0';
+ break;
+ case INDESC_FILE:
+ line = line_location(indesc, loc, buf, sizeof(buf));
+ break;
+ case INDESC_INTERNAL:
+ case INDESC_NETLINK:
+ break;
+ default:
+ BUG("invalid input descriptor type %u\n", indesc->type);
+ }
+
+ f = octx->error_fp;
+
+ if (indesc->type == INDESC_NETLINK) {
+ fprintf(f, "%s: ", indesc->name);
+ if (error_record_names[erec->type])
+ fprintf(f, "%s: ", error_record_names[erec->type]);
+ 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;
+ }
+
+ print_location(f, indesc, loc);
+
+ if (error_record_names[erec->type])
+ fprintf(f, "%s: ", error_record_names[erec->type]);
+ fprintf(f, "%s\n", erec->msg);
+
+ if (line) {
+ fprintf(f, "%s\n", line);
+
+ end = 0;
+ for (l = erec->num_locations - 1; l >= 0; l--) {
+ loc = &erec->locations[l];
+ end = max(end, loc->last_column);
+ }
+ pbuf = xmalloc(end + 1);
+ memset(pbuf, ' ', end + 1);
+ for (i = 0; i < end && line[i]; i++) {
+ if (line[i] == '\t')
+ pbuf[i] = '\t';
+ }
+ for (l = erec->num_locations - 1; l >= 0; l--) {
+ loc = &erec->locations[l];
+ for (i = loc->first_column ? loc->first_column - 1 : 0;
+ i < loc->last_column; i++)
+ pbuf[i] = l ? '~' : '^';
+ }
+ pbuf[end] = '\0';
+ fprintf(f, "%s", pbuf);
+ xfree(pbuf);
+ }
+ fprintf(f, "\n");
+}
+
+void erec_print_list(struct output_ctx *octx, struct list_head *list,
+ unsigned int debug_mask)
+{
+ struct error_record *erec, *next;
+
+ list_for_each_entry_safe(erec, next, list, list) {
+ list_del(&erec->list);
+ erec_print(octx, erec, debug_mask);
+ erec_destroy(erec);
+ }
+}
+
+int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
+ const struct location *l1,
+ const struct location *l2,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, l1, fmt, ap);
+ if (l2 != NULL)
+ erec_add_location(erec, l2);
+ va_end(ap);
+ erec_queue(erec, ctx->msgs);
+ return -1;
+}
diff --git a/src/evaluate.c b/src/evaluate.c
new file mode 100644
index 0000000..2196e92
--- /dev/null
+++ b/src/evaluate.c
@@ -0,0 +1,5857 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_synproxy.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_log.h>
+#include <linux/netfilter_ipv4.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <errno.h>
+
+#include <expression.h>
+#include <statement.h>
+#include <intervals.h>
+#include <netlink.h>
+#include <time.h>
+#include <rule.h>
+#include <cache.h>
+#include <erec.h>
+#include <gmputil.h>
+#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[] = {
+ [BYTEORDER_INVALID] = "invalid",
+ [BYTEORDER_HOST_ENDIAN] = "host endian",
+ [BYTEORDER_BIG_ENDIAN] = "big endian",
+};
+
+#define chain_error(ctx, s1, fmt, args...) \
+ __stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args)
+#define monitor_error(ctx, s1, fmt, args...) \
+ __stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args)
+#define cmd_error(ctx, loc, fmt, args...) \
+ __stmt_binary_error(ctx, loc, NULL, fmt, ## args)
+
+static int __fmtstring(3, 4) set_error(struct eval_ctx *ctx,
+ const struct set *set,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, &set->location, fmt, ap);
+ va_end(ap);
+ erec_queue(erec, ctx->msgs);
+ return -1;
+}
+
+static void key_fix_dtype_byteorder(struct expr *key)
+{
+ const struct datatype *dtype = key->dtype;
+
+ if (dtype->byteorder == key->byteorder)
+ return;
+
+ __datatype_set(key, set_datatype_alloc(dtype, key->byteorder));
+}
+
+static int set_evaluate(struct eval_ctx *ctx, struct set *set);
+static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
+ const char *name,
+ struct expr *key,
+ struct expr *data,
+ struct expr *expr)
+{
+ struct cmd *cmd;
+ struct set *set;
+ struct handle h;
+
+ if (set_is_datamap(expr->set_flags))
+ key_fix_dtype_byteorder(key);
+
+ set = set_alloc(&expr->location);
+ set->flags = NFT_SET_ANONYMOUS | expr->set_flags;
+ set->handle.set.name = xstrdup(name);
+ set->key = key;
+ set->data = data;
+ set->init = expr;
+ set->automerge = set->flags & NFT_SET_INTERVAL;
+
+ if (ctx->table != NULL)
+ list_add_tail(&set->list, &ctx->table->sets);
+ else {
+ handle_merge(&set->handle, &ctx->cmd->handle);
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &set->handle);
+ h.set.location = expr->location;
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &h, &expr->location, set);
+ cmd->location = set->location;
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ }
+
+ set_evaluate(ctx, set);
+
+ return set_ref_expr_alloc(&expr->location, set);
+}
+
+static enum ops byteorder_conversion_op(struct expr *expr,
+ enum byteorder byteorder)
+{
+ switch (expr->byteorder) {
+ case BYTEORDER_HOST_ENDIAN:
+ if (byteorder == BYTEORDER_BIG_ENDIAN)
+ return OP_HTON;
+ break;
+ case BYTEORDER_BIG_ENDIAN:
+ if (byteorder == BYTEORDER_HOST_ENDIAN)
+ return OP_NTOH;
+ break;
+ default:
+ break;
+ }
+ BUG("invalid byte order conversion %u => %u\n",
+ expr->byteorder, byteorder);
+}
+
+static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
+ enum byteorder byteorder)
+{
+ enum datatypes basetype;
+ enum ops op;
+
+ assert(!expr_is_constant(*expr) || expr_is_singleton(*expr));
+
+ if ((*expr)->byteorder == byteorder)
+ return 0;
+
+ /* Conversion for EXPR_CONCAT is handled for single composing ranges */
+ if ((*expr)->etype == EXPR_CONCAT) {
+ struct expr *i, *next, *unary;
+
+ list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+ if (i->byteorder == BYTEORDER_BIG_ENDIAN)
+ continue;
+
+ basetype = expr_basetype(i)->type;
+ if (basetype == TYPE_STRING)
+ continue;
+
+ assert(basetype == TYPE_INTEGER);
+
+ op = byteorder_conversion_op(i, byteorder);
+ unary = unary_expr_alloc(&i->location, op, i);
+ if (expr_evaluate(ctx, &unary) < 0)
+ return -1;
+
+ list_replace(&i->list, &unary->list);
+ }
+
+ return 0;
+ }
+
+ basetype = expr_basetype(*expr)->type;
+ switch (basetype) {
+ case TYPE_INTEGER:
+ break;
+ case TYPE_STRING:
+ return 0;
+ default:
+ return expr_error(ctx->msgs, *expr,
+ "Byteorder mismatch: %s expected %s, %s got %s",
+ byteorder_names[byteorder],
+ expr_name(*expr),
+ byteorder_names[(*expr)->byteorder]);
+ }
+
+ if (expr_is_constant(*expr) || div_round_up((*expr)->len, BITS_PER_BYTE) < 2)
+ (*expr)->byteorder = byteorder;
+ else {
+ op = byteorder_conversion_op(*expr, byteorder);
+ *expr = unary_expr_alloc(&(*expr)->location, op, *expr);
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+static int table_not_found(struct eval_ctx *ctx)
+{
+ struct table *table;
+
+ table = table_lookup_fuzzy(&ctx->cmd->handle, &ctx->nft->cache);
+ if (table == NULL)
+ return cmd_error(ctx, &ctx->cmd->handle.table.location,
+ "%s", strerror(ENOENT));
+
+ return cmd_error(ctx, &ctx->cmd->handle.table.location,
+ "%s; did you mean table ‘%s’ in family %s?",
+ strerror(ENOENT), table->handle.table.name,
+ family2str(table->handle.family));
+}
+
+static int chain_not_found(struct eval_ctx *ctx)
+{
+ const struct table *table;
+ struct chain *chain;
+
+ chain = chain_lookup_fuzzy(&ctx->cmd->handle, &ctx->nft->cache, &table);
+ if (chain == NULL)
+ return cmd_error(ctx, &ctx->cmd->handle.chain.location,
+ "%s", strerror(ENOENT));
+
+ return cmd_error(ctx, &ctx->cmd->handle.chain.location,
+ "%s; did you mean chain ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT), chain->handle.chain.name,
+ family2str(chain->handle.family),
+ table->handle.table.name);
+}
+
+static int set_not_found(struct eval_ctx *ctx, const struct location *loc,
+ const char *set_name)
+{
+ const struct table *table;
+ struct set *set;
+
+ set = set_lookup_fuzzy(set_name, &ctx->nft->cache, &table);
+ if (set == NULL)
+ return cmd_error(ctx, loc, "%s", strerror(ENOENT));
+
+ return cmd_error(ctx, loc,
+ "%s; did you mean %s ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT),
+ set_is_map(set->flags) ? "map" : "set",
+ set->handle.set.name,
+ family2str(set->handle.family),
+ table->handle.table.name);
+}
+
+static int flowtable_not_found(struct eval_ctx *ctx, const struct location *loc,
+ const char *ft_name)
+{
+ const struct table *table;
+ struct flowtable *ft;
+
+ ft = flowtable_lookup_fuzzy(ft_name, &ctx->nft->cache, &table);
+ if (!ft)
+ return cmd_error(ctx, loc, "%s", strerror(ENOENT));
+
+ return cmd_error(ctx, loc,
+ "%s; did you mean flowtable ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT), ft->handle.flowtable.name,
+ family2str(ft->handle.family),
+ table->handle.table.name);
+}
+
+/*
+ * Symbol expression: parse symbol and evaluate resulting expression.
+ */
+static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct parse_ctx parse_ctx = {
+ .tbl = &ctx->nft->output.tbl,
+ .input = &ctx->nft->input,
+ };
+ struct error_record *erec;
+ struct table *table;
+ struct set *set;
+ struct expr *new;
+
+ switch ((*expr)->symtype) {
+ case SYMBOL_VALUE:
+ datatype_set(*expr, ctx->ectx.dtype);
+ erec = symbol_parse(&parse_ctx, *expr, &new);
+ if (erec != NULL) {
+ erec_queue(erec, ctx->msgs);
+ return -1;
+ }
+ break;
+ case SYMBOL_SET:
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
+ if (table == NULL)
+ return table_not_found(ctx);
+
+ set = set_cache_find(table, (*expr)->identifier);
+ if (set == NULL || !set->key)
+ return set_not_found(ctx, &(*expr)->location,
+ (*expr)->identifier);
+
+ new = set_ref_expr_alloc(&(*expr)->location, set);
+ break;
+ }
+
+ expr_free(*expr);
+ *expr = new;
+
+ return expr_evaluate(ctx, expr);
+}
+
+static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE), datalen;
+ struct expr *value, *prefix;
+ int data_len = ctx->ectx.len > 0 ? ctx->ectx.len : len + 1;
+ char data[data_len];
+
+ if (ctx->ectx.len > 0) {
+ if (expr->len > ctx->ectx.len)
+ return expr_error(ctx->msgs, expr,
+ "String exceeds maximum length of %u",
+ ctx->ectx.len / BITS_PER_BYTE);
+ expr->len = ctx->ectx.len;
+ }
+
+ memset(data + len, 0, data_len - len);
+ mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
+
+ if (strlen(data) == 0)
+ return expr_error(ctx->msgs, expr,
+ "Empty string is not allowed");
+
+ datalen = strlen(data) - 1;
+ if (data[datalen] != '*') {
+ /* We need to reallocate the constant expression with the right
+ * expression length to avoid problems on big endian.
+ */
+ value = constant_expr_alloc(&expr->location, ctx->ectx.dtype,
+ BYTEORDER_HOST_ENDIAN,
+ expr->len, data);
+ expr_free(expr);
+ *exprp = value;
+ return 0;
+ }
+
+ if (datalen == 0)
+ return expr_error(ctx->msgs, expr,
+ "All-wildcard strings are not supported");
+
+ if (data[datalen - 1] == '\\') {
+ char unescaped_str[data_len];
+
+ memset(unescaped_str, 0, sizeof(unescaped_str));
+ xstrunescape(data, unescaped_str);
+
+ value = constant_expr_alloc(&expr->location, ctx->ectx.dtype,
+ BYTEORDER_HOST_ENDIAN,
+ expr->len, unescaped_str);
+ expr_free(expr);
+ *exprp = value;
+ return 0;
+ }
+
+ data[datalen] = 0;
+ value = constant_expr_alloc(&expr->location, ctx->ectx.dtype,
+ BYTEORDER_HOST_ENDIAN,
+ expr->len, data);
+
+ prefix = prefix_expr_alloc(&expr->location, value,
+ datalen * BITS_PER_BYTE);
+ datatype_set(prefix, ctx->ectx.dtype);
+ prefix->flags |= EXPR_F_CONSTANT;
+ prefix->byteorder = BYTEORDER_HOST_ENDIAN;
+ prefix->len = expr->len;
+
+ expr_free(expr);
+ *exprp = prefix;
+ return 0;
+}
+
+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 &&
+ mpz_cmp_ui(expr->value, ctx->ectx.maxval) > 0) {
+ valstr = mpz_get_str(NULL, 10, expr->value);
+ expr_error(ctx->msgs, expr,
+ "Value %s exceeds valid range 0-%u",
+ valstr, ctx->ectx.maxval);
+ free(valstr);
+ return -1;
+ }
+
+ 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);
+ mpz_clear(mask);
+ return -1;
+ }
+ expr->byteorder = ctx->ectx.byteorder;
+ expr->len = masklen;
+ mpz_clear(mask);
+ return 0;
+}
+
+static int expr_evaluate_value(struct eval_ctx *ctx, struct expr **expr)
+{
+ switch (expr_basetype(*expr)->type) {
+ case TYPE_INTEGER:
+ if (expr_evaluate_integer(ctx, expr) < 0)
+ return -1;
+ break;
+ case TYPE_STRING:
+ if (expr_evaluate_string(ctx, expr) < 0)
+ return -1;
+ break;
+ default:
+ BUG("invalid basetype %s\n", expr_basetype(*expr)->name);
+ }
+ return 0;
+}
+
+/*
+ * Primary expressions determine the datatype context.
+ */
+static int expr_evaluate_primary(struct eval_ctx *ctx, struct expr **expr)
+{
+ __expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->byteorder,
+ (*expr)->len, 0);
+ return 0;
+}
+
+static int
+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);
+
+ 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);
+
+ 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);
+ if (stmt_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;
+}
+
+static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset,
+ unsigned int *extra_len)
+{
+ unsigned int new_offset, len;
+ int shift;
+
+ new_offset = offset % BITS_PER_BYTE;
+ len = round_up(expr->len, BITS_PER_BYTE);
+ shift = len - (new_offset + expr->len);
+ while (shift < 0) {
+ shift += BITS_PER_BYTE;
+ *extra_len += BITS_PER_BYTE;
+ }
+ return shift;
+}
+
+static void 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;
+
+ switch (expr->etype) {
+ case EXPR_PAYLOAD:
+ shift = expr_offset_shift(expr, expr->payload.offset,
+ &extra_len);
+ break;
+ case EXPR_EXTHDR:
+ shift = expr_offset_shift(expr, expr->exthdr.offset,
+ &extra_len);
+ break;
+ default:
+ BUG("Unknown expression %s\n", expr_name(expr));
+ }
+
+ masklen = len + shift;
+ assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE);
+
+ mpz_init2(bitmask, masklen);
+ mpz_bitmask(bitmask, len);
+ mpz_lshift_ui(bitmask, shift);
+
+ mask = constant_expr_alloc(&expr->location, expr_basetype(expr),
+ BYTEORDER_HOST_ENDIAN, masklen, NULL);
+ mpz_set(mask->value, bitmask);
+ mpz_clear(bitmask);
+
+ and = binop_expr_alloc(&expr->location, OP_AND, expr, mask);
+ and->dtype = expr->dtype;
+ and->byteorder = expr->byteorder;
+ and->len = masklen;
+
+ if (shift) {
+ if (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,
+ sizeof(shift), &shift);
+
+ rshift = binop_expr_alloc(&expr->location, OP_RSHIFT, and, off);
+ rshift->dtype = expr->dtype;
+ rshift->byteorder = byteorder;
+ rshift->len = masklen;
+
+ *exprp = rshift;
+ } else
+ *exprp = and;
+
+ if (extra_len)
+ expr->len += extra_len;
+}
+
+static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+
+ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
+ datatype_set(expr, &boolean_type);
+
+ if (expr_evaluate_primary(ctx, exprp) < 0)
+ return -1;
+
+ if (expr->exthdr.offset % BITS_PER_BYTE != 0 ||
+ expr->len % BITS_PER_BYTE != 0)
+ expr_evaluate_bits(ctx, exprp);
+
+ switch (expr->exthdr.op) {
+ case NFT_EXTHDR_OP_TCPOPT: {
+ static const unsigned int max_tcpoptlen = (15 * 4 - 20) * BITS_PER_BYTE;
+ unsigned int totlen;
+
+ totlen = expr->exthdr.tmpl->len + expr->exthdr.offset;
+
+ if (totlen > max_tcpoptlen)
+ return expr_error(ctx->msgs, expr,
+ "offset and size %u exceeds max tcp headerlen (%u)",
+ totlen, max_tcpoptlen);
+ break;
+ }
+ case NFT_EXTHDR_OP_IPV4: {
+ static const unsigned int max_ipoptlen = 40 * BITS_PER_BYTE;
+ unsigned int totlen;
+
+ totlen = expr->exthdr.offset + expr->exthdr.tmpl->len;
+
+ if (totlen > max_ipoptlen)
+ return expr_error(ctx->msgs, expr,
+ "offset and size %u exceeds max ip option len (%u)",
+ totlen, max_ipoptlen);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Exthdr expression: check whether dependencies are fulfilled, otherwise
+ * generate the necessary relational expression and prepend it to the current
+ * statement.
+ */
+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;
+ break;
+ case NFT_EXTHDR_OP_IPV6:
+ default:
+ dependency = &proto_ip6;
+ break;
+ }
+
+ assert(dependency);
+
+ pctx = eval_proto_ctx(ctx);
+ base = pctx->protocol[pb].desc;
+ if (base == dependency)
+ return __expr_evaluate_exthdr(ctx, exprp);
+
+ if (base)
+ return expr_error(ctx->msgs, expr,
+ "cannot use exthdr with %s", base->name);
+
+ if (exthdr_gen_dependency(ctx, expr, dependency, pb - 1, &nstmt) < 0)
+ return -1;
+
+ list_add(&nstmt->list, &ctx->rule->stmts);
+
+ return __expr_evaluate_exthdr(ctx, exprp);
+}
+
+/* dependency supersede.
+ *
+ * 'inet' is a 'phony' l2 dependency used by NFPROTO_INET to fulfil network
+ * header dependency, i.e. ensure that 'ip saddr 1.2.3.4' only sees ip headers.
+ *
+ * If a match expression that depends on a particular L2 header, e.g. ethernet,
+ * is used, we thus get a conflict since we already have a l2 header dependency.
+ *
+ * But in the inet case we can just ignore the conflict since only another
+ * restriction is added, and these are not mutually exclusive.
+ *
+ * Example: inet filter in ip saddr 1.2.3.4 ether saddr a:b:c:d:e:f
+ *
+ * ip saddr adds meta dependency on ipv4 packets
+ * ether saddr adds another dependency on ethernet frames.
+ */
+static int meta_iiftype_gen_dependency(struct eval_ctx *ctx,
+ struct expr *payload, struct stmt **res)
+{
+ struct stmt *nstmt;
+ uint16_t type;
+
+ if (proto_dev_type(payload->payload.desc, &type) < 0)
+ return expr_error(ctx->msgs, payload,
+ "protocol specification is invalid "
+ "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 (ctx->inner_desc)
+ nstmt->expr->left->meta.inner_desc = ctx->inner_desc;
+
+ *res = nstmt;
+ return 0;
+}
+
+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)
+{
+ enum proto_bases base = payload->payload.base;
+ struct stmt *nstmt = NULL;
+ struct proto_ctx *pctx;
+ int link, err;
+
+ pctx = eval_proto_ctx(ctx);
+
+ if (payload->payload.base == PROTO_BASE_LL_HDR) {
+ 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 (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)
+ return 1;
+
+ if (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;
+ }
+
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+
+ return 0;
+}
+
+/*
+ * Payload expression: check whether dependencies are fulfilled, otherwise
+ * generate the necessary relational expression and prepend it to the current
+ * statement.
+ */
+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;
+
+ 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 = 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 ||
+ 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);
+
+ payload->payload.offset += pctx->stacked_ll[0]->length;
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ return 1;
+ }
+ goto check_icmp;
+ }
+
+ if (payload->payload.base == desc->base &&
+ proto_ctx_is_ambiguous(pctx, base)) {
+ desc = proto_ctx_find_conflict(pctx, base, payload->payload.desc);
+ assert(desc);
+
+ return expr_error(ctx->msgs, payload,
+ "conflicting protocols specified: %s vs. %s",
+ desc->name,
+ payload->payload.desc->name);
+ }
+
+ /* No conflict: Same payload protocol as context, adjust offset
+ * if needed.
+ */
+ if (desc == payload->payload.desc) {
+ const struct proto_hdr_template *tmpl;
+
+ if (desc->base == PROTO_BASE_LL_HDR) {
+ unsigned int i;
+
+ for (i = 0; i < pctx->stacked_ll_count; i++)
+ payload->payload.offset += pctx->stacked_ll[i]->length;
+ }
+check_icmp:
+ if (desc != &proto_icmp && desc != &proto_icmp6)
+ return 0;
+
+ tmpl = expr->payload.tmpl;
+
+ if (!tmpl || !tmpl->icmp_dep)
+ return 0;
+
+ if (payload_gen_icmp_dependency(ctx, expr, &nstmt) < 0)
+ return -1;
+
+ if (nstmt)
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+
+ return 0;
+ }
+ /* If we already have context and this payload is on the same
+ * base, try to resolve the protocol conflict.
+ */
+ if (payload->payload.base == desc->base) {
+ err = resolve_protocol_conflict(ctx, desc, payload);
+ if (err <= 0)
+ return err;
+
+ desc = pctx->protocol[base].desc;
+ if (desc == payload->payload.desc)
+ return 0;
+ }
+ return expr_error(ctx->msgs, payload,
+ "conflicting protocols specified: %s vs. %s",
+ pctx->protocol[base].desc->name,
+ payload->payload.desc->name);
+}
+
+static bool payload_needs_adjustment(const struct expr *expr)
+{
+ return expr->payload.offset % BITS_PER_BYTE != 0 ||
+ expr->len % BITS_PER_BYTE != 0;
+}
+
+static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+
+ if (expr->payload.evaluated)
+ return 0;
+
+ if (__expr_evaluate_payload(ctx, expr) < 0)
+ return -1;
+
+ if (expr_evaluate_primary(ctx, exprp) < 0)
+ return -1;
+
+ if (payload_needs_adjustment(expr))
+ expr_evaluate_bits(ctx, exprp);
+
+ 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.
+ */
+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;
+
+ 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 (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 (pctx->family == NFPROTO_IPV4)
+ return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip6");
+ break;
+ default:
+ break;
+ }
+
+ return expr_evaluate_primary(ctx, expr);
+}
+
+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;
+
+ pctx = eval_proto_ctx(ctx);
+ base_now = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+
+ switch (ct->ct.nfproto) {
+ case NFPROTO_IPV4:
+ base = &proto_ip;
+ break;
+ case NFPROTO_IPV6:
+ base = &proto_ip6;
+ break;
+ default:
+ base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (base == &proto_ip)
+ ct->ct.nfproto = NFPROTO_IPV4;
+ else if (base == &proto_ip)
+ ct->ct.nfproto = NFPROTO_IPV6;
+
+ if (base)
+ break;
+
+ return expr_error(ctx->msgs, ct,
+ "cannot determine ip protocol version, use \"ip %1$caddr\" or \"ip6 %1$caddr\" instead",
+ ct->ct.key == NFT_CT_SRC ? 's' : 'd');
+ }
+
+ /* no additional dependency needed? */
+ if (base == base_now)
+ return 0;
+
+ if (base_now && base_now != base)
+ return expr_error(ctx->msgs, ct,
+ "conflicting dependencies: %s vs. %s\n",
+ base->name,
+ pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name);
+ switch (pctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ return 0;
+ }
+
+ left = ct_expr_alloc(&ct->location, NFT_CT_L3PROTOCOL, ct->ct.direction);
+
+ right = constant_expr_alloc(&ct->location, left->dtype,
+ left->dtype->byteorder, left->len,
+ constant_data_ptr(ct->ct.nfproto, left->len));
+ dep = relational_expr_alloc(&ct->location, OP_EQ, left, right);
+
+ relational_expr_pctx_update(pctx, dep);
+
+ nstmt = expr_stmt_alloc(&dep->location, dep);
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+
+ return 0;
+}
+
+/*
+ * CT expression: update the protocol dependant types bases on the protocol
+ * context.
+ */
+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;
+
+ pctx = eval_proto_ctx(ctx);
+ base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+
+ switch (ct->ct.key) {
+ case NFT_CT_SRC:
+ case NFT_CT_DST:
+ ct_gen_nh_dependency(ctx, ct);
+ break;
+ case NFT_CT_SRC_IP:
+ case NFT_CT_DST_IP:
+ if (base == &proto_ip6) {
+ error = &proto_ip;
+ goto err_conflict;
+ }
+ break;
+ case NFT_CT_SRC_IP6:
+ case NFT_CT_DST_IP6:
+ if (base == &proto_ip) {
+ error = &proto_ip6;
+ goto err_conflict;
+ }
+ break;
+ default:
+ break;
+ }
+
+ ct_expr_update_type(pctx, ct);
+
+ return expr_evaluate_primary(ctx, expr);
+
+err_conflict:
+ return stmt_binary_error(ctx, ct,
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
+ "conflicting protocols specified: %s vs. %s",
+ base->name, error->name);
+}
+
+/*
+ * Prefix expression: the argument must be a constant value of integer or
+ * string base type; the prefix length must be less than or equal to the type
+ * width.
+ */
+static int expr_evaluate_prefix(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *prefix = *expr, *base, *and, *mask;
+
+ if (expr_evaluate(ctx, &prefix->prefix) < 0)
+ return -1;
+ base = prefix->prefix;
+
+ if (!expr_is_constant(base))
+ return expr_error(ctx->msgs, prefix,
+ "Prefix expression is undefined for "
+ "non-constant expressions");
+
+ switch (expr_basetype(base)->type) {
+ case TYPE_INTEGER:
+ case TYPE_STRING:
+ break;
+ default:
+ return expr_error(ctx->msgs, prefix,
+ "Prefix expression is undefined for "
+ "%s types", base->dtype->desc);
+ }
+
+ if (prefix->prefix_len > base->len)
+ return expr_error(ctx->msgs, prefix,
+ "Prefix length %u is invalid for type "
+ "of %u bits width",
+ prefix->prefix_len, base->len);
+
+ /* Clear the uncovered bits of the base value */
+ mask = constant_expr_alloc(&prefix->location, expr_basetype(base),
+ BYTEORDER_HOST_ENDIAN, base->len, NULL);
+ switch (expr_basetype(base)->type) {
+ case TYPE_INTEGER:
+ mpz_prefixmask(mask->value, base->len, prefix->prefix_len);
+ break;
+ case TYPE_STRING:
+ mpz_bitmask(mask->value, prefix->prefix_len);
+ break;
+ }
+ and = binop_expr_alloc(&prefix->location, OP_AND, base, mask);
+ prefix->prefix = and;
+ if (expr_evaluate(ctx, &prefix->prefix) < 0)
+ return -1;
+ base = prefix->prefix;
+ assert(expr_is_constant(base));
+
+ prefix->dtype = base->dtype;
+ prefix->byteorder = base->byteorder;
+ prefix->len = base->len;
+ prefix->flags |= EXPR_F_CONSTANT;
+ return 0;
+}
+
+/*
+ * Range expression: both sides must be constants of integer base type.
+ */
+static int expr_evaluate_range_expr(struct eval_ctx *ctx,
+ const struct expr *range,
+ struct expr **expr)
+{
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ if (expr_basetype(*expr)->type != TYPE_INTEGER)
+ return expr_binary_error(ctx->msgs, *expr, range,
+ "Range expression is undefined for "
+ "%s types", (*expr)->dtype->desc);
+ if (!expr_is_constant(*expr))
+ return expr_binary_error(ctx->msgs, *expr, range,
+ "Range is not constant");
+ return 0;
+}
+
+static int __expr_evaluate_range(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *range = *expr;
+
+ if (expr_evaluate_range_expr(ctx, range, &range->left) < 0)
+ return -1;
+ if (expr_evaluate_range_expr(ctx, range, &range->right) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int expr_evaluate_range(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *range = *expr, *left, *right;
+ int rc;
+
+ rc = __expr_evaluate_range(ctx, expr);
+ if (rc)
+ return rc;
+
+ left = range->left;
+ right = range->right;
+
+ if (mpz_cmp(left->value, right->value) > 0)
+ return expr_error(ctx->msgs, range,
+ "Range has zero or negative size");
+ datatype_set(range, left->dtype);
+ range->flags |= EXPR_F_CONSTANT;
+ return 0;
+}
+
+/*
+ * Unary expressions: unary expressions are only generated internally for
+ * byteorder conversion of non-constant numerical expressions.
+ */
+static int expr_evaluate_unary(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *unary = *expr, *arg = unary->arg;
+ enum byteorder byteorder;
+
+ /* unary expression arguments has already been evaluated. */
+
+ assert(!expr_is_constant(arg));
+ assert(expr_basetype(arg)->type == TYPE_INTEGER);
+ assert(arg->etype != EXPR_UNARY);
+
+ switch (unary->op) {
+ case OP_HTON:
+ assert(arg->byteorder == BYTEORDER_HOST_ENDIAN);
+ byteorder = BYTEORDER_BIG_ENDIAN;
+ break;
+ case OP_NTOH:
+ assert(arg->byteorder == BYTEORDER_BIG_ENDIAN);
+ byteorder = BYTEORDER_HOST_ENDIAN;
+ break;
+ default:
+ BUG("invalid unary operation %u\n", unary->op);
+ }
+
+ unary->dtype = arg->dtype;
+ unary->byteorder = byteorder;
+ unary->len = arg->len;
+ return 0;
+}
+
+/*
+ * Binops
+ */
+static int constant_binop_simplify(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *op = *expr, *left = (*expr)->left, *right = (*expr)->right;
+ struct expr *new;
+ mpz_t val, mask;
+
+ assert(left->etype == EXPR_VALUE);
+ assert(right->etype == EXPR_VALUE);
+ assert(left->byteorder == right->byteorder);
+
+ mpz_init2(val, op->len);
+ mpz_init_bitmask(mask, op->len);
+
+ switch (op->op) {
+ case OP_AND:
+ mpz_and(val, left->value, right->value);
+ mpz_and(val, val, mask);
+ break;
+ case OP_XOR:
+ mpz_xor(val, left->value, right->value);
+ mpz_and(val, val, mask);
+ break;
+ case OP_OR:
+ mpz_ior(val, left->value, right->value);
+ mpz_and(val, val, mask);
+ break;
+ case OP_LSHIFT:
+ assert(left->byteorder == BYTEORDER_HOST_ENDIAN);
+ mpz_set(val, left->value);
+ mpz_lshift_ui(val, mpz_get_uint32(right->value));
+ mpz_and(val, val, mask);
+ break;
+ case OP_RSHIFT:
+ assert(left->byteorder == BYTEORDER_HOST_ENDIAN);
+ mpz_set(val, left->value);
+ mpz_and(val, val, mask);
+ mpz_rshift_ui(val, mpz_get_uint32(right->value));
+ break;
+ default:
+ BUG("invalid binary operation %u\n", op->op);
+ }
+
+ new = constant_expr_alloc(&op->location, op->dtype, op->byteorder,
+ op->len, NULL);
+ mpz_set(new->value, val);
+
+ expr_free(*expr);
+ *expr = new;
+
+ mpz_clear(mask);
+ mpz_clear(val);
+
+ return expr_evaluate(ctx, 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 = mpz_get_uint32(right->value);
+ unsigned int max_shift_len;
+
+ 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",
+ shift, max_shift_len);
+
+ /* Both sides need to be in host byte order */
+ if (byteorder_conversion(ctx, &op->left, BYTEORDER_HOST_ENDIAN) < 0)
+ return -1;
+ left = op->left;
+ if (byteorder_conversion(ctx, &op->right, BYTEORDER_HOST_ENDIAN) < 0)
+ return -1;
+
+ datatype_set(op, &integer_type);
+ op->byteorder = BYTEORDER_HOST_ENDIAN;
+ op->len = max_shift_len;
+
+ if (expr_is_constant(left))
+ return constant_binop_simplify(ctx, expr);
+ return 0;
+}
+
+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;
+
+ /* 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;
+
+ datatype_set(op, dtype);
+ op->byteorder = byteorder;
+ op->len = max_len;
+
+ if (expr_is_constant(left))
+ return constant_binop_simplify(ctx, expr);
+ return 0;
+}
+
+/*
+ * Binop expression: both sides must be of integer base type. The left
+ * hand side may be either constant or non-constant; in case its constant
+ * it must be a singleton. The ride hand side must always be a constant
+ * singleton.
+ */
+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;
+
+ if (expr_evaluate(ctx, &op->left) < 0)
+ return -1;
+ left = op->left;
+
+ if (op->op == OP_LSHIFT || op->op == OP_RSHIFT) {
+ if (left->len > max_shift_len)
+ max_shift_len = left->len;
+
+ __expr_set_context(&ctx->ectx, &integer_type,
+ left->byteorder, max_shift_len, 0);
+ }
+
+ if (expr_evaluate(ctx, &op->right) < 0)
+ return -1;
+ right = op->right;
+
+ switch (expr_basetype(left)->type) {
+ case TYPE_INTEGER:
+ case TYPE_STRING:
+ break;
+ default:
+ return expr_binary_error(ctx->msgs, left, op,
+ "Binary operation (%s) is undefined "
+ "for %s types",
+ sym, left->dtype->desc);
+ }
+
+ if (expr_is_constant(left) && !expr_is_singleton(left))
+ return expr_binary_error(ctx->msgs, left, op,
+ "Binary operation (%s) is undefined "
+ "for %s expressions",
+ sym, expr_name(left));
+
+ if (!expr_is_constant(right))
+ return expr_binary_error(ctx->msgs, right, op,
+ "Right hand side of binary operation "
+ "(%s) must be constant", sym);
+
+ if (!expr_is_singleton(right))
+ return expr_binary_error(ctx->msgs, left, op,
+ "Binary operation (%s) is undefined "
+ "for %s expressions",
+ sym, expr_name(right));
+
+ /* The grammar guarantees this */
+ assert(datatype_equal(expr_basetype(left), expr_basetype(right)));
+
+ switch (op->op) {
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ return expr_evaluate_shift(ctx, expr);
+ case OP_AND:
+ case OP_XOR:
+ case OP_OR:
+ return expr_evaluate_bitwise(ctx, expr);
+ default:
+ BUG("invalid binary operation %u\n", op->op);
+ }
+}
+
+static int list_member_evaluate(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *next = list_entry((*expr)->list.next, struct expr, list);
+ int err;
+
+ assert(*expr != next);
+ list_del(&(*expr)->list);
+ err = expr_evaluate(ctx, expr);
+ list_add_tail(&(*expr)->list, &next->list);
+ return err;
+}
+
+static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
+{
+ const struct datatype *dtype = ctx->ectx.dtype, *tmp;
+ uint32_t type = dtype ? dtype->type : 0, ntype = 0;
+ int off = dtype ? dtype->subtypes : 0;
+ unsigned int flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+ const struct list_head *expressions = NULL;
+ struct expr *i, *next, *key = NULL;
+ const struct expr *key_ctx = NULL;
+ bool runaway = false;
+ uint32_t size = 0;
+
+ if (ctx->ectx.key && ctx->ectx.key->etype == EXPR_CONCAT) {
+ key_ctx = ctx->ectx.key;
+ assert(!list_empty(&ctx->ectx.key->expressions));
+ key = list_first_entry(&ctx->ectx.key->expressions, struct expr, list);
+ expressions = &ctx->ectx.key->expressions;
+ }
+
+ list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+ enum byteorder bo = BYTEORDER_INVALID;
+ unsigned dsize_bytes, dsize = 0;
+
+ if (runaway) {
+ return expr_binary_error(ctx->msgs, *expr, key_ctx,
+ "too many concatenation components");
+ }
+
+ if (i->etype == EXPR_CT &&
+ (i->ct.key == NFT_CT_SRC ||
+ i->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, i,
+ "specify either ip or ip6 for address matching");
+
+ if (expr_is_constant(*expr) && dtype && off == 0)
+ return expr_binary_error(ctx->msgs, i, *expr,
+ "unexpected concat component, "
+ "expecting %s",
+ dtype->desc);
+
+ if (key) {
+ tmp = key->dtype;
+ dsize = key->len;
+ bo = key->byteorder;
+ off--;
+ } else if (dtype == NULL || off == 0) {
+ tmp = datatype_lookup(TYPE_INVALID);
+ } else {
+ tmp = concat_subtype_lookup(type, --off);
+ dsize = tmp->size;
+ bo = tmp->byteorder;
+ }
+
+ __expr_set_context(&ctx->ectx, tmp, bo, dsize, 0);
+
+ if (list_member_evaluate(ctx, &i) < 0)
+ return -1;
+ flags &= i->flags;
+
+ if (!key && i->dtype->type == TYPE_INTEGER) {
+ struct datatype *clone;
+
+ clone = datatype_clone(i->dtype);
+ clone->size = i->len;
+ clone->byteorder = i->byteorder;
+ __datatype_set(i, clone);
+ }
+
+ if (dtype == NULL && i->dtype->size == 0)
+ return expr_binary_error(ctx->msgs, i, *expr,
+ "can not use variable sized "
+ "data types (%s) in concat "
+ "expressions",
+ i->dtype->name);
+ if (dsize == 0) /* reload after evaluation or clone above */
+ dsize = i->dtype->size;
+
+ ntype = concat_subtype_add(ntype, i->dtype->type);
+
+ dsize_bytes = div_round_up(dsize, BITS_PER_BYTE);
+ (*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
+ size += netlink_padded_len(dsize);
+ if (key && expressions) {
+ if (list_is_last(&key->list, expressions))
+ runaway = true;
+
+ key = list_next_entry(key, list);
+ }
+
+ ctx->inner_desc = NULL;
+ }
+
+ (*expr)->flags |= flags;
+ __datatype_set(*expr, concat_type_alloc(ntype));
+ (*expr)->len = size;
+
+ if (off > 0)
+ return expr_error(ctx->msgs, *expr,
+ "datatype mismatch, expected %s, "
+ "expression has type %s",
+ dtype->desc, (*expr)->dtype->desc);
+
+ expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->len);
+ if (!key_ctx)
+ ctx->ectx.key = *expr;
+ else
+ ctx->ectx.key = key_ctx;
+
+ return 0;
+}
+
+static int expr_evaluate_list(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *list = *expr, *new, *i, *next;
+ mpz_t val;
+
+ mpz_init_set_ui(val, 0);
+ list_for_each_entry_safe(i, next, &list->expressions, list) {
+ if (list_member_evaluate(ctx, &i) < 0)
+ return -1;
+ if (i->etype != EXPR_VALUE)
+ return expr_error(ctx->msgs, i,
+ "List member must be a constant "
+ "value");
+ if (i->dtype->basetype->type != TYPE_BITMASK)
+ return expr_error(ctx->msgs, i,
+ "Basetype of type %s is not bitmask",
+ i->dtype->desc);
+ mpz_ior(val, val, i->value);
+ }
+
+ new = constant_expr_alloc(&list->location, ctx->ectx.dtype,
+ BYTEORDER_HOST_ENDIAN, ctx->ectx.len, NULL);
+ mpz_set(new->value, val);
+ mpz_clear(val);
+
+ expr_free(*expr);
+ *expr = new;
+ return 0;
+}
+
+static int __expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr *elem)
+{
+ int num_elem_exprs = 0, num_set_exprs = 0;
+ struct set *set = ctx->set;
+ struct stmt *stmt;
+
+ list_for_each_entry(stmt, &elem->stmt_list, list)
+ num_elem_exprs++;
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ num_set_exprs++;
+
+ if (num_elem_exprs > 0) {
+ struct stmt *set_stmt, *elem_stmt;
+
+ if (num_set_exprs > 0 && num_elem_exprs != num_set_exprs) {
+ return expr_error(ctx->msgs, elem,
+ "number of statements mismatch, set expects %d "
+ "but element has %d", num_set_exprs,
+ num_elem_exprs);
+ } else if (num_set_exprs == 0) {
+ if (!(set->flags & NFT_SET_ANONYMOUS) &&
+ !(set->flags & NFT_SET_EVAL)) {
+ elem_stmt = list_first_entry(&elem->stmt_list, struct stmt, list);
+ return stmt_error(ctx, elem_stmt,
+ "missing statement in %s declaration",
+ set_is_map(set->flags) ? "map" : "set");
+ }
+ return 0;
+ }
+
+ set_stmt = list_first_entry(&set->stmt_list, struct stmt, list);
+
+ list_for_each_entry(elem_stmt, &elem->stmt_list, list) {
+ if (set_stmt->ops != elem_stmt->ops) {
+ return stmt_error(ctx, elem_stmt,
+ "statement mismatch, element expects %s, "
+ "but %s has type %s",
+ elem_stmt->ops->name,
+ set_is_map(set->flags) ? "map" : "set",
+ set_stmt->ops->name);
+ }
+ set_stmt = list_next_entry(set_stmt, list);
+ }
+ }
+
+ return 0;
+}
+
+static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *elem = *expr;
+ const struct expr *key;
+
+ if (ctx->set) {
+ if (__expr_evaluate_set_elem(ctx, elem) < 0)
+ return -1;
+
+ key = ctx->set->key;
+ __expr_set_context(&ctx->ectx, key->dtype, key->byteorder, key->len, 0);
+ ctx->ectx.key = key;
+ }
+
+ if (expr_evaluate(ctx, &elem->key) < 0)
+ return -1;
+
+ if (ctx->set &&
+ !(ctx->set->flags & (NFT_SET_ANONYMOUS | NFT_SET_INTERVAL))) {
+ switch (elem->key->etype) {
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ 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;
+ }
+ }
+
+ datatype_set(elem, elem->key->dtype);
+ elem->len = elem->key->len;
+ elem->flags = elem->key->flags;
+
+ return 0;
+
+err_missing_flag:
+ return expr_error(ctx->msgs, key,
+ "You must add 'flags interval' to your %s declaration if you want to add %s elements",
+ set_is_map(ctx->set->flags) ? "map" : "set", expr_name(key));
+}
+
+static const struct expr *expr_set_elem(const struct expr *expr)
+{
+ if (expr->etype == EXPR_MAPPING)
+ return expr->left;
+
+ return expr;
+}
+
+static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
+ struct expr *init)
+{
+ int ret;
+
+ if (!init)
+ return 0;
+
+ ret = 0;
+ switch (ctx->cmd->op) {
+ case CMD_CREATE:
+ case CMD_ADD:
+ case CMD_INSERT:
+ if (set->automerge) {
+ ret = set_automerge(ctx->msgs, ctx->cmd, set, init,
+ ctx->nft->debug_mask);
+ } else {
+ ret = set_overlap(ctx->msgs, set, init);
+ }
+ break;
+ case CMD_DELETE:
+ case CMD_DESTROY:
+ ret = set_delete(ctx->msgs, ctx->cmd, set, init,
+ ctx->nft->debug_mask);
+ break;
+ case CMD_GET:
+ break;
+ default:
+ BUG("unhandled op %d\n", ctx->cmd->op);
+ break;
+ }
+
+ return ret;
+}
+
+static void expr_evaluate_set_ref(struct eval_ctx *ctx, struct expr *expr)
+{
+ struct set *set = expr->set;
+
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ ctx->ectx.key = set->key;
+}
+
+static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *set = *expr, *i, *next;
+ const struct expr *elem;
+
+ list_for_each_entry_safe(i, next, &set->expressions, list) {
+ if (list_member_evaluate(ctx, &i) < 0)
+ return -1;
+
+ if (i->etype == EXPR_MAPPING &&
+ i->left->etype == EXPR_SET_ELEM &&
+ i->left->key->etype == EXPR_SET) {
+ struct expr *new, *j;
+
+ list_for_each_entry(j, &i->left->key->expressions, list) {
+ new = mapping_expr_alloc(&i->location,
+ expr_get(j),
+ expr_get(i->right));
+ list_add_tail(&new->list, &set->expressions);
+ set->size++;
+ }
+ list_del(&i->list);
+ expr_free(i);
+ continue;
+ }
+
+ elem = expr_set_elem(i);
+
+ if (elem->etype == EXPR_SET_ELEM &&
+ elem->key->etype == EXPR_SET_REF)
+ return expr_error(ctx->msgs, i,
+ "Set reference cannot be part of another set");
+
+ if (elem->etype == EXPR_SET_ELEM &&
+ elem->key->etype == EXPR_SET) {
+ struct expr *new = expr_get(elem->key);
+
+ set->set_flags |= elem->key->set_flags;
+ list_replace(&i->list, &new->list);
+ expr_free(i);
+ i = new;
+ elem = expr_set_elem(i);
+ }
+
+ if (!expr_is_constant(i))
+ return expr_error(ctx->msgs, i,
+ "Set member is not constant");
+
+ if (i->etype == EXPR_SET) {
+ /* Merge recursive set definitions */
+ list_splice_tail_init(&i->expressions, &i->list);
+ list_del(&i->list);
+ set->size += i->size - 1;
+ set->set_flags |= i->set_flags;
+ expr_free(i);
+ } else if (!expr_is_singleton(i)) {
+ set->set_flags |= NFT_SET_INTERVAL;
+ if (elem->key->etype == EXPR_CONCAT)
+ set->set_flags |= NFT_SET_CONCAT;
+ }
+ }
+
+ if (ctx->set) {
+ if (ctx->set->flags & NFT_SET_CONCAT)
+ set->set_flags |= NFT_SET_CONCAT;
+ }
+
+ set->set_flags |= NFT_SET_CONSTANT;
+
+ datatype_set(set, ctx->ectx.dtype);
+ set->len = ctx->ectx.len;
+ set->flags |= EXPR_F_CONSTANT;
+
+ return 0;
+}
+
+static int binop_transfer(struct eval_ctx *ctx, struct expr **expr);
+
+static void map_set_concat_info(struct expr *map)
+{
+ map->mappings->set->flags |= map->mappings->set->init->set_flags;
+
+ if (map->mappings->set->flags & NFT_SET_INTERVAL &&
+ map->map->etype == EXPR_CONCAT) {
+ memcpy(&map->mappings->set->desc.field_len, &map->map->field_len,
+ sizeof(map->mappings->set->desc.field_len));
+ map->mappings->set->desc.field_count = map->map->field_count;
+ map->mappings->flags |= NFT_SET_CONCAT;
+ }
+}
+
+static void __mapping_expr_expand(struct expr *i)
+{
+ struct expr *j, *range, *next;
+
+ assert(i->etype == EXPR_MAPPING);
+ switch (i->right->etype) {
+ case EXPR_VALUE:
+ range = range_expr_alloc(&i->location, expr_get(i->right), expr_get(i->right));
+ expr_free(i->right);
+ i->right = range;
+ break;
+ case EXPR_CONCAT:
+ list_for_each_entry_safe(j, next, &i->right->expressions, list) {
+ if (j->etype != EXPR_VALUE)
+ continue;
+
+ range = range_expr_alloc(&j->location, expr_get(j), expr_get(j));
+ list_replace(&j->list, &range->list);
+ expr_free(j);
+ }
+ i->right->flags &= ~EXPR_F_SINGLETON;
+ break;
+ default:
+ break;
+ }
+}
+
+static int mapping_expr_expand(struct eval_ctx *ctx)
+{
+ struct expr *i;
+
+ if (!set_is_anonymous(ctx->set->flags))
+ return 0;
+
+ list_for_each_entry(i, &ctx->set->init->expressions, list) {
+ if (i->etype != EXPR_MAPPING)
+ return expr_error(ctx->msgs, i,
+ "expected mapping, not %s", expr_name(i));
+ __mapping_expr_expand(i);
+ }
+
+ return 0;
+}
+
+static bool datatype_compatible(const struct datatype *a, const struct datatype *b)
+{
+ return (a->type == TYPE_MARK &&
+ datatype_equal(datatype_basetype(a), datatype_basetype(b))) ||
+ datatype_equal(a, b);
+}
+
+static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *map = *expr, *mappings;
+ struct expr_ctx ectx = ctx->ectx;
+ struct expr *key, *data;
+
+ if (map->map->etype == EXPR_CT &&
+ (map->map->ct.key == NFT_CT_SRC ||
+ map->map->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, map->map,
+ "specify either ip or ip6 for address matching");
+ else if (map->map->etype == EXPR_CONCAT) {
+ struct expr *i;
+
+ list_for_each_entry(i, &map->map->expressions, list) {
+ if (i->etype == EXPR_CT &&
+ (i->ct.key == NFT_CT_SRC ||
+ i->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, i,
+ "specify either ip or ip6 for address matching");
+ }
+ }
+
+ expr_set_context(&ctx->ectx, NULL, 0);
+ ctx->stmt_len = 0;
+ if (expr_evaluate(ctx, &map->map) < 0)
+ return -1;
+ if (expr_is_constant(map->map))
+ return expr_error(ctx->msgs, map->map,
+ "Map expression can not be constant");
+
+ mappings = map->mappings;
+ mappings->set_flags |= NFT_SET_MAP;
+
+ switch (map->mappings->etype) {
+ case EXPR_SET:
+ if (ctx->ectx.key && ctx->ectx.key->etype == EXPR_CONCAT) {
+ key = expr_clone(ctx->ectx.key);
+ } else {
+ key = constant_expr_alloc(&map->location,
+ ctx->ectx.dtype,
+ ctx->ectx.byteorder,
+ ctx->ectx.len, NULL);
+ }
+
+ if (ectx.dtype->type == TYPE_VERDICT) {
+ data = verdict_expr_alloc(&netlink_location, 0, NULL);
+ } else {
+ const struct datatype *dtype;
+
+ dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
+ data = constant_expr_alloc(&netlink_location, dtype,
+ dtype->byteorder, ectx.len, NULL);
+ datatype_free(dtype);
+ }
+
+ mappings = implicit_set_declaration(ctx, "__map%d",
+ key, data,
+ mappings);
+
+ if (ectx.len && mappings->set->data->len != ectx.len)
+ BUG("%d vs %d\n", mappings->set->data->len, ectx.len);
+
+ map->mappings = mappings;
+
+ ctx->set = mappings->set;
+ if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
+ return -1;
+
+ if (set_is_interval(map->mappings->set->init->set_flags) &&
+ !(map->mappings->set->init->set_flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0)
+ return -1;
+
+ expr_set_context(&ctx->ectx, ctx->set->key->dtype, ctx->set->key->len);
+ if (binop_transfer(ctx, expr) < 0)
+ return -1;
+
+ if (ctx->set->data->flags & EXPR_F_INTERVAL) {
+ ctx->set->data->len *= 2;
+
+ if (mapping_expr_expand(ctx))
+ return -1;
+ }
+
+ ctx->set->key->len = ctx->ectx.len;
+ ctx->set = NULL;
+ map = *expr;
+
+ map_set_concat_info(map);
+ break;
+ case EXPR_SYMBOL:
+ if (expr_evaluate(ctx, &map->mappings) < 0)
+ return -1;
+ if (map->mappings->etype != EXPR_SET_REF ||
+ !set_is_datamap(map->mappings->set->flags))
+ return expr_error(ctx->msgs, map->mappings,
+ "Expression is not a map");
+ break;
+ case EXPR_SET_REF:
+ /* symbol has been already evaluated to set reference */
+ break;
+ default:
+ BUG("invalid mapping expression %s\n",
+ expr_name(map->mappings));
+ }
+
+ if (!datatype_compatible(map->mappings->set->key->dtype, map->map->dtype))
+ return expr_binary_error(ctx->msgs, map->mappings, map->map,
+ "datatype mismatch, map expects %s, "
+ "mapping expression has type %s",
+ map->mappings->set->key->dtype->desc,
+ map->map->dtype->desc);
+
+ datatype_set(map, map->mappings->set->data->dtype);
+ map->flags |= EXPR_F_CONSTANT;
+
+ /* Data for range lookups needs to be in big endian order */
+ if (map->mappings->set->flags & NFT_SET_INTERVAL &&
+ byteorder_conversion(ctx, &map->map, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+
+ return 0;
+}
+
+static bool data_mapping_has_interval(struct expr *data)
+{
+ struct expr *i;
+
+ if (data->etype == EXPR_RANGE ||
+ data->etype == EXPR_PREFIX)
+ return true;
+
+ if (data->etype != EXPR_CONCAT)
+ return false;
+
+ list_for_each_entry(i, &data->expressions, list) {
+ if (i->etype == EXPR_RANGE ||
+ i->etype == EXPR_PREFIX)
+ return true;
+ }
+
+ return false;
+}
+
+static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *mapping = *expr;
+ struct set *set = ctx->set;
+ uint32_t datalen;
+
+ if (set == NULL)
+ return expr_error(ctx->msgs, mapping,
+ "mapping outside of map context");
+ if (!set_is_map(set->flags))
+ return set_error(ctx, set, "set is not a map");
+
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ if (expr_evaluate(ctx, &mapping->left) < 0)
+ return -1;
+ if (!expr_is_constant(mapping->left))
+ return expr_error(ctx->msgs, mapping->left,
+ "Key must be a constant");
+ mapping->flags |= mapping->left->flags & EXPR_F_SINGLETON;
+
+ assert(set->data != NULL);
+ if (!set_is_anonymous(set->flags) &&
+ set->data->flags & EXPR_F_INTERVAL)
+ datalen = set->data->len / 2;
+ else
+ datalen = set->data->len;
+ __expr_set_context(&ctx->ectx, set->data->dtype,
+ set->data->byteorder, datalen, 0);
+
+ if (expr_evaluate(ctx, &mapping->right) < 0)
+ return -1;
+ if (!expr_is_constant(mapping->right))
+ return expr_error(ctx->msgs, mapping->right,
+ "Value must be a constant");
+
+ if (set_is_anonymous(set->flags) &&
+ data_mapping_has_interval(mapping->right))
+ set->data->flags |= EXPR_F_INTERVAL;
+
+ if (!set_is_anonymous(set->flags) &&
+ set->data->flags & EXPR_F_INTERVAL)
+ __mapping_expr_expand(mapping);
+
+ if (!(set->data->flags & EXPR_F_INTERVAL) &&
+ !expr_is_singleton(mapping->right))
+ return expr_error(ctx->msgs, mapping->right,
+ "Value must be a singleton");
+
+ mapping->flags |= EXPR_F_CONSTANT;
+ return 0;
+}
+
+/* We got datatype context via statement. If the basetype is compatible, set
+ * this expression datatype to the one of the statement to make it datatype
+ * compatible. This is a more conservative approach than enabling datatype
+ * compatibility between two different datatypes whose basetype is the same,
+ * let's revisit this later once users come with valid usecases to generalize
+ * this.
+ */
+static void expr_dtype_integer_compatible(struct eval_ctx *ctx,
+ struct expr *expr)
+{
+ if (ctx->ectx.dtype &&
+ ctx->ectx.dtype->basetype == &integer_type &&
+ ctx->ectx.len == 4 * BITS_PER_BYTE) {
+ datatype_set(expr, ctx->ectx.dtype);
+ expr->len = ctx->ectx.len;
+ }
+}
+
+static int expr_evaluate_numgen(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+ unsigned int maxval;
+
+ expr_dtype_integer_compatible(ctx, expr);
+
+ maxval = expr->numgen.mod + expr->numgen.offset - 1;
+ __expr_set_context(&ctx->ectx, expr->dtype, expr->byteorder, expr->len,
+ maxval);
+ return 0;
+}
+
+static int expr_evaluate_hash(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+ unsigned int maxval;
+
+ expr_dtype_integer_compatible(ctx, expr);
+
+ expr_set_context(&ctx->ectx, NULL, 0);
+ if (expr->hash.expr &&
+ expr_evaluate(ctx, &expr->hash.expr) < 0)
+ return -1;
+
+ /* expr_evaluate_primary() sets the context to what to the input
+ * expression to be hashed. Since this input is transformed to a 4 bytes
+ * integer, restore context to the datatype that results from hashing.
+ */
+ maxval = expr->hash.mod + expr->hash.offset - 1;
+ __expr_set_context(&ctx->ectx, expr->dtype, expr->byteorder, expr->len,
+ maxval);
+
+ return 0;
+}
+
+/*
+ * Transfer the invertible binops to the constant side of an equality
+ * expression. A left shift is only invertible if the low n bits are
+ * zero.
+ */
+static int binop_can_transfer(struct eval_ctx *ctx,
+ struct expr *left, struct expr *right)
+{
+ int err;
+
+ switch (right->etype) {
+ case EXPR_VALUE:
+ break;
+ case EXPR_SET_ELEM:
+ return binop_can_transfer(ctx, left, right->key);
+ case EXPR_RANGE:
+ err = binop_can_transfer(ctx, left, right->left);
+ if (err <= 0)
+ return err;
+ return binop_can_transfer(ctx, left, right->right);
+ case EXPR_MAPPING:
+ return binop_can_transfer(ctx, left, right->left);
+ default:
+ return 0;
+ }
+
+ switch (left->op) {
+ case OP_LSHIFT:
+ if (mpz_scan1(right->value, 0) < mpz_get_uint32(left->right->value))
+ return expr_binary_error(ctx->msgs, right, left,
+ "Comparison is always false");
+ return 1;
+ case OP_RSHIFT:
+ if (ctx->ectx.len < right->len + mpz_get_uint32(left->right->value))
+ ctx->ectx.len += mpz_get_uint32(left->right->value);
+ return 1;
+ case OP_XOR:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int binop_transfer_one(struct eval_ctx *ctx,
+ const struct expr *left, struct expr **right)
+{
+ int err;
+
+ switch ((*right)->etype) {
+ case EXPR_MAPPING:
+ return binop_transfer_one(ctx, left, &(*right)->left);
+ case EXPR_VALUE:
+ break;
+ case EXPR_SET_ELEM:
+ return binop_transfer_one(ctx, left, &(*right)->key);
+ case EXPR_RANGE:
+ err = binop_transfer_one(ctx, left, &(*right)->left);
+ if (err < 0)
+ return err;
+ return binop_transfer_one(ctx, left, &(*right)->right);
+ default:
+ return 0;
+ }
+
+ switch (left->op) {
+ case OP_LSHIFT:
+ (*right) = binop_expr_alloc(&(*right)->location, OP_RSHIFT,
+ *right, expr_get(left->right));
+ break;
+ case OP_RSHIFT:
+ (*right) = binop_expr_alloc(&(*right)->location, OP_LSHIFT,
+ *right, expr_get(left->right));
+ break;
+ case OP_XOR:
+ (*right) = binop_expr_alloc(&(*right)->location, OP_XOR,
+ *right, expr_get(left->right));
+ break;
+ default:
+ BUG("invalid binary operation %u\n", left->op);
+ }
+
+ return expr_evaluate(ctx, right);
+}
+
+static void binop_transfer_handle_lhs(struct expr **expr)
+{
+ struct expr *tmp, *left = *expr;
+ unsigned int shift;
+
+ assert(left->etype == EXPR_BINOP);
+
+ switch (left->op) {
+ case OP_RSHIFT:
+ /* Mask out the bits the shift would have masked out */
+ shift = mpz_get_uint8(left->right->value);
+ mpz_bitmask(left->right->value, left->left->len);
+ mpz_lshift_ui(left->right->value, shift);
+ left->op = OP_AND;
+ break;
+ case OP_LSHIFT:
+ case OP_XOR:
+ tmp = expr_get(left->left);
+ datatype_set(tmp, left->dtype);
+ expr_free(left);
+ *expr = tmp;
+ break;
+ default:
+ BUG("invalid binop operation %u", left->op);
+ }
+}
+
+static int __binop_transfer(struct eval_ctx *ctx,
+ struct expr *left, struct expr **right)
+{
+ struct expr *i, *next;
+ int err;
+
+ assert(left->etype == EXPR_BINOP);
+
+ switch ((*right)->etype) {
+ case EXPR_VALUE:
+ err = binop_can_transfer(ctx, left, *right);
+ if (err <= 0)
+ return err;
+ if (binop_transfer_one(ctx, left, right) < 0)
+ return -1;
+ break;
+ case EXPR_RANGE:
+ err = binop_can_transfer(ctx, left, *right);
+ if (err <= 0)
+ return err;
+ if (binop_transfer_one(ctx, left, right) < 0)
+ return -1;
+ break;
+ case EXPR_SET:
+ list_for_each_entry(i, &(*right)->expressions, list) {
+ err = binop_can_transfer(ctx, left, i);
+ if (err <= 0)
+ return err;
+ }
+ list_for_each_entry_safe(i, next, &(*right)->expressions, list) {
+ list_del(&i->list);
+ err = binop_transfer_one(ctx, left, &i);
+ list_add_tail(&i->list, &next->list);
+ if (err < 0)
+ return err;
+ }
+ break;
+ case EXPR_SET_REF:
+ if (!set_is_anonymous((*right)->set->flags))
+ return 0;
+
+ return __binop_transfer(ctx, left, &(*right)->set->init);
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct expr *left = (*expr)->left;
+ int ret;
+
+ if (left->etype != EXPR_BINOP)
+ return 0;
+
+ ret = __binop_transfer(ctx, left, &(*expr)->right);
+ if (ret <= 0)
+ return ret;
+
+ binop_transfer_handle_lhs(&(*expr)->left);
+ return 0;
+}
+
+static bool lhs_is_meta_hour(const struct expr *meta)
+{
+ if (meta->etype != EXPR_META)
+ return false;
+
+ return meta->meta.key == NFT_META_TIME_HOUR ||
+ meta->meta.key == NFT_META_TIME_DAY;
+}
+
+static void swap_values(struct expr *range)
+{
+ struct expr *left_tmp;
+
+ left_tmp = range->left;
+ range->left = range->right;
+ range->right = left_tmp;
+}
+
+static bool range_needs_swap(const struct expr *range)
+{
+ const struct expr *right = range->right;
+ const struct expr *left = range->left;
+
+ 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)
+ return ret;
+
+ range = rel->right;
+
+ /*
+ * We may need to do this for proper cross-day ranges,
+ * e.g. meta hour 23:15-03:22
+ */
+ if (range_needs_swap(range)) {
+ if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION)
+ nft_print(&ctx->nft->output,
+ "Inverting range values for cross-day hour matching\n\n");
+
+ if (rel->op == OP_EQ || rel->op == OP_IMPLICIT) {
+ swap_values(range);
+ rel->op = OP_NEQ;
+ } else if (rel->op == OP_NEQ) {
+ swap_values(range);
+ rel->op = OP_EQ;
+ }
+ }
+ }
+
+ if (expr_evaluate(ctx, &rel->right) < 0)
+ return -1;
+ right = rel->right;
+
+ if (!expr_is_constant(right))
+ return expr_binary_error(ctx->msgs, right, rel,
+ "Right hand side of relational "
+ "expression (%s) must be constant",
+ expr_op_symbols[rel->op]);
+ if (expr_is_constant(left))
+ return expr_binary_error(ctx->msgs, left, right,
+ "Relational expression (%s) has "
+ "constant value",
+ expr_op_symbols[rel->op]);
+
+ if (!datatype_equal(left->dtype, right->dtype))
+ return expr_binary_error(ctx->msgs, right, left,
+ "datatype mismatch, expected %s, "
+ "expression has type %s",
+ left->dtype->desc,
+ right->dtype->desc);
+
+ /*
+ * Statements like 'ct secmark 12' are parsed as relational,
+ * disallow constant value on the right hand side.
+ */
+ if (((left->etype == EXPR_META &&
+ left->meta.key == NFT_META_SECMARK) ||
+ (left->etype == EXPR_CT &&
+ left->ct.key == NFT_CT_SECMARK)) &&
+ right->flags & EXPR_F_CONSTANT)
+ return expr_binary_error(ctx->msgs, right, left,
+ "Cannot be used with right hand side constant value");
+
+ 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:
+ /*
+ * Update protocol context for payload and meta iiftype
+ * equality expressions.
+ */
+ relational_expr_pctx_update(pctx, rel);
+
+ /* fall through */
+ case OP_NEQ:
+ case OP_NEG:
+ if (rel->op == OP_NEG) {
+ if (left->etype == EXPR_BINOP)
+ return expr_binary_error(ctx->msgs, left, right,
+ "cannot combine negation with binary expression");
+ if (right->etype != EXPR_VALUE ||
+ right->dtype->basetype == NULL ||
+ right->dtype->basetype->type != TYPE_BITMASK)
+ return expr_binary_error(ctx->msgs, left, right,
+ "negation can only be used with singleton bitmask values. Did you mean \"!=\"?");
+ }
+
+ switch (right->etype) {
+ case EXPR_RANGE:
+ if (byteorder_conversion(ctx, &rel->left, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+ if (byteorder_conversion(ctx, &right->left, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+ if (byteorder_conversion(ctx, &right->right, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+ break;
+ case EXPR_PREFIX:
+ if (byteorder_conversion(ctx, &right->prefix, left->byteorder) < 0)
+ return -1;
+ break;
+ case EXPR_VALUE:
+ if (byteorder_conversion(ctx, &rel->right, left->byteorder) < 0)
+ return -1;
+ break;
+ case EXPR_SET:
+ if (right->size == 0)
+ return expr_error(ctx->msgs, right, "Set is empty");
+
+ right = rel->right =
+ implicit_set_declaration(ctx, "__set%d",
+ expr_get(left), NULL,
+ right);
+ /* fall through */
+ case EXPR_SET_REF:
+ if (rel->left->etype == EXPR_CT &&
+ (rel->left->ct.key == NFT_CT_SRC ||
+ rel->left->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, left,
+ "specify either ip or ip6 for address matching");
+
+ /* Data for range lookups needs to be in big endian order */
+ if (right->set->flags & NFT_SET_INTERVAL &&
+ byteorder_conversion(ctx, &rel->left, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+ break;
+ case EXPR_CONCAT:
+ return expr_binary_error(ctx->msgs, left, right,
+ "Use concatenations with sets and maps, not singleton values");
+ break;
+ default:
+ BUG("invalid expression type %s\n", expr_name(right));
+ }
+ break;
+ case OP_LT:
+ case OP_GT:
+ case OP_LTE:
+ case OP_GTE:
+ switch (left->etype) {
+ case EXPR_CONCAT:
+ return expr_binary_error(ctx->msgs, left, rel,
+ "Relational expression (%s) is undefined "
+ "for %s expressions",
+ expr_op_symbols[rel->op],
+ expr_name(left));
+ default:
+ break;
+ }
+
+ if (!expr_is_singleton(right))
+ return expr_binary_error(ctx->msgs, right, rel,
+ "Relational expression (%s) is undefined "
+ "for %s expressions",
+ expr_op_symbols[rel->op],
+ expr_name(right));
+
+ if (byteorder_conversion(ctx, &rel->left, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+ if (byteorder_conversion(ctx, &rel->right, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+ break;
+ default:
+ BUG("invalid relational operation %u\n", rel->op);
+ }
+
+ if (binop_transfer(ctx, expr) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int expr_evaluate_fib(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+
+ if (expr->flags & EXPR_F_BOOLEAN) {
+ expr->fib.flags |= NFTA_FIB_F_PRESENT;
+ datatype_set(expr, &boolean_type);
+ }
+ return expr_evaluate_primary(ctx, 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 (pctx->family != NFPROTO_INET &&
+ meta->flags & EXPR_F_PROTOCOL)
+ return expr_error(ctx->msgs, meta,
+ "meta nfproto is only useful in the inet family");
+ break;
+ case NFT_META_TIME_DAY:
+ __expr_set_context(&ctx->ectx, meta->dtype, meta->byteorder,
+ meta->len, 6);
+ return 0;
+ default:
+ break;
+ }
+
+ return expr_evaluate_primary(ctx, exprp);
+}
+
+static int expr_evaluate_socket(struct eval_ctx *ctx, struct expr **expr)
+{
+ enum nft_socket_keys key = (*expr)->socket.key;
+ int maxval = 0;
+
+ if (key == NFT_SOCKET_TRANSPARENT ||
+ key == NFT_SOCKET_WILDCARD)
+ maxval = 1;
+ __expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->byteorder,
+ (*expr)->len, maxval);
+ return 0;
+}
+
+static int expr_evaluate_osf(struct eval_ctx *ctx, struct expr **expr)
+{
+ struct netlink_ctx nl_ctx = {
+ .nft = ctx->nft,
+ .seqnum = time(NULL),
+ };
+
+ nfnl_osf_load_fingerprints(&nl_ctx, 0);
+
+ return expr_evaluate_primary(ctx, expr);
+}
+
+static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct symbol *sym = (*exprp)->sym;
+ struct expr *new;
+
+ /* If variable is reused from different locations in the ruleset, then
+ * clone expression.
+ */
+ if (sym->refcnt > 2)
+ new = expr_clone(sym->expr);
+ else
+ new = expr_get(sym->expr);
+
+ if (expr_evaluate(ctx, &new) < 0) {
+ expr_free(new);
+ return -1;
+ }
+
+ expr_free(*exprp);
+ *exprp = new;
+
+ return 0;
+}
+
+static int expr_evaluate_xfrm(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ struct expr *expr = *exprp;
+
+ switch (pctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_INET:
+ break;
+ default:
+ return expr_error(ctx->msgs, expr, "ipsec expression is only"
+ " valid in ip/ip6/inet tables");
+ }
+
+ return expr_evaluate_primary(ctx, exprp);
+}
+
+static int expr_evaluate_flagcmp(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp, *binop, *rel;
+
+ if (expr->op != OP_EQ &&
+ expr->op != OP_NEQ)
+ return expr_error(ctx->msgs, expr, "either == or != is allowed");
+
+ binop = binop_expr_alloc(&expr->location, OP_AND,
+ expr_get(expr->flagcmp.expr),
+ expr_get(expr->flagcmp.mask));
+ rel = relational_expr_alloc(&expr->location, expr->op, binop,
+ expr_get(expr->flagcmp.value));
+ expr_free(expr);
+ *exprp = rel;
+
+ return expr_evaluate(ctx, exprp);
+}
+
+static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
+{
+ if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION) {
+ struct error_record *erec;
+ erec = erec_create(EREC_INFORMATIONAL, &(*expr)->location,
+ "Evaluate %s", expr_name(*expr));
+ erec_print(&ctx->nft->output, erec, ctx->nft->debug_mask);
+ expr_print(*expr, &ctx->nft->output);
+ nft_print(&ctx->nft->output, "\n\n");
+ erec_destroy(erec);
+ }
+
+ switch ((*expr)->etype) {
+ case EXPR_SYMBOL:
+ return expr_evaluate_symbol(ctx, 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);
+ case EXPR_META:
+ return expr_evaluate_meta(ctx, expr);
+ case EXPR_SOCKET:
+ return expr_evaluate_socket(ctx, expr);
+ case EXPR_OSF:
+ return expr_evaluate_osf(ctx, expr);
+ case EXPR_FIB:
+ return expr_evaluate_fib(ctx, expr);
+ case EXPR_PAYLOAD:
+ return expr_evaluate_payload_inner(ctx, expr);
+ case EXPR_RT:
+ return expr_evaluate_rt(ctx, expr);
+ case EXPR_CT:
+ return expr_evaluate_ct(ctx, expr);
+ case EXPR_PREFIX:
+ return expr_evaluate_prefix(ctx, expr);
+ case EXPR_RANGE:
+ return expr_evaluate_range(ctx, expr);
+ case EXPR_UNARY:
+ return expr_evaluate_unary(ctx, expr);
+ case EXPR_BINOP:
+ return expr_evaluate_binop(ctx, expr);
+ case EXPR_CONCAT:
+ return expr_evaluate_concat(ctx, expr);
+ case EXPR_LIST:
+ return expr_evaluate_list(ctx, expr);
+ case EXPR_SET:
+ return expr_evaluate_set(ctx, expr);
+ case EXPR_SET_ELEM:
+ return expr_evaluate_set_elem(ctx, expr);
+ case EXPR_MAP:
+ return expr_evaluate_map(ctx, expr);
+ case EXPR_MAPPING:
+ return expr_evaluate_mapping(ctx, expr);
+ case EXPR_RELATIONAL:
+ return expr_evaluate_relational(ctx, expr);
+ case EXPR_NUMGEN:
+ return expr_evaluate_numgen(ctx, expr);
+ case EXPR_HASH:
+ return expr_evaluate_hash(ctx, expr);
+ case EXPR_XFRM:
+ return expr_evaluate_xfrm(ctx, expr);
+ case EXPR_SET_ELEM_CATCHALL:
+ return 0;
+ case EXPR_FLAGCMP:
+ return expr_evaluate_flagcmp(ctx, expr);
+ default:
+ BUG("unknown expression type %s\n", expr_name(*expr));
+ }
+}
+
+static int stmt_evaluate_expr(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ memset(&ctx->ectx, 0, sizeof(ctx->ectx));
+ return expr_evaluate(ctx, &stmt->expr);
+}
+
+static int stmt_prefix_conversion(struct eval_ctx *ctx, struct expr **expr,
+ enum byteorder byteorder)
+{
+ struct expr *mask, *and, *or, *prefix, *base, *range;
+ int ret;
+
+ prefix = *expr;
+ base = prefix->prefix;
+
+ if (base->etype != EXPR_VALUE)
+ return expr_error(ctx->msgs, prefix,
+ "you cannot specify a prefix here, "
+ "unknown type %s", base->dtype->name);
+
+ if (!expr_is_constant(base))
+ return expr_error(ctx->msgs, prefix,
+ "Prefix expression is undefined for "
+ "non-constant expressions");
+
+ if (expr_basetype(base)->type != TYPE_INTEGER)
+ return expr_error(ctx->msgs, prefix,
+ "Prefix expression expected integer value");
+
+ mask = constant_expr_alloc(&prefix->location, expr_basetype(base),
+ BYTEORDER_HOST_ENDIAN, base->len, NULL);
+
+ mpz_prefixmask(mask->value, base->len, prefix->prefix_len);
+ and = binop_expr_alloc(&prefix->location, OP_AND, expr_get(base), mask);
+
+ mask = constant_expr_alloc(&prefix->location, expr_basetype(base),
+ BYTEORDER_HOST_ENDIAN, base->len, NULL);
+ mpz_bitmask(mask->value, prefix->len - prefix->prefix_len);
+ or = binop_expr_alloc(&prefix->location, OP_OR, expr_get(base), mask);
+
+ range = range_expr_alloc(&prefix->location, and, or);
+ ret = expr_evaluate(ctx, &range);
+ if (ret < 0) {
+ expr_free(range);
+ return ret;
+ }
+
+ expr_free(*expr);
+ *expr = range;
+ return 0;
+}
+
+static int __stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ if ((*expr)->etype == EXPR_PAYLOAD &&
+ (*expr)->dtype->type == TYPE_INTEGER &&
+ ((*expr)->dtype->type != datatype_basetype(dtype)->type ||
+ (*expr)->len != len))
+ return stmt_binary_error(ctx, *expr, stmt,
+ "datatype mismatch: expected %s, "
+ "expression has type %s with length %d",
+ dtype->desc, (*expr)->dtype->desc,
+ (*expr)->len);
+
+ 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:
+ return stmt_binary_error(ctx, *expr, stmt,
+ "you cannot use a set here, unknown "
+ "value to use");
+ case EXPR_SET_REF:
+ return stmt_binary_error(ctx, *expr, stmt,
+ "you cannot reference a set here, "
+ "unknown value to use");
+ case EXPR_RT:
+ 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;
+ }
+
+ return 0;
+}
+
+static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ __expr_set_context(&ctx->ectx, dtype, byteorder, len, 0);
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
+/* like stmt_evaluate_arg, but keep existing context created
+ * by previous expr_evaluate().
+ *
+ * This is needed for add/update statements:
+ * ctx->ectx.key has the set key, which may be needed for 'typeof'
+ * sets: the 'add/update' expression might contain integer data types.
+ *
+ * Without the key we cannot derive the element size.
+ */
+static int stmt_evaluate_key(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
+static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ if (stmt_evaluate_arg(ctx, stmt, &verdict_type, 0, 0, &stmt->expr) < 0)
+ return -1;
+
+ switch (stmt->expr->etype) {
+ case EXPR_VERDICT:
+ if (stmt->expr->verdict != NFT_CONTINUE)
+ stmt->flags |= STMT_F_TERMINAL;
+ if (stmt->expr->chain != NULL) {
+ 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");
+ }
+ }
+ break;
+ case EXPR_MAP:
+ break;
+ default:
+ BUG("invalid verdict expression %s\n", expr_name(stmt->expr));
+ }
+ return 0;
+}
+
+static bool stmt_evaluate_payload_need_csum(const struct expr *payload)
+{
+ const struct proto_desc *desc;
+
+ if (payload->payload.base == PROTO_BASE_INNER_HDR)
+ return true;
+
+ desc = payload->payload.desc;
+
+ return desc && desc->checksum_key;
+}
+
+static int stmt_evaluate_exthdr(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *exthdr;
+
+ 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);
+}
+
+static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *mask, *and, *xor, *payload_bytes;
+ unsigned int masklen, extra_len = 0;
+ unsigned int payload_byte_size, payload_byte_offset;
+ uint8_t shift_imm, data[NFT_REG_SIZE];
+ struct expr *payload;
+ 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;
+
+ payload = stmt->payload.expr;
+ if (stmt_evaluate_arg(ctx, stmt, payload->dtype, payload->len,
+ payload->byteorder, &stmt->payload.val) < 0)
+ return -1;
+
+ if (!expr_is_constant(stmt->payload.val) &&
+ byteorder_conversion(ctx, &stmt->payload.val,
+ payload->byteorder) < 0)
+ return -1;
+
+ need_csum = stmt_evaluate_payload_need_csum(payload);
+
+ if (!payload_needs_adjustment(payload)) {
+
+ /* We still need to munge the payload in case we have to
+ * update checksum and the length is not even because
+ * kernel checksum functions cannot deal with odd lengths.
+ */
+ if (!need_csum || ((payload->len / BITS_PER_BYTE) & 1) == 0)
+ return 0;
+ }
+
+ payload_byte_offset = payload->payload.offset / BITS_PER_BYTE;
+
+ shift_imm = expr_offset_shift(payload, payload->payload.offset,
+ &extra_len);
+ payload_byte_size = div_round_up(payload->len + extra_len,
+ BITS_PER_BYTE);
+
+ if (need_csum && payload_byte_size & 1) {
+ payload_byte_size++;
+
+ if (payload_byte_offset & 1) { /* prefer 16bit aligned fetch */
+ payload_byte_offset--;
+ assert(payload->payload.offset >= BITS_PER_BYTE);
+ } else {
+ shift_imm += BITS_PER_BYTE;
+ }
+ }
+
+ if (shift_imm) {
+ struct expr *off, *lshift;
+
+ off = constant_expr_alloc(&payload->location,
+ expr_basetype(payload),
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(shift_imm), &shift_imm);
+
+ lshift = binop_expr_alloc(&payload->location, OP_LSHIFT,
+ stmt->payload.val, off);
+ lshift->dtype = payload->dtype;
+ lshift->byteorder = payload->byteorder;
+
+ stmt->payload.val = lshift;
+ }
+
+ masklen = payload_byte_size * BITS_PER_BYTE;
+ mpz_init_bitmask(ff, masklen);
+
+ mpz_init2(bitmask, masklen);
+ mpz_bitmask(bitmask, payload->len);
+ mpz_lshift_ui(bitmask, shift_imm);
+
+ mpz_xor(bitmask, ff, bitmask);
+ mpz_clear(ff);
+
+ assert(sizeof(data) * BITS_PER_BYTE >= masklen);
+ mpz_export_data(data, bitmask, payload->byteorder, payload_byte_size);
+ mask = constant_expr_alloc(&payload->location, expr_basetype(payload),
+ payload->byteorder, masklen, data);
+ mpz_clear(bitmask);
+
+ payload_bytes = payload_expr_alloc(&payload->location, NULL, 0);
+ payload_init_raw(payload_bytes, payload->payload.base,
+ payload_byte_offset * BITS_PER_BYTE,
+ payload_byte_size * BITS_PER_BYTE);
+
+ payload_bytes->payload.is_raw = 1;
+ payload_bytes->payload.desc = payload->payload.desc;
+ payload_bytes->byteorder = payload->byteorder;
+
+ payload->len = payload_bytes->len;
+ payload->payload.offset = payload_bytes->payload.offset;
+
+ and = binop_expr_alloc(&payload->location, OP_AND, payload_bytes, mask);
+
+ and->dtype = payload_bytes->dtype;
+ and->byteorder = payload_bytes->byteorder;
+ and->len = payload_bytes->len;
+
+ xor = binop_expr_alloc(&payload->location, OP_XOR, and,
+ stmt->payload.val);
+ xor->dtype = payload->dtype;
+ xor->byteorder = payload->byteorder;
+ xor->len = mask->len;
+
+ stmt->payload.val = xor;
+
+ return expr_evaluate(ctx, &stmt->payload.val);
+}
+
+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)
+ return -1;
+ if (expr_is_constant(stmt->meter.key))
+ return expr_error(ctx->msgs, stmt->meter.key,
+ "Meter key expression can not be constant");
+ if (stmt->meter.key->comment)
+ return expr_error(ctx->msgs, stmt->meter.key,
+ "Meter key expression can not contain comments");
+
+ /* Declare an empty set */
+ key = stmt->meter.key;
+ set = set_expr_alloc(&key->location, NULL);
+ set->set_flags |= NFT_SET_EVAL;
+ if (key->timeout)
+ set->set_flags |= NFT_SET_TIMEOUT;
+
+ setref = implicit_set_declaration(ctx, stmt->meter.name,
+ expr_get(key), NULL, set);
+
+ setref->set->desc.size = stmt->meter.size;
+ stmt->meter.set = setref;
+
+ if (stmt_evaluate(ctx, stmt->meter.stmt) < 0)
+ return -1;
+ if (!(stmt->meter.stmt->flags & STMT_F_STATEFUL))
+ return stmt_binary_error(ctx, stmt->meter.stmt, stmt,
+ "meter statement must be stateful");
+
+ return 0;
+}
+
+static int stmt_evaluate_meta(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ 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);
+ ctx->stmt_len = 0;
+
+ return ret;
+}
+
+static int stmt_evaluate_ct(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ 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);
+ ctx->stmt_len = 0;
+
+ 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");
+
+ return 0;
+}
+
+static int reject_payload_gen_dependency_tcp(struct eval_ctx *ctx,
+ struct stmt *stmt,
+ struct expr **payload)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_desc *desc;
+
+ desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+ if (desc != NULL)
+ return 0;
+ *payload = payload_expr_alloc(&stmt->location, &proto_tcp,
+ TCPHDR_UNSPEC);
+ return 1;
+}
+
+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 = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (base != NULL)
+ return 0;
+
+ if (stmt->reject.icmp_code < 0)
+ return stmt_error(ctx, stmt, "missing icmp error type");
+
+ /* Generate a network dependency */
+ switch (stmt->reject.family) {
+ case NFPROTO_IPV4:
+ *payload = payload_expr_alloc(&stmt->location, &proto_ip,
+ IPHDR_PROTOCOL);
+ break;
+ case NFPROTO_IPV6:
+ *payload = payload_expr_alloc(&stmt->location, &proto_ip6,
+ IP6HDR_NEXTHDR);
+ break;
+ default:
+ BUG("unknown reject family");
+ }
+ return 1;
+}
+
+static int stmt_reject_gen_dependency(struct eval_ctx *ctx, struct stmt *stmt,
+ struct expr *expr)
+{
+ struct expr *payload = NULL;
+ struct stmt *nstmt;
+ int ret;
+
+ switch (stmt->reject.type) {
+ case NFT_REJECT_TCP_RST:
+ ret = reject_payload_gen_dependency_tcp(ctx, stmt, &payload);
+ break;
+ case NFT_REJECT_ICMP_UNREACH:
+ ret = reject_payload_gen_dependency_family(ctx, stmt, &payload);
+ break;
+ default:
+ BUG("cannot generate reject dependency for type %d",
+ stmt->reject.type);
+ }
+ if (ret <= 0)
+ return ret;
+
+ if (payload_gen_dependency(ctx, payload, &nstmt) < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * Unlike payload deps this adds the dependency at the beginning, i.e.
+ * log ... reject with tcp-reset
+ * turns into
+ * meta l4proto tcp log ... reject with tcp-reset
+ *
+ * Otherwise we'd log things that won't be rejected.
+ */
+ list_add(&nstmt->list, &ctx->rule->stmts);
+out:
+ xfree(payload);
+ return ret;
+}
+
+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;
+
+ switch (stmt->reject.type) {
+ case NFT_REJECT_TCP_RST:
+ break;
+ case NFT_REJECT_ICMPX_UNREACH:
+ break;
+ case NFT_REJECT_ICMP_UNREACH:
+ base = pctx->protocol[PROTO_BASE_LL_HDR].desc;
+ protocol = proto_find_num(base, desc);
+ switch (protocol) {
+ case NFPROTO_IPV4:
+ case __constant_htons(ETH_P_IP):
+ if (stmt->reject.family == NFPROTO_IPV4)
+ break;
+ return stmt_binary_error(ctx, stmt->reject.expr,
+ &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,
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
+ "conflicting protocols specified: ip vs ip6");
+ default:
+ return stmt_error(ctx, stmt,
+ "cannot infer ICMP reject variant to use: explicit value required.\n");
+ }
+ break;
+ }
+
+ return 0;
+}
+
+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 = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc != NULL &&
+ stmt_evaluate_reject_inet_family(ctx, stmt, desc) < 0)
+ return -1;
+ if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
+ return 0;
+ if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+ return -1;
+ return 0;
+}
+
+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 = pctx->protocol[PROTO_BASE_LL_HDR].desc;
+ protocol = proto_find_num(base, desc);
+ switch (protocol) {
+ case __constant_htons(ETH_P_IP):
+ case __constant_htons(ETH_P_IPV6):
+ break;
+ default:
+ return stmt_binary_error(ctx, stmt,
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
+ "cannot reject this network family");
+ }
+ break;
+ case NFT_REJECT_ICMP_UNREACH:
+ 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,
+ &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,
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
+ "conflicting protocols specified: ip vs ip6");
+ default:
+ return stmt_binary_error(ctx, stmt,
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
+ "cannot reject this network family");
+ }
+ break;
+ }
+
+ return 0;
+}
+
+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 = 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 = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc != NULL &&
+ stmt_evaluate_reject_bridge_family(ctx, stmt, desc) < 0)
+ return -1;
+ if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
+ return 0;
+ if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+ return -1;
+ return 0;
+}
+
+static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
+ struct expr *expr)
+{
+ 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:
+ case NFPROTO_IPV6:
+ switch (stmt->reject.type) {
+ case NFT_REJECT_TCP_RST:
+ if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+ return -1;
+ break;
+ case NFT_REJECT_ICMPX_UNREACH:
+ return stmt_binary_error(ctx, stmt->reject.expr, stmt,
+ "abstracted ICMP unreachable not supported");
+ case NFT_REJECT_ICMP_UNREACH:
+ if (stmt->reject.family == pctx->family)
+ break;
+ return stmt_binary_error(ctx, stmt->reject.expr, stmt,
+ "conflicting protocols specified: ip vs ip6");
+ }
+ break;
+ case NFPROTO_BRIDGE:
+ case NFPROTO_NETDEV:
+ if (stmt_evaluate_reject_bridge(ctx, stmt, expr) < 0)
+ return -1;
+ break;
+ case NFPROTO_INET:
+ if (stmt_evaluate_reject_inet(ctx, stmt, expr) < 0)
+ return -1;
+ break;
+ }
+
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+}
+
+static int stmt_evaluate_reject_default(struct eval_ctx *ctx,
+ struct stmt *stmt)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_desc *desc, *base;
+ int protocol;
+
+ switch (pctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
+ 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 = 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 = pctx->protocol[PROTO_BASE_LL_HDR].desc;
+ protocol = proto_find_num(base, desc);
+ switch (protocol) {
+ case NFPROTO_IPV4:
+ case __constant_htons(ETH_P_IP):
+ stmt->reject.family = NFPROTO_IPV4;
+ stmt->reject.icmp_code = ICMP_PORT_UNREACH;
+ break;
+ case NFPROTO_IPV6:
+ case __constant_htons(ETH_P_IPV6):
+ stmt->reject.family = NFPROTO_IPV6;
+ stmt->reject.icmp_code = ICMP6_DST_UNREACH_NOPORT;
+ break;
+ }
+ break;
+ case NFPROTO_BRIDGE:
+ case NFPROTO_NETDEV:
+ desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc == NULL) {
+ stmt->reject.type = NFT_REJECT_ICMPX_UNREACH;
+ stmt->reject.icmp_code = NFT_REJECT_ICMPX_PORT_UNREACH;
+ break;
+ }
+ stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
+ base = pctx->protocol[PROTO_BASE_LL_HDR].desc;
+ protocol = proto_find_num(base, desc);
+ switch (protocol) {
+ case __constant_htons(ETH_P_IP):
+ stmt->reject.family = NFPROTO_IPV4;
+ stmt->reject.icmp_code = ICMP_PORT_UNREACH;
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ stmt->reject.family = NFPROTO_IPV6;
+ stmt->reject.icmp_code = ICMP6_DST_UNREACH_NOPORT;
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int stmt_evaluate_reject_icmp(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct parse_ctx parse_ctx = {
+ .tbl = &ctx->nft->output.tbl,
+ .input = &ctx->nft->input,
+ };
+ struct error_record *erec;
+ struct expr *code;
+
+ erec = symbol_parse(&parse_ctx, stmt->reject.expr, &code);
+ if (erec != NULL) {
+ erec_queue(erec, ctx->msgs);
+ return -1;
+ }
+ stmt->reject.icmp_code = mpz_get_uint8(code->value);
+ expr_free(code);
+
+ return 0;
+}
+
+static int stmt_evaluate_reset(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_desc *desc, *base;
+ int protonum;
+
+ desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+ if (desc == NULL)
+ return 0;
+
+ base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (base == NULL)
+ base = &proto_inet_service;
+
+ protonum = proto_find_num(base, desc);
+ switch (protonum) {
+ case IPPROTO_TCP:
+ break;
+ default:
+ if (stmt->reject.type == NFT_REJECT_TCP_RST) {
+ return stmt_binary_error(ctx, stmt,
+ &pctx->protocol[PROTO_BASE_TRANSPORT_HDR],
+ "you cannot use tcp reset with this protocol");
+ }
+ break;
+ }
+ return 0;
+}
+
+static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *expr = ctx->cmd->expr;
+
+ if (stmt->reject.icmp_code < 0) {
+ if (stmt_evaluate_reject_default(ctx, stmt) < 0)
+ return -1;
+ } else if (stmt->reject.expr != NULL) {
+ if (stmt_evaluate_reject_icmp(ctx, stmt) < 0)
+ return -1;
+ } else {
+ if (stmt_evaluate_reset(ctx, stmt) < 0)
+ return -1;
+ }
+
+ return stmt_evaluate_reject_family(ctx, stmt, expr);
+}
+
+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 (pctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ if (stmt->nat.family == NFPROTO_UNSPEC)
+ stmt->nat.family = pctx->family;
+ return 0;
+ case NFPROTO_INET:
+ if (!stmt->nat.addr) {
+ stmt->nat.family = NFPROTO_INET;
+ return 0;
+ }
+ if (stmt->nat.family != NFPROTO_UNSPEC)
+ return 0;
+
+ nproto = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+
+ if (nproto == &proto_ip)
+ stmt->nat.family = NFPROTO_IPV4;
+ else if (nproto == &proto_ip6)
+ stmt->nat.family = NFPROTO_IPV6;
+
+ return 0;
+ default:
+ return stmt_error(ctx, stmt,
+ "NAT is only supported for IPv4/IPv6");
+ }
+}
+
+static const struct datatype *get_addr_dtype(uint8_t family)
+{
+ switch (family) {
+ case NFPROTO_IPV4:
+ return &ipaddr_type;
+ case NFPROTO_IPV6:
+ return &ip6addr_type;
+ }
+
+ return &invalid_type;
+}
+
+static int evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
+ struct expr **expr)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct datatype *dtype;
+
+ dtype = get_addr_dtype(pctx->family);
+
+ return stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ expr);
+}
+
+static bool nat_evaluate_addr_has_th_expr(const struct expr *map)
+{
+ const struct expr *i, *concat;
+
+ if (!map || map->etype != EXPR_MAP)
+ return false;
+
+ concat = map->map;
+ if (concat ->etype != EXPR_CONCAT)
+ return false;
+
+ list_for_each_entry(i, &concat->expressions, list) {
+ enum proto_bases base;
+
+ if (i->etype == EXPR_PAYLOAD &&
+ i->payload.base == PROTO_BASE_TRANSPORT_HDR &&
+ i->payload.desc != &proto_th)
+ return true;
+
+ if ((i->flags & EXPR_F_PROTOCOL) == 0)
+ continue;
+
+ switch (i->etype) {
+ case EXPR_META:
+ base = i->meta.base;
+ break;
+ case EXPR_PAYLOAD:
+ base = i->payload.base;
+ break;
+ default:
+ return false;
+ }
+
+ if (base == PROTO_BASE_NETWORK_HDR)
+ return true;
+ }
+
+ return false;
+}
+
+static int nat_evaluate_transport(struct eval_ctx *ctx, struct stmt *stmt,
+ struct expr **expr)
+{
+ struct proto_ctx *pctx = 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))
+ return stmt_binary_error(ctx, *expr, stmt,
+ "transport protocol mapping is only "
+ "valid after transport protocol match");
+
+ return 0;
+}
+
+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_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 = 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,
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
+ "conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in %s statement",
+ pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name,
+ family2str(family),
+ stmt->ops->name);
+ return 0;
+}
+
+static 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)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct datatype *dtype;
+ int err;
+
+ if (pctx->family == NFPROTO_INET) {
+ if (*family == NFPROTO_INET ||
+ *family == NFPROTO_UNSPEC)
+ expr_family_infer(pctx, *addr, family);
+
+ dtype = get_addr_dtype(*family);
+ if (dtype->size == 0) {
+ return stmt_error(ctx, stmt,
+ "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);
+ } else {
+ err = evaluate_addr(ctx, stmt, addr);
+ }
+
+ return err;
+}
+
+static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ struct expr *one, *two, *data, *tmp;
+ const struct datatype *dtype = NULL;
+ const struct datatype *dtype2;
+ int addr_type;
+ int err;
+
+ if (stmt->nat.family == NFPROTO_INET)
+ expr_family_infer(pctx, stmt->nat.addr, &stmt->nat.family);
+
+ switch (stmt->nat.family) {
+ case NFPROTO_IPV4:
+ addr_type = TYPE_IPADDR;
+ break;
+ case NFPROTO_IPV6:
+ addr_type = TYPE_IP6ADDR;
+ break;
+ default:
+ return stmt_error(ctx, stmt,
+ "specify `%s ip' or '%s ip6' in %s table to disambiguate",
+ stmt_name(stmt), stmt_name(stmt), family2str(pctx->family));
+ }
+ dtype = concat_type_alloc((addr_type << TYPE_BITS) | TYPE_INET_SERVICE);
+
+ expr_set_context(&ctx->ectx, dtype, dtype->size);
+ if (expr_evaluate(ctx, &stmt->nat.addr)) {
+ err = -1;
+ goto out;
+ }
+
+ if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL &&
+ !nat_evaluate_addr_has_th_expr(stmt->nat.addr)) {
+ err = stmt_binary_error(ctx, stmt->nat.addr, stmt,
+ "transport protocol mapping is only "
+ "valid after transport protocol match");
+ goto out;
+ }
+
+ if (stmt->nat.addr->etype != EXPR_MAP) {
+ err = 0;
+ goto out;
+ }
+
+ data = stmt->nat.addr->mappings->set->data;
+ if (data->flags & EXPR_F_INTERVAL)
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+
+ datatype_set(data, dtype);
+
+ if (expr_ops(data)->type != EXPR_CONCAT) {
+ err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->nat.addr);
+ goto out;
+ }
+
+ one = list_first_entry(&data->expressions, struct expr, list);
+ two = list_entry(one->list.next, struct expr, list);
+
+ if (one == two || !list_is_last(&two->list, &data->expressions)) {
+ err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->nat.addr);
+ goto out;
+ }
+
+ dtype2 = get_addr_dtype(stmt->nat.family);
+ tmp = one;
+ err = __stmt_evaluate_arg(ctx, stmt, dtype2, dtype2->size,
+ BYTEORDER_BIG_ENDIAN,
+ &tmp);
+ if (err < 0)
+ goto out;
+ if (tmp != one)
+ BUG("Internal error: Unexpected alteration of l3 expression");
+
+ tmp = two;
+ err = nat_evaluate_transport(ctx, stmt, &tmp);
+ if (err < 0)
+ goto out;
+ if (tmp != two)
+ BUG("Internal error: Unexpected alteration of l4 expression");
+
+out:
+ datatype_free(dtype);
+ return err;
+}
+
+static bool nat_concat_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *i;
+
+ if (stmt->nat.addr->etype != EXPR_MAP)
+ return false;
+
+ switch (stmt->nat.addr->mappings->etype) {
+ case EXPR_SET:
+ list_for_each_entry(i, &stmt->nat.addr->mappings->expressions, list) {
+ if (i->etype == EXPR_MAPPING &&
+ i->right->etype == EXPR_CONCAT) {
+ stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
+ return true;
+ }
+ }
+ break;
+ case EXPR_SYMBOL:
+ /* expr_evaluate_map() see EXPR_SET_REF after this evaluation. */
+ if (expr_evaluate(ctx, &stmt->nat.addr->mappings))
+ return false;
+
+ if (stmt->nat.addr->mappings->set->data->etype == EXPR_CONCAT ||
+ stmt->nat.addr->mappings->set->data->dtype->subtypes) {
+ stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ int err;
+
+ err = nat_evaluate_family(ctx, stmt);
+ if (err < 0)
+ return err;
+
+ if (stmt->nat.addr != NULL) {
+ err = stmt_evaluate_l3proto(ctx, stmt, stmt->nat.family);
+ if (err < 0)
+ return err;
+
+ if (nat_concat_map(ctx, stmt) ||
+ stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+
+ err = stmt_evaluate_nat_map(ctx, stmt);
+ if (err < 0)
+ return err;
+
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+ }
+
+ err = stmt_evaluate_addr(ctx, stmt, &stmt->nat.family,
+ &stmt->nat.addr);
+ if (err < 0)
+ return err;
+ }
+
+ if (stmt->nat.proto != NULL) {
+ err = nat_evaluate_transport(ctx, stmt, &stmt->nat.proto);
+ if (err < 0)
+ return err;
+
+ stmt->nat.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
+ }
+
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+}
+
+static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ int err;
+
+ switch (pctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6: /* fallthrough */
+ if (stmt->tproxy.family == NFPROTO_UNSPEC)
+ stmt->tproxy.family = pctx->family;
+ break;
+ case NFPROTO_INET:
+ break;
+ default:
+ return stmt_error(ctx, stmt,
+ "tproxy is only supported for IPv4/IPv6/INET");
+ }
+
+ if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL)
+ return stmt_error(ctx, stmt, "Transparent proxy support requires"
+ " transport protocol match");
+
+ if (!stmt->tproxy.addr && !stmt->tproxy.port)
+ return stmt_error(ctx, stmt, "Either address or port must be specified!");
+
+ err = stmt_evaluate_l3proto(ctx, stmt, stmt->tproxy.family);
+ if (err < 0)
+ 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,
+ &stmt->tproxy.addr);
+
+ if (err < 0)
+ return err;
+ }
+
+ 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;
+ }
+
+ return 0;
+}
+
+static int stmt_evaluate_synproxy(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ if (stmt->synproxy.flags != 0 &&
+ !(stmt->synproxy.flags & (NF_SYNPROXY_OPT_MSS |
+ NF_SYNPROXY_OPT_WSCALE |
+ NF_SYNPROXY_OPT_TIMESTAMP |
+ NF_SYNPROXY_OPT_SACK_PERM)))
+ return stmt_error(ctx, stmt, "This flags are not supported for SYNPROXY");
+
+ return 0;
+}
+
+static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
+ enum cmd_ops op);
+
+static int stmt_evaluate_chain(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct chain *chain = stmt->chain.chain;
+ struct cmd *cmd;
+
+ chain->flags |= CHAIN_F_BINDING;
+
+ if (ctx->table != NULL) {
+ list_add_tail(&chain->list, &ctx->table->chains);
+ } else {
+ struct rule *rule, *next;
+ struct handle h;
+
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &chain->handle);
+ h.family = ctx->rule->handle.family;
+ xfree(h.table.name);
+ h.table.name = xstrdup(ctx->rule->handle.table.name);
+ h.chain.location = stmt->location;
+ h.chain_id = chain->handle.chain_id;
+
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &h, &stmt->location,
+ chain);
+ cmd->location = stmt->location;
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ h.chain_id = chain->handle.chain_id;
+
+ list_for_each_entry_safe(rule, next, &chain->rules, list) {
+ struct eval_ctx rule_ctx = {
+ .nft = ctx->nft,
+ .msgs = ctx->msgs,
+ .cmd = ctx->cmd,
+ };
+ struct handle h2 = {};
+
+ handle_merge(&rule->handle, &ctx->rule->handle);
+ xfree(rule->handle.table.name);
+ rule->handle.table.name = xstrdup(ctx->rule->handle.table.name);
+ xfree(rule->handle.chain.name);
+ rule->handle.chain.name = NULL;
+ rule->handle.chain_id = chain->handle.chain_id;
+ if (rule_evaluate(&rule_ctx, rule, CMD_INVALID) < 0)
+ return -1;
+
+ handle_merge(&h2, &rule->handle);
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h2,
+ &rule->location, rule);
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ list_del(&rule->list);
+ }
+ }
+
+ return 0;
+}
+
+static int stmt_evaluate_optstrip(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ return expr_evaluate(ctx, &stmt->optstrip.expr);
+}
+
+static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ int err;
+
+ switch (pctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ if (stmt->dup.to == NULL)
+ return stmt_error(ctx, stmt,
+ "missing destination address");
+ err = evaluate_addr(ctx, stmt, &stmt->dup.to);
+ if (err < 0)
+ return err;
+
+ if (stmt->dup.dev != NULL) {
+ err = stmt_evaluate_arg(ctx, stmt, &ifindex_type,
+ sizeof(uint32_t) * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN,
+ &stmt->dup.dev);
+ if (err < 0)
+ return err;
+ }
+ break;
+ case NFPROTO_NETDEV:
+ if (stmt->dup.to == NULL)
+ return stmt_error(ctx, stmt,
+ "missing destination interface");
+ if (stmt->dup.dev != NULL)
+ return stmt_error(ctx, stmt, "cannot specify device");
+
+ err = stmt_evaluate_arg(ctx, stmt, &ifindex_type,
+ sizeof(uint32_t) * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN, &stmt->dup.to);
+ if (err < 0)
+ return err;
+ break;
+ default:
+ return stmt_error(ctx, stmt, "unsupported family");
+ }
+ 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 (pctx->family) {
+ case NFPROTO_NETDEV:
+ if (stmt->fwd.dev == NULL)
+ return stmt_error(ctx, stmt,
+ "missing destination interface");
+
+ err = stmt_evaluate_arg(ctx, stmt, &ifindex_type,
+ sizeof(uint32_t) * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN, &stmt->fwd.dev);
+ if (err < 0)
+ return err;
+
+ if (stmt->fwd.addr != NULL) {
+ switch (stmt->fwd.family) {
+ case NFPROTO_IPV4:
+ dtype = &ipaddr_type;
+ len = 4 * BITS_PER_BYTE;
+ break;
+ case NFPROTO_IPV6:
+ dtype = &ip6addr_type;
+ len = 16 * BITS_PER_BYTE;
+ break;
+ default:
+ return stmt_error(ctx, stmt, "missing family");
+ }
+ err = stmt_evaluate_arg(ctx, stmt, dtype, len,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->fwd.addr);
+ if (err < 0)
+ return err;
+ }
+ break;
+ default:
+ return stmt_error(ctx, stmt, "unsupported family");
+ }
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+}
+
+static int stmt_evaluate_queue(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ if (stmt->queue.queue != NULL) {
+ if (stmt_evaluate_arg(ctx, stmt, &integer_type, 16,
+ BYTEORDER_HOST_ENDIAN,
+ &stmt->queue.queue) < 0)
+ return -1;
+
+ if ((stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT) &&
+ stmt->queue.queue->etype != EXPR_RANGE)
+ return expr_error(ctx->msgs, stmt->queue.queue,
+ "fanout requires a range to be "
+ "specified");
+
+ if (ctx->ectx.maxval > USHRT_MAX)
+ return expr_error(ctx->msgs, stmt->queue.queue,
+ "queue expression max value exceeds %u", USHRT_MAX);
+ }
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+}
+
+static int stmt_evaluate_log_prefix(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ char tmp[NF_LOG_PREFIXLEN] = {};
+ char prefix[NF_LOG_PREFIXLEN];
+ size_t len = sizeof(prefix);
+ size_t offset = 0;
+ struct expr *expr;
+
+ if (stmt->log.prefix->etype != EXPR_LIST) {
+ if (stmt->log.prefix &&
+ div_round_up(stmt->log.prefix->len, BITS_PER_BYTE) >= NF_LOG_PREFIXLEN)
+ return expr_error(ctx->msgs, stmt->log.prefix, "log prefix is too long");
+
+ return 0;
+ }
+
+ prefix[0] = '\0';
+
+ list_for_each_entry(expr, &stmt->log.prefix->expressions, list) {
+ int ret;
+
+ switch (expr->etype) {
+ case EXPR_VALUE:
+ expr_to_string(expr, tmp);
+ ret = snprintf(prefix + offset, len, "%s", tmp);
+ break;
+ case EXPR_VARIABLE:
+ ret = snprintf(prefix + offset, len, "%s",
+ expr->sym->expr->identifier);
+ break;
+ default:
+ BUG("unknown expression type %s\n", expr_name(expr));
+ break;
+ }
+ SNPRINTF_BUFFER_SIZE(ret, &len, &offset);
+ }
+
+ if (len == 0)
+ return stmt_error(ctx, stmt, "log prefix is too long");
+
+ expr = constant_expr_alloc(&stmt->log.prefix->location, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(prefix) * BITS_PER_BYTE, prefix);
+ expr_free(stmt->log.prefix);
+ stmt->log.prefix = expr;
+
+ return 0;
+}
+
+static int stmt_evaluate_log(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ int ret = 0;
+
+ if (stmt->log.flags & (STMT_LOG_GROUP | STMT_LOG_SNAPLEN |
+ STMT_LOG_QTHRESHOLD)) {
+ if (stmt->log.flags & STMT_LOG_LEVEL)
+ return stmt_error(ctx, stmt,
+ "level and group are mutually exclusive");
+ if (stmt->log.logflags)
+ return stmt_error(ctx, stmt,
+ "flags and group are mutually exclusive");
+ }
+ if (stmt->log.level == NFT_LOGLEVEL_AUDIT &&
+ (stmt->log.flags & ~STMT_LOG_LEVEL || stmt->log.logflags))
+ return stmt_error(ctx, stmt,
+ "log level audit doesn't support any further options");
+
+ if (stmt->log.prefix)
+ ret = stmt_evaluate_log_prefix(ctx, stmt);
+
+ return ret;
+}
+
+static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct set *this_set;
+ struct stmt *this;
+
+ expr_set_context(&ctx->ectx, NULL, 0);
+ if (expr_evaluate(ctx, &stmt->set.set) < 0)
+ return -1;
+ if (stmt->set.set->etype != EXPR_SET_REF)
+ return expr_error(ctx->msgs, stmt->set.set,
+ "Expression does not refer to a set");
+
+ if (stmt_evaluate_key(ctx, stmt,
+ stmt->set.set->set->key->dtype,
+ stmt->set.set->set->key->len,
+ stmt->set.set->set->key->byteorder,
+ &stmt->set.key->key) < 0)
+ return -1;
+ if (expr_is_constant(stmt->set.key))
+ return expr_error(ctx->msgs, stmt->set.key,
+ "Key expression can not be constant");
+ if (stmt->set.key->comment != NULL)
+ return expr_error(ctx->msgs, stmt->set.key,
+ "Key expression comments are not supported");
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ if (stmt_evaluate(ctx, this) < 0)
+ return -1;
+ if (!(this->flags & STMT_F_STATEFUL))
+ return stmt_error(ctx, this,
+ "statement must be stateful");
+ }
+
+ this_set = stmt->set.set->set;
+
+ /* Make sure EVAL flag is set on set definition so that kernel
+ * picks a set that allows updates from the packet path.
+ *
+ * Alternatively we could error out in case 'flags dynamic' was
+ * not given, but we can repair this here.
+ */
+ this_set->flags |= NFT_SET_EVAL;
+ return 0;
+}
+
+static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct stmt *this;
+
+ expr_set_context(&ctx->ectx, NULL, 0);
+ if (expr_evaluate(ctx, &stmt->map.set) < 0)
+ return -1;
+ if (stmt->map.set->etype != EXPR_SET_REF)
+ return expr_error(ctx->msgs, stmt->map.set,
+ "Expression does not refer to a set");
+
+ if (stmt_evaluate_key(ctx, stmt,
+ stmt->map.set->set->key->dtype,
+ stmt->map.set->set->key->len,
+ stmt->map.set->set->key->byteorder,
+ &stmt->map.key->key) < 0)
+ return -1;
+ if (expr_is_constant(stmt->map.key))
+ return expr_error(ctx->msgs, stmt->map.key,
+ "Key expression can not be constant");
+ if (stmt->map.key->comment != NULL)
+ return expr_error(ctx->msgs, stmt->map.key,
+ "Key expression comments are not supported");
+
+ if (stmt_evaluate_arg(ctx, stmt,
+ stmt->map.set->set->data->dtype,
+ stmt->map.set->set->data->len,
+ stmt->map.set->set->data->byteorder,
+ &stmt->map.data->key) < 0)
+ return -1;
+ if (expr_is_constant(stmt->map.data))
+ return expr_error(ctx->msgs, stmt->map.data,
+ "Data expression can not be constant");
+ 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)
+ return -1;
+ if (!(this->flags & STMT_F_STATEFUL))
+ return stmt_error(ctx, this,
+ "statement must be stateful");
+ }
+
+ return 0;
+}
+
+static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *map = stmt->objref.expr;
+ struct expr *mappings;
+ struct expr *key;
+
+ expr_set_context(&ctx->ectx, NULL, 0);
+ if (expr_evaluate(ctx, &map->map) < 0)
+ return -1;
+ if (expr_is_constant(map->map))
+ return expr_error(ctx->msgs, map->map,
+ "Map expression can not be constant");
+
+ mappings = map->mappings;
+ mappings->set_flags |= NFT_SET_OBJECT;
+
+ switch (map->mappings->etype) {
+ case EXPR_SET:
+ key = constant_expr_alloc(&stmt->location,
+ ctx->ectx.dtype,
+ ctx->ectx.byteorder,
+ ctx->ectx.len, NULL);
+
+ mappings = implicit_set_declaration(ctx, "__objmap%d",
+ key, NULL, mappings);
+ mappings->set->objtype = stmt->objref.type;
+
+ map->mappings = mappings;
+
+ ctx->set = mappings->set;
+ if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
+ return -1;
+
+ if (set_is_interval(map->mappings->set->init->set_flags) &&
+ !(map->mappings->set->init->set_flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0)
+ return -1;
+
+ ctx->set = NULL;
+
+ map_set_concat_info(map);
+ /* fall through */
+ case EXPR_SYMBOL:
+ if (expr_evaluate(ctx, &map->mappings) < 0)
+ return -1;
+ if (map->mappings->etype != EXPR_SET_REF)
+ return expr_error(ctx->msgs, map->mappings,
+ "Expression is not a map");
+ if (!set_is_objmap(map->mappings->set->flags))
+ return expr_error(ctx->msgs, map->mappings,
+ "Expression is not a map with objects");
+ break;
+ default:
+ BUG("invalid mapping expression %s\n",
+ expr_name(map->mappings));
+ }
+
+ if (!datatype_compatible(map->mappings->set->key->dtype, map->map->dtype))
+ return expr_binary_error(ctx->msgs, map->mappings, map->map,
+ "datatype mismatch, map expects %s, "
+ "mapping expression has type %s",
+ map->mappings->set->key->dtype->desc,
+ map->map->dtype->desc);
+
+ datatype_set(map, map->mappings->set->data->dtype);
+ map->flags |= EXPR_F_CONSTANT;
+
+ /* Data for range lookups needs to be in big endian order */
+ if (map->mappings->set->flags & NFT_SET_INTERVAL &&
+ byteorder_conversion(ctx, &map->map, BYTEORDER_BIG_ENDIAN) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int stmt_evaluate_objref(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ /* We need specific map evaluation for stateful objects. */
+ if (stmt->objref.expr->etype == EXPR_MAP)
+ return stmt_evaluate_objref_map(ctx, stmt);
+
+ if (stmt_evaluate_arg(ctx, stmt,
+ &string_type, NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN, &stmt->objref.expr) < 0)
+ return -1;
+
+ if (!expr_is_constant(stmt->objref.expr))
+ return expr_error(ctx->msgs, stmt->objref.expr,
+ "Counter expression must be constant");
+
+ return 0;
+}
+
+int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION) {
+ struct error_record *erec;
+ erec = erec_create(EREC_INFORMATIONAL, &stmt->location,
+ "Evaluate %s", stmt->ops->name);
+ erec_print(&ctx->nft->output, erec, ctx->nft->debug_mask);
+ stmt_print(stmt, &ctx->nft->output);
+ nft_print(&ctx->nft->output, "\n\n");
+ erec_destroy(erec);
+ }
+
+ switch (stmt->ops->type) {
+ case STMT_CONNLIMIT:
+ case STMT_COUNTER:
+ case STMT_LAST:
+ case STMT_LIMIT:
+ case STMT_QUOTA:
+ case STMT_NOTRACK:
+ case STMT_FLOW_OFFLOAD:
+ return 0;
+ case STMT_EXPRESSION:
+ return stmt_evaluate_expr(ctx, stmt);
+ case STMT_VERDICT:
+ return stmt_evaluate_verdict(ctx, stmt);
+ case STMT_PAYLOAD:
+ return stmt_evaluate_payload(ctx, stmt);
+ case STMT_EXTHDR:
+ return stmt_evaluate_exthdr(ctx, stmt);
+ case STMT_METER:
+ return stmt_evaluate_meter(ctx, stmt);
+ case STMT_META:
+ return stmt_evaluate_meta(ctx, stmt);
+ case STMT_CT:
+ return stmt_evaluate_ct(ctx, stmt);
+ case STMT_LOG:
+ return stmt_evaluate_log(ctx, stmt);
+ case STMT_REJECT:
+ return stmt_evaluate_reject(ctx, stmt);
+ case STMT_NAT:
+ return stmt_evaluate_nat(ctx, stmt);
+ case STMT_TPROXY:
+ return stmt_evaluate_tproxy(ctx, stmt);
+ case STMT_QUEUE:
+ return stmt_evaluate_queue(ctx, stmt);
+ case STMT_DUP:
+ return stmt_evaluate_dup(ctx, stmt);
+ case STMT_FWD:
+ return stmt_evaluate_fwd(ctx, stmt);
+ case STMT_SET:
+ return stmt_evaluate_set(ctx, stmt);
+ case STMT_OBJREF:
+ return stmt_evaluate_objref(ctx, stmt);
+ case STMT_MAP:
+ return stmt_evaluate_map(ctx, stmt);
+ case STMT_SYNPROXY:
+ return stmt_evaluate_synproxy(ctx, stmt);
+ case STMT_CHAIN:
+ return stmt_evaluate_chain(ctx, stmt);
+ case STMT_OPTSTRIP:
+ return stmt_evaluate_optstrip(ctx, stmt);
+ default:
+ BUG("unknown statement type %s\n", stmt->ops->name);
+ }
+}
+
+static int setelem_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+ struct set *set;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
+ if (table == NULL)
+ return table_not_found(ctx);
+
+ set = set_cache_find(table, ctx->cmd->handle.set.name);
+ if (set == NULL)
+ return set_not_found(ctx, &ctx->cmd->handle.set.location,
+ ctx->cmd->handle.set.name);
+
+ if (set->key == NULL)
+ return -1;
+
+ set->existing_set = set;
+ ctx->set = set;
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ if (expr_evaluate(ctx, &cmd->expr) < 0)
+ return -1;
+
+ cmd->elem.set = set_get(set);
+ if (set_is_interval(ctx->set->flags)) {
+ if (!(set->flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, cmd->expr) < 0)
+ return -1;
+
+ assert(cmd->expr->etype == EXPR_SET);
+ cmd->expr->set_flags |= NFT_SET_INTERVAL;
+ }
+
+ ctx->set = NULL;
+
+ return 0;
+}
+
+static int set_key_data_error(struct eval_ctx *ctx, const struct set *set,
+ const struct datatype *dtype,
+ const char *name)
+{
+ const char *hint = "";
+
+ if (dtype->size == 0)
+ hint = ". Try \"typeof expression\" instead of \"type datatype\".";
+
+ return set_error(ctx, set, "unqualified type %s "
+ "specified in %s definition%s",
+ dtype->name, name, hint);
+}
+
+static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
+{
+ unsigned int flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+ uint32_t ntype = 0, size = 0;
+ struct expr *i, *next;
+
+ list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+ unsigned dsize_bytes;
+
+ if (i->etype == EXPR_CT &&
+ (i->ct.key == NFT_CT_SRC ||
+ i->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, i,
+ "specify either ip or ip6 for address matching");
+
+ if (i->etype == EXPR_PAYLOAD &&
+ i->dtype->type == TYPE_INTEGER) {
+ struct datatype *dtype;
+
+ dtype = datatype_clone(i->dtype);
+ dtype->size = i->len;
+ dtype->byteorder = i->byteorder;
+ __datatype_set(i, dtype);
+ }
+
+ if (i->dtype->size == 0 && i->len == 0)
+ return expr_binary_error(ctx->msgs, i, *expr,
+ "can not use variable sized "
+ "data types (%s) in concat "
+ "expressions",
+ i->dtype->name);
+
+ 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);
+ (*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
+ size += netlink_padded_len(i->len);
+ }
+
+ (*expr)->flags |= flags;
+ __datatype_set(*expr, concat_type_alloc(ntype));
+ (*expr)->len = size;
+
+ expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->len);
+ ctx->ectx.key = *expr;
+
+ return 0;
+}
+
+static int elems_evaluate(struct eval_ctx *ctx, struct set *set)
+{
+ ctx->set = set;
+ if (set->init != NULL) {
+ __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) &&
+ interval_set_eval(ctx, ctx->set, set->init) < 0)
+ return -1;
+
+ ctx->set = NULL;
+
+ return 0;
+}
+
+static int set_evaluate(struct eval_ctx *ctx, struct set *set)
+{
+ struct set *existing_set = NULL;
+ unsigned int num_stmts = 0;
+ struct table *table;
+ struct stmt *stmt;
+ const char *type;
+
+ if (!set_is_anonymous(set->flags)) {
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ set->handle.table.name,
+ set->handle.family);
+ if (table == NULL)
+ return table_not_found(ctx);
+
+ existing_set = set_cache_find(table, set->handle.set.name);
+ if (!existing_set)
+ set_cache_add(set_get(set), table);
+
+ if (existing_set && existing_set->flags & NFT_SET_EVAL) {
+ uint32_t existing_flags = existing_set->flags & ~NFT_SET_EVAL;
+ uint32_t new_flags = set->flags & ~NFT_SET_EVAL;
+
+ if (existing_flags == new_flags)
+ set->flags |= NFT_SET_EVAL;
+ }
+ }
+
+ if (!(set->flags & NFT_SET_INTERVAL) && set->automerge)
+ return set_error(ctx, set, "auto-merge only works with interval sets");
+
+ type = set_is_map(set->flags) ? "map" : "set";
+
+ if (set->key == NULL)
+ return set_error(ctx, set, "%s definition does not specify key",
+ type);
+
+ if (set->key->len == 0) {
+ if (set->key->etype == EXPR_CONCAT &&
+ set_expr_evaluate_concat(ctx, &set->key) < 0)
+ return -1;
+
+ if (set->key->len == 0)
+ return set_key_data_error(ctx, set,
+ set->key->dtype, type);
+ }
+
+ if (set->flags & NFT_SET_INTERVAL && set->key->etype == EXPR_CONCAT) {
+ memcpy(&set->desc.field_len, &set->key->field_len,
+ sizeof(set->desc.field_len));
+ set->desc.field_count = set->key->field_count;
+ set->flags |= NFT_SET_CONCAT;
+ }
+
+ if (set_is_datamap(set->flags)) {
+ if (set->data == NULL)
+ return set_error(ctx, set, "map definition does not "
+ "specify mapping data type");
+
+ if (set->data->etype == EXPR_CONCAT &&
+ set_expr_evaluate_concat(ctx, &set->data) < 0)
+ return -1;
+
+ if (set->data->flags & EXPR_F_INTERVAL)
+ set->data->len *= 2;
+
+ if (set->data->len == 0 && set->data->dtype->type != TYPE_VERDICT)
+ return set_key_data_error(ctx, set,
+ set->data->dtype, type);
+ } else if (set_is_objmap(set->flags)) {
+ assert(set->data == NULL);
+ set->data = constant_expr_alloc(&netlink_location, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
+ NULL);
+
+ }
+
+ /* Default timeout value implies timeout support */
+ if (set->timeout)
+ set->flags |= NFT_SET_TIMEOUT;
+
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts > 1)
+ set->flags |= NFT_SET_EXPR;
+
+ if (set_is_anonymous(set->flags)) {
+ if (set_is_interval(set->init->set_flags) &&
+ !(set->init->set_flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, set, set->init) < 0)
+ return -1;
+
+ return 0;
+ }
+
+ set->existing_set = existing_set;
+
+ return 0;
+}
+
+static bool evaluate_priority(struct eval_ctx *ctx, struct prio_spec *prio,
+ int family, int hook)
+{
+ char prio_str[NFT_NAME_MAXLEN];
+ char prio_fst[NFT_NAME_MAXLEN];
+ struct location loc;
+ int priority;
+ int prio_snd;
+ char op;
+
+ expr_set_context(&ctx->ectx, &priority_type, NFT_NAME_MAXLEN * BITS_PER_BYTE);
+
+ if (expr_evaluate(ctx, &prio->expr) < 0)
+ return false;
+ if (prio->expr->etype != EXPR_VALUE) {
+ expr_error(ctx->msgs, prio->expr, "%s is not a valid "
+ "priority expression", expr_name(prio->expr));
+ return false;
+ }
+ if (prio->expr->dtype->type == TYPE_INTEGER)
+ return true;
+
+ mpz_export_data(prio_str, prio->expr->value, BYTEORDER_HOST_ENDIAN,
+ NFT_NAME_MAXLEN);
+ loc = prio->expr->location;
+
+ if (sscanf(prio_str, "%s %c %d", prio_fst, &op, &prio_snd) < 3) {
+ priority = std_prio_lookup(prio_str, family, hook);
+ if (priority == NF_IP_PRI_LAST)
+ return false;
+ } else {
+ priority = std_prio_lookup(prio_fst, family, hook);
+ if (priority == NF_IP_PRI_LAST)
+ return false;
+ if (op == '+')
+ priority += prio_snd;
+ else if (op == '-')
+ priority -= prio_snd;
+ else
+ return false;
+ }
+ expr_free(prio->expr);
+ prio->expr = constant_expr_alloc(&loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE,
+ &priority);
+ return true;
+}
+
+static bool evaluate_expr_variable(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr;
+
+ if (expr_evaluate(ctx, exprp) < 0)
+ return false;
+
+ expr = *exprp;
+ if (expr->etype != EXPR_VALUE &&
+ expr->etype != EXPR_SET) {
+ expr_error(ctx->msgs, expr, "%s is not a valid "
+ "variable expression", expr_name(expr));
+ return false;
+ }
+
+ return true;
+}
+
+static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr)
+{
+ struct expr *expr, *next, *key;
+ LIST_HEAD(tmp);
+
+ if ((*dev_expr)->etype == EXPR_VARIABLE) {
+ expr_set_context(&ctx->ectx, &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE);
+ if (!evaluate_expr_variable(ctx, dev_expr))
+ return false;
+ }
+
+ if ((*dev_expr)->etype != EXPR_SET &&
+ (*dev_expr)->etype != EXPR_LIST)
+ return true;
+
+ list_for_each_entry_safe(expr, next, &(*dev_expr)->expressions, list) {
+ list_del(&expr->list);
+
+ switch (expr->etype) {
+ case EXPR_VARIABLE:
+ expr_set_context(&ctx->ectx, &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE);
+ if (!evaluate_expr_variable(ctx, &expr))
+ return false;
+ break;
+ case EXPR_SET_ELEM:
+ key = expr_clone(expr->key);
+ expr_free(expr);
+ expr = key;
+ break;
+ case EXPR_VALUE:
+ break;
+ default:
+ BUG("invalid expression type %s\n", expr_name(expr));
+ break;
+ }
+
+ list_add(&expr->list, &tmp);
+ }
+ list_splice_init(&tmp, &(*dev_expr)->expressions);
+
+ return true;
+}
+
+static uint32_t str2hooknum(uint32_t family, const char *hook);
+
+static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
+{
+ struct table *table;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
+ if (table == NULL)
+ return table_not_found(ctx);
+
+ if (!ft_cache_find(table, ft->handle.flowtable.name)) {
+ if (!ft->hook.name)
+ 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);
+ if (ft->hook.num == NF_INET_NUMHOOKS)
+ return chain_error(ctx, ft, "invalid hook %s",
+ ft->hook.name);
+ if (!evaluate_priority(ctx, &ft->priority, NFPROTO_NETDEV, ft->hook.num))
+ return __stmt_binary_error(ctx, &ft->priority.loc, NULL,
+ "invalid priority expression %s.",
+ expr_name(ft->priority.expr));
+ }
+
+ if (ft->dev_expr && !evaluate_device_expr(ctx, &ft->dev_expr))
+ return -1;
+
+ return 0;
+}
+
+/* make src point at dst, either via handle.position or handle.position_id */
+static void link_rules(struct rule *src, struct rule *dst)
+{
+ static uint32_t ref_id = 0;
+
+ if (dst->handle.handle.id) {
+ /* dst is in kernel, make src reference it by handle */
+ src->handle.position.id = dst->handle.handle.id;
+ src->handle.position.location = src->handle.index.location;
+ return;
+ }
+
+ /* dst is not in kernel, make src reference it by per-transaction ID */
+ if (!dst->handle.rule_id)
+ dst->handle.rule_id = ++ref_id;
+ src->handle.position_id = dst->handle.rule_id;
+}
+
+static int rule_cache_update(struct eval_ctx *ctx, enum cmd_ops op)
+{
+ struct rule *rule = ctx->rule, *ref = NULL;
+ struct table *table;
+ struct chain *chain;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ rule->handle.table.name,
+ rule->handle.family);
+ if (!table)
+ return table_not_found(ctx);
+
+ chain = chain_cache_find(table, rule->handle.chain.name);
+ if (!chain)
+ return chain_not_found(ctx);
+
+ if (rule->handle.index.id) {
+ ref = rule_lookup_by_index(chain, rule->handle.index.id);
+ if (!ref)
+ return cmd_error(ctx, &rule->handle.index.location,
+ "Could not process rule: %s",
+ strerror(ENOENT));
+
+ link_rules(rule, ref);
+ } else if (rule->handle.handle.id) {
+ ref = rule_lookup(chain, rule->handle.handle.id);
+ if (!ref)
+ return cmd_error(ctx, &rule->handle.handle.location,
+ "Could not process rule: %s",
+ strerror(ENOENT));
+ } else if (rule->handle.position.id) {
+ ref = rule_lookup(chain, rule->handle.position.id);
+ if (!ref)
+ return cmd_error(ctx, &rule->handle.position.location,
+ "Could not process rule: %s",
+ strerror(ENOENT));
+ }
+
+ switch (op) {
+ case CMD_INSERT:
+ rule_get(rule);
+ if (ref)
+ list_add_tail(&rule->list, &ref->list);
+ else
+ list_add(&rule->list, &chain->rules);
+ break;
+ case CMD_ADD:
+ rule_get(rule);
+ if (ref)
+ list_add(&rule->list, &ref->list);
+ else
+ list_add_tail(&rule->list, &chain->rules);
+ break;
+ case CMD_REPLACE:
+ rule_get(rule);
+ list_add(&rule->list, &ref->list);
+ /* fall through */
+ case CMD_DELETE:
+ list_del(&ref->list);
+ rule_free(ref);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
+ enum cmd_ops op)
+{
+ struct stmt *stmt, *tstmt = NULL;
+ struct error_record *erec;
+
+ 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;
+ list_for_each_entry(stmt, &rule->stmts, list) {
+ if (tstmt != NULL)
+ return stmt_binary_error(ctx, stmt, tstmt,
+ "Statement after terminal "
+ "statement has no effect");
+
+ ctx->stmt = stmt;
+ if (stmt_evaluate(ctx, stmt) < 0)
+ return -1;
+ if (stmt->flags & STMT_F_TERMINAL)
+ tstmt = stmt;
+
+ ctx->inner_desc = NULL;
+ }
+
+ erec = rule_postprocess(rule);
+ if (erec != NULL) {
+ erec_queue(erec, ctx->msgs);
+ return -1;
+ }
+
+ if (nft_cache_needs_update(&ctx->nft->cache))
+ return rule_cache_update(ctx, op);
+
+ return 0;
+}
+
+static uint32_t str2hooknum(uint32_t family, const char *hook)
+{
+ if (!hook)
+ return NF_INET_NUMHOOKS;
+
+ switch (family) {
+ case NFPROTO_INET:
+ if (!strcmp(hook, "ingress"))
+ return NF_INET_INGRESS;
+ /* fall through */
+ case NFPROTO_IPV4:
+ case NFPROTO_BRIDGE:
+ case NFPROTO_IPV6:
+ /* These families have overlapping values for each hook */
+ if (!strcmp(hook, "prerouting"))
+ return NF_INET_PRE_ROUTING;
+ else if (!strcmp(hook, "input"))
+ return NF_INET_LOCAL_IN;
+ else if (!strcmp(hook, "forward"))
+ return NF_INET_FORWARD;
+ else if (!strcmp(hook, "postrouting"))
+ return NF_INET_POST_ROUTING;
+ else if (!strcmp(hook, "output"))
+ return NF_INET_LOCAL_OUT;
+ break;
+ case NFPROTO_ARP:
+ if (!strcmp(hook, "input"))
+ return NF_ARP_IN;
+ else if (!strcmp(hook, "forward"))
+ return NF_ARP_FORWARD;
+ else if (!strcmp(hook, "output"))
+ return NF_ARP_OUT;
+ break;
+ case NFPROTO_NETDEV:
+ if (!strcmp(hook, "ingress"))
+ return NF_NETDEV_INGRESS;
+ else if (!strcmp(hook, "egress"))
+ return NF_NETDEV_EGRESS;
+ break;
+ default:
+ break;
+ }
+
+ return NF_INET_NUMHOOKS;
+}
+
+static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
+{
+ 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);
+
+ if (chain == NULL) {
+ if (!chain_cache_find(table, ctx->cmd->handle.chain.name)) {
+ chain = chain_alloc();
+ handle_merge(&chain->handle, &ctx->cmd->handle);
+ chain_cache_add(chain, table);
+ }
+ return 0;
+ } else if (!(chain->flags & CHAIN_F_BINDING)) {
+ if (!chain_cache_find(table, chain->handle.chain.name))
+ chain_cache_add(chain_get(chain), table);
+ }
+
+ if (chain->flags & CHAIN_F_BASECHAIN) {
+ chain->hook.num = str2hooknum(chain->handle.family,
+ chain->hook.name);
+ if (chain->hook.num == NF_INET_NUMHOOKS)
+ return __stmt_binary_error(ctx, &chain->hook.loc, NULL,
+ "The %s family does not support this hook",
+ family2str(chain->handle.family));
+
+ if (!evaluate_priority(ctx, &chain->priority,
+ chain->handle.family, chain->hook.num))
+ return __stmt_binary_error(ctx, &chain->priority.loc, NULL,
+ "invalid priority expression %s in this context.",
+ expr_name(chain->priority.expr));
+ if (chain->policy) {
+ expr_set_context(&ctx->ectx, &policy_type,
+ NFT_NAME_MAXLEN * BITS_PER_BYTE);
+ if (!evaluate_expr_variable(ctx, &chain->policy))
+ return chain_error(ctx, chain, "invalid policy expression %s",
+ expr_name(chain->policy));
+ }
+ }
+
+ if (chain->dev_expr) {
+ if (!(chain->flags & CHAIN_F_BASECHAIN))
+ chain->flags |= CHAIN_F_BASECHAIN;
+
+ if (chain->handle.family == NFPROTO_NETDEV ||
+ (chain->handle.family == NFPROTO_INET &&
+ chain->hook.num == NF_INET_INGRESS)) {
+ if (chain->dev_expr &&
+ !evaluate_device_expr(ctx, &chain->dev_expr))
+ return -1;
+ } else if (chain->dev_expr) {
+ return __stmt_binary_error(ctx, &chain->dev_expr->location, NULL,
+ "This chain type cannot be bound to device");
+ }
+ }
+
+ return 0;
+}
+
+static int ct_expect_evaluate(struct eval_ctx *ctx, struct obj *obj)
+{
+ struct ct_expect *ct = &obj->ct_expect;
+
+ if (!ct->l4proto ||
+ !ct->dport ||
+ !ct->timeout ||
+ !ct->size)
+ return __stmt_binary_error(ctx, &obj->location, NULL,
+ "missing options");
+
+ return 0;
+}
+
+static int ct_timeout_evaluate(struct eval_ctx *ctx, struct obj *obj)
+{
+ struct ct_timeout *ct = &obj->ct_timeout;
+ struct timeout_state *ts, *next;
+ unsigned int i;
+
+ for (i = 0; i < timeout_protocol[ct->l4proto].array_size; i++)
+ ct->timeout[i] = timeout_protocol[ct->l4proto].dflt_timeout[i];
+
+ list_for_each_entry_safe(ts, next, &ct->timeout_list, head) {
+ if (timeout_str2num(ct->l4proto, ts) < 0)
+ return __stmt_binary_error(ctx, &ts->location, NULL,
+ "invalid state for this protocol");
+
+ ct->timeout[ts->timeout_index] = ts->timeout_value;
+ list_del(&ts->head);
+ xfree(ts->timeout_str);
+ xfree(ts);
+ }
+
+ return 0;
+}
+
+static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
+{
+ struct table *table;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
+ if (!table)
+ return table_not_found(ctx);
+
+ if (!obj_cache_find(table, obj->handle.obj.name, obj->type))
+ obj_cache_add(obj_get(obj), table);
+
+ switch (obj->type) {
+ case NFT_OBJECT_CT_TIMEOUT:
+ return ct_timeout_evaluate(ctx, obj);
+ case NFT_OBJECT_CT_EXPECT:
+ return ct_expect_evaluate(ctx, obj);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int table_evaluate(struct eval_ctx *ctx, struct table *table)
+{
+ if (!table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family)) {
+ if (!table) {
+ table = table_alloc();
+ handle_merge(&table->handle, &ctx->cmd->handle);
+ table_cache_add(table, &ctx->nft->cache);
+ } else {
+ table_cache_add(table_get(table), &ctx->nft->cache);
+ }
+ }
+
+ return 0;
+}
+
+static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
+ case CMD_OBJ_SET:
+ handle_merge(&cmd->set->handle, &cmd->handle);
+ return set_evaluate(ctx, cmd->set);
+ case CMD_OBJ_SETELEMS:
+ return elems_evaluate(ctx, cmd->set);
+ case CMD_OBJ_RULE:
+ handle_merge(&cmd->rule->handle, &cmd->handle);
+ return rule_evaluate(ctx, cmd->rule, cmd->op);
+ case CMD_OBJ_CHAIN:
+ return chain_evaluate(ctx, cmd->chain);
+ case CMD_OBJ_TABLE:
+ return table_evaluate(ctx, cmd->table);
+ case CMD_OBJ_FLOWTABLE:
+ handle_merge(&cmd->flowtable->handle, &cmd->handle);
+ return flowtable_evaluate(ctx, cmd->flowtable);
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_SYNPROXY:
+ handle_merge(&cmd->object->handle, &cmd->handle);
+ return obj_evaluate(ctx, cmd->object);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+}
+
+static void table_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+
+ if (!cmd->handle.table.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ table_cache_del(table);
+ table_free(table);
+}
+
+static void chain_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+ struct chain *chain;
+
+ if (!cmd->handle.chain.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ chain = chain_cache_find(table, cmd->handle.chain.name);
+ if (!chain)
+ return;
+
+ chain_cache_del(chain);
+ chain_free(chain);
+}
+
+static void set_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+ struct set *set;
+
+ if (!cmd->handle.set.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ set = set_cache_find(table, cmd->handle.set.name);
+ if (!set)
+ return;
+
+ set_cache_del(set);
+ set_free(set);
+}
+
+static void ft_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct flowtable *ft;
+ struct table *table;
+
+ if (!cmd->handle.flowtable.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return;
+
+ ft_cache_del(ft);
+ flowtable_free(ft);
+}
+
+static void obj_del_cache(struct eval_ctx *ctx, struct cmd *cmd, int type)
+{
+ struct table *table;
+ struct obj *obj;
+
+ if (!cmd->handle.obj.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ obj = obj_cache_find(table, cmd->handle.obj.name, type);
+ if (!obj)
+ return;
+
+ obj_cache_del(obj);
+ obj_free(obj);
+}
+
+static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
+ case CMD_OBJ_SET:
+ set_del_cache(ctx, cmd);
+ return 0;
+ case CMD_OBJ_RULE:
+ return 0;
+ case CMD_OBJ_CHAIN:
+ chain_del_cache(ctx, cmd);
+ return 0;
+ case CMD_OBJ_TABLE:
+ table_del_cache(ctx, cmd);
+ return 0;
+ case CMD_OBJ_FLOWTABLE:
+ ft_del_cache(ctx, cmd);
+ return 0;
+ case CMD_OBJ_COUNTER:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_COUNTER);
+ return 0;
+ case CMD_OBJ_QUOTA:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_QUOTA);
+ return 0;
+ case CMD_OBJ_CT_HELPER:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ return 0;
+ case CMD_OBJ_CT_TIMEOUT:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
+ return 0;
+ case CMD_OBJ_LIMIT:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_LIMIT);
+ return 0;
+ case CMD_OBJ_SECMARK:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_SECMARK);
+ return 0;
+ case CMD_OBJ_CT_EXPECT:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_CT_EXPECT);
+ return 0;
+ case CMD_OBJ_SYNPROXY:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_SYNPROXY);
+ return 0;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+}
+
+static int cmd_evaluate_get(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+}
+
+static int obj_not_found(struct eval_ctx *ctx, const struct location *loc,
+ const char *obj_name)
+{
+ const struct table *table;
+ struct obj *obj;
+
+ obj = obj_lookup_fuzzy(obj_name, &ctx->nft->cache, &table);
+ if (obj == NULL)
+ return cmd_error(ctx, loc, "%s", strerror(ENOENT));
+
+ return cmd_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);
+}
+
+static int cmd_evaluate_list_obj(struct eval_ctx *ctx, const struct cmd *cmd,
+ uint32_t obj_type)
+{
+ const struct table *table;
+
+ if (obj_type == NFT_OBJECT_UNSPEC)
+ obj_type = NFT_OBJECT_COUNTER;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (table == NULL)
+ return table_not_found(ctx);
+
+ if (!obj_cache_find(table, cmd->handle.obj.name, obj_type))
+ return obj_not_found(ctx, &cmd->handle.obj.location,
+ cmd->handle.obj.name);
+
+ return 0;
+}
+
+static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct flowtable *ft;
+ struct table *table;
+ struct set *set;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (cmd->handle.table.name == NULL)
+ return 0;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return table_not_found(ctx);
+
+ return 0;
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ 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);
+ 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(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,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return table_not_found(ctx);
+
+ if (!chain_cache_find(table, cmd->handle.chain.name))
+ return chain_not_found(ctx);
+
+ return 0;
+ case CMD_OBJ_FLOWTABLE:
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return table_not_found(ctx);
+
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return flowtable_not_found(ctx, &ctx->cmd->handle.flowtable.location,
+ ctx->cmd->handle.flowtable.name);
+
+ return 0;
+ case CMD_OBJ_QUOTA:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_QUOTA);
+ case CMD_OBJ_COUNTER:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_COUNTER);
+ case CMD_OBJ_CT_HELPER:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
+ case CMD_OBJ_LIMIT:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
+ case CMD_OBJ_SECMARK:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_SECMARK);
+ case CMD_OBJ_CT_EXPECT:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_CT_EXPECT);
+ case CMD_OBJ_SYNPROXY:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_SYNPROXY);
+ case CMD_OBJ_COUNTERS:
+ case CMD_OBJ_QUOTAS:
+ case CMD_OBJ_CT_HELPERS:
+ case CMD_OBJ_LIMITS:
+ case CMD_OBJ_SETS:
+ 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,
+ cmd->handle.table.name,
+ cmd->handle.family))
+ return table_not_found(ctx);
+
+ return 0;
+ case CMD_OBJ_CHAINS:
+ case CMD_OBJ_RULESET:
+ case CMD_OBJ_METERS:
+ case CMD_OBJ_MAPS:
+ return 0;
+ case CMD_OBJ_HOOKS:
+ if (cmd->handle.chain.name) {
+ int hooknum = str2hooknum(cmd->handle.family, cmd->handle.chain.name);
+
+ if (hooknum == NF_INET_NUMHOOKS)
+ return chain_not_found(ctx);
+
+ cmd->handle.chain_id = hooknum;
+ }
+ return 0;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+}
+
+static int cmd_evaluate_reset(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_COUNTER:
+ 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,
+ cmd->handle.table.name,
+ cmd->handle.family))
+ return table_not_found(ctx);
+
+ return 0;
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ return cmd_evaluate_list(ctx, cmd);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+}
+
+static void __flush_set_cache(struct set *set)
+{
+ if (set->init != NULL) {
+ expr_free(set->init);
+ set->init = NULL;
+ }
+}
+
+static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct cache *table_cache = &ctx->nft->cache.table_cache;
+ struct table *table;
+ struct set *set;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_RULESET:
+ break;
+ case CMD_OBJ_TABLE:
+ /* Flushing a table does not empty the sets in the table nor remove
+ * any chains.
+ */
+ case CMD_OBJ_CHAIN:
+ /* Chains don't hold sets */
+ break;
+ case CMD_OBJ_SET:
+ table = table_cache_find(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));
+
+ __flush_set_cache(set);
+
+ return 0;
+ case CMD_OBJ_MAP:
+ table = table_cache_find(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 (!map_is_literal(set->flags))
+ return cmd_error(ctx, &ctx->cmd->handle.set.location,
+ "%s", strerror(ENOENT));
+
+ __flush_set_cache(set);
+
+ return 0;
+ case CMD_OBJ_METER:
+ table = table_cache_find(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));
+
+ __flush_set_cache(set);
+
+ return 0;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ return 0;
+}
+
+static int cmd_evaluate_rename(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_CHAIN:
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return table_not_found(ctx);
+
+ if (!chain_cache_find(table, ctx->cmd->handle.chain.name))
+ return chain_not_found(ctx);
+
+ break;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ return 0;
+}
+
+enum {
+ CMD_MONITOR_EVENT_ANY,
+ CMD_MONITOR_EVENT_NEW,
+ CMD_MONITOR_EVENT_DEL,
+ CMD_MONITOR_EVENT_MAX
+};
+
+static uint32_t monitor_flags[CMD_MONITOR_EVENT_MAX][CMD_MONITOR_OBJ_MAX] = {
+ [CMD_MONITOR_EVENT_ANY] = {
+ [CMD_MONITOR_OBJ_ANY] = 0xffffffff,
+ [CMD_MONITOR_OBJ_TABLES] = (1 << NFT_MSG_NEWTABLE) |
+ (1 << NFT_MSG_DELTABLE),
+ [CMD_MONITOR_OBJ_CHAINS] = (1 << NFT_MSG_NEWCHAIN) |
+ (1 << NFT_MSG_DELCHAIN),
+ [CMD_MONITOR_OBJ_RULES] = (1 << NFT_MSG_NEWRULE) |
+ (1 << NFT_MSG_DELRULE),
+ [CMD_MONITOR_OBJ_SETS] = (1 << NFT_MSG_NEWSET) |
+ (1 << NFT_MSG_DELSET),
+ [CMD_MONITOR_OBJ_ELEMS] = (1 << NFT_MSG_NEWSETELEM) |
+ (1 << NFT_MSG_DELSETELEM),
+ [CMD_MONITOR_OBJ_RULESET] = (1 << NFT_MSG_NEWTABLE) |
+ (1 << NFT_MSG_DELTABLE) |
+ (1 << NFT_MSG_NEWCHAIN) |
+ (1 << NFT_MSG_DELCHAIN) |
+ (1 << NFT_MSG_NEWRULE) |
+ (1 << NFT_MSG_DELRULE) |
+ (1 << NFT_MSG_NEWSET) |
+ (1 << NFT_MSG_DELSET) |
+ (1 << NFT_MSG_NEWSETELEM) |
+ (1 << NFT_MSG_DELSETELEM) |
+ (1 << NFT_MSG_NEWOBJ) |
+ (1 << NFT_MSG_DELOBJ),
+ [CMD_MONITOR_OBJ_TRACE] = (1 << NFT_MSG_TRACE),
+ },
+ [CMD_MONITOR_EVENT_NEW] = {
+ [CMD_MONITOR_OBJ_ANY] = (1 << NFT_MSG_NEWTABLE) |
+ (1 << NFT_MSG_NEWCHAIN) |
+ (1 << NFT_MSG_NEWRULE) |
+ (1 << NFT_MSG_NEWSET) |
+ (1 << NFT_MSG_NEWSETELEM),
+ [CMD_MONITOR_OBJ_TABLES] = (1 << NFT_MSG_NEWTABLE),
+ [CMD_MONITOR_OBJ_CHAINS] = (1 << NFT_MSG_NEWCHAIN),
+ [CMD_MONITOR_OBJ_RULES] = (1 << NFT_MSG_NEWRULE),
+ [CMD_MONITOR_OBJ_SETS] = (1 << NFT_MSG_NEWSET),
+ [CMD_MONITOR_OBJ_ELEMS] = (1 << NFT_MSG_NEWSETELEM),
+ [CMD_MONITOR_OBJ_RULESET] = (1 << NFT_MSG_NEWTABLE) |
+ (1 << NFT_MSG_NEWCHAIN) |
+ (1 << NFT_MSG_NEWRULE) |
+ (1 << NFT_MSG_NEWSET) |
+ (1 << NFT_MSG_NEWSETELEM) |
+ (1 << NFT_MSG_NEWOBJ),
+ [CMD_MONITOR_OBJ_TRACE] = 0,
+ },
+ [CMD_MONITOR_EVENT_DEL] = {
+ [CMD_MONITOR_OBJ_ANY] = (1 << NFT_MSG_DELTABLE) |
+ (1 << NFT_MSG_DELCHAIN) |
+ (1 << NFT_MSG_DELRULE) |
+ (1 << NFT_MSG_DELSET) |
+ (1 << NFT_MSG_DELSETELEM),
+ [CMD_MONITOR_OBJ_TABLES] = (1 << NFT_MSG_DELTABLE),
+ [CMD_MONITOR_OBJ_CHAINS] = (1 << NFT_MSG_DELCHAIN),
+ [CMD_MONITOR_OBJ_RULES] = (1 << NFT_MSG_DELRULE),
+ [CMD_MONITOR_OBJ_SETS] = (1 << NFT_MSG_DELSET),
+ [CMD_MONITOR_OBJ_ELEMS] = (1 << NFT_MSG_DELSETELEM),
+ [CMD_MONITOR_OBJ_RULESET] = (1 << NFT_MSG_DELTABLE) |
+ (1 << NFT_MSG_DELCHAIN) |
+ (1 << NFT_MSG_DELRULE) |
+ (1 << NFT_MSG_DELSET) |
+ (1 << NFT_MSG_DELSETELEM) |
+ (1 << NFT_MSG_DELOBJ),
+ [CMD_MONITOR_OBJ_TRACE] = 0,
+ },
+};
+
+static int cmd_evaluate_monitor(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ uint32_t event;
+
+ if (cmd->monitor->event == NULL)
+ event = CMD_MONITOR_EVENT_ANY;
+ else if (strcmp(cmd->monitor->event, "new") == 0)
+ event = CMD_MONITOR_EVENT_NEW;
+ else if (strcmp(cmd->monitor->event, "destroy") == 0)
+ event = CMD_MONITOR_EVENT_DEL;
+ else {
+ return monitor_error(ctx, cmd->monitor, "invalid event %s",
+ cmd->monitor->event);
+ }
+
+ cmd->monitor->flags = monitor_flags[event][cmd->monitor->type];
+ return 0;
+}
+
+static int cmd_evaluate_export(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ if (cmd->markup->format == __NFT_OUTPUT_NOTSUPP)
+ return cmd_error(ctx, &cmd->location,
+ "this output type is not supported, use nft -j list ruleset for JSON support instead");
+ else if (cmd->markup->format == NFTNL_OUTPUT_JSON)
+ return cmd_error(ctx, &cmd->location,
+ "JSON export is no longer supported, use 'nft -j list ruleset' instead");
+
+ return 0;
+}
+
+static int cmd_evaluate_import(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ if (cmd->markup->format == __NFT_OUTPUT_NOTSUPP)
+ return cmd_error(ctx, &cmd->location,
+ "this output type not supported");
+
+ return 0;
+}
+
+static const char * const cmd_op_name[] = {
+ [CMD_INVALID] = "invalid",
+ [CMD_ADD] = "add",
+ [CMD_REPLACE] = "replace",
+ [CMD_CREATE] = "create",
+ [CMD_INSERT] = "insert",
+ [CMD_DELETE] = "delete",
+ [CMD_GET] = "get",
+ [CMD_LIST] = "list",
+ [CMD_FLUSH] = "flush",
+ [CMD_RENAME] = "rename",
+ [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)
+ return "unknown";
+
+ return cmd_op_name[op];
+}
+
+int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION) {
+ struct error_record *erec;
+
+ erec = erec_create(EREC_INFORMATIONAL, &cmd->location,
+ "Evaluate %s", cmd_op_to_name(cmd->op));
+ erec_print(&ctx->nft->output, erec, ctx->nft->debug_mask);
+ nft_print(&ctx->nft->output, "\n\n");
+ erec_destroy(erec);
+ }
+
+ memset(&ctx->ectx, 0, sizeof(ctx->ectx));
+
+ ctx->cmd = cmd;
+ switch (cmd->op) {
+ case CMD_ADD:
+ case CMD_REPLACE:
+ case CMD_CREATE:
+ 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);
+ case CMD_LIST:
+ return cmd_evaluate_list(ctx, cmd);
+ case CMD_RESET:
+ return cmd_evaluate_reset(ctx, cmd);
+ case CMD_FLUSH:
+ return cmd_evaluate_flush(ctx, cmd);
+ case CMD_RENAME:
+ return cmd_evaluate_rename(ctx, cmd);
+ case CMD_EXPORT:
+ return cmd_evaluate_export(ctx, cmd);
+ case CMD_DESCRIBE:
+ return 0;
+ case CMD_MONITOR:
+ return cmd_evaluate_monitor(ctx, cmd);
+ case CMD_IMPORT:
+ return cmd_evaluate_import(ctx, cmd);
+ default:
+ BUG("invalid command operation %u\n", cmd->op);
+ };
+}
diff --git a/src/expression.c b/src/expression.c
new file mode 100644
index 0000000..a21dfec
--- /dev/null
+++ b/src/expression.c
@@ -0,0 +1,1563 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <expression.h>
+#include <statement.h>
+#include <datatype.h>
+#include <netlink.h>
+#include <rule.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <list.h>
+#include <erec.h>
+#include <json.h>
+
+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;
+extern const struct expr_ops payload_expr_ops;
+extern const struct expr_ops rt_expr_ops;
+extern const struct expr_ops socket_expr_ops;
+extern const struct expr_ops xfrm_expr_ops;
+
+struct expr *expr_alloc(const struct location *loc, enum expr_types etype,
+ const struct datatype *dtype, enum byteorder byteorder,
+ unsigned int len)
+{
+ struct expr *expr;
+
+ expr = xzalloc(sizeof(*expr));
+ expr->location = *loc;
+ expr->dtype = datatype_get(dtype);
+ expr->etype = etype;
+ expr->byteorder = byteorder;
+ expr->len = len;
+ expr->refcnt = 1;
+ init_list_head(&expr->list);
+ return expr;
+}
+
+struct expr *expr_clone(const struct expr *expr)
+{
+ struct expr *new;
+
+ new = expr_alloc(&expr->location, expr->etype,
+ expr->dtype, expr->byteorder, expr->len);
+ new->flags = expr->flags;
+ new->op = expr->op;
+ expr_ops(expr)->clone(new, expr);
+ return new;
+}
+
+struct expr *expr_get(struct expr *expr)
+{
+ expr->refcnt++;
+ return expr;
+}
+
+static void expr_destroy(struct expr *e)
+{
+ const struct expr_ops *ops = expr_ops(e);
+
+ if (ops->destroy)
+ ops->destroy(e);
+}
+
+void expr_free(struct expr *expr)
+{
+ if (expr == NULL)
+ return;
+ if (--expr->refcnt > 0)
+ return;
+
+ datatype_free(expr->dtype);
+
+ /* EXPR_INVALID expressions lack ->ops structure.
+ * This happens for compound types.
+ */
+ if (expr->etype != EXPR_INVALID)
+ expr_destroy(expr);
+ xfree(expr);
+}
+
+void expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct expr_ops *ops = expr_ops(expr);
+
+ if (ops->print)
+ ops->print(expr, octx);
+}
+
+bool expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ assert(e1->flags & EXPR_F_SINGLETON);
+ assert(e2->flags & EXPR_F_SINGLETON);
+
+ if (e1->etype != e2->etype)
+ return false;
+
+ return expr_ops(e1)->cmp(e1, e2);
+}
+
+const char *expr_name(const struct expr *e)
+{
+ return expr_ops(e)->name;
+}
+
+void expr_describe(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct datatype *dtype = expr->dtype, *edtype = NULL;
+ unsigned int len = expr->len;
+ const char *delim = "";
+
+ if (dtype == &invalid_type &&
+ expr->etype == EXPR_SYMBOL)
+ edtype = datatype_lookup_byname(expr->identifier);
+
+ if (edtype) {
+ dtype = edtype;
+ nft_print(octx, "datatype %s (%s)",
+ dtype->name, dtype->desc);
+ len = dtype->size;
+ } else {
+ nft_print(octx, "%s expression, datatype %s (%s)",
+ expr_name(expr), dtype->name, dtype->desc);
+
+ if (dtype == &invalid_type)
+ return;
+ }
+
+ if (dtype->basetype != NULL) {
+ nft_print(octx, " (basetype ");
+ for (dtype = dtype->basetype; dtype != NULL;
+ dtype = dtype->basetype) {
+ nft_print(octx, "%s%s", delim, dtype->desc);
+ delim = ", ";
+ }
+ nft_print(octx, ")");
+ }
+
+ if (expr_basetype(expr)->type == TYPE_STRING) {
+ if (len)
+ nft_print(octx, ", %u characters",
+ len / BITS_PER_BYTE);
+ else
+ nft_print(octx, ", dynamic length");
+ } else
+ nft_print(octx, ", %u bits", len);
+
+ if (!edtype)
+ edtype = expr->dtype;
+
+ nft_print(octx, "\n");
+
+ if (edtype->sym_tbl != NULL) {
+ nft_print(octx, "\npre-defined symbolic constants ");
+ if (edtype->sym_tbl->base == BASE_DECIMAL)
+ nft_print(octx, "(in decimal):\n");
+ else
+ nft_print(octx, "(in hexadecimal):\n");
+ symbol_table_print(edtype->sym_tbl, edtype,
+ expr->byteorder, octx);
+ } else if (edtype->describe) {
+ edtype->describe(octx);
+ }
+}
+
+void expr_to_string(const struct expr *expr, char *string)
+{
+ int len = expr->len / BITS_PER_BYTE;
+
+ assert(expr->dtype == &string_type);
+
+ mpz_export_data(string, expr->value, BYTEORDER_HOST_ENDIAN, len);
+}
+
+void expr_set_type(struct expr *expr, const struct datatype *dtype,
+ enum byteorder byteorder)
+{
+ const struct expr_ops *ops = expr_ops(expr);
+
+ if (ops->set_type)
+ ops->set_type(expr, dtype, byteorder);
+ else {
+ datatype_set(expr, dtype);
+ expr->byteorder = byteorder;
+ }
+}
+
+const struct datatype *expr_basetype(const struct expr *expr)
+{
+ const struct datatype *type = expr->dtype;
+
+ while (type->basetype != NULL)
+ type = type->basetype;
+ return type;
+}
+
+int __fmtstring(4, 5) expr_binary_error(struct list_head *msgs,
+ const struct expr *e1, const struct expr *e2,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, &e1->location, fmt, ap);
+ if (e2 != NULL)
+ erec_add_location(erec, &e2->location);
+ va_end(ap);
+ erec_queue(erec, msgs);
+ return -1;
+}
+
+static void verdict_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ datatype_print(expr, octx);
+}
+
+static bool verdict_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ if (e1->verdict != e2->verdict)
+ return false;
+
+ if ((e1->verdict == NFT_JUMP ||
+ e1->verdict == NFT_GOTO) &&
+ expr_cmp(e1->chain, e2->chain))
+ return true;
+
+ return false;
+}
+
+static void verdict_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->verdict = expr->verdict;
+ if (expr->chain != NULL)
+ new->chain = expr_clone(expr->chain);
+}
+
+static void verdict_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->chain);
+}
+
+static int verdict_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ return 0;
+}
+
+static struct expr *verdict_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ struct expr *e;
+
+ e = symbol_expr_alloc(&internal_location, SYMBOL_VALUE, NULL, "verdict");
+ e->dtype = &verdict_type;
+ e->len = NFT_REG_SIZE * BITS_PER_BYTE;
+ return e;
+}
+
+static const struct expr_ops verdict_expr_ops = {
+ .type = EXPR_VERDICT,
+ .name = "verdict",
+ .print = verdict_expr_print,
+ .json = verdict_expr_json,
+ .cmp = verdict_expr_cmp,
+ .clone = verdict_expr_clone,
+ .destroy = verdict_expr_destroy,
+ .build_udata = verdict_expr_build_udata,
+ .parse_udata = verdict_expr_parse_udata,
+};
+
+struct expr *verdict_expr_alloc(const struct location *loc,
+ int verdict, struct expr *chain)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_VERDICT, &verdict_type,
+ BYTEORDER_INVALID, 0);
+ expr->verdict = verdict;
+ if (chain != NULL)
+ expr->chain = chain;
+ expr->flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+ return expr;
+}
+
+static void symbol_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_print(octx, "%s", expr->identifier);
+}
+
+static void symbol_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->symtype = expr->symtype;
+ new->scope = expr->scope;
+ new->identifier = xstrdup(expr->identifier);
+}
+
+static void symbol_expr_destroy(struct expr *expr)
+{
+ xfree(expr->identifier);
+}
+
+static const struct expr_ops symbol_expr_ops = {
+ .type = EXPR_SYMBOL,
+ .name = "symbol",
+ .print = symbol_expr_print,
+ .clone = symbol_expr_clone,
+ .destroy = symbol_expr_destroy,
+};
+
+struct expr *symbol_expr_alloc(const struct location *loc,
+ enum symbol_types type, struct scope *scope,
+ const char *identifier)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_SYMBOL, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->symtype = type;
+ expr->scope = scope;
+ expr->identifier = xstrdup(identifier);
+ return expr;
+}
+
+static void variable_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "$%s", expr->sym->identifier);
+}
+
+static void variable_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->scope = expr->scope;
+ new->sym = expr->sym;
+
+ expr->sym->refcnt++;
+}
+
+static void variable_expr_destroy(struct expr *expr)
+{
+ expr->sym->refcnt--;
+}
+
+static const struct expr_ops variable_expr_ops = {
+ .type = EXPR_VARIABLE,
+ .name = "variable",
+ .print = variable_expr_print,
+ .clone = variable_expr_clone,
+ .destroy = variable_expr_destroy,
+};
+
+struct expr *variable_expr_alloc(const struct location *loc,
+ struct scope *scope, struct symbol *sym)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_VARIABLE, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->scope = scope;
+ expr->sym = sym;
+ return expr;
+}
+
+static void constant_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ datatype_print(expr, octx);
+}
+
+static bool constant_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return expr_basetype(e1) == expr_basetype(e2) &&
+ !mpz_cmp(e1->value, e2->value);
+}
+
+static void constant_expr_clone(struct expr *new, const struct expr *expr)
+{
+ mpz_init_set(new->value, expr->value);
+}
+
+static void constant_expr_destroy(struct expr *expr)
+{
+ mpz_clear(expr->value);
+}
+
+static const struct expr_ops constant_expr_ops = {
+ .type = EXPR_VALUE,
+ .name = "value",
+ .print = constant_expr_print,
+ .json = constant_expr_json,
+ .cmp = constant_expr_cmp,
+ .clone = constant_expr_clone,
+ .destroy = constant_expr_destroy,
+};
+
+struct expr *constant_expr_alloc(const struct location *loc,
+ const struct datatype *dtype,
+ enum byteorder byteorder,
+ unsigned int len, const void *data)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_VALUE, dtype, byteorder, len);
+ expr->flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+
+ mpz_init2(expr->value, len);
+ if (data != NULL)
+ mpz_import_data(expr->value, data, byteorder,
+ div_round_up(len, BITS_PER_BYTE));
+
+ return expr;
+}
+
+struct expr *constant_expr_join(const struct expr *e1, const struct expr *e2)
+{
+ unsigned int len = (e1->len + e2->len) / BITS_PER_BYTE, tmp;
+ unsigned char data[len];
+
+ assert(e1->etype == EXPR_VALUE);
+ assert(e2->etype == EXPR_VALUE);
+
+ tmp = e1->len / BITS_PER_BYTE;
+ mpz_export_data(data, e1->value, e1->byteorder, tmp);
+ mpz_export_data(data + tmp, e2->value, e2->byteorder,
+ e2->len / BITS_PER_BYTE);
+
+ return constant_expr_alloc(&e1->location, &invalid_type,
+ BYTEORDER_INVALID, len * BITS_PER_BYTE,
+ data);
+}
+
+struct expr *constant_expr_splice(struct expr *expr, unsigned int len)
+{
+ struct expr *slice;
+ mpz_t mask;
+
+ assert(expr->etype == EXPR_VALUE);
+ assert(len <= expr->len);
+
+ slice = constant_expr_alloc(&expr->location, &invalid_type,
+ BYTEORDER_INVALID, len, NULL);
+ mpz_init2(mask, len);
+ mpz_bitmask(mask, len);
+ mpz_lshift_ui(mask, expr->len - len);
+
+ mpz_set(slice->value, expr->value);
+ mpz_and(slice->value, slice->value, mask);
+ mpz_rshift_ui(slice->value, expr->len - len);
+ mpz_clear(mask);
+
+ expr->len -= len;
+ return slice;
+}
+
+/*
+ * Allocate a constant expression with a single bit set at position n.
+ */
+struct expr *flag_expr_alloc(const struct location *loc,
+ const struct datatype *dtype,
+ enum byteorder byteorder,
+ unsigned int len, unsigned long n)
+{
+ struct expr *expr;
+
+ assert(n < len);
+
+ expr = constant_expr_alloc(loc, dtype, byteorder, len, NULL);
+ mpz_set_ui(expr->value, 1);
+ mpz_lshift_ui(expr->value, n);
+
+ return expr;
+}
+
+/*
+ * Convert an expression of basetype TYPE_BITMASK into a series of inclusive
+ * OR binop expressions of the individual flag values.
+ */
+struct expr *bitmask_expr_to_binops(struct expr *expr)
+{
+ struct expr *binop, *flag;
+ unsigned long n;
+
+ assert(expr->etype == EXPR_VALUE);
+ assert(expr->dtype->basetype->type == TYPE_BITMASK);
+
+ n = mpz_popcount(expr->value);
+ if (n == 0 || n == 1)
+ return expr;
+
+ binop = NULL;
+ n = 0;
+ while ((n = mpz_scan1(expr->value, n)) != ULONG_MAX) {
+ flag = flag_expr_alloc(&expr->location, expr->dtype,
+ expr->byteorder, expr->len, n);
+ if (binop != NULL)
+ binop = binop_expr_alloc(&expr->location,
+ OP_OR, binop, flag);
+ else
+ binop = flag;
+
+ n++;
+ }
+
+ expr_free(expr);
+ return binop;
+}
+
+static void prefix_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ expr_print(expr->prefix, octx);
+ nft_print(octx, "/%u", expr->prefix_len);
+}
+
+static void prefix_expr_set_type(const struct expr *expr,
+ const struct datatype *type,
+ enum byteorder byteorder)
+{
+ expr_set_type(expr->prefix, type, byteorder);
+}
+
+static void prefix_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->prefix = expr_clone(expr->prefix);
+ new->prefix_len = expr->prefix_len;
+}
+
+static void prefix_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->prefix);
+}
+
+static const struct expr_ops prefix_expr_ops = {
+ .type = EXPR_PREFIX,
+ .name = "prefix",
+ .print = prefix_expr_print,
+ .json = prefix_expr_json,
+ .set_type = prefix_expr_set_type,
+ .clone = prefix_expr_clone,
+ .destroy = prefix_expr_destroy,
+};
+
+struct expr *prefix_expr_alloc(const struct location *loc,
+ struct expr *expr, unsigned int prefix_len)
+{
+ struct expr *prefix;
+
+ prefix = expr_alloc(loc, EXPR_PREFIX, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ prefix->prefix = expr;
+ prefix->prefix_len = prefix_len;
+ return prefix;
+}
+
+const char *expr_op_symbols[] = {
+ [OP_INVALID] = "invalid",
+ [OP_HTON] = "hton",
+ [OP_NTOH] = "ntoh",
+ [OP_AND] = "&",
+ [OP_OR] = "|",
+ [OP_XOR] = "^",
+ [OP_LSHIFT] = "<<",
+ [OP_RSHIFT] = ">>",
+ [OP_EQ] = "==",
+ [OP_NEQ] = "!=",
+ [OP_LT] = "<",
+ [OP_GT] = ">",
+ [OP_LTE] = "<=",
+ [OP_GTE] = ">=",
+ [OP_NEG] = "!",
+};
+
+static void unary_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ expr_print(expr->arg, octx);
+}
+
+static void unary_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->arg = expr_clone(expr->arg);
+}
+
+static void unary_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->arg);
+}
+
+static const struct expr_ops unary_expr_ops = {
+ .type = EXPR_UNARY,
+ .name = "unary",
+ .print = unary_expr_print,
+ .json = unary_expr_json,
+ .clone = unary_expr_clone,
+ .destroy = unary_expr_destroy,
+};
+
+struct expr *unary_expr_alloc(const struct location *loc,
+ enum ops op, struct expr *arg)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_UNARY, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->op = op;
+ expr->arg = arg;
+ return expr;
+}
+
+static uint8_t expr_binop_precedence[OP_MAX + 1] = {
+ [OP_LSHIFT] = 1,
+ [OP_RSHIFT] = 1,
+ [OP_AND] = 2,
+ [OP_XOR] = 3,
+ [OP_OR] = 4,
+};
+
+static void binop_arg_print(const struct expr *op, const struct expr *arg,
+ struct output_ctx *octx)
+{
+ bool prec = false;
+
+ if (arg->etype == EXPR_BINOP &&
+ expr_binop_precedence[op->op] != 0 &&
+ expr_binop_precedence[op->op] < expr_binop_precedence[arg->op])
+ prec = 1;
+
+ if (prec)
+ nft_print(octx, "(");
+ expr_print(arg, octx);
+ if (prec)
+ nft_print(octx, ")");
+}
+
+bool must_print_eq_op(const struct expr *expr)
+{
+ if (expr->right->dtype->basetype != NULL &&
+ expr->right->dtype->basetype->type == TYPE_BITMASK &&
+ expr->right->etype == EXPR_VALUE)
+ return true;
+
+ return expr->left->etype == EXPR_BINOP;
+}
+
+static void binop_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ binop_arg_print(expr, expr->left, octx);
+
+ if (expr_op_symbols[expr->op] &&
+ (expr->op != OP_EQ || must_print_eq_op(expr)))
+ nft_print(octx, " %s ", expr_op_symbols[expr->op]);
+ else
+ nft_print(octx, " ");
+
+ binop_arg_print(expr, expr->right, octx);
+}
+
+static void binop_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->left = expr_clone(expr->left);
+ new->right = expr_clone(expr->right);
+}
+
+static void binop_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->left);
+ expr_free(expr->right);
+}
+
+static const struct expr_ops binop_expr_ops = {
+ .type = EXPR_BINOP,
+ .name = "binop",
+ .print = binop_expr_print,
+ .json = binop_expr_json,
+ .clone = binop_expr_clone,
+ .destroy = binop_expr_destroy,
+};
+
+struct expr *binop_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *left, struct expr *right)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_BINOP, left->dtype,
+ left->byteorder, 0);
+ expr->left = left;
+ expr->op = op;
+ expr->right = right;
+ return expr;
+}
+
+static const struct expr_ops relational_expr_ops = {
+ .type = EXPR_RELATIONAL,
+ .name = "relational",
+ .print = binop_expr_print,
+ .json = relational_expr_json,
+ .destroy = binop_expr_destroy,
+};
+
+struct expr *relational_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *left, struct expr *right)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_RELATIONAL, &verdict_type,
+ BYTEORDER_INVALID, 0);
+ expr->left = left;
+ expr->op = op;
+ expr->right = right;
+
+ if (right->dtype == &boolean_type)
+ left->flags |= EXPR_F_BOOLEAN;
+
+ return expr;
+}
+
+void relational_expr_pctx_update(struct proto_ctx *ctx,
+ const struct expr *expr)
+{
+ const struct expr *left = expr->left, *right = expr->right;
+ const struct expr_ops *ops;
+ const struct expr *i;
+
+ assert(expr->etype == EXPR_RELATIONAL);
+ assert(expr->op == OP_EQ || expr->op == OP_IMPLICIT);
+
+ ops = expr_ops(left);
+ if (ops->pctx_update &&
+ (left->flags & EXPR_F_PROTOCOL)) {
+ if (expr_is_singleton(right))
+ ops->pctx_update(ctx, &expr->location, left, right);
+ else if (right->etype == EXPR_SET) {
+ list_for_each_entry(i, &right->expressions, list) {
+ if (i->etype == EXPR_SET_ELEM &&
+ i->key->etype == EXPR_VALUE)
+ ops->pctx_update(ctx, &expr->location, left, i->key);
+ }
+ }
+ }
+}
+
+static void range_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned int flags = octx->flags;
+
+ octx->flags &= ~(NFT_CTX_OUTPUT_SERVICE |
+ NFT_CTX_OUTPUT_REVERSEDNS |
+ NFT_CTX_OUTPUT_GUID);
+ octx->flags |= NFT_CTX_OUTPUT_NUMERIC_ALL;
+ expr_print(expr->left, octx);
+ nft_print(octx, "-");
+ expr_print(expr->right, octx);
+ octx->flags = flags;
+}
+
+static void range_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->left = expr_clone(expr->left);
+ new->right = expr_clone(expr->right);
+}
+
+static void range_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->left);
+ expr_free(expr->right);
+}
+
+static void range_expr_set_type(const struct expr *expr,
+ const struct datatype *type,
+ enum byteorder byteorder)
+{
+ expr_set_type(expr->left, type, byteorder);
+ expr_set_type(expr->right, type, byteorder);
+}
+
+static const struct expr_ops range_expr_ops = {
+ .type = EXPR_RANGE,
+ .name = "range",
+ .print = range_expr_print,
+ .json = range_expr_json,
+ .clone = range_expr_clone,
+ .destroy = range_expr_destroy,
+ .set_type = range_expr_set_type,
+};
+
+struct expr *range_expr_alloc(const struct location *loc,
+ struct expr *left, struct expr *right)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_RANGE, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->left = left;
+ expr->right = right;
+ return expr;
+}
+
+struct expr *compound_expr_alloc(const struct location *loc,
+ enum expr_types etype)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, etype, &invalid_type, BYTEORDER_INVALID, 0);
+ init_list_head(&expr->expressions);
+ return expr;
+}
+
+static void compound_expr_clone(struct expr *new, const struct expr *expr)
+{
+ struct expr *i;
+
+ init_list_head(&new->expressions);
+ list_for_each_entry(i, &expr->expressions, list)
+ compound_expr_add(new, expr_clone(i));
+}
+
+static void compound_expr_destroy(struct expr *expr)
+{
+ struct expr *i, *next;
+
+ list_for_each_entry_safe(i, next, &expr->expressions, list)
+ expr_free(i);
+}
+
+static void compound_expr_print(const struct expr *expr, const char *delim,
+ struct output_ctx *octx)
+{
+ const struct expr *i;
+ const char *d = "";
+
+ list_for_each_entry(i, &expr->expressions, list) {
+ nft_print(octx, "%s", d);
+ expr_print(i, octx);
+ d = delim;
+ }
+}
+
+void compound_expr_add(struct expr *compound, struct expr *expr)
+{
+ list_add_tail(&expr->list, &compound->expressions);
+ compound->size++;
+}
+
+void compound_expr_remove(struct expr *compound, struct expr *expr)
+{
+ compound->size--;
+ list_del(&expr->list);
+}
+
+static void concat_expr_destroy(struct expr *expr)
+{
+ compound_expr_destroy(expr);
+}
+
+static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ compound_expr_print(expr, " . ", octx);
+}
+
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX NFT_REG32_SIZE
+
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA 1
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX 2
+
+static struct expr *expr_build_udata_recurse(struct expr *e)
+{
+ switch (e->etype) {
+ case EXPR_BINOP:
+ return e->left;
+ default:
+ break;
+ }
+
+ return e;
+}
+
+static int concat_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *concat_expr)
+{
+ struct nftnl_udata *nest;
+ struct expr *expr, *tmp;
+ unsigned int i = 0;
+
+ list_for_each_entry_safe(expr, tmp, &concat_expr->expressions, list) {
+ struct nftnl_udata *nest_expr;
+ int err;
+
+ expr = expr_build_udata_recurse(expr);
+ if (!expr_ops(expr)->build_udata || i >= NFT_REG32_SIZE)
+ return -1;
+
+ nest = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_NEST + i);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE, expr->etype);
+ nest_expr = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA);
+ err = expr_ops(expr)->build_udata(udbuf, expr);
+ if (err < 0)
+ return err;
+ nftnl_udata_nest_end(udbuf, nest_expr);
+ nftnl_udata_nest_end(udbuf, nest);
+ i++;
+ }
+
+ return 0;
+}
+
+static int concat_parse_udata_nest(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ if (type >= NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX)
+ return -1;
+
+ if (len <= sizeof(uint32_t))
+ return -1;
+
+ ud[type] = attr;
+ return 0;
+}
+
+static int concat_parse_udata_nested(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA:
+ if (len <= sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *concat_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX] = {};
+ const struct datatype *dtype;
+ struct expr *concat_expr;
+ uint32_t dt = 0, len = 0;
+ unsigned int i;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ concat_parse_udata_nest, ud);
+ if (err < 0)
+ return NULL;
+
+ concat_expr = concat_expr_alloc(&internal_location);
+ if (!concat_expr)
+ return NULL;
+
+ for (i = 0; i < array_size(ud); i++) {
+ const struct nftnl_udata *nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX];
+ const struct nftnl_udata *nested, *subdata;
+ const struct expr_ops *ops;
+ struct expr *expr;
+ uint32_t etype;
+
+ if (ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i] == NULL)
+ break;
+
+ nested = ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i];
+ err = nftnl_udata_parse(nftnl_udata_get(nested), nftnl_udata_len(nested),
+ concat_parse_udata_nested, nest_ud);
+ if (err < 0)
+ goto err_free;
+
+ etype = nftnl_udata_get_u32(nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE]);
+ ops = expr_ops_by_type_u32(etype);
+ if (!ops || !ops->parse_udata)
+ goto err_free;
+
+ subdata = nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA];
+ expr = ops->parse_udata(subdata);
+ if (!expr)
+ goto err_free;
+
+ dt = concat_subtype_add(dt, expr->dtype->type);
+ compound_expr_add(concat_expr, expr);
+ len += netlink_padded_len(expr->len);
+ }
+
+ dtype = concat_type_alloc(dt);
+ if (!dtype)
+ goto err_free;
+
+ __datatype_set(concat_expr, dtype);
+ concat_expr->len = len;
+
+ return concat_expr;
+
+err_free:
+ expr_free(concat_expr);
+ return NULL;
+}
+
+static const struct expr_ops concat_expr_ops = {
+ .type = EXPR_CONCAT,
+ .name = "concat",
+ .print = concat_expr_print,
+ .json = concat_expr_json,
+ .clone = compound_expr_clone,
+ .destroy = concat_expr_destroy,
+ .build_udata = concat_expr_build_udata,
+ .parse_udata = concat_expr_parse_udata,
+};
+
+struct expr *concat_expr_alloc(const struct location *loc)
+{
+ return compound_expr_alloc(loc, EXPR_CONCAT);
+}
+
+static void list_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ compound_expr_print(expr, ",", octx);
+}
+
+static const struct expr_ops list_expr_ops = {
+ .type = EXPR_LIST,
+ .name = "list",
+ .print = list_expr_print,
+ .json = list_expr_json,
+ .clone = compound_expr_clone,
+ .destroy = compound_expr_destroy,
+};
+
+struct expr *list_expr_alloc(const struct location *loc)
+{
+ return compound_expr_alloc(loc, EXPR_LIST);
+}
+
+static const char *calculate_delim(const struct expr *expr, int *count)
+{
+ const char *newline = ",\n\t\t\t ";
+ const char *singleline = ", ";
+
+ if (set_is_anonymous(expr->set_flags))
+ return singleline;
+
+ if (!expr->dtype)
+ return newline;
+
+ switch (expr->dtype->type) {
+ case TYPE_NFPROTO:
+ case TYPE_INTEGER:
+ case TYPE_ARPOP:
+ case TYPE_INET_PROTOCOL:
+ case TYPE_INET_SERVICE:
+ case TYPE_TCP_FLAG:
+ case TYPE_DCCP_PKTTYPE:
+ case TYPE_MARK:
+ case TYPE_IFINDEX:
+ case TYPE_CLASSID:
+ case TYPE_UID:
+ case TYPE_GID:
+ case TYPE_CT_DIR:
+ if (*count < 5)
+ return singleline;
+ *count = 0;
+ break;
+ case TYPE_IPADDR:
+ case TYPE_CT_STATE:
+ case TYPE_CT_STATUS:
+ case TYPE_PKTTYPE:
+ if (*count < 2)
+ return singleline;
+ *count = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return newline;
+}
+
+static void set_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct expr *i;
+ const char *d = "";
+ int count = 0;
+
+ nft_print(octx, "{ ");
+
+ list_for_each_entry(i, &expr->expressions, list) {
+ nft_print(octx, "%s", d);
+ expr_print(i, octx);
+ count++;
+ d = calculate_delim(expr, &count);
+ }
+
+ nft_print(octx, " }");
+}
+
+static void set_expr_set_type(const struct expr *expr,
+ const struct datatype *dtype,
+ enum byteorder byteorder)
+{
+ struct expr *i;
+
+ list_for_each_entry(i, &expr->expressions, list)
+ expr_set_type(i, dtype, byteorder);
+}
+
+static const struct expr_ops set_expr_ops = {
+ .type = EXPR_SET,
+ .name = "set",
+ .print = set_expr_print,
+ .json = set_expr_json,
+ .set_type = set_expr_set_type,
+ .clone = compound_expr_clone,
+ .destroy = compound_expr_destroy,
+};
+
+struct expr *set_expr_alloc(const struct location *loc, const struct set *set)
+{
+ struct expr *set_expr = compound_expr_alloc(loc, EXPR_SET);
+
+ if (!set)
+ return set_expr;
+
+ set_expr->set_flags = set->flags;
+ datatype_set(set_expr, set->key->dtype);
+
+ return set_expr;
+}
+
+static void mapping_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ expr_print(expr->left, octx);
+ nft_print(octx, " : ");
+ expr_print(expr->right, octx);
+}
+
+static void mapping_expr_set_type(const struct expr *expr,
+ const struct datatype *dtype,
+ enum byteorder byteorder)
+{
+ expr_set_type(expr->left, dtype, byteorder);
+}
+
+static void mapping_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->left = expr_clone(expr->left);
+ new->right = expr_clone(expr->right);
+}
+
+static void mapping_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->left);
+ expr_free(expr->right);
+}
+
+static const struct expr_ops mapping_expr_ops = {
+ .type = EXPR_MAPPING,
+ .name = "mapping",
+ .print = mapping_expr_print,
+ .json = mapping_expr_json,
+ .set_type = mapping_expr_set_type,
+ .clone = mapping_expr_clone,
+ .destroy = mapping_expr_destroy,
+};
+
+struct expr *mapping_expr_alloc(const struct location *loc,
+ struct expr *from, struct expr *to)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_MAPPING, from->dtype,
+ from->byteorder, 0);
+ expr->left = from;
+ expr->right = to;
+ return expr;
+}
+
+static bool __set_expr_is_vmap(const struct expr *mappings)
+{
+ const struct expr *mapping;
+
+ if (list_empty(&mappings->expressions))
+ return false;
+
+ mapping = list_first_entry(&mappings->expressions, struct expr, list);
+ if (mapping->etype == EXPR_MAPPING &&
+ mapping->right->etype == EXPR_VERDICT)
+ return true;
+
+ return false;
+}
+
+static bool set_expr_is_vmap(const struct expr *expr)
+{
+
+ if (expr->mappings->etype == EXPR_SET)
+ return __set_expr_is_vmap(expr->mappings);
+
+ return false;
+}
+
+static void map_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ expr_print(expr->map, octx);
+ if ((expr->mappings->etype == EXPR_SET_REF &&
+ expr->mappings->set->data->dtype->type == TYPE_VERDICT) ||
+ set_expr_is_vmap(expr))
+ nft_print(octx, " vmap ");
+ else
+ nft_print(octx, " map ");
+
+ expr_print(expr->mappings, octx);
+}
+
+static void map_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->map = expr_clone(expr->map);
+ new->mappings = expr_clone(expr->mappings);
+}
+
+static void map_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->map);
+ expr_free(expr->mappings);
+}
+
+static const struct expr_ops map_expr_ops = {
+ .type = EXPR_MAP,
+ .name = "map",
+ .print = map_expr_print,
+ .json = map_expr_json,
+ .clone = map_expr_clone,
+ .destroy = map_expr_destroy,
+};
+
+struct expr *map_expr_alloc(const struct location *loc, struct expr *arg,
+ struct expr *mappings)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_MAP, &invalid_type, BYTEORDER_INVALID, 0);
+ expr->map = arg;
+ expr->mappings = mappings;
+ return expr;
+}
+
+static void set_ref_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ if (set_is_meter(expr->set->flags))
+ nft_print(octx, "%s", expr->set->handle.set.name);
+ else if (set_is_anonymous(expr->set->flags))
+ expr_print(expr->set->init, octx);
+ else
+ nft_print(octx, "@%s", expr->set->handle.set.name);
+}
+
+static void set_ref_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->set = set_get(expr->set);
+}
+
+static void set_ref_expr_destroy(struct expr *expr)
+{
+ set_free(expr->set);
+}
+
+static const struct expr_ops set_ref_expr_ops = {
+ .type = EXPR_SET_REF,
+ .name = "set reference",
+ .print = set_ref_expr_print,
+ .json = set_ref_expr_json,
+ .clone = set_ref_expr_clone,
+ .destroy = set_ref_expr_destroy,
+};
+
+struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_SET_REF, set->key->dtype, 0, 0);
+ expr->set = set_get(set);
+ expr->flags |= EXPR_F_CONSTANT;
+ return expr;
+}
+
+static void set_elem_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ struct stmt *stmt;
+
+ expr_print(expr->key, octx);
+ list_for_each_entry(stmt, &expr->stmt_list, list) {
+ nft_print(octx, " ");
+ stmt_print(stmt, octx);
+ }
+ if (expr->timeout) {
+ nft_print(octx, " timeout ");
+ time_print(expr->timeout, octx);
+ }
+ if (!nft_output_stateless(octx) && expr->expiration) {
+ nft_print(octx, " expires ");
+ time_print(expr->expiration, octx);
+ }
+ if (expr->comment)
+ nft_print(octx, " comment \"%s\"", expr->comment);
+}
+
+static void set_elem_expr_destroy(struct expr *expr)
+{
+ struct stmt *stmt, *next;
+
+ xfree(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)
+{
+ new->expiration = expr->expiration;
+ new->timeout = expr->timeout;
+ if (expr->comment)
+ new->comment = xstrdup(expr->comment);
+ init_list_head(&new->stmt_list);
+}
+
+static void set_elem_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->key = expr_clone(expr->key);
+ __set_elem_expr_clone(new, expr);
+}
+
+static const struct expr_ops set_elem_expr_ops = {
+ .type = EXPR_SET_ELEM,
+ .name = "set element",
+ .clone = set_elem_expr_clone,
+ .print = set_elem_expr_print,
+ .json = set_elem_expr_json,
+ .destroy = set_elem_expr_destroy,
+};
+
+struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_SET_ELEM, key->dtype,
+ key->byteorder, key->len);
+ expr->key = key;
+ init_list_head(&expr->stmt_list);
+
+ return expr;
+}
+
+static void set_elem_catchall_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "*");
+}
+
+static void set_elem_catchall_expr_clone(struct expr *new, const struct expr *expr)
+{
+ __set_elem_expr_clone(new, expr);
+}
+
+static const struct expr_ops set_elem_catchall_expr_ops = {
+ .type = EXPR_SET_ELEM_CATCHALL,
+ .name = "catch-all set element",
+ .print = set_elem_catchall_expr_print,
+ .json = set_elem_catchall_expr_json,
+ .clone = set_elem_catchall_expr_clone,
+};
+
+struct expr *set_elem_catchall_expr_alloc(const struct location *loc)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_SET_ELEM_CATCHALL, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+
+ return expr;
+}
+
+static void flagcmp_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ expr_print(expr->flagcmp.expr, octx);
+
+ if (expr->op == OP_NEQ)
+ nft_print(octx, " != ");
+ else
+ nft_print(octx, " ");
+
+ expr_print(expr->flagcmp.value, octx);
+ nft_print(octx, " / ");
+ expr_print(expr->flagcmp.mask, octx);
+}
+
+static void flagcmp_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->flagcmp.expr = expr_clone(expr->flagcmp.expr);
+ new->flagcmp.mask = expr_clone(expr->flagcmp.mask);
+ new->flagcmp.value = expr_clone(expr->flagcmp.value);
+}
+
+static void flagcmp_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->flagcmp.expr);
+ expr_free(expr->flagcmp.mask);
+ expr_free(expr->flagcmp.value);
+}
+
+static const struct expr_ops flagcmp_expr_ops = {
+ .type = EXPR_FLAGCMP,
+ .name = "flags comparison",
+ .print = flagcmp_expr_print,
+ .json = flagcmp_expr_json,
+ .clone = flagcmp_expr_clone,
+ .destroy = flagcmp_expr_destroy,
+};
+
+struct expr *flagcmp_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *match, struct expr *mask,
+ struct expr *value)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_FLAGCMP, match->dtype, match->byteorder,
+ match->len);
+ expr->op = op;
+ expr->flagcmp.expr = match;
+ expr->flagcmp.mask = mask;
+ /* json output needs this operation for compatibility */
+ expr->flagcmp.mask->op = OP_OR;
+ expr->flagcmp.value = value;
+
+ return expr;
+}
+
+void range_expr_value_low(mpz_t rop, const struct expr *expr)
+{
+ switch (expr->etype) {
+ case EXPR_VALUE:
+ return mpz_set(rop, expr->value);
+ case EXPR_PREFIX:
+ return range_expr_value_low(rop, expr->prefix);
+ case EXPR_RANGE:
+ return range_expr_value_low(rop, expr->left);
+ case EXPR_MAPPING:
+ return range_expr_value_low(rop, expr->left);
+ case EXPR_SET_ELEM:
+ return range_expr_value_low(rop, expr->key);
+ default:
+ BUG("invalid range expression type %s\n", expr_name(expr));
+ }
+}
+
+void range_expr_value_high(mpz_t rop, const struct expr *expr)
+{
+ mpz_t tmp;
+
+ switch (expr->etype) {
+ case EXPR_VALUE:
+ return mpz_set(rop, expr->value);
+ case EXPR_PREFIX:
+ range_expr_value_low(rop, expr->prefix);
+ assert(expr->len >= expr->prefix_len);
+ mpz_init_bitmask(tmp, expr->len - expr->prefix_len);
+ mpz_add(rop, rop, tmp);
+ mpz_clear(tmp);
+ return;
+ case EXPR_RANGE:
+ return range_expr_value_high(rop, expr->right);
+ case EXPR_MAPPING:
+ return range_expr_value_high(rop, expr->left);
+ case EXPR_SET_ELEM:
+ return range_expr_value_high(rop, expr->key);
+ default:
+ BUG("invalid range expression type %s\n", expr_name(expr));
+ }
+}
+
+static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
+{
+ switch (etype) {
+ case EXPR_INVALID: break;
+ case EXPR_VERDICT: return &verdict_expr_ops;
+ case EXPR_SYMBOL: return &symbol_expr_ops;
+ case EXPR_VARIABLE: return &variable_expr_ops;
+ case EXPR_VALUE: return &constant_expr_ops;
+ case EXPR_PREFIX: return &prefix_expr_ops;
+ case EXPR_RANGE: return &range_expr_ops;
+ case EXPR_PAYLOAD: return &payload_expr_ops;
+ case EXPR_EXTHDR: return &exthdr_expr_ops;
+ case EXPR_META: return &meta_expr_ops;
+ case EXPR_SOCKET: return &socket_expr_ops;
+ case EXPR_OSF: return &osf_expr_ops;
+ case EXPR_CT: return &ct_expr_ops;
+ case EXPR_CONCAT: return &concat_expr_ops;
+ case EXPR_LIST: return &list_expr_ops;
+ case EXPR_SET: return &set_expr_ops;
+ case EXPR_SET_REF: return &set_ref_expr_ops;
+ case EXPR_SET_ELEM: return &set_elem_expr_ops;
+ case EXPR_MAPPING: return &mapping_expr_ops;
+ case EXPR_MAP: return &map_expr_ops;
+ case EXPR_UNARY: return &unary_expr_ops;
+ case EXPR_BINOP: return &binop_expr_ops;
+ case EXPR_RELATIONAL: return &relational_expr_ops;
+ case EXPR_NUMGEN: return &numgen_expr_ops;
+ case EXPR_HASH: return &hash_expr_ops;
+ case EXPR_RT: return &rt_expr_ops;
+ case EXPR_FIB: return &fib_expr_ops;
+ case EXPR_XFRM: return &xfrm_expr_ops;
+ case EXPR_SET_ELEM_CATCHALL: return &set_elem_catchall_expr_ops;
+ case EXPR_FLAGCMP: return &flagcmp_expr_ops;
+ }
+
+ return NULL;
+}
+
+const struct expr_ops *expr_ops(const struct expr *e)
+{
+ const struct expr_ops *ops;
+
+ ops = __expr_ops_by_type(e->etype);
+ if (!ops)
+ BUG("Unknown expression type %d\n", e->etype);
+
+ return ops;
+}
+
+const struct expr_ops *expr_ops_by_type_u32(uint32_t value)
+{
+ if (value > EXPR_MAX)
+ return NULL;
+
+ return __expr_ops_by_type(value);
+}
diff --git a/src/exthdr.c b/src/exthdr.c
new file mode 100644
index 0000000..60c7cd1
--- /dev/null
+++ b/src/exthdr.c
@@ -0,0 +1,610 @@
+/*
+ * Exthdr expression protocol and type definitions and related functions.
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+
+#include <utils.h>
+#include <headers.h>
+#include <expression.h>
+#include <statement.h>
+#include <sctp_chunk.h>
+
+static const struct exthdr_desc *exthdr_definitions[PROTO_DESC_MAX + 1] = {
+ [EXTHDR_DESC_HBH] = &exthdr_hbh,
+ [EXTHDR_DESC_RT] = &exthdr_rt,
+ [EXTHDR_DESC_RT0] = &exthdr_rt0,
+ [EXTHDR_DESC_RT2] = &exthdr_rt2,
+ [EXTHDR_DESC_SRH] = &exthdr_rt4,
+ [EXTHDR_DESC_FRAG] = &exthdr_frag,
+ [EXTHDR_DESC_DST] = &exthdr_dst,
+ [EXTHDR_DESC_MH] = &exthdr_mh,
+};
+
+static const struct exthdr_desc *exthdr_find_desc(enum exthdr_desc_id desc_id)
+{
+ if (desc_id >= EXTHDR_DESC_UNKNOWN &&
+ desc_id <= EXTHDR_DESC_MAX)
+ return exthdr_definitions[desc_id];
+
+ return NULL;
+}
+
+static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *name = expr->exthdr.desc ?
+ expr->exthdr.desc->name : "unknown-exthdr";
+
+ if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
+ /* Offset calculation is a bit hacky at this point.
+ * There might be a tcp option one day with another
+ * multiplicator
+ */
+ unsigned int offset = expr->exthdr.offset / 64;
+
+ if (expr->exthdr.desc == NULL) {
+ if (expr->exthdr.offset == 0 &&
+ expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) {
+ nft_print(octx, "tcp option %d", expr->exthdr.raw_type);
+ return;
+ }
+
+ nft_print(octx, "tcp option @%u,%u,%u", expr->exthdr.raw_type,
+ expr->exthdr.offset, expr->len);
+ return;
+ }
+
+ nft_print(octx, "tcp option %s", name);
+ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
+ return;
+ if (offset)
+ nft_print(octx, "%d", offset);
+ nft_print(octx, " %s", expr->exthdr.tmpl->token);
+ } else if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
+ nft_print(octx, "ip option %s", name);
+ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
+ return;
+ nft_print(octx, " %s", expr->exthdr.tmpl->token);
+ } else if (expr->exthdr.op == NFT_EXTHDR_OP_SCTP) {
+ nft_print(octx, "sctp chunk %s", expr->exthdr.desc->name);
+ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
+ return;
+ nft_print(octx, " %s", expr->exthdr.tmpl->token);
+ } else if (expr->exthdr.op == NFT_EXTHDR_OP_DCCP) {
+ nft_print(octx, "dccp option %d", expr->exthdr.raw_type);
+ return;
+ } else {
+ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
+ nft_print(octx, "exthdr %s", name);
+ else {
+ nft_print(octx, "%s %s", name,
+ expr->exthdr.tmpl->token);
+ }
+ }
+}
+
+static bool exthdr_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->exthdr.desc == e2->exthdr.desc &&
+ e1->exthdr.tmpl == e2->exthdr.tmpl &&
+ e1->exthdr.op == e2->exthdr.op &&
+ e1->exthdr.raw_type == e2->exthdr.raw_type &&
+ e1->exthdr.flags == e2->exthdr.flags;
+}
+
+static void exthdr_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->exthdr.desc = expr->exthdr.desc;
+ new->exthdr.tmpl = expr->exthdr.tmpl;
+ new->exthdr.offset = expr->exthdr.offset;
+ new->exthdr.op = expr->exthdr.op;
+ new->exthdr.flags = expr->exthdr.flags;
+ new->exthdr.raw_type = expr->exthdr.raw_type;
+}
+
+#define NFTNL_UDATA_EXTHDR_DESC 0
+#define NFTNL_UDATA_EXTHDR_TYPE 1
+#define NFTNL_UDATA_EXTHDR_OP 2
+#define NFTNL_UDATA_EXTHDR_MAX 3
+
+static int exthdr_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_EXTHDR_DESC:
+ case NFTNL_UDATA_EXTHDR_TYPE:
+ case NFTNL_UDATA_EXTHDR_OP:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *exthdr_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_EXTHDR_MAX + 1] = {};
+ enum nft_exthdr_op op = NFT_EXTHDR_OP_IPV6;
+ const struct exthdr_desc *desc;
+ unsigned int type;
+ uint32_t desc_id;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ exthdr_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_EXTHDR_DESC] ||
+ !ud[NFTNL_UDATA_EXTHDR_TYPE])
+ return NULL;
+
+ if (ud[NFTNL_UDATA_EXTHDR_OP])
+ op = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_OP]);
+
+ desc_id = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_DESC]);
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_TYPE]);
+
+ switch (op) {
+ case NFT_EXTHDR_OP_IPV6:
+ desc = exthdr_find_desc(desc_id);
+
+ return exthdr_expr_alloc(&internal_location, desc, type);
+ case NFT_EXTHDR_OP_TCPOPT:
+ return tcpopt_expr_alloc(&internal_location,
+ desc_id, type);
+ case NFT_EXTHDR_OP_IPV4:
+ return ipopt_expr_alloc(&internal_location,
+ desc_id, type);
+ case NFT_EXTHDR_OP_SCTP:
+ return sctp_chunk_expr_alloc(&internal_location,
+ desc_id, type);
+ case NFT_EXTHDR_OP_DCCP:
+ return dccpopt_expr_alloc(&internal_location, type);
+ case __NFT_EXTHDR_OP_MAX:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static unsigned int expr_exthdr_type(const struct exthdr_desc *desc,
+ const struct proto_hdr_template *tmpl)
+{
+ return (unsigned int)(tmpl - &desc->templates[0]);
+}
+
+static int exthdr_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ const struct proto_hdr_template *tmpl = expr->exthdr.tmpl;
+ const struct exthdr_desc *desc = expr->exthdr.desc;
+ unsigned int type = expr_exthdr_type(desc, tmpl);
+ enum nft_exthdr_op op = expr->exthdr.op;
+
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_TYPE, type);
+ switch (op) {
+ case NFT_EXTHDR_OP_IPV6:
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, desc->id);
+ break;
+ case NFT_EXTHDR_OP_TCPOPT:
+ case NFT_EXTHDR_OP_IPV4:
+ case NFT_EXTHDR_OP_SCTP:
+ case NFT_EXTHDR_OP_DCCP:
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_OP, op);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, expr->exthdr.raw_type);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+const struct expr_ops exthdr_expr_ops = {
+ .type = EXPR_EXTHDR,
+ .name = "exthdr",
+ .print = exthdr_expr_print,
+ .json = exthdr_expr_json,
+ .cmp = exthdr_expr_cmp,
+ .clone = exthdr_expr_clone,
+ .build_udata = exthdr_expr_build_udata,
+ .parse_udata = exthdr_expr_parse_udata,
+};
+
+static const struct proto_hdr_template exthdr_unknown_template =
+ PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
+
+struct expr *exthdr_expr_alloc(const struct location *loc,
+ const struct exthdr_desc *desc,
+ uint8_t type)
+{
+ const struct proto_hdr_template *tmpl;
+ struct expr *expr;
+
+ if (desc != NULL)
+ tmpl = &desc->templates[type];
+ else
+ tmpl = &exthdr_unknown_template;
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+ BYTEORDER_BIG_ENDIAN, tmpl->len);
+ expr->exthdr.desc = desc;
+ expr->exthdr.raw_type = desc ? desc->type : 0;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.offset = tmpl->offset;
+ return expr;
+}
+
+static void exthdr_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ expr_print(stmt->exthdr.expr, octx);
+ nft_print(octx, " set ");
+ expr_print(stmt->exthdr.val, octx);
+}
+
+static void exthdr_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->exthdr.expr);
+ expr_free(stmt->exthdr.val);
+}
+
+static const struct stmt_ops exthdr_stmt_ops = {
+ .type = STMT_EXTHDR,
+ .name = "exthdr",
+ .print = exthdr_stmt_print,
+ .json = exthdr_stmt_json,
+ .destroy = exthdr_stmt_destroy,
+};
+
+struct stmt *exthdr_stmt_alloc(const struct location *loc,
+ struct expr *expr, struct expr *val)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &exthdr_stmt_ops);
+ stmt->exthdr.expr = expr;
+ stmt->exthdr.val = val;
+ return stmt;
+}
+
+static const struct exthdr_desc *exthdr_protocols[UINT8_MAX + 1] = {
+ [IPPROTO_HOPOPTS] = &exthdr_hbh,
+ [IPPROTO_ROUTING] = &exthdr_rt,
+ [IPPROTO_FRAGMENT] = &exthdr_frag,
+ [IPPROTO_DSTOPTS] = &exthdr_dst,
+ [IPPROTO_MH] = &exthdr_mh,
+};
+
+const struct exthdr_desc *exthdr_find_proto(uint8_t proto)
+{
+ assert(exthdr_protocols[proto]);
+
+ return exthdr_protocols[proto];
+}
+
+static const struct proto_hdr_template *
+exthdr_rt_find(struct expr *expr, const struct exthdr_desc *desc)
+{
+ const struct proto_hdr_template *tmpl;
+ unsigned int i;
+
+ for (i = 0; i < array_size(desc->templates); i++) {
+ tmpl = &desc->templates[i];
+ if (tmpl->offset == expr->exthdr.offset &&
+ tmpl->len == expr->len) {
+ expr->exthdr.desc = desc;
+ return tmpl;
+ }
+ }
+
+ return NULL;
+}
+
+void exthdr_init_raw(struct expr *expr, uint8_t type,
+ unsigned int offset, unsigned int len,
+ enum nft_exthdr_op op, uint32_t flags)
+{
+ const struct proto_hdr_template *tmpl = &exthdr_unknown_template;
+ unsigned int i;
+
+ assert(expr->etype == EXPR_EXTHDR);
+ expr->exthdr.raw_type = type;
+
+ if (op == NFT_EXTHDR_OP_TCPOPT)
+ return tcpopt_init_raw(expr, type, offset, len, flags);
+ if (op == NFT_EXTHDR_OP_IPV4)
+ return ipopt_init_raw(expr, type, offset, len, flags, true);
+ if (op == NFT_EXTHDR_OP_SCTP)
+ return sctp_chunk_init_raw(expr, type, offset, len, flags);
+ if (op == NFT_EXTHDR_OP_DCCP)
+ return dccpopt_init_raw(expr, type, offset, len);
+
+ expr->len = len;
+ expr->exthdr.flags = flags;
+ expr->exthdr.offset = offset;
+ expr->exthdr.desc = NULL;
+
+ expr->exthdr.desc = exthdr_protocols[type];
+
+ if (expr->exthdr.desc == NULL)
+ goto out;
+
+ for (i = 0; i < array_size(expr->exthdr.desc->templates); i++) {
+ tmpl = &expr->exthdr.desc->templates[i];
+ if (tmpl->offset == offset && tmpl->len == len)
+ goto out;
+ }
+
+ if (expr->exthdr.desc == &exthdr_rt) {
+ tmpl = exthdr_rt_find(expr, &exthdr_rt4);
+ if (tmpl)
+ goto out;
+ tmpl = exthdr_rt_find(expr, &exthdr_rt0);
+ if (tmpl)
+ goto out;
+ tmpl = exthdr_rt_find(expr, &exthdr_rt2);
+ if (tmpl)
+ goto out;
+ }
+
+ tmpl = &exthdr_unknown_template;
+ out:
+ expr->exthdr.tmpl = tmpl;
+ if (flags & NFT_EXTHDR_F_PRESENT)
+ datatype_set(expr, &boolean_type);
+ else
+ datatype_set(expr, tmpl->dtype);
+}
+
+static unsigned int mask_length(const struct expr *mask)
+{
+ unsigned long off = mpz_scan1(mask->value, 0);
+
+ return mpz_scan0(mask->value, off + 1);
+}
+
+bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned int *shift)
+{
+ unsigned int off, mask_offset, mask_len;
+ bool found;
+
+ mask_offset = mpz_scan1(mask->value, 0);
+ mask_len = mask_length(mask);
+
+ off = expr->exthdr.offset;
+ off += round_up(mask->len, BITS_PER_BYTE) - mask_len;
+
+ /* Handle ip options after the offset and mask have been calculated. */
+ switch (expr->exthdr.op) {
+ case NFT_EXTHDR_OP_IPV4:
+ found = ipopt_find_template(expr, off, mask_len - mask_offset);
+ break;
+ case NFT_EXTHDR_OP_TCPOPT:
+ found = tcpopt_find_template(expr, off, mask_len - mask_offset);
+ break;
+ case NFT_EXTHDR_OP_IPV6:
+ exthdr_init_raw(expr, expr->exthdr.raw_type,
+ off, mask_len - mask_offset, expr->exthdr.op, 0);
+
+ /* still failed to find a template... Bug. */
+ if (expr->exthdr.tmpl == &exthdr_unknown_template)
+ return false;
+ found = true;
+ break;
+ default:
+ found = false;
+ break;
+ }
+
+ if (found)
+ *shift = mask_offset;
+
+ return found;
+}
+
+#define HDR_TEMPLATE(__name, __dtype, __type, __member) \
+ PROTO_HDR_TEMPLATE(__name, __dtype, \
+ BYTEORDER_BIG_ENDIAN, \
+ offsetof(__type, __member) * 8, \
+ field_sizeof(__type, __member) * 8)
+
+/*
+ * Hop-by-hop options
+ */
+
+#define HBH_FIELD(__name, __member, __dtype) \
+ HDR_TEMPLATE(__name, __dtype, struct ip6_hbh, __member)
+
+const struct exthdr_desc exthdr_hbh = {
+ .name = "hbh",
+ .id = EXTHDR_DESC_HBH,
+ .type = IPPROTO_HOPOPTS,
+ .templates = {
+ [HBHHDR_NEXTHDR] = HBH_FIELD("nexthdr", ip6h_nxt, &inet_protocol_type),
+ [HBHHDR_HDRLENGTH] = HBH_FIELD("hdrlength", ip6h_len, &integer_type),
+ },
+};
+
+/*
+ * Routing header
+ */
+
+const struct exthdr_desc exthdr_rt2 = {
+ .name = "rt2",
+ .id = EXTHDR_DESC_RT2,
+ .type = IPPROTO_ROUTING,
+ .templates = {
+ [RT2HDR_RESERVED] = {},
+ [RT2HDR_ADDR] = {},
+ },
+};
+
+#define RT0_FIELD(__name, __member, __dtype) \
+ HDR_TEMPLATE(__name, __dtype, struct ip6_rthdr0, __member)
+
+const struct exthdr_desc exthdr_rt0 = {
+ .name = "rt0",
+ .id = EXTHDR_DESC_RT0,
+ .type = IPPROTO_ROUTING,
+ .templates = {
+ [RT0HDR_RESERVED] = RT0_FIELD("reserved", ip6r0_reserved, &integer_type),
+ [RT0HDR_ADDR_1] = RT0_FIELD("addr[1]", ip6r0_addr[0], &ip6addr_type),
+ [RT0HDR_ADDR_1 + 1] = RT0_FIELD("addr[2]", ip6r0_addr[1], &ip6addr_type),
+ // ...
+ },
+};
+
+#define RT4_FIELD(__name, __member, __dtype) \
+ HDR_TEMPLATE(__name, __dtype, struct ip6_rt4, __member)
+
+const struct exthdr_desc exthdr_rt4 = {
+ .name = "srh",
+ .id = EXTHDR_DESC_SRH,
+ .type = IPPROTO_ROUTING,
+ .templates = {
+ [RT4HDR_LASTENT] = RT4_FIELD("last-entry", ip6r4_last_entry, &integer_type),
+ [RT4HDR_FLAGS] = RT4_FIELD("flags", ip6r4_flags, &integer_type),
+ [RT4HDR_TAG] = RT4_FIELD("tag", ip6r4_tag, &integer_type),
+ [RT4HDR_SID_1] = RT4_FIELD("sid[1]", ip6r4_segments[0], &ip6addr_type),
+ [RT4HDR_SID_1 + 1] = RT4_FIELD("sid[2]", ip6r4_segments[1], &ip6addr_type),
+ // ...
+ },
+};
+
+
+#define RT_FIELD(__name, __member, __dtype) \
+ HDR_TEMPLATE(__name, __dtype, struct ip6_rthdr, __member)
+
+const struct exthdr_desc exthdr_rt = {
+ .name = "rt",
+ .id = EXTHDR_DESC_RT,
+ .type = IPPROTO_ROUTING,
+#if 0
+ .protocol_key = RTHDR_TYPE,
+ .protocols = {
+ [0] = &exthdr_rt0,
+ [2] = &exthdr_rt2,
+ },
+#endif
+ .templates = {
+ [RTHDR_NEXTHDR] = RT_FIELD("nexthdr", ip6r_nxt, &inet_protocol_type),
+ [RTHDR_HDRLENGTH] = RT_FIELD("hdrlength", ip6r_len, &integer_type),
+ [RTHDR_TYPE] = RT_FIELD("type", ip6r_type, &integer_type),
+ [RTHDR_SEG_LEFT] = RT_FIELD("seg-left", ip6r_segleft, &integer_type),
+ },
+};
+
+/*
+ * Fragment header
+ */
+
+#define FRAG_FIELD(__name, __member, __dtype) \
+ HDR_TEMPLATE(__name, __dtype, struct ip6_frag, __member)
+
+const struct exthdr_desc exthdr_frag = {
+ .name = "frag",
+ .id = EXTHDR_DESC_FRAG,
+ .type = IPPROTO_FRAGMENT,
+ .templates = {
+ [FRAGHDR_NEXTHDR] = FRAG_FIELD("nexthdr", ip6f_nxt, &inet_protocol_type),
+ [FRAGHDR_RESERVED] = FRAG_FIELD("reserved", ip6f_reserved, &integer_type),
+ [FRAGHDR_FRAG_OFF] = PROTO_HDR_TEMPLATE("frag-off", &integer_type,
+ BYTEORDER_BIG_ENDIAN,
+ 16, 13),
+ [FRAGHDR_RESERVED2] = PROTO_HDR_TEMPLATE("reserved2", &integer_type,
+ BYTEORDER_BIG_ENDIAN,
+ 29, 2),
+ [FRAGHDR_MFRAGS] = PROTO_HDR_TEMPLATE("more-fragments", &integer_type,
+ BYTEORDER_BIG_ENDIAN,
+ 31, 1),
+ [FRAGHDR_ID] = FRAG_FIELD("id", ip6f_ident, &integer_type),
+ },
+};
+
+/*
+ * DST options
+ */
+
+#define DST_FIELD(__name, __member, __dtype) \
+ HDR_TEMPLATE(__name, __dtype, struct ip6_dest, __member)
+
+const struct exthdr_desc exthdr_dst = {
+ .name = "dst",
+ .id = EXTHDR_DESC_DST,
+ .type = IPPROTO_DSTOPTS,
+ .templates = {
+ [DSTHDR_NEXTHDR] = DST_FIELD("nexthdr", ip6d_nxt, &inet_protocol_type),
+ [DSTHDR_HDRLENGTH] = DST_FIELD("hdrlength", ip6d_len, &integer_type),
+ },
+};
+
+/*
+ * Mobility header
+ */
+
+#define MH_FIELD(__name, __member, __dtype) \
+ HDR_TEMPLATE(__name, __dtype, struct ip6_mh, __member)
+
+static const struct symbol_table mh_type_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("binding-refresh-request", IP6_MH_TYPE_BRR),
+ SYMBOL("home-test-init", IP6_MH_TYPE_HOTI),
+ SYMBOL("careof-test-init", IP6_MH_TYPE_COTI),
+ SYMBOL("home-test", IP6_MH_TYPE_HOT),
+ SYMBOL("careof-test", IP6_MH_TYPE_COT),
+ SYMBOL("binding-update", IP6_MH_TYPE_BU),
+ SYMBOL("binding-acknowledgement", IP6_MH_TYPE_BACK),
+ SYMBOL("binding-error", IP6_MH_TYPE_BERROR),
+ SYMBOL("fast-binding-update", IP6_MH_TYPE_FBU),
+ SYMBOL("fast-binding-acknowledgement", IP6_MH_TYPE_FBACK),
+ SYMBOL("fast-binding-advertisement", IP6_MH_TYPE_FNA),
+ SYMBOL("experimental-mobility-header", IP6_MH_TYPE_EMH),
+ SYMBOL("home-agent-switch-message", IP6_MH_TYPE_HASM),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype mh_type_type = {
+ .type = TYPE_MH_TYPE,
+ .name = "mh_type",
+ .desc = "Mobility Header Type",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &mh_type_tbl,
+};
+
+const struct exthdr_desc exthdr_mh = {
+ .name = "mh",
+ .id = EXTHDR_DESC_MH,
+ .type = IPPROTO_MH,
+ .templates = {
+ [MHHDR_NEXTHDR] = MH_FIELD("nexthdr", ip6mh_proto, &inet_protocol_type),
+ [MHHDR_HDRLENGTH] = MH_FIELD("hdrlength", ip6mh_hdrlen, &integer_type),
+ [MHHDR_TYPE] = MH_FIELD("type", ip6mh_type, &mh_type_type),
+ [MHHDR_RESERVED] = MH_FIELD("reserved", ip6mh_reserved, &integer_type),
+ [MHHDR_CHECKSUM] = MH_FIELD("checksum", ip6mh_cksum, &integer_type),
+ },
+};
diff --git a/src/fib.c b/src/fib.c
new file mode 100644
index 0000000..e95271c
--- /dev/null
+++ b/src/fib.c
@@ -0,0 +1,202 @@
+/*
+ * FIB 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 (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 <fib.h>
+
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+
+static const char *fib_result[NFT_FIB_RESULT_MAX + 1] = {
+ [NFT_FIB_RESULT_OIF] = "oif",
+ [NFT_FIB_RESULT_OIFNAME] = "oifname",
+ [NFT_FIB_RESULT_ADDRTYPE] = "type",
+};
+
+static const struct symbol_table addrtype_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("unspec", RTN_UNSPEC),
+ SYMBOL("unicast", RTN_UNICAST),
+ SYMBOL("local", RTN_LOCAL),
+ SYMBOL("broadcast", RTN_BROADCAST),
+ SYMBOL("anycast", RTN_ANYCAST),
+ SYMBOL("multicast", RTN_MULTICAST),
+ SYMBOL("blackhole", RTN_BLACKHOLE),
+ SYMBOL("unreachable", RTN_UNREACHABLE),
+ SYMBOL("prohibit", RTN_PROHIBIT),
+ SYMBOL_LIST_END
+ }
+};
+
+const struct datatype fib_addr_type = {
+ .type = TYPE_FIB_ADDR,
+ .name = "fib_addrtype",
+ .desc = "fib address type",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &addrtype_tbl,
+};
+
+const char *fib_result_str(enum nft_fib_result result)
+{
+ if (result <= NFT_FIB_RESULT_MAX)
+ return fib_result[result];
+
+ return "unknown";
+}
+
+static void __fib_expr_print_f(unsigned int *flags, unsigned int f,
+ const char *s, struct output_ctx *octx)
+{
+ if ((*flags & f) == 0)
+ return;
+
+ nft_print(octx, "%s", s);
+ *flags &= ~f;
+ if (*flags)
+ nft_print(octx, " . ");
+}
+
+static void fib_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned int flags = expr->fib.flags & ~NFTA_FIB_F_PRESENT;
+
+ nft_print(octx, "fib ");
+ __fib_expr_print_f(&flags, NFTA_FIB_F_SADDR, "saddr", octx);
+ __fib_expr_print_f(&flags, NFTA_FIB_F_DADDR, "daddr", octx);
+ __fib_expr_print_f(&flags, NFTA_FIB_F_MARK, "mark", octx);
+ __fib_expr_print_f(&flags, NFTA_FIB_F_IIF, "iif", octx);
+ __fib_expr_print_f(&flags, NFTA_FIB_F_OIF, "oif", octx);
+
+ if (flags)
+ nft_print(octx, "0x%x", flags);
+
+ nft_print(octx, " %s", fib_result_str(expr->fib.result));
+}
+
+static bool fib_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->fib.result == e2->fib.result &&
+ e1->fib.flags == e2->fib.flags;
+}
+
+static void fib_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->fib.result = expr->fib.result;
+ new->fib.flags= expr->fib.flags;
+}
+
+#define NFTNL_UDATA_FIB_RESULT 0
+#define NFTNL_UDATA_FIB_FLAGS 1
+#define NFTNL_UDATA_FIB_MAX 2
+
+static int fib_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_FIB_RESULT, expr->fib.result);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_FIB_FLAGS, expr->fib.flags);
+
+ return 0;
+}
+
+static int fib_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_FIB_RESULT:
+ case NFTNL_UDATA_FIB_FLAGS:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *fib_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_FIB_MAX + 1] = {};
+ uint32_t flags, result;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ fib_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_FIB_RESULT] ||
+ !ud[NFTNL_UDATA_FIB_FLAGS])
+ return NULL;
+
+ result = nftnl_udata_get_u32(ud[NFTNL_UDATA_FIB_RESULT]);
+ flags = nftnl_udata_get_u32(ud[NFTNL_UDATA_FIB_FLAGS]);
+
+ return fib_expr_alloc(&internal_location, flags, result);
+}
+
+const struct expr_ops fib_expr_ops = {
+ .type = EXPR_FIB,
+ .name = "fib",
+ .print = fib_expr_print,
+ .json = fib_expr_json,
+ .cmp = fib_expr_cmp,
+ .clone = fib_expr_clone,
+ .parse_udata = fib_expr_parse_udata,
+ .build_udata = fib_expr_build_udata,
+};
+
+struct expr *fib_expr_alloc(const struct location *loc,
+ unsigned int flags, unsigned int result)
+{
+ const struct datatype *type;
+ unsigned int len = 4 * BITS_PER_BYTE;
+ struct expr *expr;
+
+ switch (result) {
+ case NFT_FIB_RESULT_OIF:
+ type = &ifindex_type;
+ break;
+ case NFT_FIB_RESULT_OIFNAME:
+ type = &string_type;
+ len = IFNAMSIZ * BITS_PER_BYTE;
+ break;
+ case NFT_FIB_RESULT_ADDRTYPE:
+ type = &fib_addr_type;
+ break;
+ default:
+ BUG("Unknown result %d\n", result);
+ }
+
+ if (flags & NFTA_FIB_F_PRESENT)
+ type = &boolean_type;
+
+ expr = expr_alloc(loc, EXPR_FIB, type,
+ BYTEORDER_HOST_ENDIAN, len);
+
+ expr->fib.result = result;
+ expr->fib.flags = flags;
+
+ return expr;
+}
diff --git a/src/gmputil.c b/src/gmputil.c
new file mode 100644
index 0000000..cb26b55
--- /dev/null
+++ b/src/gmputil.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nftables.h>
+#include <datatype.h>
+#include <utils.h>
+
+void mpz_bitmask(mpz_t rop, unsigned int width)
+{
+ mpz_set_ui(rop, 0);
+ mpz_setbit(rop, width);
+ mpz_sub_ui(rop, rop, 1);
+}
+
+void mpz_init_bitmask(mpz_t rop, unsigned int width)
+{
+ mpz_init2(rop, width);
+ mpz_bitmask(rop, width);
+}
+
+void mpz_prefixmask(mpz_t rop, unsigned int width, unsigned int prefix_len)
+{
+ mpz_bitmask(rop, prefix_len);
+ mpz_lshift_ui(rop, width - prefix_len);
+}
+
+void mpz_lshift_ui(mpz_t rop, unsigned int n)
+{
+ mpz_mul_2exp(rop, rop, n);
+}
+
+void mpz_rshift_ui(mpz_t rop, unsigned int n)
+{
+ mpz_tdiv_q_2exp(rop, rop, n);
+}
+
+#define mpz_get_type(type, endian, op) \
+({ \
+ type ret = 0; \
+ size_t cnt; \
+ mpz_export(&ret, &cnt, MPZ_LSWF, sizeof(ret), endian, 0, op); \
+ assert(cnt <= 1); \
+ ret; \
+ })
+
+uint64_t mpz_get_uint64(const mpz_t op)
+{
+ return mpz_get_type(uint64_t, MPZ_HOST_ENDIAN, op);
+}
+
+uint32_t mpz_get_uint32(const mpz_t op)
+{
+ return mpz_get_type(uint32_t, MPZ_HOST_ENDIAN, op);
+}
+
+uint16_t mpz_get_uint16(const mpz_t op)
+{
+ return mpz_get_type(uint16_t, MPZ_HOST_ENDIAN, op);
+}
+
+uint8_t mpz_get_uint8(const mpz_t op)
+{
+ return mpz_get_type(uint8_t, MPZ_HOST_ENDIAN, op);
+}
+
+uint32_t mpz_get_be32(const mpz_t op)
+{
+ return mpz_get_type(uint32_t, MPZ_BIG_ENDIAN, op);
+}
+
+uint16_t mpz_get_be16(const mpz_t op)
+{
+ return mpz_get_type(uint16_t, MPZ_BIG_ENDIAN, op);
+}
+
+void *__mpz_export_data(void *data, const mpz_t op, enum byteorder byteorder,
+ unsigned int len)
+{
+ enum mpz_word_order order;
+ enum mpz_byte_order endian;
+
+ switch (byteorder) {
+ case BYTEORDER_BIG_ENDIAN:
+ default:
+ order = MPZ_MSWF;
+ endian = MPZ_BIG_ENDIAN;
+ break;
+ case BYTEORDER_HOST_ENDIAN:
+ order = MPZ_HWO;
+ endian = MPZ_HOST_ENDIAN;
+ break;
+ }
+
+ memset(data, 0, len);
+ mpz_export(data, NULL, order, len, endian, 0, op);
+ return data;
+}
+
+void __mpz_import_data(mpz_t rop, const void *data, enum byteorder byteorder,
+ unsigned int len)
+{
+ enum mpz_word_order order;
+ enum mpz_byte_order endian;
+
+ switch (byteorder) {
+ case BYTEORDER_BIG_ENDIAN:
+ default:
+ order = MPZ_MSWF;
+ endian = MPZ_BIG_ENDIAN;
+ break;
+ case BYTEORDER_HOST_ENDIAN:
+ order = MPZ_HWO;
+ endian = MPZ_HOST_ENDIAN;
+ break;
+ }
+
+ mpz_import(rop, len, order, 1, endian, 0, data);
+}
+
+void __mpz_switch_byteorder(mpz_t rop, unsigned int len)
+{
+ char data[len];
+
+ __mpz_export_data(data, rop, BYTEORDER_BIG_ENDIAN, len);
+ __mpz_import_data(rop, data, BYTEORDER_HOST_ENDIAN, len);
+}
+
+#ifndef HAVE_LIBGMP
+/* mini-gmp doesn't have a gmp_printf so we use our own minimal
+ * variant here which is able to format a single mpz_t.
+ */
+int mpz_vfprintf(FILE *fp, const char *f, va_list args)
+{
+ const mpz_t *value = va_arg(args, const mpz_t *);
+ int n = 0;
+
+ while (*f) {
+ if (*f != '%') {
+ if (fputc(*f, fp) != *f)
+ return -1;
+
+ ++n;
+ } else {
+ unsigned long prec = 0;
+ int base;
+ size_t len;
+ char *str;
+ bool ok;
+
+ if (*++f == '.')
+ prec = strtoul(++f, (char**)&f, 10);
+
+ if (*f++ != 'Z')
+ return -1;
+
+ if (*f == 'u')
+ base = 10;
+ else if (*f == 'x')
+ base = 16;
+ else
+ return -1;
+
+ len = mpz_sizeinbase(*value, base);
+ while (prec-- > len) {
+ if (fputc('0', fp) != '0')
+ return -1;
+
+ ++n;
+ }
+
+ str = mpz_get_str(NULL, base, *value);
+ ok = str && fwrite(str, 1, len, fp) == len;
+ free(str);
+
+ if (!ok)
+ return -1;
+
+ n += len;
+ }
+ ++f;
+ }
+ return n;
+}
+#endif
diff --git a/src/hash.c b/src/hash.c
new file mode 100644
index 0000000..1c8c00a
--- /dev/null
+++ b/src/hash.c
@@ -0,0 +1,165 @@
+/*
+ * Hash expression definitions.
+ *
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <nftables.h>
+#include <expression.h>
+#include <datatype.h>
+#include <gmputil.h>
+#include <hash.h>
+#include <utils.h>
+
+static void hash_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ switch (expr->hash.type) {
+ case NFT_HASH_SYM:
+ nft_print(octx, "symhash");
+ break;
+ case NFT_HASH_JENKINS:
+ default:
+ nft_print(octx, "jhash ");
+ expr_print(expr->hash.expr, octx);
+ }
+
+ nft_print(octx, " mod %u", expr->hash.mod);
+ if (expr->hash.seed_set)
+ nft_print(octx, " seed 0x%x", expr->hash.seed);
+ if (expr->hash.offset)
+ nft_print(octx, " offset %u", expr->hash.offset);
+}
+
+static bool hash_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return (!e1->hash.expr ||
+ expr_cmp(e1->hash.expr, e2->hash.expr)) &&
+ e1->hash.mod == e2->hash.mod &&
+ e1->hash.seed_set == e2->hash.seed_set &&
+ e1->hash.seed == e2->hash.seed &&
+ e1->hash.offset == e2->hash.offset &&
+ e1->hash.type == e2->hash.type;
+}
+
+static void hash_expr_clone(struct expr *new, const struct expr *expr)
+{
+ if (expr->hash.expr)
+ new->hash.expr = expr_clone(expr->hash.expr);
+ new->hash.mod = expr->hash.mod;
+ new->hash.seed_set = expr->hash.seed_set;
+ new->hash.seed = expr->hash.seed;
+ new->hash.offset = expr->hash.offset;
+ new->hash.type = expr->hash.type;
+}
+
+static void hash_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->hash.expr);
+}
+
+#define NFTNL_UDATA_HASH_TYPE 0
+#define NFTNL_UDATA_HASH_OFFSET 1
+#define NFTNL_UDATA_HASH_MOD 2
+#define NFTNL_UDATA_HASH_SEED 3
+#define NFTNL_UDATA_HASH_SEED_SET 4
+#define NFTNL_UDATA_HASH_MAX 5
+
+static int hash_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_TYPE, expr->hash.type);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_OFFSET, expr->hash.offset);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_MOD, expr->hash.mod);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_SEED, expr->hash.seed);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_SEED_SET, expr->hash.seed_set);
+
+ return 0;
+}
+
+static int hash_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_HASH_TYPE:
+ case NFTNL_UDATA_HASH_OFFSET:
+ case NFTNL_UDATA_HASH_SEED:
+ case NFTNL_UDATA_HASH_SEED_SET:
+ case NFTNL_UDATA_HASH_MOD:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *hash_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_HASH_MAX + 1] = {};
+ uint32_t type, seed, seed_set, mod, offset;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ hash_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_HASH_TYPE] ||
+ !ud[NFTNL_UDATA_HASH_OFFSET] ||
+ !ud[NFTNL_UDATA_HASH_SEED] ||
+ !ud[NFTNL_UDATA_HASH_MOD] ||
+ !ud[NFTNL_UDATA_HASH_SEED_SET])
+ return NULL;
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_TYPE]);
+ offset = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_OFFSET]);
+ seed = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_SEED]);
+ seed_set = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_SEED_SET]);
+ mod = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_MOD]);
+
+ return hash_expr_alloc(&internal_location, mod, seed_set, seed,
+ offset, type);
+}
+
+const struct expr_ops hash_expr_ops = {
+ .type = EXPR_HASH,
+ .name = "hash",
+ .print = hash_expr_print,
+ .json = hash_expr_json,
+ .cmp = hash_expr_cmp,
+ .clone = hash_expr_clone,
+ .destroy = hash_expr_destroy,
+ .parse_udata = hash_expr_parse_udata,
+ .build_udata = hash_expr_build_udata,
+};
+
+struct expr *hash_expr_alloc(const struct location *loc,
+ uint32_t mod,
+ bool seed_set, uint32_t seed,
+ uint32_t offset,
+ enum nft_hash_types type)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_HASH, &integer_type,
+ BYTEORDER_HOST_ENDIAN, 4 * BITS_PER_BYTE);
+ expr->hash.mod = mod;
+ expr->hash.seed_set = seed_set;
+ expr->hash.seed = seed;
+ expr->hash.offset = offset;
+ expr->hash.type = type;
+
+ return expr;
+}
diff --git a/src/iface.c b/src/iface.c
new file mode 100644
index 0000000..428acaa
--- /dev/null
+++ b/src/iface.c
@@ -0,0 +1,173 @@
+/*
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <stdio.h>
+#include <net/if.h>
+#include <time.h>
+#include <errno.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/rtnetlink.h>
+
+#include <nftables.h>
+#include <list.h>
+#include <netlink.h>
+#include <iface.h>
+
+static LIST_HEAD(iface_list);
+static bool iface_cache_init;
+
+static int data_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type = mnl_attr_get_type(attr);
+
+ if (mnl_attr_type_valid(attr, IFLA_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case IFLA_IFNAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+ netlink_abi_error();
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nlattr *tb[IFLA_MAX + 1] = {};
+ struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh);
+ struct iface *iface;
+
+ iface = xmalloc(sizeof(struct iface));
+ iface->ifindex = ifm->ifi_index;
+ mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb);
+ snprintf(iface->name, IFNAMSIZ, "%s", mnl_attr_get_str(tb[IFLA_IFNAME]));
+ list_add(&iface->list, &iface_list);
+
+ return MNL_CB_OK;
+}
+
+static int iface_mnl_talk(struct mnl_socket *nl, uint32_t portid)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ struct rtgenmsg *rt;
+ bool eintr = false;
+ uint32_t seq;
+ int ret;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = RTM_GETLINK;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_seq = seq = time(NULL);
+ rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
+ rt->rtgen_family = AF_PACKET;
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+ return -1;
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
+ if (ret == 0)
+ break;
+ if (ret < 0) {
+ if (errno != EINTR)
+ return ret;
+
+ /* process all pending messages before reporting EINTR */
+ eintr = true;
+ }
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ }
+
+ if (eintr) {
+ ret = -1;
+ errno = EINTR;
+ }
+
+ return ret;
+}
+
+void iface_cache_update(void)
+{
+ struct mnl_socket *nl;
+ uint32_t portid;
+ int ret;
+
+ nl = mnl_socket_open(NETLINK_ROUTE);
+ if (nl == NULL)
+ netlink_init_error();
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
+ netlink_init_error();
+
+ portid = mnl_socket_get_portid(nl);
+
+ do {
+ ret = iface_mnl_talk(nl, portid);
+ } while (ret < 0 && errno == EINTR);
+
+ if (ret == -1)
+ netlink_init_error();
+
+ mnl_socket_close(nl);
+
+ iface_cache_init = true;
+}
+
+void iface_cache_release(void)
+{
+ struct iface *iface, *next;
+
+ if (!iface_cache_init)
+ return;
+
+ list_for_each_entry_safe(iface, next, &iface_list, list) {
+ list_del(&iface->list);
+ free(iface);
+ }
+ iface_cache_init = false;
+}
+
+unsigned int nft_if_nametoindex(const char *name)
+{
+ struct iface *iface;
+
+ if (!iface_cache_init)
+ iface_cache_update();
+
+ list_for_each_entry(iface, &iface_list, list) {
+ if (strncmp(name, iface->name, IFNAMSIZ) == 0)
+ return iface->ifindex;
+ }
+ return 0;
+}
+
+char *nft_if_indextoname(unsigned int ifindex, char *name)
+{
+ struct iface *iface;
+
+ if (!iface_cache_init)
+ iface_cache_update();
+
+ list_for_each_entry(iface, &iface_list, list) {
+ if (iface->ifindex == ifindex) {
+ snprintf(name, IFNAMSIZ, "%s", iface->name);
+ return name;
+ }
+ }
+ return NULL;
+}
diff --git a/src/intervals.c b/src/intervals.c
new file mode 100644
index 0000000..85de019
--- /dev/null
+++ b/src/intervals.c
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2022 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <nftables.h>
+#include <expression.h>
+#include <intervals.h>
+#include <rule.h>
+
+static void setelem_expr_to_range(struct expr *expr)
+{
+ unsigned char data[sizeof(struct in6_addr) * BITS_PER_BYTE];
+ struct expr *key, *value;
+ mpz_t rop;
+
+ assert(expr->etype == EXPR_SET_ELEM);
+
+ switch (expr->key->etype) {
+ case EXPR_SET_ELEM_CATCHALL:
+ case EXPR_RANGE:
+ break;
+ case EXPR_PREFIX:
+ mpz_init(rop);
+ mpz_bitmask(rop, expr->key->len - expr->key->prefix_len);
+ if (expr_basetype(expr)->type == TYPE_STRING)
+ mpz_switch_byteorder(expr->key->prefix->value, expr->len / BITS_PER_BYTE);
+
+ mpz_ior(rop, rop, expr->key->prefix->value);
+ mpz_export_data(data, rop, expr->key->prefix->byteorder,
+ expr->key->prefix->len / BITS_PER_BYTE);
+ mpz_clear(rop);
+ value = constant_expr_alloc(&expr->location,
+ expr->key->prefix->dtype,
+ expr->key->prefix->byteorder,
+ expr->key->prefix->len, data);
+ key = range_expr_alloc(&expr->location,
+ expr_get(expr->key->prefix),
+ value);
+ expr_free(expr->key);
+ expr->key = key;
+ break;
+ case EXPR_VALUE:
+ if (expr_basetype(expr)->type == TYPE_STRING)
+ mpz_switch_byteorder(expr->key->value, expr->len / BITS_PER_BYTE);
+
+ key = range_expr_alloc(&expr->location,
+ expr_clone(expr->key),
+ expr_get(expr->key));
+ expr_free(expr->key);
+ expr->key = key;
+ break;
+ default:
+ BUG("unhandled key type %d\n", expr->key->etype);
+ }
+}
+
+struct set_automerge_ctx {
+ struct set *set;
+ struct expr *init;
+ struct expr *purge;
+ unsigned int debug_mask;
+};
+
+static void purge_elem(struct set_automerge_ctx *ctx, struct expr *i)
+{
+ if (ctx->debug_mask & NFT_DEBUG_SEGTREE) {
+ pr_gmp_debug("remove: [%Zx-%Zx]\n",
+ i->key->left->value,
+ i->key->right->value);
+ }
+ list_move_tail(&i->list, &ctx->purge->expressions);
+}
+
+static void remove_overlapping_range(struct set_automerge_ctx *ctx,
+ struct expr *prev, struct expr *i)
+{
+ if (i->flags & EXPR_F_KERNEL) {
+ purge_elem(ctx, i);
+ return;
+ }
+ list_del(&i->list);
+ expr_free(i);
+ ctx->init->size--;
+}
+
+struct range {
+ mpz_t low;
+ mpz_t high;
+};
+
+static bool merge_ranges(struct set_automerge_ctx *ctx,
+ struct expr *prev, struct expr *i,
+ struct range *prev_range, struct range *range)
+{
+ if (prev->flags & EXPR_F_KERNEL) {
+ purge_elem(ctx, prev);
+ expr_free(i->key->left);
+ i->key->left = expr_get(prev->key->left);
+ mpz_set(prev_range->high, range->high);
+ return true;
+ } else if (i->flags & EXPR_F_KERNEL) {
+ purge_elem(ctx, i);
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->right);
+ mpz_set(prev_range->high, range->high);
+ } else {
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->right);
+ mpz_set(prev_range->high, range->high);
+ list_del(&i->list);
+ expr_free(i);
+ ctx->init->size--;
+ }
+ return false;
+}
+
+static void set_sort_splice(struct expr *init, struct set *set)
+{
+ struct set *existing_set = set->existing_set;
+
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+
+ if (!existing_set)
+ return;
+
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ list_splice_sorted(&existing_set->init->expressions,
+ &init->expressions);
+ init_list_head(&existing_set->init->expressions);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
+}
+
+static void setelem_automerge(struct set_automerge_ctx *ctx)
+{
+ struct expr *i, *next, *prev = NULL;
+ struct range range, prev_range;
+ mpz_t rop;
+
+ mpz_init(prev_range.low);
+ mpz_init(prev_range.high);
+ mpz_init(range.low);
+ mpz_init(range.high);
+ mpz_init(rop);
+
+ list_for_each_entry_safe(i, next, &ctx->init->expressions, list) {
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ range_expr_value_low(range.low, i);
+ range_expr_value_high(range.high, i);
+
+ if (!prev) {
+ prev = i;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ continue;
+ }
+
+ if (mpz_cmp(prev_range.low, range.low) <= 0 &&
+ mpz_cmp(prev_range.high, range.high) >= 0) {
+ remove_overlapping_range(ctx, prev, i);
+ continue;
+ } else if (mpz_cmp(range.low, prev_range.high) <= 0) {
+ if (merge_ranges(ctx, prev, i, &prev_range, &range))
+ prev = i;
+ continue;
+ } else if (ctx->set->automerge) {
+ mpz_sub(rop, range.low, prev_range.high);
+ /* two contiguous ranges */
+ if (mpz_cmp_ui(rop, 1) == 0) {
+ if (merge_ranges(ctx, prev, i, &prev_range, &range))
+ prev = i;
+ continue;
+ }
+ }
+
+ prev = i;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ }
+
+ mpz_clear(prev_range.low);
+ mpz_clear(prev_range.high);
+ mpz_clear(range.low);
+ mpz_clear(range.high);
+ mpz_clear(rop);
+}
+
+static struct expr *interval_expr_key(struct expr *i)
+{
+ struct expr *elem;
+
+ switch (i->etype) {
+ case EXPR_MAPPING:
+ elem = i->left;
+ break;
+ case EXPR_SET_ELEM:
+ elem = i;
+ break;
+ default:
+ BUG("unhandled expression type %d\n", i->etype);
+ return NULL;
+ }
+
+ return elem;
+}
+
+void set_to_range(struct expr *init)
+{
+ struct expr *i, *elem;
+
+ list_for_each_entry(i, &init->expressions, list) {
+ elem = interval_expr_key(i);
+ setelem_expr_to_range(elem);
+ }
+}
+
+int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
+ struct expr *init, unsigned int debug_mask)
+{
+ struct set *existing_set = set->existing_set;
+ struct set_automerge_ctx ctx = {
+ .set = set,
+ .init = init,
+ .debug_mask = debug_mask,
+ };
+ struct expr *i, *next, *clone;
+ struct cmd *purge_cmd;
+ struct handle h = {};
+
+ if (set->flags & NFT_SET_MAP) {
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+ return 0;
+ }
+
+ set_sort_splice(init, set);
+
+ ctx.purge = set_expr_alloc(&internal_location, set);
+
+ setelem_automerge(&ctx);
+
+ list_for_each_entry_safe(i, next, &init->expressions, list) {
+ if (i->flags & EXPR_F_KERNEL) {
+ list_move_tail(&i->list, &existing_set->init->expressions);
+ } else if (existing_set) {
+ if (debug_mask & NFT_DEBUG_SEGTREE) {
+ pr_gmp_debug("add: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ }
+ clone = expr_clone(i);
+ clone->flags |= EXPR_F_KERNEL;
+ list_add_tail(&clone->list, &existing_set->init->expressions);
+ }
+ }
+
+ if (list_empty(&ctx.purge->expressions)) {
+ expr_free(ctx.purge);
+ return 0;
+ }
+
+ handle_merge(&h, &set->handle);
+ purge_cmd = cmd_alloc(CMD_DELETE, CMD_OBJ_ELEMENTS, &h, &init->location, ctx.purge);
+ purge_cmd->elem.set = set_get(set);
+ list_add_tail(&purge_cmd->list, &cmd->list);
+
+ return 0;
+}
+
+static void remove_elem(struct expr *prev, struct set *set, struct expr *purge)
+{
+ struct expr *clone;
+
+ if (prev->flags & EXPR_F_KERNEL) {
+ clone = expr_clone(prev);
+ list_move_tail(&clone->list, &purge->expressions);
+ }
+}
+
+static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *i)
+{
+ prev->flags &= ~EXPR_F_KERNEL;
+ expr_free(prev->key->left);
+ prev->key->left = expr_get(i->key->right);
+ mpz_add_ui(prev->key->left->value, prev->key->left->value, 1);
+ list_move(&prev->list, &set->existing_set->init->expressions);
+}
+
+static void adjust_elem_left(struct set *set, struct expr *prev, struct expr *i,
+ struct expr *purge)
+{
+ remove_elem(prev, set, purge);
+ __adjust_elem_left(set, prev, i);
+
+ list_del(&i->list);
+ expr_free(i);
+}
+
+static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr *i)
+{
+ prev->flags &= ~EXPR_F_KERNEL;
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->left);
+ mpz_sub_ui(prev->key->right->value, prev->key->right->value, 1);
+ list_move(&prev->list, &set->existing_set->init->expressions);
+}
+
+static void adjust_elem_right(struct set *set, struct expr *prev, struct expr *i,
+ struct expr *purge)
+{
+ remove_elem(prev, set, purge);
+ __adjust_elem_right(set, prev, i);
+
+ list_del(&i->list);
+ expr_free(i);
+}
+
+static void split_range(struct set *set, struct expr *prev, struct expr *i,
+ struct expr *purge)
+{
+ struct expr *clone;
+
+ if (prev->flags & EXPR_F_KERNEL) {
+ clone = expr_clone(prev);
+ list_move_tail(&clone->list, &purge->expressions);
+ }
+
+ prev->flags &= ~EXPR_F_KERNEL;
+ clone = expr_clone(prev);
+ expr_free(clone->key->left);
+ clone->key->left = expr_get(i->key->right);
+ mpz_add_ui(clone->key->left->value, i->key->right->value, 1);
+ list_add_tail(&clone->list, &set->existing_set->init->expressions);
+
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->left);
+ mpz_sub_ui(prev->key->right->value, i->key->left->value, 1);
+ list_move(&prev->list, &set->existing_set->init->expressions);
+
+ list_del(&i->list);
+ expr_free(i);
+}
+
+static int setelem_adjust(struct set *set, struct expr *purge,
+ struct range *prev_range, struct range *range,
+ struct expr *prev, struct expr *i)
+{
+ if (mpz_cmp(prev_range->low, range->low) == 0 &&
+ mpz_cmp(prev_range->high, range->high) > 0) {
+ if (i->flags & EXPR_F_REMOVE)
+ adjust_elem_left(set, prev, i, purge);
+ } else if (mpz_cmp(prev_range->low, range->low) < 0 &&
+ mpz_cmp(prev_range->high, range->high) == 0) {
+ if (i->flags & EXPR_F_REMOVE)
+ adjust_elem_right(set, prev, i, purge);
+ } else if (mpz_cmp(prev_range->low, range->low) < 0 &&
+ mpz_cmp(prev_range->high, range->high) > 0) {
+ if (i->flags & EXPR_F_REMOVE)
+ split_range(set, prev, i, purge);
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int setelem_delete(struct list_head *msgs, struct set *set,
+ struct expr *purge, struct expr *elems,
+ unsigned int debug_mask)
+{
+ struct expr *i, *next, *prev = NULL;
+ struct range range, prev_range;
+ int err = 0;
+ mpz_t rop;
+
+ mpz_init(prev_range.low);
+ mpz_init(prev_range.high);
+ mpz_init(range.low);
+ mpz_init(range.high);
+ mpz_init(rop);
+
+ list_for_each_entry_safe(i, next, &elems->expressions, list) {
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ range_expr_value_low(range.low, i);
+ range_expr_value_high(range.high, i);
+
+ if (!prev && i->flags & EXPR_F_REMOVE) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
+ }
+
+ if (!(i->flags & EXPR_F_REMOVE)) {
+ prev = i;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ continue;
+ }
+
+ if (mpz_cmp(prev_range.low, range.low) == 0 &&
+ mpz_cmp(prev_range.high, range.high) == 0) {
+ if (i->flags & EXPR_F_REMOVE) {
+ if (prev->flags & EXPR_F_KERNEL)
+ list_move_tail(&prev->list, &purge->expressions);
+
+ list_del(&i->list);
+ expr_free(i);
+ }
+ } else if (set->automerge) {
+ if (setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
+ }
+ } else if (i->flags & EXPR_F_REMOVE) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
+ }
+ prev = NULL;
+ }
+err:
+ mpz_clear(prev_range.low);
+ mpz_clear(prev_range.high);
+ mpz_clear(range.low);
+ mpz_clear(range.high);
+ mpz_clear(rop);
+
+ return err;
+}
+
+static void automerge_delete(struct list_head *msgs, struct set *set,
+ struct expr *init, unsigned int debug_mask)
+{
+ struct set_automerge_ctx ctx = {
+ .set = set,
+ .init = init,
+ .debug_mask = debug_mask,
+ };
+
+ ctx.purge = set_expr_alloc(&internal_location, set);
+ list_expr_sort(&init->expressions);
+ setelem_automerge(&ctx);
+ expr_free(ctx.purge);
+}
+
+static int __set_delete(struct list_head *msgs, struct expr *i, struct set *set,
+ struct expr *init, struct set *existing_set,
+ unsigned int debug_mask)
+{
+ i->flags |= EXPR_F_REMOVE;
+ list_move(&i->list, &existing_set->init->expressions);
+ list_expr_sort(&existing_set->init->expressions);
+
+ return setelem_delete(msgs, set, init, existing_set->init, debug_mask);
+}
+
+/* detection for unexisting intervals already exists in Linux kernels >= 5.7. */
+int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
+ struct expr *init, unsigned int debug_mask)
+{
+ struct set *existing_set = set->existing_set;
+ struct expr *i, *next, *add, *clone;
+ struct handle h = {};
+ struct cmd *add_cmd;
+ LIST_HEAD(del_list);
+ int err;
+
+ set_to_range(init);
+ if (set->automerge)
+ automerge_delete(msgs, set, init, debug_mask);
+
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
+
+ list_splice_init(&init->expressions, &del_list);
+
+ list_for_each_entry_safe(i, next, &del_list, list) {
+ err = __set_delete(msgs, i, set, init, existing_set, debug_mask);
+ if (err < 0) {
+ list_splice(&del_list, &init->expressions);
+ return err;
+ }
+ }
+
+ add = set_expr_alloc(&internal_location, set);
+ list_for_each_entry(i, &existing_set->init->expressions, list) {
+ if (!(i->flags & EXPR_F_KERNEL)) {
+ clone = expr_clone(i);
+ list_add_tail(&clone->list, &add->expressions);
+ i->flags |= EXPR_F_KERNEL;
+ }
+ }
+
+ if (debug_mask & NFT_DEBUG_SEGTREE) {
+ list_for_each_entry(i, &init->expressions, list)
+ pr_gmp_debug("remove: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ list_for_each_entry(i, &add->expressions, list)
+ pr_gmp_debug("add: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ list_for_each_entry(i, &existing_set->init->expressions, list)
+ pr_gmp_debug("existing: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ }
+
+ if (list_empty(&add->expressions)) {
+ expr_free(add);
+ return 0;
+ }
+
+ handle_merge(&h, &cmd->handle);
+ add_cmd = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &h, &cmd->location, add);
+ add_cmd->elem.set = set_get(set);
+ list_add(&add_cmd->list, &cmd->list);
+
+ return 0;
+}
+
+static int setelem_overlap(struct list_head *msgs, struct set *set,
+ struct expr *init)
+{
+ struct expr *i, *next, *elem, *prev = NULL;
+ struct range range, prev_range;
+ int err = 0;
+ mpz_t rop;
+
+ mpz_init(prev_range.low);
+ mpz_init(prev_range.high);
+ mpz_init(range.low);
+ mpz_init(range.high);
+ mpz_init(rop);
+
+ list_for_each_entry_safe(elem, next, &init->expressions, list) {
+ i = interval_expr_key(elem);
+
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ range_expr_value_low(range.low, i);
+ range_expr_value_high(range.high, i);
+
+ if (!prev) {
+ prev = elem;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ continue;
+ }
+
+ if (mpz_cmp(prev_range.low, range.low) == 0 &&
+ mpz_cmp(prev_range.high, range.high) == 0)
+ goto next;
+
+ if (mpz_cmp(prev_range.low, range.low) <= 0 &&
+ mpz_cmp(prev_range.high, range.high) >= 0) {
+ if (prev->flags & EXPR_F_KERNEL)
+ expr_error(msgs, i, "interval overlaps with an existing one");
+ else if (elem->flags & EXPR_F_KERNEL)
+ expr_error(msgs, prev, "interval overlaps with an existing one");
+ else
+ expr_binary_error(msgs, i, prev,
+ "conflicting intervals specified");
+ err = -1;
+ goto err_out;
+ } else if (mpz_cmp(range.low, prev_range.high) <= 0) {
+ if (prev->flags & EXPR_F_KERNEL)
+ expr_error(msgs, i, "interval overlaps with an existing one");
+ else if (elem->flags & EXPR_F_KERNEL)
+ expr_error(msgs, prev, "interval overlaps with an existing one");
+ else
+ expr_binary_error(msgs, i, prev,
+ "conflicting intervals specified");
+ err = -1;
+ goto err_out;
+ }
+next:
+ prev = elem;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ }
+
+err_out:
+ mpz_clear(prev_range.low);
+ mpz_clear(prev_range.high);
+ mpz_clear(range.low);
+ mpz_clear(range.high);
+ mpz_clear(rop);
+
+ return err;
+}
+
+/* overlap detection for intervals already exists in Linux kernels >= 5.7. */
+int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
+{
+ struct set *existing_set = set->existing_set;
+ struct expr *i, *n, *clone;
+ int err;
+
+ set_sort_splice(init, set);
+
+ err = setelem_overlap(msgs, set, init);
+
+ list_for_each_entry_safe(i, n, &init->expressions, list) {
+ if (i->flags & EXPR_F_KERNEL)
+ list_move_tail(&i->list, &existing_set->init->expressions);
+ else if (existing_set) {
+ clone = expr_clone(i);
+ clone->flags |= EXPR_F_KERNEL;
+ list_add_tail(&clone->list, &existing_set->init->expressions);
+ }
+ }
+
+ return err;
+}
+
+static bool segtree_needs_first_segment(const struct set *set,
+ const struct expr *init, bool add)
+{
+ if (add && !set->root) {
+ /* Add the first segment in four situations:
+ *
+ * 1) This is an anonymous set.
+ * 2) This set exists and it is empty.
+ * 3) New empty set and, separately, new elements are added.
+ * 4) This set is created with a number of initial elements.
+ */
+ if ((set_is_anonymous(set->flags)) ||
+ (set->init && set->init->size == 0) ||
+ (set->init == NULL && init) ||
+ (set->init == init)) {
+ return true;
+ }
+ }
+ /* This is an update for a set that already contains elements, so don't
+ * add the first non-matching elements otherwise we hit EEXIST.
+ */
+ return false;
+}
+
+int set_to_intervals(const struct set *set, struct expr *init, bool add)
+{
+ struct expr *i, *n, *prev = NULL, *elem, *newelem = NULL, *root, *expr;
+ LIST_HEAD(intervals);
+ uint32_t flags;
+ mpz_t p, q;
+
+ mpz_init2(p, set->key->len);
+ mpz_init2(q, set->key->len);
+
+ list_for_each_entry_safe(i, n, &init->expressions, list) {
+ flags = 0;
+
+ elem = interval_expr_key(i);
+
+ if (elem->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ if (!prev && segtree_needs_first_segment(set, init, add) &&
+ mpz_cmp_ui(elem->key->left->value, 0)) {
+ mpz_set_ui(p, 0);
+ expr = constant_expr_alloc(&internal_location,
+ set->key->dtype,
+ set->key->byteorder,
+ set->key->len, NULL);
+ mpz_set(expr->value, p);
+ root = set_elem_expr_alloc(&internal_location, expr);
+ if (i->etype == EXPR_MAPPING) {
+ root = mapping_expr_alloc(&internal_location,
+ root,
+ expr_get(i->right));
+ }
+ root->flags |= EXPR_F_INTERVAL_END;
+ list_add(&root->list, &intervals);
+ init->size++;
+ }
+
+ if (newelem) {
+ mpz_set(p, interval_expr_key(newelem)->key->value);
+ if (set->key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(p, set->key->len / BITS_PER_BYTE);
+
+ if (!(set->flags & NFT_SET_ANONYMOUS) ||
+ mpz_cmp(p, elem->key->left->value) != 0)
+ list_add_tail(&newelem->list, &intervals);
+ else
+ expr_free(newelem);
+ }
+ newelem = NULL;
+
+ if (mpz_scan0(elem->key->right->value, 0) != set->key->len) {
+ mpz_add_ui(p, elem->key->right->value, 1);
+ expr = constant_expr_alloc(&elem->key->location, set->key->dtype,
+ set->key->byteorder, set->key->len,
+ NULL);
+ mpz_set(expr->value, p);
+ if (set->key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(expr->value, set->key->len / BITS_PER_BYTE);
+
+ newelem = set_elem_expr_alloc(&expr->location, expr);
+ if (i->etype == EXPR_MAPPING) {
+ newelem = mapping_expr_alloc(&expr->location,
+ newelem,
+ expr_get(i->right));
+ }
+ newelem->flags |= EXPR_F_INTERVAL_END;
+ } else {
+ flags = NFTNL_SET_ELEM_F_INTERVAL_OPEN;
+ }
+
+ expr = constant_expr_alloc(&elem->key->location, set->key->dtype,
+ set->key->byteorder, set->key->len, NULL);
+
+ mpz_set(expr->value, elem->key->left->value);
+ if (set->key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(expr->value, set->key->len / BITS_PER_BYTE);
+
+ expr_free(elem->key);
+ elem->key = expr;
+ i->elem_flags |= flags;
+ init->size++;
+ list_move_tail(&i->list, &intervals);
+
+ prev = i;
+ }
+
+ if (newelem)
+ list_add_tail(&newelem->list, &intervals);
+
+ list_splice_init(&intervals, &init->expressions);
+
+ mpz_clear(p);
+ mpz_clear(q);
+
+ return 0;
+}
diff --git a/src/ipopt.c b/src/ipopt.c
new file mode 100644
index 0000000..37f779d
--- /dev/null
+++ b/src/ipopt.c
@@ -0,0 +1,145 @@
+#include <nft.h>
+
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+
+#include <utils.h>
+#include <headers.h>
+#include <expression.h>
+#include <ipopt.h>
+
+static const struct proto_hdr_template ipopt_unknown_template =
+ PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
+
+#define PHT(__token, __offset, __len) \
+ PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
+ __offset, __len)
+static const struct exthdr_desc ipopt_lsrr = {
+ .name = "lsrr",
+ .type = IPOPT_LSRR,
+ .templates = {
+ [IPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8),
+ [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8),
+ [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32),
+ },
+};
+
+static const struct exthdr_desc ipopt_rr = {
+ .name = "rr",
+ .type = IPOPT_RR,
+ .templates = {
+ [IPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8),
+ [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8),
+ [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32),
+ },
+};
+
+static const struct exthdr_desc ipopt_ssrr = {
+ .name = "ssrr",
+ .type = IPOPT_SSRR,
+ .templates = {
+ [IPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8),
+ [IPOPT_FIELD_PTR] = PHT("ptr", 16, 8),
+ [IPOPT_FIELD_ADDR_0] = PHT("addr", 24, 32),
+ },
+};
+
+static const struct exthdr_desc ipopt_ra = {
+ .name = "ra",
+ .type = IPOPT_RA,
+ .templates = {
+ [IPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ [IPOPT_FIELD_LENGTH] = PHT("length", 8, 8),
+ [IPOPT_FIELD_VALUE] = PHT("value", 16, 16),
+ },
+};
+
+const struct exthdr_desc *ipopt_protocols[UINT8_MAX] = {
+ [IPOPT_LSRR] = &ipopt_lsrr,
+ [IPOPT_RR] = &ipopt_rr,
+ [IPOPT_SSRR] = &ipopt_ssrr,
+ [IPOPT_RA] = &ipopt_ra,
+};
+
+struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
+ uint8_t field)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct exthdr_desc *desc;
+ struct expr *expr;
+
+ desc = ipopt_protocols[type];
+ tmpl = &desc->templates[field];
+ if (!tmpl)
+ return NULL;
+
+ if (!tmpl->len)
+ return NULL;
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+ BYTEORDER_BIG_ENDIAN, tmpl->len);
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.op = NFT_EXTHDR_OP_IPV4;
+ expr->exthdr.offset = tmpl->offset;
+ expr->exthdr.raw_type = desc->type;
+
+ return expr;
+}
+
+void ipopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+ unsigned int len, uint32_t flags, bool set_unknown)
+{
+ const struct proto_hdr_template *tmpl;
+ unsigned int i;
+
+ assert(expr->etype == EXPR_EXTHDR);
+
+ expr->len = len;
+ expr->exthdr.flags = flags;
+ expr->exthdr.offset = offset;
+
+ assert(type < array_size(ipopt_protocols));
+ expr->exthdr.desc = ipopt_protocols[type];
+ expr->exthdr.flags = flags;
+
+ for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
+ tmpl = &expr->exthdr.desc->templates[i];
+
+ /* Make sure that it's the right template based on offset and len */
+ if (tmpl->offset != offset || tmpl->len != len)
+ continue;
+
+ if (flags & NFT_EXTHDR_F_PRESENT)
+ expr->dtype = &boolean_type;
+ else
+ expr->dtype = tmpl->dtype;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.op = NFT_EXTHDR_OP_IPV4;
+ break;
+ }
+ if (i == array_size(expr->exthdr.desc->templates) && set_unknown) {
+ expr->exthdr.tmpl = &ipopt_unknown_template;
+ expr->exthdr.op = NFT_EXTHDR_OP_IPV4;
+ }
+}
+
+bool ipopt_find_template(struct expr *expr, unsigned int offset,
+ unsigned int len)
+{
+ if (expr->exthdr.tmpl != &ipopt_unknown_template)
+ return false;
+
+ ipopt_init_raw(expr, expr->exthdr.desc->type, offset, len, 0, false);
+
+ if (expr->exthdr.tmpl == &ipopt_unknown_template)
+ return false;
+
+ return true;
+}
diff --git a/src/json.c b/src/json.c
new file mode 100644
index 0000000..068c423
--- /dev/null
+++ b/src/json.c
@@ -0,0 +1,2090 @@
+/*
+ * Copyright (c) Red Hat GmbH. Author: Phil Sutter <phil@nwl.cc>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <stdio.h>
+
+#include <expression.h>
+#include <list.h>
+#include <netlink.h>
+#include <rule.h>
+#include <rt.h>
+#include "nftutils.h"
+
+#include <netdb.h>
+#include <netinet/icmp6.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_synproxy.h>
+#include <linux/xfrm.h>
+#include <pwd.h>
+#include <grp.h>
+#include <jansson.h>
+#include <syslog.h>
+
+#ifdef DEBUG
+#define __json_pack json_pack
+#define json_pack(...) ({ \
+ json_t *__out = __json_pack(__VA_ARGS__); \
+ assert(__out); \
+ __out; \
+})
+#endif
+
+static json_t *expr_print_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct expr_ops *ops;
+ char buf[1024];
+ FILE *fp;
+
+ ops = expr_ops(expr);
+ if (ops->json)
+ return ops->json(expr, octx);
+
+ fprintf(stderr, "warning: expr ops %s have no json callback\n",
+ expr_name(expr));
+
+ fp = octx->output_fp;
+ octx->output_fp = fmemopen(buf, 1024, "w");
+
+ ops->print(expr, octx);
+
+ fclose(octx->output_fp);
+ octx->output_fp = fp;
+
+ return json_pack("s", buf);
+}
+
+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_r(namedup, " .", &tok_safe);
+ while (tok) {
+ json_t *jtok = json_string(tok);
+ if (!root)
+ root = jtok;
+ else if (json_is_string(root))
+ root = json_pack("[o, o]", root, jtok);
+ else
+ json_array_append_new(root, jtok);
+ tok = strtok_r(NULL, " .", &tok_safe);
+ }
+ xfree(namedup);
+ return root;
+}
+
+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;
+ 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;
+ const char *type, *datatype_ext = NULL;
+
+ if (set_is_datamap(set->flags)) {
+ type = "map";
+ datatype_ext = set->data->dtype->name;
+ } else if (set_is_objmap(set->flags)) {
+ type = "map";
+ datatype_ext = obj_type_name(set->objtype);
+ } else if (set_is_meter(set->flags)) {
+ type = "meter";
+ } else {
+ type = "set";
+ }
+
+ root = json_pack("{s:s, s:s, s:s, s:o, s:I}",
+ "family", family2str(set->handle.family),
+ "name", set->handle.set.name,
+ "table", set->handle.table.name,
+ "type", set_dtype_json(set->key),
+ "handle", set->handle.handle.id);
+
+ if (set->comment)
+ json_object_set_new(root, "comment", json_string(set->comment));
+ if (datatype_ext)
+ json_object_set_new(root, "map", json_string(datatype_ext));
+
+ if (!(set->flags & (NFT_SET_CONSTANT))) {
+ if (set->policy != NFT_SET_POL_PERFORMANCE) {
+ tmp = json_pack("s", set_policy2str(set->policy));
+ json_object_set_new(root, "policy", tmp);
+ }
+ if (set->desc.size) {
+ tmp = json_pack("i", set->desc.size);
+ json_object_set_new(root, "size", tmp);
+ }
+ }
+
+ tmp = json_array();
+ if (set->flags & NFT_SET_CONSTANT)
+ json_array_append_new(tmp, json_pack("s", "constant"));
+ if (set->flags & NFT_SET_INTERVAL)
+ 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);
+ } else {
+ if (json_array_size(tmp))
+ json_object_set(root, "flags", json_array_get(tmp, 0));
+ json_decref(tmp);
+ }
+
+ if (set->timeout) {
+ tmp = json_integer(set->timeout / 1000);
+ json_object_set_new(root, "timeout", tmp);
+ }
+ if (set->gc_int) {
+ tmp = json_pack("i", set->gc_int / 1000);
+ json_object_set_new(root, "gc-interval", tmp);
+ }
+
+ if (!nft_output_terse(octx) && set->init && set->init->size > 0) {
+ json_t *array = json_array();
+ const struct expr *i;
+
+ list_for_each_entry(i, &set->init->expressions, list)
+ json_array_append_new(array, expr_print_json(i, octx));
+
+ 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);
+}
+
+/* XXX: Merge with set_print_json()? */
+static json_t *element_print_json(struct output_ctx *octx,
+ const struct set *set)
+{
+ json_t *root = expr_print_json(set->init, octx);
+
+ return json_pack("{s: {s:s, s:s, s:s, s:o}}", "element",
+ "family", family2str(set->handle.family),
+ "table", set->handle.table.name,
+ "name", set->handle.set.name,
+ "elem", root);
+}
+
+static json_t *rule_print_json(struct output_ctx *octx,
+ const struct rule *rule)
+{
+ const struct stmt *stmt;
+ json_t *root, *tmp;
+
+ root = json_pack("{s:s, s:s, s:s, s:I}",
+ "family", family2str(rule->handle.family),
+ "table", rule->handle.table.name,
+ "chain", rule->handle.chain.name,
+ "handle", rule->handle.handle.id);
+ if (rule->comment)
+ json_object_set_new(root, "comment",
+ json_string(rule->comment));
+
+ tmp = json_array();
+ list_for_each_entry(stmt, &rule->stmts, list)
+ json_array_append_new(tmp, stmt_print_json(stmt, octx));
+
+ if (json_array_size(tmp))
+ json_object_set_new(root, "expr", tmp);
+ else {
+ fprintf(stderr, "rule without statements?!\n");
+ json_decref(tmp);
+ }
+
+ return json_pack("{s:o}", "rule", root);
+}
+
+static json_t *chain_print_json(const struct chain *chain)
+{
+ int priority, policy, n = 0;
+ struct expr *dev, *expr;
+ json_t *root, *tmp;
+
+ root = json_pack("{s:s, s:s, s:s, s:I}",
+ "family", family2str(chain->handle.family),
+ "table", chain->handle.table.name,
+ "name", chain->handle.chain.name,
+ "handle", chain->handle.handle.id);
+
+ if (chain->comment)
+ json_object_set_new(root, "comment", json_string(chain->comment));
+
+ if (chain->flags & CHAIN_F_BASECHAIN) {
+ mpz_export_data(&priority, chain->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ mpz_export_data(&policy, chain->policy->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ tmp = json_pack("{s:s, s:s, s:i, s:s}",
+ "type", chain->type.str,
+ "hook", hooknum2str(chain->handle.family,
+ 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));
+ }
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ }
+
+ return json_pack("{s:o}", "chain", root);
+}
+
+static json_t *proto_name_json(uint8_t proto)
+{
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (nft_getprotobynumber(proto, name, sizeof(name)))
+ return json_string(name);
+ return json_integer(proto);
+}
+
+static json_t *timeout_policy_json(uint8_t l4, const uint32_t *timeout)
+{
+ json_t *root = NULL;
+ unsigned int i;
+
+ for (i = 0; i < timeout_protocol[l4].array_size; i++) {
+ if (timeout[i] == timeout_protocol[l4].dflt_timeout[i])
+ continue;
+
+ if (!root)
+ root = json_object();
+ json_object_set_new(root, timeout_protocol[l4].state_to_name[i],
+ json_integer(timeout[i]));
+ }
+ return root ? : json_null();
+}
+
+static json_t *obj_print_json(const struct obj *obj)
+{
+ const char *rate_unit = NULL, *burst_unit = NULL;
+ const char *type = obj_type_name(obj->type);
+ json_t *root, *tmp, *flags;
+ uint64_t rate, burst;
+
+ root = json_pack("{s:s, s:s, s:s, s:I}",
+ "family", family2str(obj->handle.family),
+ "name", obj->handle.obj.name,
+ "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}",
+ "packets", obj->counter.packets,
+ "bytes", obj->counter.bytes);
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ case NFT_OBJECT_QUOTA:
+ tmp = json_pack("{s:I, s:I, s:b}",
+ "bytes", obj->quota.bytes,
+ "used", obj->quota.used,
+ "inv", obj->quota.flags & NFT_QUOTA_F_INV);
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ case NFT_OBJECT_SECMARK:
+ tmp = json_pack("{s:s}",
+ "context", obj->secmark.ctx);
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ case NFT_OBJECT_CT_HELPER:
+ tmp = json_pack("{s:s, s:o, s:s}",
+ "type", obj->ct_helper.name, "protocol",
+ proto_name_json(obj->ct_helper.l4proto),
+ "l3proto", family2str(obj->ct_helper.l3proto));
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ tmp = timeout_policy_json(obj->ct_timeout.l4proto,
+ obj->ct_timeout.timeout);
+ tmp = json_pack("{s:o, s:s, s:o}",
+ "protocol",
+ proto_name_json(obj->ct_timeout.l4proto),
+ "l3proto", family2str(obj->ct_timeout.l3proto),
+ "policy", tmp);
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ case NFT_OBJECT_CT_EXPECT:
+ tmp = json_pack("{s:o, s:I, s:I, s:I, s:s}",
+ "protocol",
+ proto_name_json(obj->ct_expect.l4proto),
+ "dport", obj->ct_expect.dport,
+ "timeout", obj->ct_expect.timeout,
+ "size", obj->ct_expect.size,
+ "l3proto", family2str(obj->ct_expect.l3proto));
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ case NFT_OBJECT_LIMIT:
+ rate = obj->limit.rate;
+ burst = obj->limit.burst;
+
+ if (obj->limit.type == NFT_LIMIT_PKT_BYTES) {
+ rate_unit = get_rate(obj->limit.rate, &rate);
+ burst_unit = get_rate(obj->limit.burst, &burst);
+ }
+
+ tmp = json_pack("{s:I, s:s}",
+ "rate", rate,
+ "per", get_unit(obj->limit.unit));
+
+ if (obj->limit.flags & NFT_LIMIT_F_INV)
+ json_object_set_new(tmp, "inv", json_true());
+ if (rate_unit)
+ json_object_set_new(tmp, "rate_unit",
+ json_string(rate_unit));
+ if (burst) {
+ json_object_set_new(tmp, "burst", json_integer(burst));
+ if (burst_unit)
+ json_object_set_new(tmp, "burst_unit",
+ json_string(burst_unit));
+ }
+
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ case NFT_OBJECT_SYNPROXY:
+ flags = json_array();
+ tmp = json_pack("{s:i, s:i}",
+ "mss", obj->synproxy.mss,
+ "wscale", obj->synproxy.wscale);
+ if (obj->synproxy.flags & NF_SYNPROXY_OPT_TIMESTAMP)
+ json_array_append_new(flags, json_string("timestamp"));
+ if (obj->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
+ json_array_append_new(flags, json_string("sack-perm"));
+
+ if (json_array_size(flags) > 0)
+ json_object_set_new(tmp, "flags", flags);
+ else
+ json_decref(flags);
+
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ break;
+ }
+
+ return json_pack("{s:o}", type, root);
+}
+
+static json_t *flowtable_print_json(const struct flowtable *ftable)
+{
+ json_t *root, *devs = NULL;
+ int i, priority;
+
+ mpz_export_data(&priority, ftable->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ root = json_pack("{s:s, s:s, s:s, s:I, s:s, s:i}",
+ "family", family2str(ftable->handle.family),
+ "name", ftable->handle.flowtable.name,
+ "table", ftable->handle.table.name,
+ "handle", ftable->handle.handle.id,
+ "hook", hooknum2str(NFPROTO_NETDEV, ftable->hook.num),
+ "prio", priority);
+
+ for (i = 0; i < ftable->dev_array_len; i++) {
+ const char *dev = ftable->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);
+
+ return json_pack("{s:o}", "flowtable", root);
+}
+
+static json_t *table_flags_json(const struct table *table)
+{
+ uint32_t flags = table->flags;
+ json_t *root = json_array(), *tmp;
+ int i = 0;
+
+ while (flags) {
+ if (flags & 0x1) {
+ tmp = json_string(table_flag_name(i));
+ json_array_append_new(root, tmp);
+ }
+ flags >>= 1;
+ i++;
+ }
+ switch (json_array_size(root)) {
+ case 0:
+ json_decref(root);
+ return NULL;
+ case 1:
+ json_unpack(root, "[o]", &tmp);
+ json_decref(root);
+ root = tmp;
+ break;
+ }
+ return root;
+}
+
+static json_t *table_print_json(const struct table *table)
+{
+ json_t *root, *tmp;
+
+ root = json_pack("{s:s, s:s, s:I}",
+ "family", family2str(table->handle.family),
+ "name", table->handle.table.name,
+ "handle", table->handle.handle.id);
+
+ tmp = table_flags_json(table);
+ if (tmp)
+ json_object_set_new(root, "flags", tmp);
+
+ if (table->comment)
+ json_object_set_new(root, "comment", json_string(table->comment));
+
+ return json_pack("{s:o}", "table", root);
+}
+
+json_t *flagcmp_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *left;
+
+ left = json_pack("{s:[o, o]}", expr_op_symbols[OP_AND],
+ expr_print_json(expr->flagcmp.expr, octx),
+ expr_print_json(expr->flagcmp.mask, octx));
+
+ return json_pack("{s:{s:s, s:o, s:o}}", "match",
+ "op", expr_op_symbols[expr->op] ? : "in",
+ "left", left,
+ "right", expr_print_json(expr->flagcmp.value, octx));
+}
+
+json_t *binop_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_pack("{s:[o, o]}", expr_op_symbols[expr->op],
+ expr_print_json(expr->left, octx),
+ expr_print_json(expr->right, octx));
+}
+
+json_t *relational_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_pack("{s:{s:s, s:o, s:o}}", "match",
+ "op", expr_op_symbols[expr->op] ? : "in",
+ "left", expr_print_json(expr->left, octx),
+ "right", expr_print_json(expr->right, octx));
+}
+
+json_t *range_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned int flags = octx->flags;
+ json_t *root;
+
+ octx->flags &= ~NFT_CTX_OUTPUT_SERVICE;
+ octx->flags |= NFT_CTX_OUTPUT_NUMERIC_PROTO;
+ root = json_pack("{s:[o, o]}", "range",
+ expr_print_json(expr->left, octx),
+ expr_print_json(expr->right, octx));
+ octx->flags = flags;
+
+ return root;
+}
+
+json_t *meta_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_pack("{s:{s:s}}", "meta",
+ "key", meta_templates[expr->meta.key].token);
+}
+
+json_t *payload_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *root;
+
+ 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);
+}
+
+json_t *ct_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *dirstr = ct_dir2str(expr->ct.direction);
+ enum nft_ct_keys key = expr->ct.key;
+ json_t *root;
+
+ root = json_pack("{s:s}", "key", ct_templates[key].token);
+
+ if (expr->ct.direction < 0)
+ goto out;
+
+ if (dirstr)
+ json_object_set_new(root, "dir", json_string(dirstr));
+out:
+ return json_pack("{s:o}", "ct", root);
+}
+
+json_t *concat_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *array = json_array();
+ const struct expr *i;
+
+ list_for_each_entry(i, &expr->expressions, list)
+ json_array_append_new(array, expr_print_json(i, octx));
+
+ return json_pack("{s:o}", "concat", array);
+}
+
+json_t *set_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *array = json_array();
+ const struct expr *i;
+
+ list_for_each_entry(i, &expr->expressions, list)
+ json_array_append_new(array, expr_print_json(i, octx));
+
+ return json_pack("{s:o}", "set", array);
+}
+
+json_t *set_ref_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ if (set_is_anonymous(expr->set->flags)) {
+ return expr_print_json(expr->set->init, octx);
+ } else {
+ return json_pack("s+", "@", expr->set->handle.set.name);
+ }
+}
+
+json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *root = expr_print_json(expr->key, octx);
+ struct stmt *stmt;
+ json_t *tmp;
+
+ if (!root)
+ return NULL;
+
+ /* these element attributes require formal set elem syntax */
+ if (expr->timeout || expr->expiration || expr->comment ||
+ !list_empty(&expr->stmt_list)) {
+ root = json_pack("{s:o}", "val", root);
+
+ if (expr->timeout) {
+ tmp = json_integer(expr->timeout / 1000);
+ json_object_set_new(root, "timeout", tmp);
+ }
+ if (expr->expiration) {
+ tmp = json_integer(expr->expiration / 1000);
+ json_object_set_new(root, "expires", tmp);
+ }
+ if (expr->comment) {
+ tmp = json_string(expr->comment);
+ json_object_set_new(root, "comment", tmp);
+ }
+ list_for_each_entry(stmt, &expr->stmt_list, list) {
+ tmp = stmt_print_json(stmt, octx);
+ /* XXX: detect and complain about clashes? */
+ json_object_update_missing(root, tmp);
+ json_decref(tmp);
+ /* TODO: only one statement per element. */
+ break;
+ }
+ return json_pack("{s:o}", "elem", root);
+ }
+
+ return root;
+}
+
+json_t *prefix_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *root = expr_print_json(expr->prefix, octx);
+
+ return json_pack("{s:{s:o, s:i}}", "prefix",
+ "addr", root,
+ "len", expr->prefix_len);
+}
+
+json_t *list_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *array = json_array();
+ const struct expr *i;
+
+ list_for_each_entry(i, &expr->expressions, list)
+ json_array_append_new(array, expr_print_json(i, octx));
+
+ //return json_pack("{s:s, s:o}", "type", "list", "val", array);
+ return array;
+}
+
+json_t *unary_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return expr_print_json(expr->arg, octx);
+}
+
+json_t *mapping_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_pack("[o, o]",
+ expr_print_json(expr->left, octx),
+ expr_print_json(expr->right, octx));
+}
+
+json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *type = "map";
+
+ if (expr->mappings->etype == EXPR_SET_REF &&
+ expr->mappings->set->data->dtype->type == TYPE_VERDICT)
+ type = "vmap";
+
+ return json_pack("{s:{s:o, s:o}}", type,
+ "key", expr_print_json(expr->map, octx),
+ "data", expr_print_json(expr->mappings, octx));
+}
+
+json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *desc = expr->exthdr.desc ?
+ expr->exthdr.desc->name : NULL;
+ const char *field = expr->exthdr.tmpl->token;
+ json_t *root;
+ bool is_exists = expr->exthdr.flags & NFT_EXTHDR_F_PRESENT;
+
+ if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
+ static const char *offstrs[] = { "", "1", "2", "3" };
+ unsigned int offset = expr->exthdr.offset / 64;
+ const char *offstr = "";
+
+ if (desc) {
+ if (offset < 4)
+ offstr = offstrs[offset];
+
+ root = json_pack("{s:s+}", "name", desc, offstr);
+
+ if (!is_exists)
+ json_object_set_new(root, "field", json_string(field));
+ } else {
+ root = json_pack("{s:i, s:i, s:i}",
+ "base", expr->exthdr.raw_type,
+ "offset", expr->exthdr.offset,
+ "len", expr->len);
+ }
+
+ 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));
+
+ switch (expr->exthdr.op) {
+ case NFT_EXTHDR_OP_IPV4:
+ return json_pack("{s:o}", "ip option", root);
+ case NFT_EXTHDR_OP_SCTP:
+ return json_pack("{s:o}", "sctp chunk", root);
+ default:
+ return json_pack("{s:o}", "exthdr", root);
+ }
+}
+
+json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct {
+ int verdict;
+ const char *name;
+ bool chain;
+ } verdict_tbl[] = {
+ { NFT_CONTINUE, "continue", false },
+ { NFT_BREAK, "break", false },
+ { NFT_JUMP, "jump", true },
+ { NFT_GOTO, "goto", true },
+ { NFT_RETURN, "return", false },
+ { NF_ACCEPT, "accept", false },
+ { NF_DROP, "drop", false },
+ { NF_QUEUE, "queue", false },
+ };
+ const char *name = NULL;
+ json_t *chain = NULL;
+ unsigned int i;
+
+ for (i = 0; i < array_size(verdict_tbl); i++) {
+ if (expr->verdict == verdict_tbl[i].verdict) {
+ name = verdict_tbl[i].name;
+ if (verdict_tbl[i].chain && expr->chain)
+ chain = expr_print_json(expr->chain, octx);
+ break;
+ }
+ }
+ if (!name) {
+ BUG("Unknown verdict %d.", expr->verdict);
+ return NULL;
+ }
+ if (chain)
+ return json_pack("{s:{s:o}}", name, "target", chain);
+ else
+ return json_pack("{s:n}", name);
+}
+
+json_t *rt_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *key = rt_templates[expr->rt.key].token;
+ json_t *root = json_pack("{s:s}", "key", key);
+ const char *family = NULL;
+
+ switch (expr->rt.key) {
+ case NFT_RT_NEXTHOP4:
+ family = "ip";
+ break;
+ case NFT_RT_NEXTHOP6:
+ family = "ip6";
+ break;
+ default:
+ break;
+ }
+
+ if (family)
+ json_object_set_new(root, "family", json_string(family));
+
+ return json_pack("{s:o}", "rt", root);
+}
+
+json_t *numgen_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *mode;
+
+ switch (expr->numgen.type) {
+ case NFT_NG_INCREMENTAL:
+ mode = "inc";
+ break;
+ case NFT_NG_RANDOM:
+ mode = "random";
+ break;
+ default:
+ mode = "unknown";
+ break;
+ }
+
+ return json_pack("{s:{s:s, s:i, s:i}}", "numgen",
+ "mode", mode,
+ "mod", expr->numgen.mod,
+ "offset", expr->numgen.offset);
+}
+
+json_t *hash_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *type;
+ json_t *root, *jexpr = NULL;
+
+ switch (expr->hash.type) {
+ case NFT_HASH_SYM:
+ type = "symhash";
+ break;
+ case NFT_HASH_JENKINS:
+ default:
+ type = "jhash";
+ jexpr = expr_print_json(expr->hash.expr, octx);
+ break;
+ }
+
+ root = json_pack("{s:i}", "mod", expr->hash.mod);
+ if (expr->hash.seed_set)
+ json_object_set_new(root, "seed",
+ json_integer(expr->hash.seed));
+ if (expr->hash.offset)
+ json_object_set_new(root, "offset",
+ json_integer(expr->hash.offset));
+ if (jexpr)
+ json_object_set_new(root, "expr", jexpr);
+
+ return json_pack("{s:o}", type, root);
+}
+
+json_t *fib_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *fib_flags[] = { "saddr", "daddr", "mark", "iif", "oif" };
+ unsigned int flags = expr->fib.flags & ~NFTA_FIB_F_PRESENT;
+ json_t *root;
+
+ root = json_pack("{s:s}", "result", fib_result_str(expr->fib.result));
+
+ if (flags) {
+ json_t *tmp = json_array();
+ unsigned int i;
+
+ for (i = 0; i < array_size(fib_flags); i++) {
+ if (flags & (1 << i)) {
+ json_array_append_new(tmp, json_string(fib_flags[i]));
+ flags &= ~(1 << i);
+ }
+ }
+ if (flags)
+ json_array_append_new(tmp, json_integer(flags));
+ json_object_set_new(root, "flags", tmp);
+ }
+ return json_pack("{s:o}", "fib", root);
+}
+
+static json_t *symbolic_constant_json(const struct symbol_table *tbl,
+ const struct expr *expr,
+ struct output_ctx *octx)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ const struct symbolic_constant *s;
+ uint64_t val = 0;
+
+ /* Export the data in the correct byteorder for comparison */
+ assert(expr->len / BITS_PER_BYTE <= sizeof(val));
+ mpz_export_data(constant_data_ptr(val, expr->len), expr->value,
+ expr->byteorder, len);
+
+ for (s = tbl->symbols; s->identifier != NULL; s++) {
+ if (val == s->value)
+ break;
+ }
+ if (!s->identifier)
+ return expr_basetype(expr)->json(expr, octx);
+
+ if (nft_output_numeric_symbol(octx))
+ return json_integer(val);
+ else
+ return json_string(s->identifier);
+}
+
+json_t *set_elem_catchall_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_string("*");
+}
+
+static json_t *datatype_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct datatype *dtype = expr->dtype;
+
+ do {
+ if (dtype->json)
+ return dtype->json(expr, octx);
+ if (dtype->sym_tbl)
+ return symbolic_constant_json(dtype->sym_tbl,
+ expr, octx);
+ if (dtype->print) {
+ char buf[1024];
+ FILE *ofp = octx->output_fp;
+
+ octx->output_fp = fmemopen(buf, 1024, "w");
+ dtype->print(expr, octx);
+ fclose(octx->output_fp);
+ octx->output_fp = ofp;
+
+ if (buf[0] == '"') {
+ memmove(buf, buf + 1, strlen(buf));
+ *strchrnul(buf, '"') = '\0';
+ }
+
+ return json_string(buf);
+ }
+ } while ((dtype = dtype->basetype));
+
+ BUG("datatype %s has no print method or symbol table\n",
+ expr->dtype->name);
+}
+
+json_t *constant_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return datatype_json(expr, octx);
+}
+
+json_t *socket_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_pack("{s:{s:s}}", "socket", "key",
+ socket_templates[expr->socket.key].token);
+}
+
+json_t *osf_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *root;
+
+ if (expr->osf.flags & NFT_OSF_F_VERSION)
+ root = json_pack("{s:s}", "key", "version");
+ else
+ root = json_pack("{s:s}", "key", "name");
+
+ switch (expr->osf.ttl) {
+ case 1:
+ json_object_set_new(root, "ttl", json_string("loose"));
+ break;
+ case 2:
+ json_object_set_new(root, "ttl", json_string("skip"));
+ break;
+ }
+
+ return json_pack("{s:o}", "osf", root);
+}
+
+json_t *xfrm_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *name = xfrm_templates[expr->xfrm.key].token;
+ const char *family = NULL;
+ const char *dirstr;
+ json_t *root;
+
+ switch (expr->xfrm.direction) {
+ case XFRM_POLICY_IN:
+ dirstr = "in";
+ break;
+ case XFRM_POLICY_OUT:
+ dirstr = "out";
+ break;
+ default:
+ return NULL;
+ }
+
+ switch (expr->xfrm.key) {
+ case NFT_XFRM_KEY_UNSPEC:
+ case NFT_XFRM_KEY_SPI:
+ case NFT_XFRM_KEY_REQID:
+ case __NFT_XFRM_KEY_MAX:
+ break;
+ case NFT_XFRM_KEY_DADDR_IP4:
+ case NFT_XFRM_KEY_SADDR_IP4:
+ family = "ip";
+ break;
+ case NFT_XFRM_KEY_DADDR_IP6:
+ case NFT_XFRM_KEY_SADDR_IP6:
+ family = "ip6";
+ break;
+ }
+
+ root = json_pack("{s:s}", "key", name);
+
+ if (family)
+ json_object_set_new(root, "family", json_string(family));
+
+ json_object_set_new(root, "dir", json_string(dirstr));
+ json_object_set_new(root, "spnum", json_integer(expr->xfrm.spnum));
+
+ return json_pack("{s:o}", "ipsec", root);
+}
+
+json_t *integer_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ char buf[1024] = "0x";
+
+ if (mpz_fits_ulong_p(expr->value))
+ return json_integer(mpz_get_ui(expr->value));
+
+ mpz_get_str(buf + 2, 16, expr->value);
+ return json_string(buf);
+}
+
+json_t *string_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ char data[len+1];
+
+ mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
+ data[len] = '\0';
+
+ return json_string(data);
+}
+
+json_t *boolean_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ uint64_t val = 0;
+
+ /* Export the data in the correct byteorder for comparison */
+ assert(expr->len / BITS_PER_BYTE <= sizeof(val));
+ mpz_export_data(constant_data_ptr(val, expr->len), expr->value,
+ expr->byteorder, len);
+
+ return json_boolean((int)val);
+}
+
+json_t *inet_protocol_type_json(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ if (!nft_output_numeric_proto(octx)) {
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name)))
+ return json_string(name);
+ }
+ return integer_type_json(expr, octx);
+}
+
+json_t *inet_service_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ uint16_t port = mpz_get_be16(expr->value);
+ char name[NFT_SERVNAME_MAXSIZE];
+
+ if (!nft_output_service(octx) ||
+ !nft_getservbyport(port, NULL, name, sizeof(name)))
+ return json_integer(ntohs(port));
+
+ return json_string(name);
+}
+
+json_t *mark_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return symbolic_constant_json(octx->tbl.mark, expr, octx);
+}
+
+json_t *devgroup_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return symbolic_constant_json(octx->tbl.devgroup, expr, octx);
+}
+
+json_t *ct_label_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ unsigned long bit = mpz_scan1(expr->value, 0);
+ const char *labelstr = ct_label2str(octx->tbl.ct_label, bit);
+
+ if (labelstr)
+ return json_string(labelstr);
+
+ /* can happen when connlabel.conf is altered after rules were added */
+ return json_integer(bit);
+}
+
+json_t *time_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_integer(mpz_get_uint64(expr->value) / MSEC_PER_SEC);
+}
+
+json_t *uid_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ uint32_t uid = mpz_get_uint32(expr->value);
+
+ if (nft_output_guid(octx)) {
+ struct passwd *pw = getpwuid(uid);
+
+ if (pw)
+ return json_string(pw->pw_name);
+ }
+ return json_integer(uid);
+}
+
+json_t *gid_type_json(const struct expr *expr, struct output_ctx *octx)
+{
+ uint32_t gid = mpz_get_uint32(expr->value);
+
+ if (nft_output_guid(octx)) {
+ struct group *gr = getgrgid(gid);
+
+ if (gr)
+ return json_string(gr->gr_name);
+ }
+ return json_integer(gid);
+}
+
+json_t *expr_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return expr_print_json(stmt->expr, octx);
+}
+
+json_t *flow_offload_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return json_pack("{s:{s:s, s:s+}}", "flow",
+ "op", "add", "flowtable",
+ "@", stmt->flow.table_name);
+}
+
+json_t *payload_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return json_pack("{s: {s:o, s:o}}", "mangle",
+ "key", expr_print_json(stmt->payload.expr, octx),
+ "value", expr_print_json(stmt->payload.val, octx));
+}
+
+json_t *exthdr_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return json_pack("{s: {s:o, s:o}}", "mangle",
+ "key", expr_print_json(stmt->exthdr.expr, octx),
+ "value", expr_print_json(stmt->exthdr.val, octx));
+}
+
+json_t *quota_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ const char *data_unit;
+ uint64_t bytes;
+ json_t *root;
+
+ data_unit = get_rate(stmt->quota.bytes, &bytes);
+ root = json_pack("{s:I, s:s}",
+ "val", bytes,
+ "val_unit", data_unit);
+
+ if (stmt->quota.flags & NFT_QUOTA_F_INV)
+ json_object_set_new(root, "inv", json_true());
+ if (!nft_output_stateless(octx) && stmt->quota.used) {
+ data_unit = get_rate(stmt->quota.used, &bytes);
+ json_object_set_new(root, "used", json_integer(bytes));
+ json_object_set_new(root, "used_unit", json_string(data_unit));
+ }
+
+ return json_pack("{s:o}", "quota", root);
+}
+
+json_t *ct_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ struct expr expr = {
+ .ct = {
+ .key = stmt->ct.key,
+ .direction = stmt->ct.direction,
+ .nfproto = 0,
+ },
+ };
+
+ return json_pack("{s:{s:o, s:o}}", "mangle",
+ "key", ct_expr_json(&expr, octx),
+ "value", expr_print_json(stmt->ct.expr, octx));
+}
+
+json_t *limit_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ const char *rate_unit = NULL, *burst_unit = NULL;
+ bool inv = stmt->limit.flags & NFT_LIMIT_F_INV;
+ uint64_t burst = stmt->limit.burst;
+ uint64_t rate = stmt->limit.rate;
+ json_t *root;
+
+ if (stmt->limit.type == NFT_LIMIT_PKT_BYTES) {
+ rate_unit = get_rate(stmt->limit.rate, &rate);
+ burst_unit = get_rate(stmt->limit.burst, &burst);
+ }
+
+ root = json_pack("{s:I, s:I, s:s}",
+ "rate", rate,
+ "burst", burst,
+ "per", get_unit(stmt->limit.unit));
+ if (inv)
+ json_object_set_new(root, "inv", json_boolean(inv));
+ if (rate_unit)
+ json_object_set_new(root, "rate_unit", json_string(rate_unit));
+ if (burst_unit)
+ json_object_set_new(root, "burst_unit",
+ json_string(burst_unit));
+
+ return json_pack("{s:o}", "limit", root);
+}
+
+json_t *fwd_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root, *tmp;
+
+ root = json_pack("{s:o}", "dev", expr_print_json(stmt->fwd.dev, octx));
+
+ if (stmt->fwd.addr) {
+ tmp = json_string(family2str(stmt->fwd.family));
+ json_object_set_new(root, "family", tmp);
+
+ tmp = expr_print_json(stmt->fwd.addr, octx);
+ json_object_set_new(root, "addr", tmp);
+ }
+
+ return json_pack("{s:o}", "fwd", root);
+}
+
+json_t *notrack_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return json_pack("{s:n}", "notrack");
+}
+
+json_t *dup_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root;
+
+ if (stmt->dup.to) {
+ root = json_pack("{s:o}", "addr", expr_print_json(stmt->dup.to, octx));
+ if (stmt->dup.dev)
+ json_object_set_new(root, "dev",
+ expr_print_json(stmt->dup.dev, octx));
+ } else {
+ root = json_null();
+ }
+ return json_pack("{s:o}", "dup", root);
+}
+
+json_t *meta_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root;
+
+ root = json_pack("{s:{s:s}}", "meta",
+ "key", meta_templates[stmt->meta.key].token);
+ root = json_pack("{s:o, s:o}",
+ "key", root,
+ "value", expr_print_json(stmt->meta.expr, octx));
+
+ return json_pack("{s:o}", "mangle", root);
+}
+
+json_t *log_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root = json_object(), *flags;
+
+ if (stmt->log.flags & STMT_LOG_PREFIX) {
+ char prefix[NF_LOG_PREFIXLEN] = {};
+
+ expr_to_string(stmt->log.prefix, prefix);
+ json_object_set_new(root, "prefix", json_string(prefix));
+ }
+ if (stmt->log.flags & STMT_LOG_GROUP)
+ json_object_set_new(root, "group",
+ json_integer(stmt->log.group));
+ if (stmt->log.flags & STMT_LOG_SNAPLEN)
+ json_object_set_new(root, "snaplen",
+ json_integer(stmt->log.snaplen));
+ if (stmt->log.flags & STMT_LOG_QTHRESHOLD)
+ json_object_set_new(root, "queue-threshold",
+ json_integer(stmt->log.qthreshold));
+ if ((stmt->log.flags & STMT_LOG_LEVEL) &&
+ stmt->log.level != LOG_WARNING)
+ json_object_set_new(root, "level",
+ json_string(log_level(stmt->log.level)));
+
+ flags = json_array();
+
+ if ((stmt->log.logflags & NF_LOG_MASK) == NF_LOG_MASK) {
+ json_array_append_new(flags, json_string("all"));
+ } else {
+ if (stmt->log.logflags & NF_LOG_TCPSEQ)
+ json_array_append_new(flags,
+ json_string("tcp sequence"));
+ if (stmt->log.logflags & NF_LOG_TCPOPT)
+ json_array_append_new(flags,
+ json_string("tcp options"));
+ if (stmt->log.logflags & NF_LOG_IPOPT)
+ json_array_append_new(flags, json_string("ip options"));
+ if (stmt->log.logflags & NF_LOG_UID)
+ json_array_append_new(flags, json_string("skuid"));
+ if (stmt->log.logflags & NF_LOG_MACDECODE)
+ json_array_append_new(flags, json_string("ether"));
+ }
+ if (json_array_size(flags) > 1) {
+ json_object_set_new(root, "flags", flags);
+ } else {
+ if (json_array_size(flags))
+ json_object_set(root, "flags",
+ json_array_get(flags, 0));
+ json_decref(flags);
+ }
+
+ if (!json_object_size(root)) {
+ json_decref(root);
+ root = json_null();
+ }
+
+ return json_pack("{s:o}", "log", root);
+}
+
+static json_t *nat_flags_json(uint32_t flags)
+{
+ json_t *array = json_array();
+
+ if (flags & NF_NAT_RANGE_PROTO_RANDOM)
+ json_array_append_new(array, json_string("random"));
+ if (flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ json_array_append_new(array, json_string("fully-random"));
+ if (flags & NF_NAT_RANGE_PERSISTENT)
+ json_array_append_new(array, json_string("persistent"));
+ if (flags & NF_NAT_RANGE_NETMAP)
+ json_array_append_new(array, json_string("netmap"));
+ return array;
+}
+
+static json_t *nat_type_flags_json(uint32_t type_flags)
+{
+ json_t *array = json_array();
+
+ if (type_flags & STMT_NAT_F_PREFIX)
+ json_array_append_new(array, json_string("prefix"));
+
+ return array;
+}
+
+static void nat_stmt_add_array(json_t *root, const char *name, json_t *array)
+{
+ if (json_array_size(array) > 1) {
+ json_object_set_new(root, name, array);
+ } else {
+ if (json_array_size(array))
+ json_object_set(root, name,
+ json_array_get(array, 0));
+ json_decref(array);
+ }
+}
+
+json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root = json_object();
+ json_t *array = nat_flags_json(stmt->nat.flags);
+
+ switch (stmt->nat.family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ json_object_set_new(root, "family",
+ json_string(family2str(stmt->nat.family)));
+ break;
+ }
+
+ if (stmt->nat.addr)
+ json_object_set_new(root, "addr",
+ expr_print_json(stmt->nat.addr, octx));
+
+ if (stmt->nat.proto)
+ json_object_set_new(root, "port",
+ expr_print_json(stmt->nat.proto, octx));
+
+ nat_stmt_add_array(root, "flags", array);
+
+ if (stmt->nat.type_flags) {
+ array = nat_type_flags_json(stmt->nat.type_flags);
+
+ nat_stmt_add_array(root, "type_flags", array);
+ }
+
+ if (!json_object_size(root)) {
+ json_decref(root);
+ root = json_null();
+ }
+
+ return json_pack("{s:o}", nat_etype2str(stmt->nat.type), root);
+}
+
+json_t *reject_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root, *jexpr = NULL;
+ const char *type = NULL;
+
+ switch (stmt->reject.type) {
+ case NFT_REJECT_TCP_RST:
+ type = "tcp reset";
+ break;
+ case NFT_REJECT_ICMPX_UNREACH:
+ type = "icmpx";
+ jexpr = expr_print_json(stmt->reject.expr, octx);
+ break;
+ case NFT_REJECT_ICMP_UNREACH:
+ switch (stmt->reject.family) {
+ case NFPROTO_IPV4:
+ type = "icmp";
+ jexpr = expr_print_json(stmt->reject.expr, octx);
+ break;
+ case NFPROTO_IPV6:
+ type = "icmpv6";
+ jexpr = expr_print_json(stmt->reject.expr, octx);
+ break;
+ }
+ }
+
+ if (!type && !jexpr)
+ return json_pack("{s:n}", "reject");
+
+ root = json_object();
+ if (type)
+ json_object_set_new(root, "type", json_string(type));
+ if (jexpr)
+ json_object_set_new(root, "expr", jexpr);
+
+ return json_pack("{s:o}", "reject", root);
+}
+
+json_t *counter_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ if (nft_output_stateless(octx))
+ return json_pack("{s:n}", "counter");
+
+ return json_pack("{s:{s:I, s:I}}", "counter",
+ "packets", stmt->counter.packets,
+ "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)
+{
+ 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)
+{
+ const char *name;
+
+ if (stmt->objref.type > NFT_OBJECT_MAX)
+ name = "unknown";
+ else
+ name = objref_type_name(stmt->objref.type);
+
+ return json_pack("{s:o}", name, expr_print_json(stmt->objref.expr, octx));
+}
+
+json_t *meter_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ unsigned int flags = octx->flags;
+ json_t *root, *tmp;
+
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ tmp = stmt_print_json(stmt->meter.stmt, octx);
+ octx->flags = flags;
+
+ root = json_pack("{s:o, s:o, s:i}",
+ "key", expr_print_json(stmt->meter.key, octx),
+ "stmt", tmp,
+ "size", stmt->meter.size);
+ if (stmt->meter.set) {
+ tmp = json_string(stmt->meter.set->set->handle.set.name);
+ json_object_set_new(root, "name", tmp);
+ }
+
+ return json_pack("{s:o}", "meter", root);
+}
+
+json_t *queue_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root, *flags;
+
+ root = json_object();
+
+ if (stmt->queue.queue)
+ json_object_set_new(root, "num",
+ expr_print_json(stmt->queue.queue, octx));
+
+ flags = json_array();
+ if (stmt->queue.flags & NFT_QUEUE_FLAG_BYPASS)
+ json_array_append_new(flags, json_string("bypass"));
+ if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT)
+ json_array_append_new(flags, json_string("fanout"));
+ if (json_array_size(flags) > 1) {
+ json_object_set_new(root, "flags", flags);
+ } else {
+ if (json_array_size(flags))
+ json_object_set(root, "flags",
+ json_array_get(flags, 0));
+ json_decref(flags);
+ }
+
+ if (!json_object_size(root)) {
+ json_decref(root);
+ root = json_null();
+ }
+
+ return json_pack("{s:o}", "queue", root);
+}
+
+json_t *verdict_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return expr_print_json(stmt->expr, octx);
+}
+
+json_t *connlimit_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root = json_pack("{s:i}", "val", stmt->connlimit.count);
+
+ if (stmt->connlimit.flags & NFT_CONNLIMIT_F_INV)
+ json_object_set_new(root, "inv", json_true());
+
+ return json_pack("{s:o}", "ct count", root);
+}
+
+json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *tmp, *root = json_object();
+
+ if (stmt->tproxy.table_family == NFPROTO_INET &&
+ stmt->tproxy.family != NFPROTO_UNSPEC) {
+ tmp = json_string(family2str(stmt->tproxy.family));
+ json_object_set_new(root, "family", tmp);
+ }
+
+ if (stmt->tproxy.addr) {
+ tmp = expr_print_json(stmt->tproxy.addr, octx);
+ json_object_set_new(root, "addr", tmp);
+ }
+
+ if (stmt->tproxy.port) {
+ tmp = expr_print_json(stmt->tproxy.port, octx);
+ json_object_set_new(root, "port", tmp);
+ }
+
+ return json_pack("{s:o}", "tproxy", root);
+}
+
+json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root = json_object(), *flags = json_array();
+
+ if (stmt->synproxy.flags & NF_SYNPROXY_OPT_MSS)
+ json_object_set_new(root, "mss",
+ json_integer(stmt->synproxy.mss));
+ if (stmt->synproxy.flags & NF_SYNPROXY_OPT_WSCALE)
+ json_object_set_new(root, "wscale",
+ json_integer(stmt->synproxy.wscale));
+ if (stmt->synproxy.flags & NF_SYNPROXY_OPT_TIMESTAMP)
+ json_array_append_new(flags, json_string("timestamp"));
+ if (stmt->synproxy.flags & NF_SYNPROXY_OPT_SACK_PERM)
+ json_array_append_new(flags, json_string("sack-perm"));
+
+ if (json_array_size(flags) > 0)
+ json_object_set_new(root, "flags", flags);
+ else
+ json_decref(flags);
+
+ if (!json_object_size(root)) {
+ json_decref(root);
+ root = json_null();
+ }
+
+ return json_pack("{s:o}", "synproxy", root);
+}
+
+json_t *optstrip_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return json_pack("{s:o}", "reset",
+ expr_print_json(stmt->optstrip.expr, octx));
+}
+
+json_t *xt_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ static const char *xt_typename[NFT_XT_MAX] = {
+ [NFT_XT_MATCH] = "match",
+ [NFT_XT_TARGET] = "target",
+ [NFT_XT_WATCHER] = "watcher",
+ };
+
+ return json_pack("{s:{s:s, s:s}}", "xt",
+ "type", xt_typename[stmt->xt.type],
+ "name", stmt->xt.name);
+}
+
+static json_t *table_print_json_full(struct netlink_ctx *ctx,
+ struct table *table)
+{
+ json_t *root = json_array(), *rules = json_array(), *tmp;
+ struct flowtable *flowtable;
+ struct chain *chain;
+ struct rule *rule;
+ struct obj *obj;
+ struct set *set;
+
+ tmp = table_print_json(table);
+ json_array_append_new(root, tmp);
+
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
+ tmp = obj_print_json(obj);
+ json_array_append_new(root, tmp);
+ }
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (set_is_anonymous(set->flags))
+ continue;
+ tmp = set_print_json(&ctx->nft->output, set);
+ json_array_append_new(root, tmp);
+ }
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
+ tmp = flowtable_print_json(flowtable);
+ 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(rules, tmp);
+ }
+ }
+
+ json_array_extend(root, rules);
+ json_decref(rules);
+
+ return root;
+}
+
+static json_t *do_list_ruleset_json(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ unsigned int family = cmd->handle.family;
+ json_t *root = json_array(), *tmp;
+ struct table *table;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (family != NFPROTO_UNSPEC &&
+ table->handle.family != family)
+ continue;
+
+ tmp = table_print_json_full(ctx, table);
+ json_array_extend(root, tmp);
+ json_decref(tmp);
+ }
+
+ return root;
+}
+
+static json_t *do_list_tables_json(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ unsigned int family = cmd->handle.family;
+ json_t *root = json_array();
+ struct table *table;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (family != NFPROTO_UNSPEC &&
+ table->handle.family != family)
+ continue;
+
+ json_array_append_new(root, table_print_json(table));
+ }
+
+ return root;
+}
+
+static json_t *do_list_table_json(struct netlink_ctx *ctx,
+ struct cmd *cmd, struct table *table)
+{
+ return table_print_json_full(ctx, table);
+}
+
+static json_t *do_list_chain_json(struct netlink_ctx *ctx,
+ struct cmd *cmd, struct table *table)
+{
+ json_t *root = json_array();
+ struct chain *chain;
+ struct rule *rule;
+
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
+ if (chain->handle.family != cmd->handle.family ||
+ strcmp(cmd->handle.chain.name, chain->handle.chain.name))
+ continue;
+
+ json_array_append_new(root, chain_print_json(chain));
+
+ list_for_each_entry(rule, &chain->rules, list) {
+ json_t *tmp = rule_print_json(&ctx->nft->output, rule);
+
+ json_array_append_new(root, tmp);
+ }
+ }
+
+ return root;
+}
+
+static json_t *do_list_chains_json(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ json_t *root = json_array();
+ struct table *table;
+ struct chain *chain;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
+ json_t *tmp = chain_print_json(chain);
+
+ json_array_append_new(root, tmp);
+ }
+ }
+
+ return root;
+}
+
+static json_t *do_list_set_json(struct netlink_ctx *ctx,
+ struct cmd *cmd, struct table *table)
+{
+ struct set *set = cmd->set;
+
+ 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));
+}
+
+static json_t *do_list_sets_json(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct output_ctx *octx = &ctx->nft->output;
+ json_t *root = json_array();
+ struct table *table;
+ struct set *set;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cmd->obj == CMD_OBJ_SETS &&
+ !set_is_literal(set->flags))
+ continue;
+ if (cmd->obj == CMD_OBJ_METERS &&
+ !set_is_meter(set->flags))
+ continue;
+ if (cmd->obj == CMD_OBJ_MAPS &&
+ !map_is_literal(set->flags))
+ continue;
+ json_array_append_new(root, set_print_json(octx, set));
+ }
+ }
+
+ return root;
+}
+
+static json_t *do_list_obj_json(struct netlink_ctx *ctx,
+ struct cmd *cmd, uint32_t type)
+{
+ json_t *root = json_array();
+ struct table *table;
+ struct obj *obj;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ if (cmd->handle.table.name &&
+ strcmp(cmd->handle.table.name, table->handle.table.name))
+ continue;
+
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
+ if (obj->type != type ||
+ (cmd->handle.obj.name &&
+ strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
+ continue;
+
+ json_array_append_new(root, obj_print_json(obj));
+ }
+ }
+
+ return root;
+}
+
+static json_t *do_list_flowtable_json(struct netlink_ctx *ctx,
+ struct cmd *cmd, struct table *table)
+{
+ json_t *root = json_array();
+ struct flowtable *ft;
+
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return json_null();
+
+ json_array_append_new(root, flowtable_print_json(ft));
+
+ return root;
+}
+
+static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ json_t *root = json_array(), *tmp;
+ struct flowtable *flowtable;
+ struct table *table;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
+ tmp = flowtable_print_json(flowtable);
+ json_array_append_new(root, tmp);
+ }
+ }
+
+ return root;
+}
+
+static json_t *generate_json_metainfo(void)
+{
+ return json_pack("{s: {s:s, s:s, s:i}}", "metainfo",
+ "version", PACKAGE_VERSION,
+ "release_name", RELEASE_NAME,
+ "json_schema_version", JSON_SCHEMA_VERSION);
+}
+
+int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table = NULL;
+ json_t *root;
+
+ if (cmd->handle.table.name)
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (!cmd->handle.table.name) {
+ root = do_list_tables_json(ctx, cmd);
+ break;
+ }
+ root = do_list_table_json(ctx, cmd, table);
+ break;
+ case CMD_OBJ_CHAIN:
+ root = do_list_chain_json(ctx, cmd, table);
+ break;
+ case CMD_OBJ_CHAINS:
+ root = do_list_chains_json(ctx, cmd);
+ break;
+ case CMD_OBJ_SETS:
+ root = do_list_sets_json(ctx, cmd);
+ break;
+ 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;
+ case CMD_OBJ_METERS:
+ root = do_list_sets_json(ctx, cmd);
+ break;
+ case CMD_OBJ_METER:
+ root = do_list_set_json(ctx, cmd, table);
+ break;
+ case CMD_OBJ_MAPS:
+ root = do_list_sets_json(ctx, cmd);
+ break;
+ case CMD_OBJ_MAP:
+ root = do_list_set_json(ctx, cmd, table);
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_COUNTERS:
+ root = do_list_obj_json(ctx, cmd, NFT_OBJECT_COUNTER);
+ break;
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_QUOTAS:
+ root = do_list_obj_json(ctx, cmd, NFT_OBJECT_QUOTA);
+ break;
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_HELPERS:
+ root = do_list_obj_json(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ break;
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_LIMITS:
+ root = do_list_obj_json(ctx, cmd, NFT_OBJECT_LIMIT);
+ break;
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_SECMARKS:
+ root = do_list_obj_json(ctx, cmd, NFT_OBJECT_SECMARK);
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ root = do_list_flowtable_json(ctx, cmd, table);
+ break;
+ case CMD_OBJ_FLOWTABLES:
+ root = do_list_flowtables_json(ctx, cmd);
+ break;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+
+ if (!json_is_array(root)) {
+ json_t *tmp = json_array();
+
+ json_array_append_new(tmp, root);
+ root = tmp;
+ }
+
+ json_array_insert_new(root, 0, generate_json_metainfo());
+
+ root = json_pack("{s:o}", "nftables", root);
+ json_dumpf(root, ctx->nft->output.output_fp, 0);
+ json_decref(root);
+ fprintf(ctx->nft->output.output_fp, "\n");
+ fflush(ctx->nft->output.output_fp);
+ return 0;
+}
+
+static void monitor_print_json(struct netlink_mon_handler *monh,
+ const char *cmd, json_t *obj)
+{
+ struct nft_ctx *nft = monh->ctx->nft;
+
+ obj = json_pack("{s:o}", cmd, obj);
+ if (nft_output_echo(&nft->output) && !nft->json_root) {
+ json_array_append_new(nft->json_echo, obj);
+ } else {
+ json_dumpf(obj, nft->output.output_fp, 0);
+ json_decref(obj);
+ }
+}
+
+void monitor_print_table_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct table *t)
+{
+ monitor_print_json(monh, cmd, table_print_json(t));
+}
+
+void monitor_print_chain_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct chain *c)
+{
+ monitor_print_json(monh, cmd, chain_print_json(c));
+}
+
+void monitor_print_set_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ struct output_ctx *octx = &monh->ctx->nft->output;
+
+ monitor_print_json(monh, cmd, set_print_json(octx, s));
+}
+
+void monitor_print_element_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct set *s)
+{
+ struct output_ctx *octx = &monh->ctx->nft->output;
+
+ monitor_print_json(monh, cmd, element_print_json(octx, s));
+}
+
+void monitor_print_obj_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct obj *o)
+{
+ monitor_print_json(monh, cmd, obj_print_json(o));
+}
+
+void monitor_print_rule_json(struct netlink_mon_handler *monh,
+ const char *cmd, struct rule *r)
+{
+ struct output_ctx *octx = &monh->ctx->nft->output;
+
+ monitor_print_json(monh, cmd, rule_print_json(octx, r));
+}
+
+void json_alloc_echo(struct nft_ctx *nft)
+{
+ nft->json_echo = json_array();
+ if (!nft->json_echo)
+ memory_allocation_error();
+}
diff --git a/src/libnftables.c b/src/libnftables.c
new file mode 100644
index 0000000..41f54c0
--- /dev/null
+++ b/src/libnftables.c
@@ -0,0 +1,810 @@
+/*
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <nftables/libnftables.h>
+#include <erec.h>
+#include <mnl.h>
+#include <parser.h>
+#include <utils.h>
+#include <iface.h>
+#include <cmd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+static int nft_netlink(struct nft_ctx *nft,
+ 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 = {
+ .nft = nft,
+ .msgs = msgs,
+ .list = LIST_HEAD_INIT(ctx.list),
+ .batch = mnl_batch_init(),
+ };
+ struct cmd *cmd;
+ struct mnl_err *err, *tmp;
+ LIST_HEAD(err_list);
+ int ret = 0;
+
+ if (list_empty(cmds))
+ goto out;
+
+ batch_seqnum = mnl_batch_begin(ctx.batch, mnl_seqnum_alloc(&seqnum));
+ list_for_each_entry(cmd, cmds, list) {
+ ctx.seqnum = cmd->seqnum = mnl_seqnum_alloc(&seqnum);
+ ret = do_command(&ctx, cmd);
+ if (ret < 0) {
+ netlink_io_error(&ctx, &cmd->location,
+ "Could not process rule: %s",
+ strerror(errno));
+ goto out;
+ }
+ num_cmds++;
+ }
+ if (!nft->check)
+ mnl_batch_end(ctx.batch, mnl_seqnum_alloc(&seqnum));
+
+ if (!mnl_batch_ready(ctx.batch))
+ goto out;
+
+ 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;
+ }
+
+ if (!list_empty(&err_list))
+ ret = -1;
+
+ list_for_each_entry_safe(err, tmp, &err_list, head) {
+ /* cmd seqnums are monotonic: only reset the starting position
+ * if the error seqnum is lower than the previous one.
+ */
+ if (err->seqnum < last_seqnum)
+ cmd = list_first_entry(cmds, struct cmd, list);
+
+ list_for_each_entry_from(cmd, cmds, list) {
+ last_seqnum = cmd->seqnum;
+ if (err->seqnum == cmd->seqnum ||
+ err->seqnum == batch_seqnum) {
+ nft_cmd_error(&ctx, cmd, err);
+ errno = err->err;
+ if (err->seqnum == cmd->seqnum) {
+ mnl_err_list_free(err);
+ break;
+ }
+ }
+ }
+
+ if (&cmd->list == cmds) {
+ /* not found, rewind */
+ last_seqnum = UINT32_MAX;
+ }
+ }
+ /* nfnetlink uses the first netlink message header in the batch whose
+ * sequence number is zero to report for EOPNOTSUPP and EPERM errors in
+ * some scenarios. Now it is safe to release pending errors here.
+ */
+ list_for_each_entry_safe(err, tmp, &err_list, head)
+ mnl_err_list_free(err);
+out:
+ mnl_batch_reset(ctx.batch);
+ return ret;
+}
+
+static void nft_init(struct nft_ctx *ctx)
+{
+ mark_table_init(ctx);
+ realm_table_rt_init(ctx);
+ devgroup_table_init(ctx);
+ ct_label_table_init(ctx);
+}
+
+static void nft_exit(struct nft_ctx *ctx)
+{
+ cache_free(&ctx->cache.table_cache);
+ ct_label_table_exit(ctx);
+ realm_table_rt_exit(ctx);
+ devgroup_table_exit(ctx);
+ mark_table_exit(ctx);
+}
+
+EXPORT_SYMBOL(nft_ctx_add_var);
+int nft_ctx_add_var(struct nft_ctx *ctx, const char *var)
+{
+ char *separator = strchr(var, '=');
+ int pcount = ctx->num_vars;
+ struct nft_vars *tmp;
+ const char *value;
+
+ if (!separator)
+ return -1;
+
+ tmp = xrealloc(ctx->vars, (pcount + 1) * sizeof(struct nft_vars));
+
+ *separator = '\0';
+ value = separator + 1;
+
+ ctx->vars = tmp;
+ ctx->vars[pcount].key = xstrdup(var);
+ ctx->vars[pcount].value = xstrdup(value);
+ ctx->num_vars++;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(nft_ctx_clear_vars);
+void nft_ctx_clear_vars(struct nft_ctx *ctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->num_vars; i++) {
+ xfree(ctx->vars[i].key);
+ xfree(ctx->vars[i].value);
+ }
+ ctx->num_vars = 0;
+ xfree(ctx->vars);
+}
+
+EXPORT_SYMBOL(nft_ctx_add_include_path);
+int nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path)
+{
+ char **tmp;
+ int pcount = ctx->num_include_paths;
+
+ tmp = xrealloc(ctx->include_paths, (pcount + 1) * sizeof(char *));
+
+ ctx->include_paths = tmp;
+
+ if (asprintf(&ctx->include_paths[pcount], "%s", path) < 0)
+ return -1;
+
+ ctx->num_include_paths++;
+ return 0;
+}
+
+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]);
+
+ xfree(ctx->include_paths);
+ ctx->include_paths = NULL;
+}
+
+EXPORT_SYMBOL(nft_ctx_new);
+struct nft_ctx *nft_ctx_new(uint32_t flags)
+{
+ struct nft_ctx *ctx;
+
+#ifdef HAVE_LIBXTABLES
+ xt_init();
+#endif
+
+ ctx = xzalloc(sizeof(struct nft_ctx));
+ nft_init(ctx);
+
+ ctx->state = xzalloc(sizeof(struct parser_state));
+ nft_ctx_add_include_path(ctx, DEFAULT_INCLUDE_PATH);
+ ctx->parser_max_errors = 10;
+ cache_init(&ctx->cache.table_cache);
+ ctx->top_scope = scope_alloc();
+ ctx->flags = flags;
+ ctx->output.output_fp = stdout;
+ ctx->output.error_fp = stderr;
+ init_list_head(&ctx->vars_ctx.indesc_list);
+
+ ctx->nf_sock = nft_mnl_socket_open();
+
+ return ctx;
+}
+
+static ssize_t cookie_write(void *cptr, const char *buf, size_t buflen)
+{
+ struct cookie *cookie = cptr;
+
+ if (!cookie->buflen) {
+ cookie->buflen = buflen + 1;
+ cookie->buf = xmalloc(cookie->buflen);
+ } else if (cookie->pos + buflen >= cookie->buflen) {
+ size_t newlen = cookie->buflen * 2;
+
+ while (newlen <= cookie->pos + buflen)
+ newlen *= 2;
+
+ cookie->buf = xrealloc(cookie->buf, newlen);
+ cookie->buflen = newlen;
+ }
+ memcpy(cookie->buf + cookie->pos, buf, buflen);
+ cookie->pos += buflen;
+ cookie->buf[cookie->pos] = '\0';
+
+ return buflen;
+}
+
+static int init_cookie(struct cookie *cookie)
+{
+ cookie_io_functions_t cookie_fops = {
+ .write = cookie_write,
+ };
+
+ if (cookie->orig_fp) { /* just rewind buffer */
+ if (cookie->buflen) {
+ cookie->pos = 0;
+ cookie->buf[0] = '\0';
+ }
+ return 0;
+ }
+
+ cookie->orig_fp = cookie->fp;
+
+ cookie->fp = fopencookie(cookie, "w", cookie_fops);
+ if (!cookie->fp) {
+ cookie->fp = cookie->orig_fp;
+ cookie->orig_fp = NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int exit_cookie(struct cookie *cookie)
+{
+ if (!cookie->orig_fp)
+ return 1;
+
+ fclose(cookie->fp);
+ cookie->fp = cookie->orig_fp;
+ cookie->orig_fp = NULL;
+ free(cookie->buf);
+ cookie->buf = NULL;
+ cookie->buflen = 0;
+ cookie->pos = 0;
+ return 0;
+}
+
+EXPORT_SYMBOL(nft_ctx_buffer_output);
+int nft_ctx_buffer_output(struct nft_ctx *ctx)
+{
+ return init_cookie(&ctx->output.output_cookie);
+}
+
+EXPORT_SYMBOL(nft_ctx_unbuffer_output);
+int nft_ctx_unbuffer_output(struct nft_ctx *ctx)
+{
+ return exit_cookie(&ctx->output.output_cookie);
+}
+
+EXPORT_SYMBOL(nft_ctx_buffer_error);
+int nft_ctx_buffer_error(struct nft_ctx *ctx)
+{
+ return init_cookie(&ctx->output.error_cookie);
+}
+
+EXPORT_SYMBOL(nft_ctx_unbuffer_error);
+int nft_ctx_unbuffer_error(struct nft_ctx *ctx)
+{
+ return exit_cookie(&ctx->output.error_cookie);
+}
+
+static const char *get_cookie_buffer(struct cookie *cookie)
+{
+ fflush(cookie->fp);
+
+ /* This is a bit tricky: Rewind the buffer for future use and return
+ * the old content at the same time. Therefore return an empty string
+ * if buffer position is zero, otherwise just rewind buffer position
+ * and return the unmodified buffer. */
+
+ if (!cookie->pos)
+ return "";
+
+ cookie->pos = 0;
+ return cookie->buf;
+}
+
+EXPORT_SYMBOL(nft_ctx_get_output_buffer);
+const char *nft_ctx_get_output_buffer(struct nft_ctx *ctx)
+{
+ return get_cookie_buffer(&ctx->output.output_cookie);
+}
+
+EXPORT_SYMBOL(nft_ctx_get_error_buffer);
+const char *nft_ctx_get_error_buffer(struct nft_ctx *ctx)
+{
+ return get_cookie_buffer(&ctx->output.error_cookie);
+}
+
+EXPORT_SYMBOL(nft_ctx_free);
+void nft_ctx_free(struct nft_ctx *ctx)
+{
+ mnl_socket_close(ctx->nf_sock);
+
+ exit_cookie(&ctx->output.output_cookie);
+ exit_cookie(&ctx->output.error_cookie);
+ iface_cache_release();
+ nft_cache_release(&ctx->cache);
+ nft_ctx_clear_vars(ctx);
+ nft_ctx_clear_include_paths(ctx);
+ scope_free(ctx->top_scope);
+ xfree(ctx->state);
+ nft_exit(ctx);
+ xfree(ctx);
+}
+
+EXPORT_SYMBOL(nft_ctx_set_output);
+FILE *nft_ctx_set_output(struct nft_ctx *ctx, FILE *fp)
+{
+ FILE *old = ctx->output.output_fp;
+
+ if (!fp || ferror(fp))
+ return NULL;
+
+ ctx->output.output_fp = fp;
+
+ return old;
+}
+
+EXPORT_SYMBOL(nft_ctx_set_error);
+FILE *nft_ctx_set_error(struct nft_ctx *ctx, FILE *fp)
+{
+ FILE *old = ctx->output.error_fp;
+
+ if (!fp || ferror(fp))
+ return NULL;
+
+ ctx->output.error_fp = fp;
+
+ return old;
+}
+
+EXPORT_SYMBOL(nft_ctx_get_dry_run);
+bool nft_ctx_get_dry_run(struct nft_ctx *ctx)
+{
+ return ctx->check;
+}
+
+EXPORT_SYMBOL(nft_ctx_set_dry_run);
+void nft_ctx_set_dry_run(struct nft_ctx *ctx, bool dry)
+{
+ ctx->check = dry;
+}
+
+EXPORT_SYMBOL(nft_ctx_get_optimize);
+uint32_t nft_ctx_get_optimize(struct nft_ctx *ctx)
+{
+ return ctx->optimize_flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_set_optimize);
+void nft_ctx_set_optimize(struct nft_ctx *ctx, uint32_t flags)
+{
+ ctx->optimize_flags = flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_input_get_flags);
+unsigned int nft_ctx_input_get_flags(struct nft_ctx *ctx)
+{
+ return ctx->input.flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_input_set_flags);
+unsigned int nft_ctx_input_set_flags(struct nft_ctx *ctx, unsigned int flags)
+{
+ unsigned int old_flags;
+
+ old_flags = ctx->input.flags;
+ ctx->input.flags = flags;
+ return old_flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_output_get_flags);
+unsigned int nft_ctx_output_get_flags(struct nft_ctx *ctx)
+{
+ return ctx->output.flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_output_set_flags);
+void nft_ctx_output_set_flags(struct nft_ctx *ctx, unsigned int flags)
+{
+ ctx->output.flags = flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_output_get_debug);
+unsigned int nft_ctx_output_get_debug(struct nft_ctx *ctx)
+{
+ return ctx->debug_mask;
+}
+EXPORT_SYMBOL(nft_ctx_output_set_debug);
+void nft_ctx_output_set_debug(struct nft_ctx *ctx, unsigned int mask)
+{
+ ctx->debug_mask = mask;
+}
+
+static const struct input_descriptor indesc_cmdline = {
+ .type = INDESC_BUFFER,
+ .name = "<cmdline>",
+};
+
+static int nft_parse_bison_buffer(struct nft_ctx *nft, const char *buf,
+ struct list_head *msgs, struct list_head *cmds,
+ const struct input_descriptor *indesc)
+{
+ int ret;
+
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
+ nft->scanner = scanner_init(nft->state);
+ scanner_push_buffer(nft->scanner, indesc, buf);
+
+ ret = nft_parse(nft, nft->scanner, nft->state);
+ if (ret != 0 || nft->state->nerrs > 0)
+ return -1;
+
+ return 0;
+}
+
+static char *stdin_to_buffer(void)
+{
+ unsigned int bufsiz = 16384, consumed = 0;
+ int numbytes;
+ char *buf;
+
+ buf = xmalloc(bufsiz);
+
+ numbytes = read(STDIN_FILENO, buf, bufsiz);
+ while (numbytes > 0) {
+ consumed += numbytes;
+ if (consumed == bufsiz) {
+ bufsiz *= 2;
+ buf = xrealloc(buf, bufsiz);
+ }
+ numbytes = read(STDIN_FILENO, buf + consumed, bufsiz - consumed);
+ }
+ buf[consumed] = '\0';
+
+ return buf;
+}
+
+static const struct input_descriptor indesc_stdin = {
+ .type = INDESC_STDIN,
+ .name = "/dev/stdin",
+};
+
+static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename,
+ struct list_head *msgs, struct list_head *cmds)
+{
+ int ret;
+
+ if (nft->stdin_buf)
+ return nft_parse_bison_buffer(nft, nft->stdin_buf, msgs, cmds,
+ &indesc_stdin);
+
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
+ nft->scanner = scanner_init(nft->state);
+ if (scanner_read_file(nft, filename, &internal_location) < 0)
+ return -1;
+
+ ret = nft_parse(nft, nft->scanner, nft->state);
+ if (ret != 0 || nft->state->nerrs > 0)
+ return -1;
+
+ return 0;
+}
+
+static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
+ struct list_head *cmds)
+{
+ struct nft_cache_filter *filter;
+ struct cmd *cmd, *next;
+ bool collapsed = false;
+ unsigned int flags;
+ int err = 0;
+
+ filter = nft_cache_filter_init();
+ if (nft_cache_evaluate(nft, cmds, msgs, filter, &flags) < 0) {
+ nft_cache_filter_fini(filter);
+ return -1;
+ }
+ if (nft_cache_update(nft, flags, msgs, filter) < 0) {
+ nft_cache_filter_fini(filter);
+ return -1;
+ }
+
+ nft_cache_filter_fini(filter);
+
+ if (nft_cmd_collapse(cmds))
+ collapsed = true;
+
+ list_for_each_entry(cmd, cmds, list) {
+ if (cmd->op != CMD_ADD)
+ 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) {
+ err = -1;
+ break;
+ }
+ }
+
+ if (collapsed)
+ nft_cmd_uncollapse(cmds);
+
+ if (err < 0 || nft->state->nerrs)
+ return -1;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(nft_run_cmd_from_buffer);
+int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf)
+{
+ int rc = -EINVAL, parser_rc;
+ struct cmd *cmd, *next;
+ LIST_HEAD(msgs);
+ LIST_HEAD(cmds);
+ char *nlbuf;
+
+ nlbuf = xzalloc(strlen(buf) + 2);
+ sprintf(nlbuf, "%s\n", buf);
+
+ 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,
+ &indesc_cmdline);
+
+ parser_rc = rc;
+
+ rc = nft_evaluate(nft, &msgs, &cmds);
+ if (rc < 0) {
+ if (errno == EPERM) {
+ fprintf(stderr, "%s (you must be root)\n",
+ strerror(errno));
+ }
+ goto err;
+ }
+
+ if (parser_rc) {
+ rc = parser_rc;
+ goto err;
+ }
+
+ if (nft_netlink(nft, &cmds, &msgs) != 0)
+ rc = -1;
+err:
+ erec_print_list(&nft->output, &msgs, nft->debug_mask);
+ list_for_each_entry_safe(cmd, next, &cmds, list) {
+ list_del(&cmd->list);
+ cmd_free(cmd);
+ }
+ iface_cache_release();
+ if (nft->scanner) {
+ scanner_destroy(nft);
+ nft->scanner = NULL;
+ }
+ free(nlbuf);
+
+ if (!rc &&
+ nft_output_json(&nft->output) &&
+ nft_output_echo(&nft->output))
+ json_print_echo(nft);
+
+ if (rc || nft->check)
+ nft_cache_release(&nft->cache);
+
+ return rc;
+}
+
+static int load_cmdline_vars(struct nft_ctx *ctx, struct list_head *msgs)
+{
+ unsigned int bufsize, ret, i, offset = 0;
+ LIST_HEAD(cmds);
+ char *buf;
+ int rc;
+
+ if (ctx->num_vars == 0)
+ return 0;
+
+ bufsize = 1024;
+ buf = xzalloc(bufsize + 1);
+ for (i = 0; i < ctx->num_vars; i++) {
+retry:
+ ret = snprintf(buf + offset, bufsize - offset,
+ "define %s=%s; ",
+ ctx->vars[i].key, ctx->vars[i].value);
+ if (ret >= bufsize - offset) {
+ bufsize *= 2;
+ buf = xrealloc(buf, bufsize + 1);
+ goto retry;
+ }
+ offset += ret;
+ }
+ snprintf(buf + offset, bufsize - offset, "\n");
+
+ rc = nft_parse_bison_buffer(ctx, buf, msgs, &cmds, &indesc_cmdline);
+
+ assert(list_empty(&cmds));
+ /* Stash the buffer that contains the variable definitions and zap the
+ * list of input descriptors before releasing the scanner state,
+ * otherwise error reporting path walks over released objects.
+ */
+ ctx->vars_ctx.buf = buf;
+ list_splice_init(&ctx->state->indesc_list, &ctx->vars_ctx.indesc_list);
+ scanner_destroy(ctx);
+ ctx->scanner = NULL;
+
+ return rc;
+}
+
+/* need to use stat() to, fopen() will block for named fifos and
+ * libjansson makes no checks before or after open either.
+ */
+static struct error_record *filename_is_useable(struct nft_ctx *nft, const char *name)
+{
+ unsigned int type;
+ struct stat sb;
+ int err;
+
+ err = stat(name, &sb);
+ if (err)
+ return error(&internal_location, "Could not open file \"%s\": %s\n",
+ name, strerror(errno));
+
+ type = sb.st_mode & S_IFMT;
+
+ if (type == S_IFREG || type == S_IFIFO)
+ return NULL;
+
+ if (type == S_IFCHR && 0 == strcmp(name, "/dev/stdin"))
+ return NULL;
+
+ return error(&internal_location, "Not a regular file: \"%s\"\n", name);
+}
+
+static int __nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
+{
+ struct error_record *erec;
+ struct cmd *cmd, *next;
+ int rc, parser_rc;
+ LIST_HEAD(msgs);
+ LIST_HEAD(cmds);
+
+ 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) || nft_input_json(&nft->input))
+ rc = nft_parse_json_filename(nft, filename, &msgs, &cmds);
+ if (rc == -EINVAL)
+ rc = nft_parse_bison_filename(nft, filename, &msgs, &cmds);
+
+ parser_rc = rc;
+
+ if (nft->optimize_flags)
+ nft_optimize(nft, &cmds);
+
+ rc = nft_evaluate(nft, &msgs, &cmds);
+ if (rc < 0)
+ goto err;
+
+ if (parser_rc) {
+ rc = parser_rc;
+ goto err;
+ }
+
+ if (nft_netlink(nft, &cmds, &msgs) != 0)
+ rc = -1;
+err:
+ erec_print_list(&nft->output, &msgs, nft->debug_mask);
+ list_for_each_entry_safe(cmd, next, &cmds, list) {
+ list_del(&cmd->list);
+ cmd_free(cmd);
+ }
+ iface_cache_release();
+ if (nft->scanner) {
+ scanner_destroy(nft);
+ nft->scanner = NULL;
+ }
+ if (!list_empty(&nft->vars_ctx.indesc_list)) {
+ struct input_descriptor *indesc, *next;
+
+ list_for_each_entry_safe(indesc, next, &nft->vars_ctx.indesc_list, list) {
+ if (indesc->name)
+ xfree(indesc->name);
+
+ xfree(indesc);
+ }
+ }
+ xfree(nft->vars_ctx.buf);
+
+ if (!rc &&
+ nft_output_json(&nft->output) &&
+ nft_output_echo(&nft->output))
+ json_print_echo(nft);
+
+ if (rc || nft->check)
+ nft_cache_release(&nft->cache);
+
+ scope_release(nft->state->scopes[0]);
+
+ return rc;
+}
+
+static int nft_run_optimized_file(struct nft_ctx *nft, const char *filename)
+{
+ uint32_t optimize_flags;
+ bool check;
+ int ret;
+
+ check = nft->check;
+ nft->check = true;
+ optimize_flags = nft->optimize_flags;
+ nft->optimize_flags = 0;
+
+ /* First check the original ruleset loads fine as is. */
+ ret = __nft_run_cmd_from_filename(nft, filename);
+ if (ret < 0)
+ return ret;
+
+ nft->check = check;
+ nft->optimize_flags = optimize_flags;
+
+ return __nft_run_cmd_from_filename(nft, filename);
+}
+
+EXPORT_SYMBOL(nft_run_cmd_from_filename);
+int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
+{
+ int ret;
+
+ if (!strcmp(filename, "-"))
+ filename = "/dev/stdin";
+
+ if (!strcmp(filename, "/dev/stdin") &&
+ !nft_output_json(&nft->output))
+ nft->stdin_buf = stdin_to_buffer();
+
+ if (nft->optimize_flags) {
+ ret = nft_run_optimized_file(nft, filename);
+ xfree(nft->stdin_buf);
+ return ret;
+ }
+
+ ret = __nft_run_cmd_from_filename(nft, filename);
+ xfree(nft->stdin_buf);
+
+ return ret;
+}
diff --git a/src/libnftables.map b/src/libnftables.map
new file mode 100644
index 0000000..9369f44
--- /dev/null
+++ b/src/libnftables.map
@@ -0,0 +1,40 @@
+LIBNFTABLES_1 {
+global:
+ nft_ctx_add_include_path;
+ nft_ctx_clear_include_paths;
+ nft_ctx_new;
+ nft_ctx_buffer_output;
+ nft_ctx_unbuffer_output;
+ nft_ctx_buffer_error;
+ nft_ctx_unbuffer_error;
+ nft_ctx_get_output_buffer;
+ nft_ctx_get_error_buffer;
+ nft_ctx_free;
+ nft_ctx_set_output;
+ nft_ctx_set_error;
+ nft_ctx_get_dry_run;
+ nft_ctx_set_dry_run;
+ nft_ctx_output_get_flags;
+ nft_ctx_output_set_flags;
+ nft_ctx_output_get_debug;
+ nft_ctx_output_set_debug;
+ nft_run_cmd_from_buffer;
+ nft_run_cmd_from_filename;
+
+local: *;
+};
+
+LIBNFTABLES_2 {
+ nft_ctx_add_var;
+ nft_ctx_clear_vars;
+} LIBNFTABLES_1;
+
+LIBNFTABLES_3 {
+ nft_ctx_set_optimize;
+ nft_ctx_get_optimize;
+} LIBNFTABLES_2;
+
+LIBNFTABLES_4 {
+ nft_ctx_input_get_flags;
+ nft_ctx_input_set_flags;
+} LIBNFTABLES_3;
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..9485b19
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <nftables/libnftables.h>
+#include <utils.h>
+#include <cli.h>
+
+static struct nft_ctx *nft;
+
+enum opt_indices {
+ /* General options */
+ IDX_HELP,
+ IDX_VERSION,
+ IDX_VERSION_LONG,
+ /* Ruleset input handling */
+ IDX_FILE,
+#define IDX_RULESET_INPUT_START IDX_FILE
+ IDX_DEFINE,
+ IDX_INTERACTIVE,
+ IDX_INCLUDEPATH,
+ IDX_CHECK,
+ IDX_OPTIMIZE,
+#define IDX_RULESET_INPUT_END IDX_OPTIMIZE
+ /* Ruleset list formatting */
+ IDX_HANDLE,
+#define IDX_RULESET_LIST_START IDX_HANDLE
+ IDX_STATELESS,
+ IDX_TERSE,
+ IDX_SERVICE,
+ IDX_REVERSEDNS,
+ IDX_GUID,
+ IDX_NUMERIC,
+ IDX_NUMERIC_PRIO,
+ IDX_NUMERIC_PROTO,
+ IDX_NUMERIC_TIME,
+#define IDX_RULESET_LIST_END IDX_NUMERIC_TIME
+ /* Command output formatting */
+ IDX_ECHO,
+#define IDX_CMD_OUTPUT_START IDX_ECHO
+ IDX_JSON,
+ IDX_DEBUG,
+#define IDX_CMD_OUTPUT_END IDX_DEBUG
+};
+
+enum opt_vals {
+ OPT_HELP = 'h',
+ OPT_VERSION = 'v',
+ OPT_VERSION_LONG = 'V',
+ OPT_CHECK = 'c',
+ OPT_FILE = 'f',
+ OPT_DEFINE = 'D',
+ OPT_INTERACTIVE = 'i',
+ OPT_INCLUDEPATH = 'I',
+ OPT_JSON = 'j',
+ OPT_NUMERIC = 'n',
+ OPT_STATELESS = 's',
+ OPT_IP2NAME = 'N',
+ OPT_SERVICE = 'S',
+ OPT_DEBUG = 'd',
+ OPT_HANDLE_OUTPUT = 'a',
+ OPT_ECHO = 'e',
+ OPT_GUID = 'u',
+ OPT_NUMERIC_PRIO = 'y',
+ OPT_NUMERIC_PROTO = 'p',
+ OPT_NUMERIC_TIME = 'T',
+ OPT_TERSE = 't',
+ OPT_OPTIMIZE = 'o',
+ OPT_INVALID = '?',
+};
+
+struct nft_opt {
+ const char *name;
+ enum opt_vals val;
+ const char *arg;
+ const char *help;
+};
+
+#define NFT_OPT(n, v, a, h) \
+ (struct nft_opt) { .name = n, .val = v, .arg = a, .help = h }
+
+static const struct nft_opt nft_options[] = {
+ [IDX_HELP] = NFT_OPT("help", OPT_HELP, NULL,
+ "Show this help"),
+ [IDX_VERSION] = NFT_OPT("version", OPT_VERSION, NULL,
+ "Show version information"),
+ [IDX_VERSION_LONG] = NFT_OPT(NULL, OPT_VERSION_LONG, NULL,
+ "Show extended version information"),
+ [IDX_FILE] = NFT_OPT("file", OPT_FILE, "<filename>",
+ "Read input from <filename>"),
+ [IDX_DEFINE] = NFT_OPT("define", OPT_DEFINE, "<name=value>",
+ "Define variable, e.g. --define foo=1.2.3.4"),
+ [IDX_INTERACTIVE] = NFT_OPT("interactive", OPT_INTERACTIVE, NULL,
+ "Read input from interactive CLI"),
+ [IDX_INCLUDEPATH] = NFT_OPT("includepath", OPT_INCLUDEPATH, "<directory>",
+ "Add <directory> to the paths searched for include files. Default is: " DEFAULT_INCLUDE_PATH),
+ [IDX_CHECK] = NFT_OPT("check", OPT_CHECK, NULL,
+ "Check commands validity without actually applying the changes."),
+ [IDX_HANDLE] = NFT_OPT("handle", OPT_HANDLE_OUTPUT, NULL,
+ "Output rule handle."),
+ [IDX_STATELESS] = NFT_OPT("stateless", OPT_STATELESS, NULL,
+ "Omit stateful information of ruleset."),
+ [IDX_TERSE] = NFT_OPT("terse", OPT_TERSE, NULL,
+ "Omit contents of sets."),
+ [IDX_SERVICE] = NFT_OPT("service", OPT_SERVICE, NULL,
+ "Translate ports to service names as described in /etc/services."),
+ [IDX_REVERSEDNS] = NFT_OPT("reversedns", OPT_IP2NAME, NULL,
+ "Translate IP addresses to names."),
+ [IDX_GUID] = NFT_OPT("guid", OPT_GUID, NULL,
+ "Print UID/GID as defined in /etc/passwd and /etc/group."),
+ [IDX_NUMERIC] = NFT_OPT("numeric", OPT_NUMERIC, NULL,
+ "Print fully numerical output."),
+ [IDX_NUMERIC_PRIO] = NFT_OPT("numeric-priority", OPT_NUMERIC_PRIO, NULL,
+ "Print chain priority numerically."),
+ [IDX_NUMERIC_PROTO] = NFT_OPT("numeric-protocol", OPT_NUMERIC_PROTO, NULL,
+ "Print layer 4 protocols numerically."),
+ [IDX_NUMERIC_TIME] = NFT_OPT("numeric-time", OPT_NUMERIC_TIME, NULL,
+ "Print time values numerically."),
+ [IDX_ECHO] = NFT_OPT("echo", OPT_ECHO, NULL,
+ "Echo what has been added, inserted or replaced."),
+ [IDX_JSON] = NFT_OPT("json", OPT_JSON, NULL,
+ "Format output in JSON"),
+ [IDX_DEBUG] = NFT_OPT("debug", OPT_DEBUG, "<level [,level...]>",
+ "Specify debugging level (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)"),
+ [IDX_OPTIMIZE] = NFT_OPT("optimize", OPT_OPTIMIZE, NULL,
+ "Optimize ruleset"),
+};
+
+#define NR_NFT_OPTIONS (sizeof(nft_options) / sizeof(nft_options[0]))
+
+static const char *get_optstring(void)
+{
+ static char optstring[2 * NR_NFT_OPTIONS + 2];
+
+ if (!optstring[0]) {
+ size_t i, j;
+
+ optstring[0] = '+';
+ for (i = 0, j = 1; i < NR_NFT_OPTIONS && j < sizeof(optstring); i++)
+ j += snprintf(optstring + j, sizeof(optstring) - j, "%c%s",
+ nft_options[i].val,
+ nft_options[i].arg ? ":" : "");
+
+ assert(j < sizeof(optstring));
+ }
+ return optstring;
+}
+
+static const struct option *get_options(void)
+{
+ static struct option options[NR_NFT_OPTIONS + 1];
+
+ if (!options[0].name) {
+ size_t i, j;
+
+ for (i = 0, j = 0; i < NR_NFT_OPTIONS; ++i) {
+ if (nft_options[i].name) {
+ options[j].name = nft_options[i].name;
+ options[j].val = nft_options[i].val;
+ options[j].has_arg = nft_options[i].arg != NULL;
+ j++;
+ }
+ }
+ }
+ return options;
+}
+
+static void print_option(const struct nft_opt *opt)
+{
+ char optbuf[35] = "";
+ int i;
+
+ i = snprintf(optbuf, sizeof(optbuf), " -%c", opt->val);
+ if (opt->name)
+ i += snprintf(optbuf + i, sizeof(optbuf) - i, ", --%s",
+ opt->name);
+ if (opt->arg)
+ i += snprintf(optbuf + i, sizeof(optbuf) - i, " %s", opt->arg);
+
+ printf("%-34s%s\n", optbuf, opt->help);
+}
+
+static void show_help(const char *name)
+{
+ int i;
+
+ printf("Usage: %s [ options ] [ cmds... ]\n"
+ "\n"
+ "Options (general):\n", name);
+
+ print_option(&nft_options[IDX_HELP]);
+ print_option(&nft_options[IDX_VERSION]);
+ print_option(&nft_options[IDX_VERSION_LONG]);
+
+ printf("\n"
+ "Options (ruleset input handling):"
+ "\n");
+
+ for (i = IDX_RULESET_INPUT_START; i <= IDX_RULESET_INPUT_END; i++)
+ print_option(&nft_options[i]);
+
+ printf("\n"
+ "Options (ruleset list formatting):"
+ "\n");
+
+ for (i = IDX_RULESET_LIST_START; i <= IDX_RULESET_LIST_END; i++)
+ print_option(&nft_options[i]);
+
+ printf("\n"
+ "Options (command output formatting):"
+ "\n");
+
+ for (i = IDX_CMD_OUTPUT_START; i <= IDX_CMD_OUTPUT_END; i++)
+ print_option(&nft_options[i]);
+
+ fputs("\n", stdout);
+}
+
+static void show_version(void)
+{
+ const char *cli, *minigmp, *json, *xt;
+
+#if defined(HAVE_LIBREADLINE)
+ cli = "readline";
+#elif defined(HAVE_LIBEDIT)
+ cli = "editline";
+#elif defined(HAVE_LIBLINENOISE)
+ cli = "linenoise";
+#else
+ cli = "no";
+#endif
+
+#if defined(HAVE_MINIGMP)
+ minigmp = "yes";
+#else
+ minigmp = "no";
+#endif
+
+#if defined(HAVE_JSON)
+ json = "yes";
+#else
+ json = "no";
+#endif
+
+#if defined(HAVE_XTABLES)
+ xt = "yes";
+#else
+ xt = "no";
+#endif
+
+ printf("%s v%s (%s)\n"
+ " cli: %s\n"
+ " json: %s\n"
+ " minigmp: %s\n"
+ " libxtables: %s\n",
+ PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME,
+ cli, json, minigmp, xt);
+}
+
+static const struct {
+ const char *name;
+ enum nft_debug_level level;
+} debug_param[] = {
+ {
+ .name = "scanner",
+ .level = NFT_DEBUG_SCANNER,
+ },
+ {
+ .name = "parser",
+ .level = NFT_DEBUG_PARSER,
+ },
+ {
+ .name = "eval",
+ .level = NFT_DEBUG_EVALUATION,
+ },
+ {
+ .name = "netlink",
+ .level = NFT_DEBUG_NETLINK,
+ },
+ {
+ .name = "mnl",
+ .level = NFT_DEBUG_MNL,
+ },
+ {
+ .name = "proto-ctx",
+ .level = NFT_DEBUG_PROTO_CTX,
+ },
+ {
+ .name = "segtree",
+ .level = NFT_DEBUG_SEGTREE,
+ },
+ {
+ .name = "all",
+ .level = ~0,
+ },
+};
+
+static void nft_options_error(int argc, char * const argv[], int pos)
+{
+ int i;
+
+ fprintf(stderr, "Error: syntax error, options must be specified before commands\n");
+ for (i = 0; i < argc; i++)
+ fprintf(stderr, "%s ", argv[i]);
+ printf("\n%4c%*s\n", '^', pos - 2, "~~");
+}
+
+static bool nft_options_check(int argc, char * const argv[])
+{
+ bool skip = false, nonoption = false;
+ int pos = 0, i;
+
+ for (i = 1; i < argc; i++) {
+ pos += strlen(argv[i - 1]) + 1;
+ if (argv[i][0] == '{') {
+ break;
+ } else if (skip) {
+ skip = false;
+ continue;
+ } else if (argv[i][0] == '-') {
+ 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;
+ }
+ }
+
+ return true;
+}
+
+int main(int argc, char * const *argv)
+{
+ const struct option *options = get_options();
+ bool interactive = false, define = false;
+ const char *optstring = get_optstring();
+ unsigned int output_flags = 0;
+ int i, val, rc = EXIT_SUCCESS;
+ unsigned int debug_mask;
+ char *filename = NULL;
+ unsigned int len;
+
+ /* nftables cannot be used with setuid in a safe way. */
+ if (getuid() != geteuid())
+ _exit(111);
+
+ if (!nft_options_check(argc, argv))
+ exit(EXIT_FAILURE);
+
+ nft = nft_ctx_new(NFT_CTX_DEFAULT);
+
+ while (1) {
+ val = getopt_long(argc, argv, optstring, options, NULL);
+ if (val == -1)
+ break;
+
+ switch (val) {
+ case OPT_HELP:
+ show_help(argv[0]);
+ goto out;
+ case OPT_VERSION:
+ printf("%s v%s (%s)\n",
+ PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME);
+ goto out;
+ case OPT_VERSION_LONG:
+ show_version();
+ goto out;
+ case OPT_DEFINE:
+ if (nft_ctx_add_var(nft, optarg)) {
+ fprintf(stderr,
+ "Failed to define variable '%s'\n",
+ optarg);
+ goto out_fail;
+ }
+ define = true;
+ break;
+ case OPT_CHECK:
+ nft_ctx_set_dry_run(nft, true);
+ break;
+ case OPT_FILE:
+ if (interactive) {
+ fprintf(stderr,
+ "Error: -i/--interactive and -f/--file options cannot be combined\n");
+ goto out_fail;
+ }
+ filename = optarg;
+ break;
+ case OPT_INTERACTIVE:
+ if (filename) {
+ fprintf(stderr,
+ "Error: -i/--interactive and -f/--file options cannot be combined\n");
+ goto out_fail;
+ }
+ interactive = true;
+ break;
+ case OPT_INCLUDEPATH:
+ if (nft_ctx_add_include_path(nft, optarg)) {
+ fprintf(stderr,
+ "Failed to add include path '%s'\n",
+ optarg);
+ goto out_fail;
+ }
+ break;
+ case OPT_NUMERIC:
+ output_flags |= NFT_CTX_OUTPUT_NUMERIC_ALL;
+ break;
+ case OPT_STATELESS:
+ output_flags |= NFT_CTX_OUTPUT_STATELESS;
+ break;
+ case OPT_IP2NAME:
+ output_flags |= NFT_CTX_OUTPUT_REVERSEDNS;
+ break;
+ case OPT_SERVICE:
+ output_flags |= NFT_CTX_OUTPUT_SERVICE;
+ break;
+ case OPT_DEBUG:
+ debug_mask = nft_ctx_output_get_debug(nft);
+ for (;;) {
+ unsigned int i;
+ char *end;
+
+ end = strchr(optarg, ',');
+ if (end)
+ *end = '\0';
+
+ for (i = 0; i < array_size(debug_param); i++) {
+ if (strcmp(debug_param[i].name, optarg))
+ continue;
+ debug_mask |= debug_param[i].level;
+ break;
+ }
+
+ if (i == array_size(debug_param)) {
+ fprintf(stderr, "invalid debug parameter `%s'\n",
+ optarg);
+ goto out_fail;
+ }
+
+ if (end == NULL)
+ break;
+ optarg = end + 1;
+ }
+ nft_ctx_output_set_debug(nft, debug_mask);
+ break;
+ case OPT_HANDLE_OUTPUT:
+ output_flags |= NFT_CTX_OUTPUT_HANDLE;
+ break;
+ case OPT_ECHO:
+ output_flags |= NFT_CTX_OUTPUT_ECHO;
+ break;
+ case OPT_JSON:
+#ifdef HAVE_LIBJANSSON
+ output_flags |= NFT_CTX_OUTPUT_JSON;
+#else
+ fprintf(stderr, "JSON support not compiled-in\n");
+ goto out_fail;
+#endif
+ break;
+ case OPT_GUID:
+ output_flags |= NFT_CTX_OUTPUT_GUID;
+ break;
+ case OPT_NUMERIC_PRIO:
+ output_flags |= NFT_CTX_OUTPUT_NUMERIC_PRIO;
+ break;
+ case OPT_NUMERIC_PROTO:
+ output_flags |= NFT_CTX_OUTPUT_NUMERIC_PROTO;
+ break;
+ case OPT_NUMERIC_TIME:
+ output_flags |= NFT_CTX_OUTPUT_NUMERIC_TIME;
+ break;
+ case OPT_TERSE:
+ output_flags |= NFT_CTX_OUTPUT_TERSE;
+ break;
+ case OPT_OPTIMIZE:
+ nft_ctx_set_optimize(nft, 0x1);
+ break;
+ case OPT_INVALID:
+ goto out_fail;
+ }
+ }
+
+ if (!filename && define) {
+ fprintf(stderr, "Error: -D/--define can only be used with -f/--filename\n");
+ goto out_fail;
+ }
+
+ nft_ctx_output_set_flags(nft, output_flags);
+
+ if (optind != argc) {
+ char *buf;
+
+ for (len = 0, i = optind; i < argc; i++)
+ len += strlen(argv[i]) + strlen(" ");
+
+ buf = calloc(1, len);
+ if (buf == NULL) {
+ fprintf(stderr, "%s:%u: Memory allocation failure\n",
+ __FILE__, __LINE__);
+ goto out_fail;
+ }
+ for (i = optind; i < argc; i++) {
+ strcat(buf, argv[i]);
+ if (i + 1 < argc)
+ 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]);
+ goto out_fail;
+ }
+ } else {
+ fprintf(stderr, "%s: no command specified\n", argv[0]);
+ goto out_fail;
+ }
+
+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
new file mode 100644
index 0000000..4d0e280
--- /dev/null
+++ b/src/mergesort.c
@@ -0,0 +1,122 @@
+/*
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <expression.h>
+#include <gmputil.h>
+#include <list.h>
+
+static void concat_expr_msort_value(const struct expr *expr, mpz_t value)
+{
+ unsigned int len = 0, ilen;
+ const struct expr *i;
+ char data[512];
+
+ list_for_each_entry(i, &expr->expressions, list) {
+ ilen = div_round_up(i->len, BITS_PER_BYTE);
+ mpz_export_data(data + len, i->value, i->byteorder, ilen);
+ len += ilen;
+ }
+
+ mpz_import_data(value, data, BYTEORDER_HOST_ENDIAN, len);
+}
+
+static mpz_srcptr expr_msort_value(const struct expr *expr, mpz_t value)
+{
+ switch (expr->etype) {
+ case EXPR_SET_ELEM:
+ return expr_msort_value(expr->key, value);
+ case EXPR_BINOP:
+ case EXPR_MAPPING:
+ case EXPR_RANGE:
+ return expr_msort_value(expr->left, value);
+ case EXPR_VALUE:
+ return expr->value;
+ case EXPR_CONCAT:
+ concat_expr_msort_value(expr, value);
+ break;
+ case EXPR_SET_ELEM_CATCHALL:
+ /* max value to ensure listing shows it in the last position */
+ mpz_bitmask(value, expr->len);
+ break;
+ default:
+ BUG("Unknown expression %s\n", expr_name(expr));
+ }
+ return value;
+}
+
+static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
+{
+ mpz_srcptr value1;
+ mpz_srcptr value2;
+ mpz_t value1_tmp;
+ mpz_t value2_tmp;
+ int ret;
+
+ mpz_init(value1_tmp);
+ mpz_init(value2_tmp);
+ value1 = expr_msort_value(e1, value1_tmp);
+ value2 = expr_msort_value(e2, value2_tmp);
+ ret = mpz_cmp(value1, value2);
+ mpz_clear(value1_tmp);
+ mpz_clear(value2_tmp);
+
+ return ret;
+}
+
+void list_splice_sorted(struct list_head *list, struct list_head *head)
+{
+ struct list_head *h = head->next;
+ struct list_head *l = list->next;
+
+ while (l != list) {
+ if (h == head ||
+ expr_msort_cmp(list_entry(l, typeof(struct expr), list),
+ list_entry(h, typeof(struct expr), list)) < 0) {
+ l = l->next;
+ list_add_tail(l->prev, h);
+ continue;
+ }
+
+ h = h->next;
+ }
+}
+
+static void list_cut_middle(struct list_head *list, struct list_head *head)
+{
+ struct list_head *s = head->next;
+ struct list_head *e = head->prev;
+
+ while (e != s) {
+ e = e->prev;
+
+ if (e != s)
+ s = s->next;
+ }
+
+ __list_cut_position(list, head, s);
+}
+
+void list_expr_sort(struct list_head *head)
+{
+ struct list_head *list;
+ LIST_HEAD(temp);
+
+ list = &temp;
+
+ if (list_empty(head) || list_is_singular(head))
+ return;
+
+ list_cut_middle(list, head);
+
+ list_expr_sort(head);
+ list_expr_sort(list);
+
+ list_splice_sorted(list, head);
+}
diff --git a/src/meta.c b/src/meta.c
new file mode 100644
index 0000000..b578d5e
--- /dev/null
+++ b/src/meta.c
@@ -0,0 +1,1043 @@
+/*
+ * Meta expression/statement related definition and types.
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * 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 <stdio.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <pwd.h>
+#include <grp.h>
+#include <arpa/inet.h>
+#include <linux/netfilter.h>
+#include <linux/pkt_sched.h>
+#include <linux/if_packet.h>
+#include <time.h>
+
+#include <nftables.h>
+#include <expression.h>
+#include <statement.h>
+#include <datatype.h>
+#include <meta.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <erec.h>
+#include <iface.h>
+#include <json.h>
+
+static void tchandle_type_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ uint32_t handle = mpz_get_uint32(expr->value);
+
+ switch(handle) {
+ case TC_H_ROOT:
+ nft_print(octx, "root");
+ break;
+ case TC_H_UNSPEC:
+ nft_print(octx, "none");
+ break;
+ default:
+ nft_print(octx, "%0x:%0x",
+ TC_H_MAJ(handle) >> 16,
+ TC_H_MIN(handle));
+ break;
+ }
+}
+
+static struct error_record *tchandle_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ 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, ':')) {
+ 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)
+ goto err;
+
+ handle = (tmp << 16);
+ if (str[strlen(str) - 1] == ':')
+ goto out;
+
+ errno = 0;
+ tmp = strtoull(colon + 1, NULL, 16);
+ if (errno != 0)
+ 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);
+}
+
+const struct datatype tchandle_type = {
+ .type = TYPE_CLASSID,
+ .name = "classid",
+ .desc = "TC classid",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = tchandle_type_print,
+ .parse = tchandle_type_parse,
+};
+
+static void ifindex_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ char name[IFNAMSIZ];
+ int ifindex;
+
+ ifindex = mpz_get_uint32(expr->value);
+ if (nft_if_indextoname(ifindex, name))
+ nft_print(octx, "\"%s\"", name);
+ else
+ nft_print(octx, "%d", ifindex);
+}
+
+static struct error_record *ifindex_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ int ifindex;
+
+ ifindex = nft_if_nametoindex(sym->identifier);
+ if (ifindex == 0) {
+ char *end;
+ long res;
+
+ errno = 0;
+ res = strtol(sym->identifier, &end, 10);
+
+ if (res < 0 || res > INT_MAX || *end || errno)
+ return error(&sym->location, "Interface does not exist");
+
+ ifindex = (int)res;
+ }
+
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(ifindex) * BITS_PER_BYTE, &ifindex);
+ return NULL;
+}
+
+const struct datatype ifindex_type = {
+ .type = TYPE_IFINDEX,
+ .name = "iface_index",
+ .desc = "network interface index",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 4 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = ifindex_type_print,
+ .parse = ifindex_type_parse,
+};
+
+static const struct symbol_table arphrd_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("ether", ARPHRD_ETHER),
+ SYMBOL("ppp", ARPHRD_PPP),
+ /* dummy types */
+ SYMBOL("ipip", ARPHRD_TUNNEL),
+ SYMBOL("ipip6", ARPHRD_TUNNEL6),
+ SYMBOL("loopback", ARPHRD_LOOPBACK),
+ SYMBOL("sit", ARPHRD_SIT),
+ SYMBOL("ipgre", ARPHRD_IPGRE),
+ SYMBOL_LIST_END,
+ },
+};
+
+const struct datatype arphrd_type = {
+ .type = TYPE_ARPHRD,
+ .name = "iface_type",
+ .desc = "network interface type",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 2 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &arphrd_tbl,
+};
+
+static void uid_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ struct passwd *pw;
+
+ if (nft_output_guid(octx)) {
+ uint32_t uid = mpz_get_uint32(expr->value);
+
+ pw = getpwuid(uid);
+ if (pw != NULL)
+ nft_print(octx, "\"%s\"", pw->pw_name);
+ else
+ nft_print(octx, "%d", uid);
+ return;
+ }
+ expr_basetype(expr)->print(expr, octx);
+}
+
+static struct error_record *uid_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ struct passwd *pw;
+ uid_t uid;
+ char *endptr = NULL;
+
+ pw = getpwnam(sym->identifier);
+ if (pw != NULL)
+ uid = pw->pw_uid;
+ else {
+ uint64_t _uid = strtoull(sym->identifier, &endptr, 10);
+
+ if (_uid > UINT32_MAX)
+ return error(&sym->location, "Value too large");
+ else if (*endptr)
+ return error(&sym->location, "User does not exist");
+ uid = _uid;
+ }
+
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(pw->pw_uid) * BITS_PER_BYTE, &uid);
+ return NULL;
+}
+
+const struct datatype uid_type = {
+ .type = TYPE_UID,
+ .name = "uid",
+ .desc = "user ID",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = sizeof(uid_t) * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = uid_type_print,
+ .json = uid_type_json,
+ .parse = uid_type_parse,
+};
+
+static void gid_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ struct group *gr;
+
+ if (nft_output_guid(octx)) {
+ uint32_t gid = mpz_get_uint32(expr->value);
+
+ gr = getgrgid(gid);
+ if (gr != NULL)
+ nft_print(octx, "\"%s\"", gr->gr_name);
+ else
+ nft_print(octx, "%u", gid);
+ return;
+ }
+ expr_basetype(expr)->print(expr, octx);
+}
+
+static struct error_record *gid_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ struct group *gr;
+ gid_t gid;
+ char *endptr = NULL;
+
+ gr = getgrnam(sym->identifier);
+ if (gr != NULL)
+ gid = gr->gr_gid;
+ else {
+ uint64_t _gid = strtoull(sym->identifier, &endptr, 0);
+
+ if (_gid > UINT32_MAX)
+ return error(&sym->location, "Value too large");
+ else if (*endptr)
+ return error(&sym->location, "Group does not exist");
+ gid = _gid;
+ }
+
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(gr->gr_gid) * BITS_PER_BYTE, &gid);
+ return NULL;
+}
+
+const struct datatype gid_type = {
+ .type = TYPE_GID,
+ .name = "gid",
+ .desc = "group ID",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = sizeof(gid_t) * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = gid_type_print,
+ .json = gid_type_json,
+ .parse = gid_type_parse,
+};
+
+static const struct symbol_table pkttype_type_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("host", PACKET_HOST),
+ SYMBOL("unicast", PACKET_HOST), /* backwards compat */
+ SYMBOL("broadcast", PACKET_BROADCAST),
+ SYMBOL("multicast", PACKET_MULTICAST),
+ SYMBOL("other", PACKET_OTHERHOST),
+ SYMBOL_LIST_END,
+ },
+};
+
+static void pkttype_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ return symbolic_constant_print(&pkttype_type_tbl, expr, false, octx);
+}
+
+const struct datatype pkttype_type = {
+ .type = TYPE_PKTTYPE,
+ .name = "pkt_type",
+ .desc = "packet type",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = pkttype_type_print,
+ .sym_tbl = &pkttype_type_tbl,
+};
+
+void devgroup_table_init(struct nft_ctx *ctx)
+{
+ ctx->output.tbl.devgroup = rt_symbol_table_init("/etc/iproute2/group");
+}
+
+void devgroup_table_exit(struct nft_ctx *ctx)
+{
+ rt_symbol_table_free(ctx->output.tbl.devgroup);
+}
+
+static void devgroup_type_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ return symbolic_constant_print(octx->tbl.devgroup, expr, true, octx);
+}
+
+static struct error_record *devgroup_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ return symbolic_constant_parse(ctx, sym, ctx->tbl->devgroup, res);
+}
+
+const struct datatype devgroup_type = {
+ .type = TYPE_DEVGROUP,
+ .name = "devgroup",
+ .desc = "devgroup name",
+ .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 = {
+ .type = TYPE_IFNAME,
+ .name = "ifname",
+ .desc = "network interface name",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = IFNAMSIZ * BITS_PER_BYTE,
+ .basetype = &string_type,
+};
+
+static void date_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ uint64_t tstamp64 = mpz_get_uint64(expr->value);
+ char timestr[21];
+ time_t tstamp;
+ struct tm tm;
+
+ /* Convert from nanoseconds to seconds */
+ tstamp64 /= 1000000000L;
+
+ /* Obtain current tm, to add tm_gmtoff to the timestamp */
+ tstamp = tstamp64;
+ if (localtime_r(&tstamp, &tm))
+ tstamp64 += tm.tm_gmtoff;
+
+ tstamp = tstamp64;
+ if (gmtime_r(&tstamp, &tm) &&
+ strftime(timestr, sizeof(timestr) - 1, "%Y-%m-%d %T", &tm))
+ nft_print(octx, "\"%s\"", timestr);
+ else
+ nft_print(octx, "Error converting timestamp to printed time");
+}
+
+static bool parse_iso_date(uint64_t *tstamp, const char *sym)
+{
+ struct tm cur_tm;
+ struct tm tm;
+ time_t ts;
+
+ memset(&tm, 0, sizeof(struct tm));
+
+ if (strptime(sym, "%Y-%m-%d %T", &tm))
+ goto success;
+ if (strptime(sym, "%Y-%m-%d %R", &tm))
+ goto success;
+ if (strptime(sym, "%Y-%m-%d", &tm))
+ goto success;
+
+ return false;
+
+success:
+ /*
+ * Overwriting TZ is problematic if we're parsing hour types in this same process,
+ * hence I'd rather use timegm() which doesn't take into account the TZ env variable,
+ * even though it's Linux-specific.
+ */
+ ts = timegm(&tm);
+
+ if (ts == (time_t) -1)
+ return false;
+
+ /* 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;
+
+ return true;
+}
+
+static struct error_record *date_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ const char *endptr = sym->identifier;
+ uint64_t tstamp;
+
+ if (parse_iso_date(&tstamp, sym->identifier))
+ goto success;
+
+ tstamp = strtoul(sym->identifier, (char **) &endptr, 10);
+ if (*endptr == '\0' && endptr != sym->identifier)
+ goto success;
+
+ return error(&sym->location, "Cannot parse date");
+
+success:
+ /* Convert to nanoseconds */
+ tstamp *= 1000000000L;
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(uint64_t) * BITS_PER_BYTE,
+ &tstamp);
+ return NULL;
+}
+
+static const struct symbol_table day_type_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("Sunday", 0),
+ SYMBOL("Monday", 1),
+ SYMBOL("Tuesday", 2),
+ SYMBOL("Wednesday", 3),
+ SYMBOL("Thursday", 4),
+ SYMBOL("Friday", 5),
+ SYMBOL("Saturday", 6),
+ SYMBOL_LIST_END,
+ },
+};
+
+static void day_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ return symbolic_constant_print(&day_type_tbl, expr, true, octx);
+}
+
+#define SECONDS_PER_DAY (60 * 60 * 24)
+
+static void hour_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ uint32_t seconds = mpz_get_uint32(expr->value), minutes, hours;
+ struct tm cur_tm;
+ time_t ts;
+
+ /* Obtain current tm, so that we can add tm_gmtoff */
+ ts = time(NULL);
+ if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm))
+ seconds = (seconds + cur_tm.tm_gmtoff) % SECONDS_PER_DAY;
+
+ minutes = seconds / 60;
+ seconds %= 60;
+ hours = minutes / 60;
+ minutes %= 60;
+
+ nft_print(octx, "\"%02d:%02d", hours, minutes);
+ if (seconds)
+ nft_print(octx, ":%02d", seconds);
+ nft_print(octx, "\"");
+}
+
+static struct error_record *hour_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ struct error_record *er;
+ 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));
+
+ /* First, try to parse it as a number */
+ result = strtoul(sym->identifier, (char **) &endptr, 10);
+ if (*endptr == '\0' && endptr != sym->identifier)
+ goto success;
+
+ result = 0;
+
+ /* Obtain current tm, so that we can substract tm_gmtoff */
+ ts = time(NULL);
+ 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')
+ goto convert;
+
+ endptr = strptime(sym->identifier, "%R", &tm);
+ if (endptr && *endptr == '\0')
+ goto convert;
+
+ if (endptr && *endptr)
+ return error(&sym->location, "Can't parse trailing input: \"%s\"\n", endptr);
+
+ if ((er = time_parse(&sym->location, sym->identifier, &tmp)) == NULL) {
+ result = tmp / 1000;
+ goto convert;
+ }
+
+ return er;
+
+convert:
+ /* Convert the hour to the number of seconds since midnight */
+ if (result == 0)
+ result = tm.tm_hour * 3600 + tm.tm_min * 60 + tm.tm_sec;
+
+ /* Substract tm_gmtoff to get the current time */
+ if (cur_tm) {
+ if ((long int) result >= cur_tm->tm_gmtoff)
+ result = (result - cur_tm->tm_gmtoff) % 86400;
+ else
+ result = 86400 - cur_tm->tm_gmtoff + result;
+ }
+
+success:
+ *res = constant_expr_alloc(&sym->location, sym->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(uint32_t) * BITS_PER_BYTE,
+ &result);
+ return NULL;
+}
+
+const struct datatype date_type = {
+ .type = TYPE_TIME_DATE,
+ .name = "time",
+ .desc = "Relative time of packet reception",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = sizeof(uint64_t) * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = date_type_print,
+ .parse = date_type_parse,
+};
+
+const struct datatype day_type = {
+ .type = TYPE_TIME_DAY,
+ .name = "day",
+ .desc = "Day of week of packet reception",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 1 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = day_type_print,
+ .sym_tbl = &day_type_tbl,
+};
+
+const struct datatype hour_type = {
+ .type = TYPE_TIME_HOUR,
+ .name = "hour",
+ .desc = "Hour of day of packet reception",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = sizeof(uint32_t) * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = hour_type_print,
+ .parse = hour_type_parse,
+};
+
+const struct meta_template meta_templates[] = {
+ [NFT_META_LEN] = META_TEMPLATE("length", &integer_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_PROTOCOL] = META_TEMPLATE("protocol", &ethertype_type,
+ 2 * 8, BYTEORDER_BIG_ENDIAN),
+ [NFT_META_NFPROTO] = META_TEMPLATE("nfproto", &nfproto_type,
+ 1 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_L4PROTO] = META_TEMPLATE("l4proto", &inet_protocol_type,
+ 1 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_PRIORITY] = META_TEMPLATE("priority", &tchandle_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_MARK] = META_TEMPLATE("mark", &mark_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_IIF] = META_TEMPLATE("iif", &ifindex_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_IIFNAME] = META_TEMPLATE("iifname", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_IIFTYPE] = META_TEMPLATE("iiftype", &arphrd_type,
+ 2 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_OIF] = META_TEMPLATE("oif", &ifindex_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_OIFNAME] = META_TEMPLATE("oifname", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_OIFTYPE] = META_TEMPLATE("oiftype", &arphrd_type,
+ 2 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SKUID] = META_TEMPLATE("skuid", &uid_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SKGID] = META_TEMPLATE("skgid", &gid_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_NFTRACE] = META_TEMPLATE("nftrace", &integer_type,
+ 1 , BYTEORDER_HOST_ENDIAN),
+ [NFT_META_RTCLASSID] = META_TEMPLATE("rtclassid", &realm_type,
+ 4 * 8, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_BRI_IIFNAME] = META_TEMPLATE("ibrname", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_BRI_OIFNAME] = META_TEMPLATE("obrname", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_PKTTYPE] = META_TEMPLATE("pkttype", &pkttype_type,
+ BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_CPU] = META_TEMPLATE("cpu", &integer_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_IIFGROUP] = META_TEMPLATE("iifgroup", &devgroup_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_OIFGROUP] = META_TEMPLATE("oifgroup", &devgroup_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_CGROUP] = META_TEMPLATE("cgroup", &integer_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_PRANDOM] = META_TEMPLATE("random", &integer_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_BIG_ENDIAN), /* avoid conversion; doesn't have endianess */
+ [NFT_META_SECPATH] = META_TEMPLATE("ipsec", &boolean_type,
+ BITS_PER_BYTE, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_IIFKIND] = META_TEMPLATE("iifkind", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_OIFKIND] = META_TEMPLATE("oifkind", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_BRI_IIFPVID] = META_TEMPLATE("ibrpvid", &integer_type,
+ 2 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_BRI_IIFVPROTO] = META_TEMPLATE("ibrvproto", &ethertype_type,
+ 2 * BITS_PER_BYTE,
+ BYTEORDER_BIG_ENDIAN),
+ [NFT_META_TIME_NS] = META_TEMPLATE("time", &date_type,
+ 8 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_TIME_DAY] = META_TEMPLATE("day", &day_type,
+ 1 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_TIME_HOUR] = META_TEMPLATE("hour", &hour_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SECMARK] = META_TEMPLATE("secmark", &integer_type,
+ 32, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SDIF] = META_TEMPLATE("sdif", &ifindex_type,
+ sizeof(int) * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SDIFNAME] = META_TEMPLATE("sdifname", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_BRI_BROUTE] = META_TEMPLATE("broute", &integer_type,
+ 1 , BYTEORDER_HOST_ENDIAN),
+};
+
+static bool meta_key_is_unqualified(enum nft_meta_keys key)
+{
+ switch (key) {
+ case NFT_META_IIF:
+ case NFT_META_OIF:
+ case NFT_META_IIFNAME:
+ case NFT_META_OIFNAME:
+ case NFT_META_IIFGROUP:
+ case NFT_META_OIFGROUP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void meta_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ 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", token);
+}
+
+static bool meta_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->meta.key == e2->meta.key;
+}
+
+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;
+}
+
+/**
+ * meta_expr_pctx_update - update protocol context based on meta match
+ *
+ * @ctx: protocol context
+ * @expr: relational meta expression
+ *
+ * Update LL protocol context based on IIFTYPE meta match in non-LL hooks.
+ */
+static void meta_expr_pctx_update(struct proto_ctx *ctx,
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
+{
+ const struct hook_proto_desc *h = &hook_proto_desc[ctx->family];
+ const struct proto_desc *desc;
+ uint8_t protonum;
+
+ switch (left->meta.key) {
+ case NFT_META_IIFTYPE:
+ if (h->base < PROTO_BASE_NETWORK_HDR &&
+ ctx->family != NFPROTO_INET &&
+ ctx->family != NFPROTO_NETDEV)
+ return;
+
+ desc = proto_dev_desc(mpz_get_uint16(right->value));
+ if (desc == NULL)
+ desc = &proto_unknown;
+
+ proto_ctx_update(ctx, PROTO_BASE_LL_HDR, loc, desc);
+ break;
+ case NFT_META_NFPROTO:
+ protonum = mpz_get_uint8(right->value);
+ if (protonum == NFPROTO_IPV4 && h->desc == &proto_ip)
+ break;
+ else if (protonum == NFPROTO_IPV6 && h->desc == &proto_ip6)
+ break;
+
+ desc = proto_find_upper(h->desc, protonum);
+ if (desc == NULL) {
+ desc = &proto_unknown;
+
+ if (protonum == ctx->family &&
+ h->base == PROTO_BASE_NETWORK_HDR)
+ desc = h->desc;
+ }
+
+ proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc);
+ break;
+ case NFT_META_L4PROTO:
+ desc = proto_find_upper(&proto_inet_service,
+ mpz_get_uint8(right->value));
+ if (desc == NULL)
+ desc = &proto_unknown;
+
+ proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, loc, desc);
+ break;
+ case NFT_META_PROTOCOL:
+ if (h->base != PROTO_BASE_LL_HDR)
+ return;
+
+ if (ctx->family != NFPROTO_NETDEV &&
+ ctx->family != NFPROTO_BRIDGE)
+ return;
+
+ desc = proto_find_upper(h->desc, ntohs(mpz_get_uint16(right->value)));
+ if (desc == NULL)
+ desc = &proto_unknown;
+
+ proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc);
+ break;
+ default:
+ break;
+ }
+}
+
+#define NFTNL_UDATA_META_KEY 0
+#define NFTNL_UDATA_META_INNER_DESC 1
+#define NFTNL_UDATA_META_MAX 2
+
+static int meta_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_KEY, expr->meta.key);
+
+ if (expr->meta.inner_desc) {
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_INNER_DESC,
+ expr->meta.inner_desc->id);
+ }
+
+ return 0;
+}
+
+static int meta_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_META_KEY:
+ case NFTNL_UDATA_META_INNER_DESC:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *meta_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_META_MAX + 1] = {};
+ const struct proto_desc *desc;
+ struct expr *expr;
+ uint32_t key;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ meta_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_META_KEY])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_META_KEY]);
+
+ expr = meta_expr_alloc(&internal_location, key);
+
+ if (ud[NFTNL_UDATA_META_INNER_DESC]) {
+ desc = find_proto_desc(ud[NFTNL_UDATA_META_INNER_DESC]);
+ expr->meta.inner_desc = desc;
+ }
+
+ return expr;
+}
+
+const struct expr_ops meta_expr_ops = {
+ .type = EXPR_META,
+ .name = "meta",
+ .print = meta_expr_print,
+ .json = meta_expr_json,
+ .cmp = meta_expr_cmp,
+ .clone = meta_expr_clone,
+ .pctx_update = meta_expr_pctx_update,
+ .build_udata = meta_expr_build_udata,
+ .parse_udata = meta_expr_parse_udata,
+};
+
+struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key)
+{
+ const struct meta_template *tmpl = &meta_templates[key];
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_META, tmpl->dtype,
+ tmpl->byteorder, tmpl->len);
+ expr->meta.key = key;
+
+ switch (key) {
+ case NFT_META_IIFTYPE:
+ expr->flags |= EXPR_F_PROTOCOL;
+ break;
+ case NFT_META_NFPROTO:
+ expr->flags |= EXPR_F_PROTOCOL;
+ expr->meta.base = PROTO_BASE_LL_HDR;
+ break;
+ case NFT_META_L4PROTO:
+ expr->flags |= EXPR_F_PROTOCOL;
+ expr->meta.base = PROTO_BASE_NETWORK_HDR;
+ break;
+ case NFT_META_PROTOCOL:
+ expr->flags |= EXPR_F_PROTOCOL;
+ expr->meta.base = PROTO_BASE_LL_HDR;
+ break;
+ default:
+ break;
+ }
+
+ return expr;
+}
+
+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 ", token);
+ else
+ nft_print(octx, "meta %s set ", token);
+
+ expr_print(stmt->meta.expr, octx);
+}
+
+static void meta_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->meta.expr);
+}
+
+static const struct stmt_ops meta_stmt_ops = {
+ .type = STMT_META,
+ .name = "meta",
+ .print = meta_stmt_print,
+ .json = meta_stmt_json,
+ .destroy = meta_stmt_destroy,
+};
+
+struct stmt *meta_stmt_alloc(const struct location *loc, enum nft_meta_keys key,
+ struct expr *expr)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &meta_stmt_ops);
+ stmt->meta.key = key;
+ stmt->meta.expr = expr;
+
+ if (key < array_size(meta_templates))
+ stmt->meta.tmpl = &meta_templates[key];
+
+ return stmt;
+}
+
+/*
+ * @expr: payload expression
+ * @res: dependency expression
+ *
+ * Generate a NFT_META_IIFTYPE expression to check for ethernet frames.
+ * Only works on input path.
+ */
+struct stmt *meta_stmt_meta_iiftype(const struct location *loc, uint16_t type)
+{
+ struct expr *dep, *left, *right;
+
+ left = meta_expr_alloc(loc, NFT_META_IIFTYPE);
+ right = constant_expr_alloc(loc, &arphrd_type,
+ BYTEORDER_HOST_ENDIAN,
+ 2 * BITS_PER_BYTE, &type);
+
+ dep = relational_expr_alloc(loc, OP_EQ, left, right);
+ return expr_stmt_alloc(&dep->location, dep);
+}
+
+struct error_record *meta_key_parse(const struct location *loc,
+ const char *str,
+ unsigned int *value)
+{
+ const char *sep = "";
+ size_t offset = 0;
+ unsigned int i;
+ char buf[1024];
+ size_t len;
+
+ for (i = 0; i < array_size(meta_templates); i++) {
+ if (!meta_templates[i].token || strcmp(meta_templates[i].token, str))
+ continue;
+
+ *value = i;
+ return NULL;
+ }
+
+ /* Backwards compat hack */
+ if (strcmp(str, "ibriport") == 0) {
+ *value = NFT_META_BRI_IIFNAME;
+ return NULL;
+ } else if (strcmp(str, "obriport") == 0) {
+ *value = NFT_META_BRI_OIFNAME;
+ return NULL;
+ } else if (strcmp(str, "secpath") == 0) {
+ *value = NFT_META_SECPATH;
+ return NULL;
+ }
+
+ len = (int)sizeof(buf);
+
+ for (i = 0; i < array_size(meta_templates); i++) {
+ int ret;
+
+ if (!meta_templates[i].token)
+ continue;
+
+ if (offset)
+ sep = ", ";
+
+ ret = snprintf(buf+offset, len, "%s%s", sep, meta_templates[i].token);
+ 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
new file mode 100644
index 0000000..186dc3a
--- /dev/null
+++ b/src/mini-gmp.c
@@ -0,0 +1,4412 @@
+/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
+
+ Contributed to the GNU project by Niels Möller
+
+Copyright 1991-1997, 1999-2016 Free Software Foundation, Inc.
+
+This file is part of the GNU MP Library.
+
+The GNU MP Library is free software; you can redistribute it and/or modify
+it under the terms of either:
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+or
+
+ * the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any
+ later version.
+
+or both in parallel, as here.
+
+The GNU MP Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received copies of the GNU General Public License and the
+GNU Lesser General Public License along with the GNU MP Library. If not,
+see https://www.gnu.org/licenses/. */
+
+/* NOTE: All functions in this file which are not declared in
+ mini-gmp.h are internal, and are not intended to be compatible
+ neither with GMP nor with future versions of mini-gmp. */
+
+/* Much of the material copied from GMP files, including: gmp-impl.h,
+ longlong.h, mpn/generic/add_n.c, mpn/generic/addmul_1.c,
+ mpn/generic/lshift.c, mpn/generic/mul_1.c,
+ mpn/generic/mul_basecase.c, mpn/generic/rshift.c,
+ 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 "mini-gmp.h"
+
+
+/* Macros */
+#define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
+
+#define GMP_LIMB_MAX (~ (mp_limb_t) 0)
+#define GMP_LIMB_HIGHBIT ((mp_limb_t) 1 << (GMP_LIMB_BITS - 1))
+
+#define GMP_HLIMB_BIT ((mp_limb_t) 1 << (GMP_LIMB_BITS / 2))
+#define GMP_LLIMB_MASK (GMP_HLIMB_BIT - 1)
+
+#define GMP_ULONG_BITS (sizeof(unsigned long) * CHAR_BIT)
+#define GMP_ULONG_HIGHBIT ((unsigned long) 1 << (GMP_ULONG_BITS - 1))
+
+#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
+#define GMP_NEG_CAST(T,x) (-((T)((x) + 1) - 1))
+
+#define GMP_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define GMP_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define GMP_CMP(a,b) (((a) > (b)) - ((a) < (b)))
+
+#define gmp_assert_nocarry(x) do { \
+ mp_limb_t __cy = (x); \
+ assert (__cy == 0); \
+ } while (0)
+
+#define gmp_clz(count, x) do { \
+ mp_limb_t __clz_x = (x); \
+ unsigned __clz_c; \
+ for (__clz_c = 0; \
+ (__clz_x & ((mp_limb_t) 0xff << (GMP_LIMB_BITS - 8))) == 0; \
+ __clz_c += 8) \
+ __clz_x <<= 8; \
+ for (; (__clz_x & GMP_LIMB_HIGHBIT) == 0; __clz_c++) \
+ __clz_x <<= 1; \
+ (count) = __clz_c; \
+ } while (0)
+
+#define gmp_ctz(count, x) do { \
+ mp_limb_t __ctz_x = (x); \
+ unsigned __ctz_c = 0; \
+ gmp_clz (__ctz_c, __ctz_x & - __ctz_x); \
+ (count) = GMP_LIMB_BITS - 1 - __ctz_c; \
+ } while (0)
+
+#define gmp_add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ mp_limb_t __x; \
+ __x = (al) + (bl); \
+ (sh) = (ah) + (bh) + (__x < (al)); \
+ (sl) = __x; \
+ } while (0)
+
+#define gmp_sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ mp_limb_t __x; \
+ __x = (al) - (bl); \
+ (sh) = (ah) - (bh) - ((al) < (bl)); \
+ (sl) = __x; \
+ } while (0)
+
+#define gmp_umul_ppmm(w1, w0, u, v) \
+ do { \
+ mp_limb_t __x0, __x1, __x2, __x3; \
+ unsigned __ul, __vl, __uh, __vh; \
+ mp_limb_t __u = (u), __v = (v); \
+ \
+ __ul = __u & GMP_LLIMB_MASK; \
+ __uh = __u >> (GMP_LIMB_BITS / 2); \
+ __vl = __v & GMP_LLIMB_MASK; \
+ __vh = __v >> (GMP_LIMB_BITS / 2); \
+ \
+ __x0 = (mp_limb_t) __ul * __vl; \
+ __x1 = (mp_limb_t) __ul * __vh; \
+ __x2 = (mp_limb_t) __uh * __vl; \
+ __x3 = (mp_limb_t) __uh * __vh; \
+ \
+ __x1 += __x0 >> (GMP_LIMB_BITS / 2);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += GMP_HLIMB_BIT; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + (__x1 >> (GMP_LIMB_BITS / 2)); \
+ (w0) = (__x1 << (GMP_LIMB_BITS / 2)) + (__x0 & GMP_LLIMB_MASK); \
+ } while (0)
+
+#define gmp_udiv_qrnnd_preinv(q, r, nh, nl, d, di) \
+ do { \
+ mp_limb_t _qh, _ql, _r, _mask; \
+ gmp_umul_ppmm (_qh, _ql, (nh), (di)); \
+ gmp_add_ssaaaa (_qh, _ql, _qh, _ql, (nh) + 1, (nl)); \
+ _r = (nl) - _qh * (d); \
+ _mask = -(mp_limb_t) (_r > _ql); /* both > and >= are OK */ \
+ _qh += _mask; \
+ _r += _mask & (d); \
+ if (_r >= (d)) \
+ { \
+ _r -= (d); \
+ _qh++; \
+ } \
+ \
+ (r) = _r; \
+ (q) = _qh; \
+ } while (0)
+
+#define gmp_udiv_qr_3by2(q, r1, r0, n2, n1, n0, d1, d0, dinv) \
+ do { \
+ mp_limb_t _q0, _t1, _t0, _mask; \
+ gmp_umul_ppmm ((q), _q0, (n2), (dinv)); \
+ gmp_add_ssaaaa ((q), _q0, (q), _q0, (n2), (n1)); \
+ \
+ /* Compute the two most significant limbs of n - q'd */ \
+ (r1) = (n1) - (d1) * (q); \
+ gmp_sub_ddmmss ((r1), (r0), (r1), (n0), (d1), (d0)); \
+ gmp_umul_ppmm (_t1, _t0, (d0), (q)); \
+ gmp_sub_ddmmss ((r1), (r0), (r1), (r0), _t1, _t0); \
+ (q)++; \
+ \
+ /* Conditionally adjust q and the remainders */ \
+ _mask = - (mp_limb_t) ((r1) >= _q0); \
+ (q) += _mask; \
+ gmp_add_ssaaaa ((r1), (r0), (r1), (r0), _mask & (d1), _mask & (d0)); \
+ if ((r1) >= (d1)) \
+ { \
+ if ((r1) > (d1) || (r0) >= (d0)) \
+ { \
+ (q)++; \
+ gmp_sub_ddmmss ((r1), (r0), (r1), (r0), (d1), (d0)); \
+ } \
+ } \
+ } while (0)
+
+/* Swap macros. */
+#define MP_LIMB_T_SWAP(x, y) \
+ do { \
+ mp_limb_t __mp_limb_t_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_limb_t_swap__tmp; \
+ } while (0)
+#define MP_SIZE_T_SWAP(x, y) \
+ do { \
+ mp_size_t __mp_size_t_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_size_t_swap__tmp; \
+ } while (0)
+#define MP_BITCNT_T_SWAP(x,y) \
+ do { \
+ mp_bitcnt_t __mp_bitcnt_t_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_bitcnt_t_swap__tmp; \
+ } while (0)
+#define MP_PTR_SWAP(x, y) \
+ do { \
+ mp_ptr __mp_ptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_ptr_swap__tmp; \
+ } while (0)
+#define MP_SRCPTR_SWAP(x, y) \
+ do { \
+ mp_srcptr __mp_srcptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mp_srcptr_swap__tmp; \
+ } while (0)
+
+#define MPN_PTR_SWAP(xp,xs, yp,ys) \
+ do { \
+ MP_PTR_SWAP (xp, yp); \
+ MP_SIZE_T_SWAP (xs, ys); \
+ } while(0)
+#define MPN_SRCPTR_SWAP(xp,xs, yp,ys) \
+ do { \
+ MP_SRCPTR_SWAP (xp, yp); \
+ MP_SIZE_T_SWAP (xs, ys); \
+ } while(0)
+
+#define MPZ_PTR_SWAP(x, y) \
+ do { \
+ mpz_ptr __mpz_ptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mpz_ptr_swap__tmp; \
+ } while (0)
+#define MPZ_SRCPTR_SWAP(x, y) \
+ do { \
+ mpz_srcptr __mpz_srcptr_swap__tmp = (x); \
+ (x) = (y); \
+ (y) = __mpz_srcptr_swap__tmp; \
+ } while (0)
+
+const int mp_bits_per_limb = GMP_LIMB_BITS;
+
+
+/* Memory allocation and other helper functions. */
+static void
+gmp_die (const char *msg)
+{
+ fprintf (stderr, "%s\n", msg);
+ abort();
+}
+
+static void *
+gmp_default_alloc (size_t size)
+{
+ void *p;
+
+ assert (size > 0);
+
+ p = malloc (size);
+ if (!p)
+ gmp_die("gmp_default_alloc: Virtual memory exhausted.");
+
+ return p;
+}
+
+static void *
+gmp_default_realloc (void *old, size_t old_size, size_t new_size)
+{
+ void * p;
+
+ p = realloc (old, new_size);
+
+ if (!p)
+ gmp_die("gmp_default_realloc: Virtual memory exhausted.");
+
+ return p;
+}
+
+static void
+gmp_default_free (void *p, size_t size)
+{
+ free (p);
+}
+
+static void * (*gmp_allocate_func) (size_t) = gmp_default_alloc;
+static void * (*gmp_reallocate_func) (void *, size_t, size_t) = gmp_default_realloc;
+static void (*gmp_free_func) (void *, size_t) = gmp_default_free;
+
+void
+mp_get_memory_functions (void *(**alloc_func) (size_t),
+ void *(**realloc_func) (void *, size_t, size_t),
+ void (**free_func) (void *, size_t))
+{
+ if (alloc_func)
+ *alloc_func = gmp_allocate_func;
+
+ if (realloc_func)
+ *realloc_func = gmp_reallocate_func;
+
+ if (free_func)
+ *free_func = gmp_free_func;
+}
+
+void
+mp_set_memory_functions (void *(*alloc_func) (size_t),
+ void *(*realloc_func) (void *, size_t, size_t),
+ void (*free_func) (void *, size_t))
+{
+ if (!alloc_func)
+ alloc_func = gmp_default_alloc;
+ if (!realloc_func)
+ realloc_func = gmp_default_realloc;
+ if (!free_func)
+ free_func = gmp_default_free;
+
+ gmp_allocate_func = alloc_func;
+ gmp_reallocate_func = realloc_func;
+ gmp_free_func = free_func;
+}
+
+#define gmp_xalloc(size) ((*gmp_allocate_func)((size)))
+#define gmp_free(p) ((*gmp_free_func) ((p), 0))
+
+static mp_ptr
+gmp_xalloc_limbs (mp_size_t size)
+{
+ return (mp_ptr) gmp_xalloc (size * sizeof (mp_limb_t));
+}
+
+static mp_ptr
+gmp_xrealloc_limbs (mp_ptr old, mp_size_t size)
+{
+ assert (size > 0);
+ return (mp_ptr) (*gmp_reallocate_func) (old, 0, size * sizeof (mp_limb_t));
+}
+
+
+/* MPN interface */
+
+void
+mpn_copyi (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+ mp_size_t i;
+ for (i = 0; i < n; i++)
+ d[i] = s[i];
+}
+
+void
+mpn_copyd (mp_ptr d, mp_srcptr s, mp_size_t n)
+{
+ while (--n >= 0)
+ d[n] = s[n];
+}
+
+int
+mpn_cmp (mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ while (--n >= 0)
+ {
+ if (ap[n] != bp[n])
+ return ap[n] > bp[n] ? 1 : -1;
+ }
+ return 0;
+}
+
+static int
+mpn_cmp4 (mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+ if (an != bn)
+ return an < bn ? -1 : 1;
+ else
+ return mpn_cmp (ap, bp, an);
+}
+
+static mp_size_t
+mpn_normalized_size (mp_srcptr xp, mp_size_t n)
+{
+ while (n > 0 && xp[n-1] == 0)
+ --n;
+ return n;
+}
+
+int
+mpn_zero_p(mp_srcptr rp, mp_size_t n)
+{
+ return mpn_normalized_size (rp, n) == 0;
+}
+
+void
+mpn_zero (mp_ptr rp, mp_size_t n)
+{
+ while (--n >= 0)
+ rp[n] = 0;
+}
+
+mp_limb_t
+mpn_add_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+ mp_size_t i;
+
+ assert (n > 0);
+ i = 0;
+ do
+ {
+ mp_limb_t r = ap[i] + b;
+ /* Carry out */
+ b = (r < b);
+ rp[i] = r;
+ }
+ while (++i < n);
+
+ return b;
+}
+
+mp_limb_t
+mpn_add_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ mp_size_t i;
+ mp_limb_t cy;
+
+ for (i = 0, cy = 0; i < n; i++)
+ {
+ mp_limb_t a, b, r;
+ a = ap[i]; b = bp[i];
+ r = a + cy;
+ cy = (r < cy);
+ r += b;
+ cy += (r < b);
+ rp[i] = r;
+ }
+ return cy;
+}
+
+mp_limb_t
+mpn_add (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+ mp_limb_t cy;
+
+ assert (an >= bn);
+
+ cy = mpn_add_n (rp, ap, bp, bn);
+ if (an > bn)
+ cy = mpn_add_1 (rp + bn, ap + bn, an - bn, cy);
+ return cy;
+}
+
+mp_limb_t
+mpn_sub_1 (mp_ptr rp, mp_srcptr ap, mp_size_t n, mp_limb_t b)
+{
+ mp_size_t i;
+
+ assert (n > 0);
+
+ i = 0;
+ do
+ {
+ mp_limb_t a = ap[i];
+ /* Carry out */
+ mp_limb_t cy = a < b;
+ rp[i] = a - b;
+ b = cy;
+ }
+ while (++i < n);
+
+ return b;
+}
+
+mp_limb_t
+mpn_sub_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ mp_size_t i;
+ mp_limb_t cy;
+
+ for (i = 0, cy = 0; i < n; i++)
+ {
+ mp_limb_t a, b;
+ a = ap[i]; b = bp[i];
+ b += cy;
+ cy = (b < cy);
+ cy += (a < b);
+ rp[i] = a - b;
+ }
+ return cy;
+}
+
+mp_limb_t
+mpn_sub (mp_ptr rp, mp_srcptr ap, mp_size_t an, mp_srcptr bp, mp_size_t bn)
+{
+ mp_limb_t cy;
+
+ assert (an >= bn);
+
+ cy = mpn_sub_n (rp, ap, bp, bn);
+ if (an > bn)
+ cy = mpn_sub_1 (rp + bn, ap + bn, an - bn, cy);
+ return cy;
+}
+
+mp_limb_t
+mpn_mul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+ mp_limb_t ul, cl, hpl, lpl;
+
+ assert (n >= 1);
+
+ cl = 0;
+ do
+ {
+ ul = *up++;
+ gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+ lpl += cl;
+ cl = (lpl < cl) + hpl;
+
+ *rp++ = lpl;
+ }
+ while (--n != 0);
+
+ return cl;
+}
+
+mp_limb_t
+mpn_addmul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+ mp_limb_t ul, cl, hpl, lpl, rl;
+
+ assert (n >= 1);
+
+ cl = 0;
+ do
+ {
+ ul = *up++;
+ gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+ lpl += cl;
+ cl = (lpl < cl) + hpl;
+
+ rl = *rp;
+ lpl = rl + lpl;
+ cl += lpl < rl;
+ *rp++ = lpl;
+ }
+ while (--n != 0);
+
+ return cl;
+}
+
+mp_limb_t
+mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t vl)
+{
+ mp_limb_t ul, cl, hpl, lpl, rl;
+
+ assert (n >= 1);
+
+ cl = 0;
+ do
+ {
+ ul = *up++;
+ gmp_umul_ppmm (hpl, lpl, ul, vl);
+
+ lpl += cl;
+ cl = (lpl < cl) + hpl;
+
+ rl = *rp;
+ lpl = rl - lpl;
+ cl += lpl > rl;
+ *rp++ = lpl;
+ }
+ while (--n != 0);
+
+ return cl;
+}
+
+mp_limb_t
+mpn_mul (mp_ptr rp, mp_srcptr up, mp_size_t un, mp_srcptr vp, mp_size_t vn)
+{
+ assert (un >= vn);
+ assert (vn >= 1);
+
+ /* We first multiply by the low order limb. This result can be
+ stored, not added, to rp. We also avoid a loop for zeroing this
+ way. */
+
+ rp[un] = mpn_mul_1 (rp, up, un, vp[0]);
+
+ /* Now accumulate the product of up[] and the next higher limb from
+ vp[]. */
+
+ while (--vn >= 1)
+ {
+ rp += 1, vp += 1;
+ rp[un] = mpn_addmul_1 (rp, up, un, vp[0]);
+ }
+ return rp[un];
+}
+
+void
+mpn_mul_n (mp_ptr rp, mp_srcptr ap, mp_srcptr bp, mp_size_t n)
+{
+ mpn_mul (rp, ap, n, bp, n);
+}
+
+void
+mpn_sqr (mp_ptr rp, mp_srcptr ap, mp_size_t n)
+{
+ mpn_mul (rp, ap, n, ap, n);
+}
+
+mp_limb_t
+mpn_lshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+ mp_limb_t high_limb, low_limb;
+ unsigned int tnc;
+ mp_limb_t retval;
+
+ assert (n >= 1);
+ assert (cnt >= 1);
+ assert (cnt < GMP_LIMB_BITS);
+
+ up += n;
+ rp += n;
+
+ tnc = GMP_LIMB_BITS - cnt;
+ low_limb = *--up;
+ retval = low_limb >> tnc;
+ high_limb = (low_limb << cnt);
+
+ while (--n != 0)
+ {
+ low_limb = *--up;
+ *--rp = high_limb | (low_limb >> tnc);
+ high_limb = (low_limb << cnt);
+ }
+ *--rp = high_limb;
+
+ return retval;
+}
+
+mp_limb_t
+mpn_rshift (mp_ptr rp, mp_srcptr up, mp_size_t n, unsigned int cnt)
+{
+ mp_limb_t high_limb, low_limb;
+ unsigned int tnc;
+ mp_limb_t retval;
+
+ assert (n >= 1);
+ assert (cnt >= 1);
+ assert (cnt < GMP_LIMB_BITS);
+
+ tnc = GMP_LIMB_BITS - cnt;
+ high_limb = *up++;
+ retval = (high_limb << tnc);
+ low_limb = high_limb >> cnt;
+
+ while (--n != 0)
+ {
+ high_limb = *up++;
+ *rp++ = low_limb | (high_limb << tnc);
+ low_limb = high_limb >> cnt;
+ }
+ *rp = low_limb;
+
+ return retval;
+}
+
+static mp_bitcnt_t
+mpn_common_scan (mp_limb_t limb, mp_size_t i, mp_srcptr up, mp_size_t un,
+ mp_limb_t ux)
+{
+ unsigned cnt;
+
+ assert (ux == 0 || ux == GMP_LIMB_MAX);
+ assert (0 <= i && i <= un );
+
+ while (limb == 0)
+ {
+ i++;
+ if (i == un)
+ return (ux == 0 ? ~(mp_bitcnt_t) 0 : un * GMP_LIMB_BITS);
+ limb = ux ^ up[i];
+ }
+ gmp_ctz (cnt, limb);
+ return (mp_bitcnt_t) i * GMP_LIMB_BITS + cnt;
+}
+
+mp_bitcnt_t
+mpn_scan1 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+ mp_size_t i;
+ i = bit / GMP_LIMB_BITS;
+
+ return mpn_common_scan ( ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+ i, ptr, i, 0);
+}
+
+mp_bitcnt_t
+mpn_scan0 (mp_srcptr ptr, mp_bitcnt_t bit)
+{
+ mp_size_t i;
+ i = bit / GMP_LIMB_BITS;
+
+ return mpn_common_scan (~ptr[i] & (GMP_LIMB_MAX << (bit % GMP_LIMB_BITS)),
+ i, ptr, i, GMP_LIMB_MAX);
+}
+
+void
+mpn_com (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+ while (--n >= 0)
+ *rp++ = ~ *up++;
+}
+
+mp_limb_t
+mpn_neg (mp_ptr rp, mp_srcptr up, mp_size_t n)
+{
+ while (*up == 0)
+ {
+ *rp = 0;
+ if (!--n)
+ return 0;
+ ++up; ++rp;
+ }
+ *rp = - *up;
+ mpn_com (++rp, ++up, --n);
+ return 1;
+}
+
+
+/* MPN division interface. */
+
+/* The 3/2 inverse is defined as
+
+ m = floor( (B^3-1) / (B u1 + u0)) - B
+*/
+mp_limb_t
+mpn_invert_3by2 (mp_limb_t u1, mp_limb_t u0)
+{
+ mp_limb_t r, p, m, ql;
+ unsigned ul, uh, qh;
+
+ assert (u1 >= GMP_LIMB_HIGHBIT);
+
+ /* For notation, let b denote the half-limb base, so that B = b^2.
+ Split u1 = b uh + ul. */
+ ul = u1 & GMP_LLIMB_MASK;
+ uh = u1 >> (GMP_LIMB_BITS / 2);
+
+ /* Approximation of the high half of quotient. Differs from the 2/1
+ inverse of the half limb uh, since we have already subtracted
+ u0. */
+ qh = ~u1 / uh;
+
+ /* Adjust to get a half-limb 3/2 inverse, i.e., we want
+
+ qh' = floor( (b^3 - 1) / u) - b = floor ((b^3 - b u - 1) / u
+ = floor( (b (~u) + b-1) / u),
+
+ and the remainder
+
+ r = b (~u) + b-1 - qh (b uh + ul)
+ = b (~u - qh uh) + b-1 - qh ul
+
+ Subtraction of qh ul may underflow, which implies adjustments.
+ But by normalization, 2 u >= B > qh ul, so we need to adjust by
+ at most 2.
+ */
+
+ r = ((~u1 - (mp_limb_t) qh * uh) << (GMP_LIMB_BITS / 2)) | GMP_LLIMB_MASK;
+
+ p = (mp_limb_t) qh * ul;
+ /* Adjustment steps taken from udiv_qrnnd_c */
+ if (r < p)
+ {
+ qh--;
+ r += u1;
+ if (r >= u1) /* i.e. we didn't get carry when adding to r */
+ if (r < p)
+ {
+ qh--;
+ r += u1;
+ }
+ }
+ r -= p;
+
+ /* Low half of the quotient is
+
+ ql = floor ( (b r + b-1) / u1).
+
+ This is a 3/2 division (on half-limbs), for which qh is a
+ suitable inverse. */
+
+ p = (r >> (GMP_LIMB_BITS / 2)) * qh + r;
+ /* Unlike full-limb 3/2, we can add 1 without overflow. For this to
+ work, it is essential that ql is a full mp_limb_t. */
+ ql = (p >> (GMP_LIMB_BITS / 2)) + 1;
+
+ /* By the 3/2 trick, we don't need the high half limb. */
+ r = (r << (GMP_LIMB_BITS / 2)) + GMP_LLIMB_MASK - ql * u1;
+
+ if (r >= (p << (GMP_LIMB_BITS / 2)))
+ {
+ ql--;
+ r += u1;
+ }
+ m = ((mp_limb_t) qh << (GMP_LIMB_BITS / 2)) + ql;
+ if (r >= u1)
+ {
+ m++;
+ r -= u1;
+ }
+
+ /* Now m is the 2/1 invers of u1. If u0 > 0, adjust it to become a
+ 3/2 inverse. */
+ if (u0 > 0)
+ {
+ mp_limb_t th, tl;
+ r = ~r;
+ r += u0;
+ if (r < u0)
+ {
+ m--;
+ if (r >= u1)
+ {
+ m--;
+ r -= u1;
+ }
+ r -= u1;
+ }
+ gmp_umul_ppmm (th, tl, u0, m);
+ r += th;
+ if (r < th)
+ {
+ m--;
+ m -= ((r > u1) | ((r == u1) & (tl > u0)));
+ }
+ }
+
+ return m;
+}
+
+struct gmp_div_inverse
+{
+ /* Normalization shift count. */
+ unsigned shift;
+ /* Normalized divisor (d0 unused for mpn_div_qr_1) */
+ mp_limb_t d1, d0;
+ /* Inverse, for 2/1 or 3/2. */
+ mp_limb_t di;
+};
+
+static void
+mpn_div_qr_1_invert (struct gmp_div_inverse *inv, mp_limb_t d)
+{
+ unsigned shift;
+
+ assert (d > 0);
+ gmp_clz (shift, d);
+ inv->shift = shift;
+ inv->d1 = d << shift;
+ inv->di = mpn_invert_limb (inv->d1);
+}
+
+static void
+mpn_div_qr_2_invert (struct gmp_div_inverse *inv,
+ mp_limb_t d1, mp_limb_t d0)
+{
+ unsigned shift;
+
+ assert (d1 > 0);
+ gmp_clz (shift, d1);
+ inv->shift = shift;
+ if (shift > 0)
+ {
+ d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+ d0 <<= shift;
+ }
+ inv->d1 = d1;
+ inv->d0 = d0;
+ inv->di = mpn_invert_3by2 (d1, d0);
+}
+
+static void
+mpn_div_qr_invert (struct gmp_div_inverse *inv,
+ mp_srcptr dp, mp_size_t dn)
+{
+ assert (dn > 0);
+
+ if (dn == 1)
+ mpn_div_qr_1_invert (inv, dp[0]);
+ else if (dn == 2)
+ mpn_div_qr_2_invert (inv, dp[1], dp[0]);
+ else
+ {
+ unsigned shift;
+ mp_limb_t d1, d0;
+
+ d1 = dp[dn-1];
+ d0 = dp[dn-2];
+ assert (d1 > 0);
+ gmp_clz (shift, d1);
+ inv->shift = shift;
+ if (shift > 0)
+ {
+ d1 = (d1 << shift) | (d0 >> (GMP_LIMB_BITS - shift));
+ d0 = (d0 << shift) | (dp[dn-3] >> (GMP_LIMB_BITS - shift));
+ }
+ inv->d1 = d1;
+ inv->d0 = d0;
+ inv->di = mpn_invert_3by2 (d1, d0);
+ }
+}
+
+/* Not matching current public gmp interface, rather corresponding to
+ the sbpi1_div_* functions. */
+static mp_limb_t
+mpn_div_qr_1_preinv (mp_ptr qp, mp_srcptr np, mp_size_t nn,
+ const struct gmp_div_inverse *inv)
+{
+ mp_limb_t d, di;
+ mp_limb_t r;
+ mp_ptr tp = NULL;
+
+ if (inv->shift > 0)
+ {
+ tp = gmp_xalloc_limbs (nn);
+ r = mpn_lshift (tp, np, nn, inv->shift);
+ np = tp;
+ }
+ else
+ r = 0;
+
+ d = inv->d1;
+ di = inv->di;
+ while (--nn >= 0)
+ {
+ mp_limb_t q;
+
+ gmp_udiv_qrnnd_preinv (q, r, r, np[nn], d, di);
+ if (qp)
+ qp[nn] = q;
+ }
+ if (inv->shift > 0)
+ gmp_free (tp);
+
+ return r >> inv->shift;
+}
+
+static mp_limb_t
+mpn_div_qr_1 (mp_ptr qp, mp_srcptr np, mp_size_t nn, mp_limb_t d)
+{
+ assert (d > 0);
+
+ /* Special case for powers of two. */
+ if ((d & (d-1)) == 0)
+ {
+ mp_limb_t r = np[0] & (d-1);
+ if (qp)
+ {
+ if (d <= 1)
+ mpn_copyi (qp, np, nn);
+ else
+ {
+ unsigned shift;
+ gmp_ctz (shift, d);
+ mpn_rshift (qp, np, nn, shift);
+ }
+ }
+ return r;
+ }
+ else
+ {
+ struct gmp_div_inverse inv;
+ mpn_div_qr_1_invert (&inv, d);
+ return mpn_div_qr_1_preinv (qp, np, nn, &inv);
+ }
+}
+
+static void
+mpn_div_qr_2_preinv (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+ const struct gmp_div_inverse *inv)
+{
+ unsigned shift;
+ mp_size_t i;
+ mp_limb_t d1, d0, di, r1, r0;
+ mp_ptr tp;
+
+ assert (nn >= 2);
+ shift = inv->shift;
+ d1 = inv->d1;
+ d0 = inv->d0;
+ di = inv->di;
+
+ if (shift > 0)
+ {
+ tp = gmp_xalloc_limbs (nn);
+ r1 = mpn_lshift (tp, np, nn, shift);
+ np = tp;
+ }
+ else
+ r1 = 0;
+
+ r0 = np[nn - 1];
+
+ i = nn - 2;
+ do
+ {
+ mp_limb_t n0, q;
+ n0 = np[i];
+ gmp_udiv_qr_3by2 (q, r1, r0, r1, r0, n0, d1, d0, di);
+
+ if (qp)
+ qp[i] = q;
+ }
+ while (--i >= 0);
+
+ if (shift > 0)
+ {
+ assert ((r0 << (GMP_LIMB_BITS - shift)) == 0);
+ r0 = (r0 >> shift) | (r1 << (GMP_LIMB_BITS - shift));
+ r1 >>= shift;
+
+ gmp_free (tp);
+ }
+
+ rp[1] = r1;
+ rp[0] = r0;
+}
+
+#if 0
+static void
+mpn_div_qr_2 (mp_ptr qp, mp_ptr rp, mp_srcptr np, mp_size_t nn,
+ mp_limb_t d1, mp_limb_t d0)
+{
+ struct gmp_div_inverse inv;
+ assert (nn >= 2);
+
+ mpn_div_qr_2_invert (&inv, d1, d0);
+ mpn_div_qr_2_preinv (qp, rp, np, nn, &inv);
+}
+#endif
+
+static void
+mpn_div_qr_pi1 (mp_ptr qp,
+ mp_ptr np, mp_size_t nn, mp_limb_t n1,
+ mp_srcptr dp, mp_size_t dn,
+ mp_limb_t dinv)
+{
+ mp_size_t i;
+
+ mp_limb_t d1, d0;
+ mp_limb_t cy, cy1;
+ mp_limb_t q;
+
+ assert (dn > 2);
+ assert (nn >= dn);
+
+ d1 = dp[dn - 1];
+ d0 = dp[dn - 2];
+
+ assert ((d1 & GMP_LIMB_HIGHBIT) != 0);
+ /* Iteration variable is the index of the q limb.
+ *
+ * We divide <n1, np[dn-1+i], np[dn-2+i], np[dn-3+i],..., np[i]>
+ * by <d1, d0, dp[dn-3], ..., dp[0] >
+ */
+
+ i = nn - dn;
+ do
+ {
+ mp_limb_t n0 = np[dn-1+i];
+
+ if (n1 == d1 && n0 == d0)
+ {
+ q = GMP_LIMB_MAX;
+ mpn_submul_1 (np+i, dp, dn, q);
+ n1 = np[dn-1+i]; /* update n1, last loop's value will now be invalid */
+ }
+ else
+ {
+ gmp_udiv_qr_3by2 (q, n1, n0, n1, n0, np[dn-2+i], d1, d0, dinv);
+
+ cy = mpn_submul_1 (np + i, dp, dn-2, q);
+
+ cy1 = n0 < cy;
+ n0 = n0 - cy;
+ cy = n1 < cy1;
+ n1 = n1 - cy1;
+ np[dn-2+i] = n0;
+
+ if (cy != 0)
+ {
+ n1 += d1 + mpn_add_n (np + i, np + i, dp, dn - 1);
+ q--;
+ }
+ }
+
+ if (qp)
+ qp[i] = q;
+ }
+ while (--i >= 0);
+
+ np[dn - 1] = n1;
+}
+
+static void
+mpn_div_qr_preinv (mp_ptr qp, mp_ptr np, mp_size_t nn,
+ mp_srcptr dp, mp_size_t dn,
+ const struct gmp_div_inverse *inv)
+{
+ assert (dn > 0);
+ assert (nn >= dn);
+
+ if (dn == 1)
+ np[0] = mpn_div_qr_1_preinv (qp, np, nn, inv);
+ else if (dn == 2)
+ mpn_div_qr_2_preinv (qp, np, np, nn, inv);
+ else
+ {
+ mp_limb_t nh;
+ unsigned shift;
+
+ assert (inv->d1 == dp[dn-1]);
+ assert (inv->d0 == dp[dn-2]);
+ assert ((inv->d1 & GMP_LIMB_HIGHBIT) != 0);
+
+ shift = inv->shift;
+ if (shift > 0)
+ nh = mpn_lshift (np, np, nn, shift);
+ else
+ nh = 0;
+
+ mpn_div_qr_pi1 (qp, np, nn, nh, dp, dn, inv->di);
+
+ if (shift > 0)
+ gmp_assert_nocarry (mpn_rshift (np, np, dn, shift));
+ }
+}
+
+static void
+mpn_div_qr (mp_ptr qp, mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn)
+{
+ struct gmp_div_inverse inv;
+ mp_ptr tp = NULL;
+
+ assert (dn > 0);
+ assert (nn >= dn);
+
+ mpn_div_qr_invert (&inv, dp, dn);
+ if (dn > 2 && inv.shift > 0)
+ {
+ tp = gmp_xalloc_limbs (dn);
+ gmp_assert_nocarry (mpn_lshift (tp, dp, dn, inv.shift));
+ dp = tp;
+ }
+ mpn_div_qr_preinv (qp, np, nn, dp, dn, &inv);
+ if (tp)
+ gmp_free (tp);
+}
+
+
+/* MPN base conversion. */
+static unsigned
+mpn_base_power_of_two_p (unsigned b)
+{
+ switch (b)
+ {
+ case 2: return 1;
+ case 4: return 2;
+ case 8: return 3;
+ case 16: return 4;
+ case 32: return 5;
+ case 64: return 6;
+ case 128: return 7;
+ case 256: return 8;
+ default: return 0;
+ }
+}
+
+struct mpn_base_info
+{
+ /* bb is the largest power of the base which fits in one limb, and
+ exp is the corresponding exponent. */
+ unsigned exp;
+ mp_limb_t bb;
+};
+
+static void
+mpn_get_base_info (struct mpn_base_info *info, mp_limb_t b)
+{
+ mp_limb_t m;
+ mp_limb_t p;
+ unsigned exp;
+
+ m = GMP_LIMB_MAX / b;
+ for (exp = 1, p = b; p <= m; exp++)
+ p *= b;
+
+ info->exp = exp;
+ info->bb = p;
+}
+
+static mp_bitcnt_t
+mpn_limb_size_in_base_2 (mp_limb_t u)
+{
+ unsigned shift;
+
+ assert (u > 0);
+ gmp_clz (shift, u);
+ return GMP_LIMB_BITS - shift;
+}
+
+static size_t
+mpn_get_str_bits (unsigned char *sp, unsigned bits, mp_srcptr up, mp_size_t un)
+{
+ unsigned char mask;
+ size_t sn, j;
+ mp_size_t i;
+ unsigned shift;
+
+ sn = ((un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1])
+ + bits - 1) / bits;
+
+ mask = (1U << bits) - 1;
+
+ for (i = 0, j = sn, shift = 0; j-- > 0;)
+ {
+ unsigned char digit = up[i] >> shift;
+
+ shift += bits;
+
+ if (shift >= GMP_LIMB_BITS && ++i < un)
+ {
+ shift -= GMP_LIMB_BITS;
+ digit |= up[i] << (bits - shift);
+ }
+ sp[j] = digit & mask;
+ }
+ return sn;
+}
+
+/* We generate digits from the least significant end, and reverse at
+ the end. */
+static size_t
+mpn_limb_get_str (unsigned char *sp, mp_limb_t w,
+ const struct gmp_div_inverse *binv)
+{
+ mp_size_t i;
+ for (i = 0; w > 0; i++)
+ {
+ mp_limb_t h, l, r;
+
+ h = w >> (GMP_LIMB_BITS - binv->shift);
+ l = w << binv->shift;
+
+ gmp_udiv_qrnnd_preinv (w, r, h, l, binv->d1, binv->di);
+ assert ( (r << (GMP_LIMB_BITS - binv->shift)) == 0);
+ r >>= binv->shift;
+
+ sp[i] = r;
+ }
+ return i;
+}
+
+static size_t
+mpn_get_str_other (unsigned char *sp,
+ int base, const struct mpn_base_info *info,
+ mp_ptr up, mp_size_t un)
+{
+ struct gmp_div_inverse binv;
+ size_t sn;
+ size_t i;
+
+ mpn_div_qr_1_invert (&binv, base);
+
+ sn = 0;
+
+ if (un > 1)
+ {
+ struct gmp_div_inverse bbinv;
+ mpn_div_qr_1_invert (&bbinv, info->bb);
+
+ do
+ {
+ mp_limb_t w;
+ size_t done;
+ w = mpn_div_qr_1_preinv (up, up, un, &bbinv);
+ un -= (up[un-1] == 0);
+ done = mpn_limb_get_str (sp + sn, w, &binv);
+
+ for (sn += done; done < info->exp; done++)
+ sp[sn++] = 0;
+ }
+ while (un > 1);
+ }
+ sn += mpn_limb_get_str (sp + sn, up[0], &binv);
+
+ /* Reverse order */
+ for (i = 0; 2*i + 1 < sn; i++)
+ {
+ unsigned char t = sp[i];
+ sp[i] = sp[sn - i - 1];
+ sp[sn - i - 1] = t;
+ }
+
+ return sn;
+}
+
+size_t
+mpn_get_str (unsigned char *sp, int base, mp_ptr up, mp_size_t un)
+{
+ unsigned bits;
+
+ assert (un > 0);
+ assert (up[un-1] > 0);
+
+ bits = mpn_base_power_of_two_p (base);
+ if (bits)
+ return mpn_get_str_bits (sp, bits, up, un);
+ else
+ {
+ struct mpn_base_info info;
+
+ mpn_get_base_info (&info, base);
+ return mpn_get_str_other (sp, base, &info, up, un);
+ }
+}
+
+static mp_size_t
+mpn_set_str_bits (mp_ptr rp, const unsigned char *sp, size_t sn,
+ unsigned bits)
+{
+ mp_size_t rn;
+ size_t j;
+ unsigned shift;
+
+ for (j = sn, rn = 0, shift = 0; j-- > 0; )
+ {
+ if (shift == 0)
+ {
+ rp[rn++] = sp[j];
+ shift += bits;
+ }
+ else
+ {
+ rp[rn-1] |= (mp_limb_t) sp[j] << shift;
+ shift += bits;
+ if (shift >= GMP_LIMB_BITS)
+ {
+ shift -= GMP_LIMB_BITS;
+ if (shift > 0)
+ rp[rn++] = (mp_limb_t) sp[j] >> (bits - shift);
+ }
+ }
+ }
+ rn = mpn_normalized_size (rp, rn);
+ return rn;
+}
+
+/* Result is usually normalized, except for all-zero input, in which
+ case a single zero limb is written at *RP, and 1 is returned. */
+static mp_size_t
+mpn_set_str_other (mp_ptr rp, const unsigned char *sp, size_t sn,
+ mp_limb_t b, const struct mpn_base_info *info)
+{
+ mp_size_t rn;
+ mp_limb_t w;
+ unsigned k;
+ size_t j;
+
+ assert (sn > 0);
+
+ k = 1 + (sn - 1) % info->exp;
+
+ j = 0;
+ w = sp[j++];
+ while (--k != 0)
+ w = w * b + sp[j++];
+
+ rp[0] = w;
+
+ for (rn = 1; j < sn;)
+ {
+ mp_limb_t cy;
+
+ w = sp[j++];
+ for (k = 1; k < info->exp; k++)
+ w = w * b + sp[j++];
+
+ cy = mpn_mul_1 (rp, rp, rn, info->bb);
+ cy += mpn_add_1 (rp, rp, rn, w);
+ if (cy > 0)
+ rp[rn++] = cy;
+ }
+ assert (j == sn);
+
+ return rn;
+}
+
+mp_size_t
+mpn_set_str (mp_ptr rp, const unsigned char *sp, size_t sn, int base)
+{
+ unsigned bits;
+
+ if (sn == 0)
+ return 0;
+
+ bits = mpn_base_power_of_two_p (base);
+ if (bits)
+ return mpn_set_str_bits (rp, sp, sn, bits);
+ else
+ {
+ struct mpn_base_info info;
+
+ mpn_get_base_info (&info, base);
+ return mpn_set_str_other (rp, sp, sn, base, &info);
+ }
+}
+
+
+/* MPZ interface */
+void
+mpz_init (mpz_t r)
+{
+ static const mp_limb_t dummy_limb = 0xc1a0;
+
+ r->_mp_alloc = 0;
+ r->_mp_size = 0;
+ r->_mp_d = (mp_ptr) &dummy_limb;
+}
+
+/* The utility of this function is a bit limited, since many functions
+ assigns the result variable using mpz_swap. */
+void
+mpz_init2 (mpz_t r, mp_bitcnt_t bits)
+{
+ mp_size_t rn;
+
+ bits -= (bits != 0); /* Round down, except if 0 */
+ rn = 1 + bits / GMP_LIMB_BITS;
+
+ r->_mp_alloc = rn;
+ r->_mp_size = 0;
+ r->_mp_d = gmp_xalloc_limbs (rn);
+}
+
+void
+mpz_clear (mpz_t r)
+{
+ if (r->_mp_alloc)
+ gmp_free (r->_mp_d);
+}
+
+static mp_ptr
+mpz_realloc (mpz_t r, mp_size_t size)
+{
+ size = GMP_MAX (size, 1);
+
+ if (r->_mp_alloc)
+ r->_mp_d = gmp_xrealloc_limbs (r->_mp_d, size);
+ else
+ r->_mp_d = gmp_xalloc_limbs (size);
+ r->_mp_alloc = size;
+
+ if (GMP_ABS (r->_mp_size) > size)
+ r->_mp_size = 0;
+
+ return r->_mp_d;
+}
+
+/* Realloc for an mpz_t WHAT if it has less than NEEDED limbs. */
+#define MPZ_REALLOC(z,n) ((n) > (z)->_mp_alloc \
+ ? mpz_realloc(z,n) \
+ : (z)->_mp_d)
+
+/* MPZ assignment and basic conversions. */
+void
+mpz_set_si (mpz_t r, signed long int x)
+{
+ if (x >= 0)
+ mpz_set_ui (r, x);
+ else /* (x < 0) */
+ {
+ r->_mp_size = -1;
+ MPZ_REALLOC (r, 1)[0] = GMP_NEG_CAST (unsigned long int, x);
+ }
+}
+
+void
+mpz_set_ui (mpz_t r, unsigned long int x)
+{
+ if (x > 0)
+ {
+ r->_mp_size = 1;
+ MPZ_REALLOC (r, 1)[0] = x;
+ }
+ else
+ r->_mp_size = 0;
+}
+
+void
+mpz_set (mpz_t r, const mpz_t x)
+{
+ /* Allow the NOP r == x */
+ if (r != x)
+ {
+ mp_size_t n;
+ mp_ptr rp;
+
+ n = GMP_ABS (x->_mp_size);
+ rp = MPZ_REALLOC (r, n);
+
+ mpn_copyi (rp, x->_mp_d, n);
+ r->_mp_size = x->_mp_size;
+ }
+}
+
+void
+mpz_init_set_si (mpz_t r, signed long int x)
+{
+ mpz_init (r);
+ mpz_set_si (r, x);
+}
+
+void
+mpz_init_set_ui (mpz_t r, unsigned long int x)
+{
+ mpz_init (r);
+ mpz_set_ui (r, x);
+}
+
+void
+mpz_init_set (mpz_t r, const mpz_t x)
+{
+ mpz_init (r);
+ mpz_set (r, x);
+}
+
+int
+mpz_fits_slong_p (const mpz_t u)
+{
+ mp_size_t us = u->_mp_size;
+
+ if (us == 1)
+ return u->_mp_d[0] < GMP_LIMB_HIGHBIT;
+ else if (us == -1)
+ return u->_mp_d[0] <= GMP_LIMB_HIGHBIT;
+ else
+ return (us == 0);
+}
+
+int
+mpz_fits_ulong_p (const mpz_t u)
+{
+ mp_size_t us = u->_mp_size;
+
+ return (us == (us > 0));
+}
+
+long int
+mpz_get_si (const mpz_t u)
+{
+ if (u->_mp_size < 0)
+ /* This expression is necessary to properly handle 0x80000000 */
+ return -1 - (long) ((u->_mp_d[0] - 1) & ~GMP_LIMB_HIGHBIT);
+ else
+ return (long) (mpz_get_ui (u) & ~GMP_LIMB_HIGHBIT);
+}
+
+unsigned long int
+mpz_get_ui (const mpz_t u)
+{
+ return u->_mp_size == 0 ? 0 : u->_mp_d[0];
+}
+
+size_t
+mpz_size (const mpz_t u)
+{
+ return GMP_ABS (u->_mp_size);
+}
+
+mp_limb_t
+mpz_getlimbn (const mpz_t u, mp_size_t n)
+{
+ if (n >= 0 && n < GMP_ABS (u->_mp_size))
+ return u->_mp_d[n];
+ else
+ return 0;
+}
+
+void
+mpz_realloc2 (mpz_t x, mp_bitcnt_t n)
+{
+ mpz_realloc (x, 1 + (n - (n != 0)) / GMP_LIMB_BITS);
+}
+
+mp_srcptr
+mpz_limbs_read (mpz_srcptr x)
+{
+ return x->_mp_d;
+}
+
+mp_ptr
+mpz_limbs_modify (mpz_t x, mp_size_t n)
+{
+ assert (n > 0);
+ return MPZ_REALLOC (x, n);
+}
+
+mp_ptr
+mpz_limbs_write (mpz_t x, mp_size_t n)
+{
+ return mpz_limbs_modify (x, n);
+}
+
+void
+mpz_limbs_finish (mpz_t x, mp_size_t xs)
+{
+ mp_size_t xn;
+ xn = mpn_normalized_size (x->_mp_d, GMP_ABS (xs));
+ x->_mp_size = xs < 0 ? -xn : xn;
+}
+
+mpz_srcptr
+mpz_roinit_n (mpz_t x, mp_srcptr xp, mp_size_t xs)
+{
+ x->_mp_alloc = 0;
+ x->_mp_d = (mp_ptr) xp;
+ mpz_limbs_finish (x, xs);
+ return x;
+}
+
+
+/* Conversions and comparison to double. */
+void
+mpz_set_d (mpz_t r, double x)
+{
+ int sign;
+ mp_ptr rp;
+ mp_size_t rn, i;
+ double B;
+ double Bi;
+ mp_limb_t f;
+
+ /* x != x is true when x is a NaN, and x == x * 0.5 is true when x is
+ zero or infinity. */
+ if (x != x || x == x * 0.5)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ sign = x < 0.0 ;
+ if (sign)
+ x = - x;
+
+ if (x < 1.0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+ B = 2.0 * (double) GMP_LIMB_HIGHBIT;
+ Bi = 1.0 / B;
+ for (rn = 1; x >= B; rn++)
+ x *= Bi;
+
+ rp = MPZ_REALLOC (r, rn);
+
+ f = (mp_limb_t) x;
+ x -= f;
+ assert (x < 1.0);
+ i = rn-1;
+ rp[i] = f;
+ while (--i >= 0)
+ {
+ x = B * x;
+ f = (mp_limb_t) x;
+ x -= f;
+ assert (x < 1.0);
+ rp[i] = f;
+ }
+
+ r->_mp_size = sign ? - rn : rn;
+}
+
+void
+mpz_init_set_d (mpz_t r, double x)
+{
+ mpz_init (r);
+ mpz_set_d (r, x);
+}
+
+double
+mpz_get_d (const mpz_t u)
+{
+ mp_size_t un;
+ double x;
+ double B = 2.0 * (double) GMP_LIMB_HIGHBIT;
+
+ un = GMP_ABS (u->_mp_size);
+
+ if (un == 0)
+ return 0.0;
+
+ x = u->_mp_d[--un];
+ while (un > 0)
+ x = B*x + u->_mp_d[--un];
+
+ if (u->_mp_size < 0)
+ x = -x;
+
+ return x;
+}
+
+int
+mpz_cmpabs_d (const mpz_t x, double d)
+{
+ mp_size_t xn;
+ double B, Bi;
+ mp_size_t i;
+
+ xn = x->_mp_size;
+ d = GMP_ABS (d);
+
+ if (xn != 0)
+ {
+ xn = GMP_ABS (xn);
+
+ B = 2.0 * (double) GMP_LIMB_HIGHBIT;
+ Bi = 1.0 / B;
+
+ /* Scale d so it can be compared with the top limb. */
+ for (i = 1; i < xn; i++)
+ d *= Bi;
+
+ if (d >= B)
+ return -1;
+
+ /* Compare floor(d) to top limb, subtract and cancel when equal. */
+ for (i = xn; i-- > 0;)
+ {
+ mp_limb_t f, xl;
+
+ f = (mp_limb_t) d;
+ xl = x->_mp_d[i];
+ if (xl > f)
+ return 1;
+ else if (xl < f)
+ return -1;
+ d = B * (d - f);
+ }
+ }
+ return - (d > 0.0);
+}
+
+int
+mpz_cmp_d (const mpz_t x, double d)
+{
+ if (x->_mp_size < 0)
+ {
+ if (d >= 0.0)
+ return -1;
+ else
+ return -mpz_cmpabs_d (x, d);
+ }
+ else
+ {
+ if (d < 0.0)
+ return 1;
+ else
+ return mpz_cmpabs_d (x, d);
+ }
+}
+
+
+/* MPZ comparisons and the like. */
+int
+mpz_sgn (const mpz_t u)
+{
+ return GMP_CMP (u->_mp_size, 0);
+}
+
+int
+mpz_cmp_si (const mpz_t u, long v)
+{
+ mp_size_t usize = u->_mp_size;
+
+ if (usize < -1)
+ return -1;
+ else if (v >= 0)
+ return mpz_cmp_ui (u, v);
+ else if (usize >= 0)
+ return 1;
+ else /* usize == -1 */
+ return GMP_CMP (GMP_NEG_CAST (mp_limb_t, v), u->_mp_d[0]);
+}
+
+int
+mpz_cmp_ui (const mpz_t u, unsigned long v)
+{
+ mp_size_t usize = u->_mp_size;
+
+ if (usize > 1)
+ return 1;
+ else if (usize < 0)
+ return -1;
+ else
+ return GMP_CMP (mpz_get_ui (u), v);
+}
+
+int
+mpz_cmp (const mpz_t a, const mpz_t b)
+{
+ mp_size_t asize = a->_mp_size;
+ mp_size_t bsize = b->_mp_size;
+
+ if (asize != bsize)
+ return (asize < bsize) ? -1 : 1;
+ else if (asize >= 0)
+ return mpn_cmp (a->_mp_d, b->_mp_d, asize);
+ else
+ return mpn_cmp (b->_mp_d, a->_mp_d, -asize);
+}
+
+int
+mpz_cmpabs_ui (const mpz_t u, unsigned long v)
+{
+ if (GMP_ABS (u->_mp_size) > 1)
+ return 1;
+ else
+ return GMP_CMP (mpz_get_ui (u), v);
+}
+
+int
+mpz_cmpabs (const mpz_t u, const mpz_t v)
+{
+ return mpn_cmp4 (u->_mp_d, GMP_ABS (u->_mp_size),
+ v->_mp_d, GMP_ABS (v->_mp_size));
+}
+
+void
+mpz_abs (mpz_t r, const mpz_t u)
+{
+ mpz_set (r, u);
+ r->_mp_size = GMP_ABS (r->_mp_size);
+}
+
+void
+mpz_neg (mpz_t r, const mpz_t u)
+{
+ mpz_set (r, u);
+ r->_mp_size = -r->_mp_size;
+}
+
+void
+mpz_swap (mpz_t u, mpz_t v)
+{
+ MP_SIZE_T_SWAP (u->_mp_size, v->_mp_size);
+ MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc);
+ MP_PTR_SWAP (u->_mp_d, v->_mp_d);
+}
+
+
+/* MPZ addition and subtraction */
+
+/* Adds to the absolute value. Returns new size, but doesn't store it. */
+static mp_size_t
+mpz_abs_add_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ mp_size_t an;
+ mp_ptr rp;
+ mp_limb_t cy;
+
+ an = GMP_ABS (a->_mp_size);
+ if (an == 0)
+ {
+ MPZ_REALLOC (r, 1)[0] = b;
+ return b > 0;
+ }
+
+ rp = MPZ_REALLOC (r, an + 1);
+
+ cy = mpn_add_1 (rp, a->_mp_d, an, b);
+ rp[an] = cy;
+ an += cy;
+
+ return an;
+}
+
+/* Subtract from the absolute value. Returns new size, (or -1 on underflow),
+ but doesn't store it. */
+static mp_size_t
+mpz_abs_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ mp_size_t an = GMP_ABS (a->_mp_size);
+ mp_ptr rp;
+
+ if (an == 0)
+ {
+ MPZ_REALLOC (r, 1)[0] = b;
+ return -(b > 0);
+ }
+ rp = MPZ_REALLOC (r, an);
+ if (an == 1 && a->_mp_d[0] < b)
+ {
+ rp[0] = b - a->_mp_d[0];
+ return -1;
+ }
+ else
+ {
+ gmp_assert_nocarry (mpn_sub_1 (rp, a->_mp_d, an, b));
+ return mpn_normalized_size (rp, an);
+ }
+}
+
+void
+mpz_add_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ if (a->_mp_size >= 0)
+ r->_mp_size = mpz_abs_add_ui (r, a, b);
+ else
+ r->_mp_size = -mpz_abs_sub_ui (r, a, b);
+}
+
+void
+mpz_sub_ui (mpz_t r, const mpz_t a, unsigned long b)
+{
+ if (a->_mp_size < 0)
+ r->_mp_size = -mpz_abs_add_ui (r, a, b);
+ else
+ r->_mp_size = mpz_abs_sub_ui (r, a, b);
+}
+
+void
+mpz_ui_sub (mpz_t r, unsigned long a, const mpz_t b)
+{
+ if (b->_mp_size < 0)
+ r->_mp_size = mpz_abs_add_ui (r, b, a);
+ else
+ r->_mp_size = -mpz_abs_sub_ui (r, b, a);
+}
+
+static mp_size_t
+mpz_abs_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t an = GMP_ABS (a->_mp_size);
+ mp_size_t bn = GMP_ABS (b->_mp_size);
+ mp_ptr rp;
+ mp_limb_t cy;
+
+ if (an < bn)
+ {
+ MPZ_SRCPTR_SWAP (a, b);
+ MP_SIZE_T_SWAP (an, bn);
+ }
+
+ rp = MPZ_REALLOC (r, an + 1);
+ cy = mpn_add (rp, a->_mp_d, an, b->_mp_d, bn);
+
+ rp[an] = cy;
+
+ return an + cy;
+}
+
+static mp_size_t
+mpz_abs_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t an = GMP_ABS (a->_mp_size);
+ mp_size_t bn = GMP_ABS (b->_mp_size);
+ int cmp;
+ mp_ptr rp;
+
+ cmp = mpn_cmp4 (a->_mp_d, an, b->_mp_d, bn);
+ if (cmp > 0)
+ {
+ rp = MPZ_REALLOC (r, an);
+ gmp_assert_nocarry (mpn_sub (rp, a->_mp_d, an, b->_mp_d, bn));
+ return mpn_normalized_size (rp, an);
+ }
+ else if (cmp < 0)
+ {
+ rp = MPZ_REALLOC (r, bn);
+ gmp_assert_nocarry (mpn_sub (rp, b->_mp_d, bn, a->_mp_d, an));
+ return -mpn_normalized_size (rp, bn);
+ }
+ else
+ return 0;
+}
+
+void
+mpz_add (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t rn;
+
+ if ( (a->_mp_size ^ b->_mp_size) >= 0)
+ rn = mpz_abs_add (r, a, b);
+ else
+ rn = mpz_abs_sub (r, a, b);
+
+ r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+void
+mpz_sub (mpz_t r, const mpz_t a, const mpz_t b)
+{
+ mp_size_t rn;
+
+ if ( (a->_mp_size ^ b->_mp_size) >= 0)
+ rn = mpz_abs_sub (r, a, b);
+ else
+ rn = mpz_abs_add (r, a, b);
+
+ r->_mp_size = a->_mp_size >= 0 ? rn : - rn;
+}
+
+
+/* MPZ multiplication */
+void
+mpz_mul_si (mpz_t r, const mpz_t u, long int v)
+{
+ if (v < 0)
+ {
+ mpz_mul_ui (r, u, GMP_NEG_CAST (unsigned long int, v));
+ mpz_neg (r, r);
+ }
+ else
+ mpz_mul_ui (r, u, (unsigned long int) v);
+}
+
+void
+mpz_mul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+ mp_size_t un, us;
+ mp_ptr tp;
+ mp_limb_t cy;
+
+ us = u->_mp_size;
+
+ if (us == 0 || v == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ un = GMP_ABS (us);
+
+ tp = MPZ_REALLOC (r, un + 1);
+ cy = mpn_mul_1 (tp, u->_mp_d, un, v);
+ tp[un] = cy;
+
+ un += (cy > 0);
+ r->_mp_size = (us < 0) ? - un : un;
+}
+
+void
+mpz_mul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ int sign;
+ mp_size_t un, vn, rn;
+ mpz_t t;
+ mp_ptr tp;
+
+ un = u->_mp_size;
+ vn = v->_mp_size;
+
+ if (un == 0 || vn == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ sign = (un ^ vn) < 0;
+
+ un = GMP_ABS (un);
+ vn = GMP_ABS (vn);
+
+ mpz_init2 (t, (un + vn) * GMP_LIMB_BITS);
+
+ tp = t->_mp_d;
+ if (un >= vn)
+ mpn_mul (tp, u->_mp_d, un, v->_mp_d, vn);
+ else
+ mpn_mul (tp, v->_mp_d, vn, u->_mp_d, un);
+
+ rn = un + vn;
+ rn -= tp[rn-1] == 0;
+
+ t->_mp_size = sign ? - rn : rn;
+ mpz_swap (r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_mul_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bits)
+{
+ mp_size_t un, rn;
+ mp_size_t limbs;
+ unsigned shift;
+ mp_ptr rp;
+
+ un = GMP_ABS (u->_mp_size);
+ if (un == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ limbs = bits / GMP_LIMB_BITS;
+ shift = bits % GMP_LIMB_BITS;
+
+ rn = un + limbs + (shift > 0);
+ rp = MPZ_REALLOC (r, rn);
+ if (shift > 0)
+ {
+ mp_limb_t cy = mpn_lshift (rp + limbs, u->_mp_d, un, shift);
+ rp[rn-1] = cy;
+ rn -= (cy == 0);
+ }
+ else
+ mpn_copyd (rp + limbs, u->_mp_d, un);
+
+ mpn_zero (rp, limbs);
+
+ r->_mp_size = (u->_mp_size < 0) ? - rn : rn;
+}
+
+void
+mpz_addmul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul_ui (t, u, v);
+ mpz_add (r, r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_submul_ui (mpz_t r, const mpz_t u, unsigned long int v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul_ui (t, u, v);
+ mpz_sub (r, r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_addmul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul (t, u, v);
+ mpz_add (r, r, t);
+ mpz_clear (t);
+}
+
+void
+mpz_submul (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mpz_t t;
+ mpz_init (t);
+ mpz_mul (t, u, v);
+ mpz_sub (r, r, t);
+ mpz_clear (t);
+}
+
+
+/* MPZ division */
+enum mpz_div_round_mode { GMP_DIV_FLOOR, GMP_DIV_CEIL, GMP_DIV_TRUNC };
+
+/* Allows q or r to be zero. Returns 1 iff remainder is non-zero. */
+static int
+mpz_div_qr (mpz_t q, mpz_t r,
+ const mpz_t n, const mpz_t d, enum mpz_div_round_mode mode)
+{
+ mp_size_t ns, ds, nn, dn, qs;
+ ns = n->_mp_size;
+ ds = d->_mp_size;
+
+ if (ds == 0)
+ gmp_die("mpz_div_qr: Divide by zero.");
+
+ if (ns == 0)
+ {
+ if (q)
+ q->_mp_size = 0;
+ if (r)
+ r->_mp_size = 0;
+ return 0;
+ }
+
+ nn = GMP_ABS (ns);
+ dn = GMP_ABS (ds);
+
+ qs = ds ^ ns;
+
+ if (nn < dn)
+ {
+ if (mode == GMP_DIV_CEIL && qs >= 0)
+ {
+ /* q = 1, r = n - d */
+ if (r)
+ mpz_sub (r, n, d);
+ if (q)
+ mpz_set_ui (q, 1);
+ }
+ else if (mode == GMP_DIV_FLOOR && qs < 0)
+ {
+ /* q = -1, r = n + d */
+ if (r)
+ mpz_add (r, n, d);
+ if (q)
+ mpz_set_si (q, -1);
+ }
+ else
+ {
+ /* q = 0, r = d */
+ if (r)
+ mpz_set (r, n);
+ if (q)
+ q->_mp_size = 0;
+ }
+ return 1;
+ }
+ else
+ {
+ mp_ptr np, qp;
+ mp_size_t qn, rn;
+ mpz_t tq, tr;
+
+ mpz_init_set (tr, n);
+ np = tr->_mp_d;
+
+ qn = nn - dn + 1;
+
+ if (q)
+ {
+ mpz_init2 (tq, qn * GMP_LIMB_BITS);
+ qp = tq->_mp_d;
+ }
+ else
+ qp = NULL;
+
+ mpn_div_qr (qp, np, nn, d->_mp_d, dn);
+
+ if (qp)
+ {
+ qn -= (qp[qn-1] == 0);
+
+ tq->_mp_size = qs < 0 ? -qn : qn;
+ }
+ rn = mpn_normalized_size (np, dn);
+ tr->_mp_size = ns < 0 ? - rn : rn;
+
+ if (mode == GMP_DIV_FLOOR && qs < 0 && rn != 0)
+ {
+ if (q)
+ mpz_sub_ui (tq, tq, 1);
+ if (r)
+ mpz_add (tr, tr, d);
+ }
+ else if (mode == GMP_DIV_CEIL && qs >= 0 && rn != 0)
+ {
+ if (q)
+ mpz_add_ui (tq, tq, 1);
+ if (r)
+ mpz_sub (tr, tr, d);
+ }
+
+ if (q)
+ {
+ mpz_swap (tq, q);
+ mpz_clear (tq);
+ }
+ if (r)
+ mpz_swap (tr, r);
+
+ mpz_clear (tr);
+
+ return rn != 0;
+ }
+}
+
+void
+mpz_cdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_qr (mpz_t q, mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+void
+mpz_mod (mpz_t r, const mpz_t n, const mpz_t d)
+{
+ mpz_div_qr (NULL, r, n, d, d->_mp_size >= 0 ? GMP_DIV_FLOOR : GMP_DIV_CEIL);
+}
+
+static void
+mpz_div_q_2exp (mpz_t q, const mpz_t u, mp_bitcnt_t bit_index,
+ enum mpz_div_round_mode mode)
+{
+ mp_size_t un, qn;
+ mp_size_t limb_cnt;
+ mp_ptr qp;
+ int adjust;
+
+ un = u->_mp_size;
+ if (un == 0)
+ {
+ q->_mp_size = 0;
+ return;
+ }
+ limb_cnt = bit_index / GMP_LIMB_BITS;
+ qn = GMP_ABS (un) - limb_cnt;
+ bit_index %= GMP_LIMB_BITS;
+
+ if (mode == ((un > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* un != 0 here. */
+ /* Note: Below, the final indexing at limb_cnt is valid because at
+ that point we have qn > 0. */
+ adjust = (qn <= 0
+ || !mpn_zero_p (u->_mp_d, limb_cnt)
+ || (u->_mp_d[limb_cnt]
+ & (((mp_limb_t) 1 << bit_index) - 1)));
+ else
+ adjust = 0;
+
+ if (qn <= 0)
+ qn = 0;
+ else
+ {
+ qp = MPZ_REALLOC (q, qn);
+
+ if (bit_index != 0)
+ {
+ mpn_rshift (qp, u->_mp_d + limb_cnt, qn, bit_index);
+ qn -= qp[qn - 1] == 0;
+ }
+ else
+ {
+ mpn_copyi (qp, u->_mp_d + limb_cnt, qn);
+ }
+ }
+
+ q->_mp_size = qn;
+
+ if (adjust)
+ mpz_add_ui (q, q, 1);
+ if (un < 0)
+ mpz_neg (q, q);
+}
+
+static void
+mpz_div_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t bit_index,
+ enum mpz_div_round_mode mode)
+{
+ mp_size_t us, un, rn;
+ mp_ptr rp;
+ mp_limb_t mask;
+
+ us = u->_mp_size;
+ if (us == 0 || bit_index == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+ rn = (bit_index + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+ assert (rn > 0);
+
+ rp = MPZ_REALLOC (r, rn);
+ un = GMP_ABS (us);
+
+ mask = GMP_LIMB_MAX >> (rn * GMP_LIMB_BITS - bit_index);
+
+ if (rn > un)
+ {
+ /* Quotient (with truncation) is zero, and remainder is
+ non-zero */
+ if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+ {
+ /* Have to negate and sign extend. */
+ mp_size_t i;
+
+ gmp_assert_nocarry (! mpn_neg (rp, u->_mp_d, un));
+ for (i = un; i < rn - 1; i++)
+ rp[i] = GMP_LIMB_MAX;
+
+ rp[rn-1] = mask;
+ us = -us;
+ }
+ else
+ {
+ /* Just copy */
+ if (r != u)
+ mpn_copyi (rp, u->_mp_d, un);
+
+ rn = un;
+ }
+ }
+ else
+ {
+ if (r != u)
+ mpn_copyi (rp, u->_mp_d, rn - 1);
+
+ rp[rn-1] = u->_mp_d[rn-1] & mask;
+
+ if (mode == ((us > 0) ? GMP_DIV_CEIL : GMP_DIV_FLOOR)) /* us != 0 here. */
+ {
+ /* If r != 0, compute 2^{bit_count} - r. */
+ mpn_neg (rp, rp, rn);
+
+ rp[rn-1] &= mask;
+
+ /* us is not used for anything else, so we can modify it
+ here to indicate flipped sign. */
+ us = -us;
+ }
+ }
+ rn = mpn_normalized_size (rp, rn);
+ r->_mp_size = us < 0 ? -rn : rn;
+}
+
+void
+mpz_cdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_q_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_q_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_q_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_q_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_cdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_r_2exp (r, u, cnt, GMP_DIV_CEIL);
+}
+
+void
+mpz_fdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_r_2exp (r, u, cnt, GMP_DIV_FLOOR);
+}
+
+void
+mpz_tdiv_r_2exp (mpz_t r, const mpz_t u, mp_bitcnt_t cnt)
+{
+ mpz_div_r_2exp (r, u, cnt, GMP_DIV_TRUNC);
+}
+
+void
+mpz_divexact (mpz_t q, const mpz_t n, const mpz_t d)
+{
+ gmp_assert_nocarry (mpz_div_qr (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_p (const mpz_t n, const mpz_t d)
+{
+ return mpz_div_qr (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+int
+mpz_congruent_p (const mpz_t a, const mpz_t b, const mpz_t m)
+{
+ mpz_t t;
+ int res;
+
+ /* a == b (mod 0) iff a == b */
+ if (mpz_sgn (m) == 0)
+ return (mpz_cmp (a, b) == 0);
+
+ mpz_init (t);
+ mpz_sub (t, a, b);
+ res = mpz_divisible_p (t, m);
+ mpz_clear (t);
+
+ return res;
+}
+
+static unsigned long
+mpz_div_qr_ui (mpz_t q, mpz_t r,
+ const mpz_t n, unsigned long d, enum mpz_div_round_mode mode)
+{
+ mp_size_t ns, qn;
+ mp_ptr qp;
+ mp_limb_t rl;
+ mp_size_t rs;
+
+ ns = n->_mp_size;
+ if (ns == 0)
+ {
+ if (q)
+ q->_mp_size = 0;
+ if (r)
+ r->_mp_size = 0;
+ return 0;
+ }
+
+ qn = GMP_ABS (ns);
+ if (q)
+ qp = MPZ_REALLOC (q, qn);
+ else
+ qp = NULL;
+
+ rl = mpn_div_qr_1 (qp, n->_mp_d, qn, d);
+ assert (rl < d);
+
+ rs = rl > 0;
+ rs = (ns < 0) ? -rs : rs;
+
+ if (rl > 0 && ( (mode == GMP_DIV_FLOOR && ns < 0)
+ || (mode == GMP_DIV_CEIL && ns >= 0)))
+ {
+ if (q)
+ gmp_assert_nocarry (mpn_add_1 (qp, qp, qn, 1));
+ rl = d - rl;
+ rs = -rs;
+ }
+
+ if (r)
+ {
+ MPZ_REALLOC (r, 1)[0] = rl;
+ r->_mp_size = rs;
+ }
+ if (q)
+ {
+ qn -= (qp[qn-1] == 0);
+ assert (qn == 0 || qp[qn-1] > 0);
+
+ q->_mp_size = (ns < 0) ? - qn : qn;
+ }
+
+ return rl;
+}
+
+unsigned long
+mpz_cdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, r, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, r, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_qr_ui (mpz_t q, mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_q_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_CEIL);
+}
+unsigned long
+mpz_fdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+unsigned long
+mpz_tdiv_r_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_cdiv_ui (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_CEIL);
+}
+
+unsigned long
+mpz_fdiv_ui (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_FLOOR);
+}
+
+unsigned long
+mpz_tdiv_ui (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC);
+}
+
+unsigned long
+mpz_mod_ui (mpz_t r, const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, r, n, d, GMP_DIV_FLOOR);
+}
+
+void
+mpz_divexact_ui (mpz_t q, const mpz_t n, unsigned long d)
+{
+ gmp_assert_nocarry (mpz_div_qr_ui (q, NULL, n, d, GMP_DIV_TRUNC));
+}
+
+int
+mpz_divisible_ui_p (const mpz_t n, unsigned long d)
+{
+ return mpz_div_qr_ui (NULL, NULL, n, d, GMP_DIV_TRUNC) == 0;
+}
+
+
+/* GCD */
+static mp_limb_t
+mpn_gcd_11 (mp_limb_t u, mp_limb_t v)
+{
+ unsigned shift;
+
+ assert ( (u | v) > 0);
+
+ if (u == 0)
+ return v;
+ else if (v == 0)
+ return u;
+
+ gmp_ctz (shift, u | v);
+
+ u >>= shift;
+ v >>= shift;
+
+ if ( (u & 1) == 0)
+ MP_LIMB_T_SWAP (u, v);
+
+ while ( (v & 1) == 0)
+ v >>= 1;
+
+ while (u != v)
+ {
+ if (u > v)
+ {
+ u -= v;
+ do
+ u >>= 1;
+ while ( (u & 1) == 0);
+ }
+ else
+ {
+ v -= u;
+ do
+ v >>= 1;
+ while ( (v & 1) == 0);
+ }
+ }
+ return u << shift;
+}
+
+unsigned long
+mpz_gcd_ui (mpz_t g, const mpz_t u, unsigned long v)
+{
+ mp_size_t un;
+
+ if (v == 0)
+ {
+ if (g)
+ mpz_abs (g, u);
+ }
+ else
+ {
+ un = GMP_ABS (u->_mp_size);
+ if (un != 0)
+ v = mpn_gcd_11 (mpn_div_qr_1 (NULL, u->_mp_d, un, v), v);
+
+ if (g)
+ mpz_set_ui (g, v);
+ }
+
+ return v;
+}
+
+static mp_bitcnt_t
+mpz_make_odd (mpz_t r)
+{
+ mp_bitcnt_t shift;
+
+ assert (r->_mp_size > 0);
+ /* Count trailing zeros, equivalent to mpn_scan1, because we know that there is a 1 */
+ shift = mpn_common_scan (r->_mp_d[0], 0, r->_mp_d, 0, 0);
+ mpz_tdiv_q_2exp (r, r, shift);
+
+ return shift;
+}
+
+void
+mpz_gcd (mpz_t g, const mpz_t u, const mpz_t v)
+{
+ mpz_t tu, tv;
+ mp_bitcnt_t uz, vz, gz;
+
+ if (u->_mp_size == 0)
+ {
+ mpz_abs (g, v);
+ return;
+ }
+ if (v->_mp_size == 0)
+ {
+ mpz_abs (g, u);
+ return;
+ }
+
+ mpz_init (tu);
+ mpz_init (tv);
+
+ mpz_abs (tu, u);
+ uz = mpz_make_odd (tu);
+ mpz_abs (tv, v);
+ vz = mpz_make_odd (tv);
+ gz = GMP_MIN (uz, vz);
+
+ if (tu->_mp_size < tv->_mp_size)
+ mpz_swap (tu, tv);
+
+ mpz_tdiv_r (tu, tu, tv);
+ if (tu->_mp_size == 0)
+ {
+ mpz_swap (g, tv);
+ }
+ else
+ for (;;)
+ {
+ int c;
+
+ mpz_make_odd (tu);
+ c = mpz_cmp (tu, tv);
+ if (c == 0)
+ {
+ mpz_swap (g, tu);
+ break;
+ }
+ if (c < 0)
+ mpz_swap (tu, tv);
+
+ if (tv->_mp_size == 1)
+ {
+ mp_limb_t vl = tv->_mp_d[0];
+ mp_limb_t ul = mpz_tdiv_ui (tu, vl);
+ mpz_set_ui (g, mpn_gcd_11 (ul, vl));
+ break;
+ }
+ mpz_sub (tu, tu, tv);
+ }
+ mpz_clear (tu);
+ mpz_clear (tv);
+ mpz_mul_2exp (g, g, gz);
+}
+
+void
+mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, const mpz_t u, const mpz_t v)
+{
+ mpz_t tu, tv, s0, s1, t0, t1;
+ mp_bitcnt_t uz, vz, gz;
+ mp_bitcnt_t power;
+
+ if (u->_mp_size == 0)
+ {
+ /* g = 0 u + sgn(v) v */
+ signed long sign = mpz_sgn (v);
+ mpz_abs (g, v);
+ if (s)
+ mpz_set_ui (s, 0);
+ if (t)
+ mpz_set_si (t, sign);
+ return;
+ }
+
+ if (v->_mp_size == 0)
+ {
+ /* g = sgn(u) u + 0 v */
+ signed long sign = mpz_sgn (u);
+ mpz_abs (g, u);
+ if (s)
+ mpz_set_si (s, sign);
+ if (t)
+ mpz_set_ui (t, 0);
+ return;
+ }
+
+ mpz_init (tu);
+ mpz_init (tv);
+ mpz_init (s0);
+ mpz_init (s1);
+ mpz_init (t0);
+ mpz_init (t1);
+
+ mpz_abs (tu, u);
+ uz = mpz_make_odd (tu);
+ mpz_abs (tv, v);
+ vz = mpz_make_odd (tv);
+ gz = GMP_MIN (uz, vz);
+
+ uz -= gz;
+ vz -= gz;
+
+ /* Cofactors corresponding to odd gcd. gz handled later. */
+ if (tu->_mp_size < tv->_mp_size)
+ {
+ mpz_swap (tu, tv);
+ MPZ_SRCPTR_SWAP (u, v);
+ MPZ_PTR_SWAP (s, t);
+ MP_BITCNT_T_SWAP (uz, vz);
+ }
+
+ /* Maintain
+ *
+ * u = t0 tu + t1 tv
+ * v = s0 tu + s1 tv
+ *
+ * where u and v denote the inputs with common factors of two
+ * eliminated, and det (s0, t0; s1, t1) = 2^p. Then
+ *
+ * 2^p tu = s1 u - t1 v
+ * 2^p tv = -s0 u + t0 v
+ */
+
+ /* After initial division, tu = q tv + tu', we have
+ *
+ * u = 2^uz (tu' + q tv)
+ * v = 2^vz tv
+ *
+ * or
+ *
+ * t0 = 2^uz, t1 = 2^uz q
+ * s0 = 0, s1 = 2^vz
+ */
+
+ mpz_setbit (t0, uz);
+ mpz_tdiv_qr (t1, tu, tu, tv);
+ mpz_mul_2exp (t1, t1, uz);
+
+ mpz_setbit (s1, vz);
+ power = uz + vz;
+
+ if (tu->_mp_size > 0)
+ {
+ mp_bitcnt_t shift;
+ shift = mpz_make_odd (tu);
+ mpz_mul_2exp (t0, t0, shift);
+ mpz_mul_2exp (s0, s0, shift);
+ power += shift;
+
+ for (;;)
+ {
+ int c;
+ c = mpz_cmp (tu, tv);
+ if (c == 0)
+ break;
+
+ if (c < 0)
+ {
+ /* tv = tv' + tu
+ *
+ * u = t0 tu + t1 (tv' + tu) = (t0 + t1) tu + t1 tv'
+ * v = s0 tu + s1 (tv' + tu) = (s0 + s1) tu + s1 tv' */
+
+ mpz_sub (tv, tv, tu);
+ mpz_add (t0, t0, t1);
+ mpz_add (s0, s0, s1);
+
+ shift = mpz_make_odd (tv);
+ mpz_mul_2exp (t1, t1, shift);
+ mpz_mul_2exp (s1, s1, shift);
+ }
+ else
+ {
+ mpz_sub (tu, tu, tv);
+ mpz_add (t1, t0, t1);
+ mpz_add (s1, s0, s1);
+
+ shift = mpz_make_odd (tu);
+ mpz_mul_2exp (t0, t0, shift);
+ mpz_mul_2exp (s0, s0, shift);
+ }
+ power += shift;
+ }
+ }
+
+ /* Now tv = odd part of gcd, and -s0 and t0 are corresponding
+ cofactors. */
+
+ mpz_mul_2exp (tv, tv, gz);
+ mpz_neg (s0, s0);
+
+ /* 2^p g = s0 u + t0 v. Eliminate one factor of two at a time. To
+ adjust cofactors, we need u / g and v / g */
+
+ mpz_divexact (s1, v, tv);
+ mpz_abs (s1, s1);
+ mpz_divexact (t1, u, tv);
+ mpz_abs (t1, t1);
+
+ while (power-- > 0)
+ {
+ /* s0 u + t0 v = (s0 - v/g) u - (t0 + u/g) v */
+ if (mpz_odd_p (s0) || mpz_odd_p (t0))
+ {
+ mpz_sub (s0, s0, s1);
+ mpz_add (t0, t0, t1);
+ }
+ mpz_divexact_ui (s0, s0, 2);
+ mpz_divexact_ui (t0, t0, 2);
+ }
+
+ /* Arrange so that |s| < |u| / 2g */
+ mpz_add (s1, s0, s1);
+ if (mpz_cmpabs (s0, s1) > 0)
+ {
+ mpz_swap (s0, s1);
+ mpz_sub (t0, t0, t1);
+ }
+ if (u->_mp_size < 0)
+ mpz_neg (s0, s0);
+ if (v->_mp_size < 0)
+ mpz_neg (t0, t0);
+
+ mpz_swap (g, tv);
+ if (s)
+ mpz_swap (s, s0);
+ if (t)
+ mpz_swap (t, t0);
+
+ mpz_clear (tu);
+ mpz_clear (tv);
+ mpz_clear (s0);
+ mpz_clear (s1);
+ mpz_clear (t0);
+ mpz_clear (t1);
+}
+
+void
+mpz_lcm (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mpz_t g;
+
+ if (u->_mp_size == 0 || v->_mp_size == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ mpz_init (g);
+
+ mpz_gcd (g, u, v);
+ mpz_divexact (g, u, g);
+ mpz_mul (r, g, v);
+
+ mpz_clear (g);
+ mpz_abs (r, r);
+}
+
+void
+mpz_lcm_ui (mpz_t r, const mpz_t u, unsigned long v)
+{
+ if (v == 0 || u->_mp_size == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ v /= mpz_gcd_ui (NULL, u, v);
+ mpz_mul_ui (r, u, v);
+
+ mpz_abs (r, r);
+}
+
+int
+mpz_invert (mpz_t r, const mpz_t u, const mpz_t m)
+{
+ mpz_t g, tr;
+ int invertible;
+
+ if (u->_mp_size == 0 || mpz_cmpabs_ui (m, 1) <= 0)
+ return 0;
+
+ mpz_init (g);
+ mpz_init (tr);
+
+ mpz_gcdext (g, tr, NULL, u, m);
+ invertible = (mpz_cmp_ui (g, 1) == 0);
+
+ if (invertible)
+ {
+ if (tr->_mp_size < 0)
+ {
+ if (m->_mp_size >= 0)
+ mpz_add (tr, tr, m);
+ else
+ mpz_sub (tr, tr, m);
+ }
+ mpz_swap (r, tr);
+ }
+
+ mpz_clear (g);
+ mpz_clear (tr);
+ return invertible;
+}
+
+
+/* Higher level operations (sqrt, pow and root) */
+
+void
+mpz_pow_ui (mpz_t r, const mpz_t b, unsigned long e)
+{
+ unsigned long bit;
+ mpz_t tr;
+ mpz_init_set_ui (tr, 1);
+
+ bit = GMP_ULONG_HIGHBIT;
+ do
+ {
+ mpz_mul (tr, tr, tr);
+ if (e & bit)
+ mpz_mul (tr, tr, b);
+ bit >>= 1;
+ }
+ while (bit > 0);
+
+ mpz_swap (r, tr);
+ mpz_clear (tr);
+}
+
+void
+mpz_ui_pow_ui (mpz_t r, unsigned long blimb, unsigned long e)
+{
+ mpz_t b;
+ mpz_pow_ui (r, mpz_roinit_n (b, &blimb, 1), e);
+}
+
+void
+mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
+{
+ mpz_t tr;
+ mpz_t base;
+ mp_size_t en, mn;
+ mp_srcptr mp;
+ struct gmp_div_inverse minv;
+ unsigned shift;
+ mp_ptr tp = NULL;
+
+ en = GMP_ABS (e->_mp_size);
+ mn = GMP_ABS (m->_mp_size);
+ if (mn == 0)
+ gmp_die ("mpz_powm: Zero modulo.");
+
+ if (en == 0)
+ {
+ mpz_set_ui (r, 1);
+ return;
+ }
+
+ mp = m->_mp_d;
+ mpn_div_qr_invert (&minv, mp, mn);
+ shift = minv.shift;
+
+ if (shift > 0)
+ {
+ /* To avoid shifts, we do all our reductions, except the final
+ one, using a *normalized* m. */
+ minv.shift = 0;
+
+ tp = gmp_xalloc_limbs (mn);
+ gmp_assert_nocarry (mpn_lshift (tp, mp, mn, shift));
+ mp = tp;
+ }
+
+ mpz_init (base);
+
+ if (e->_mp_size < 0)
+ {
+ if (!mpz_invert (base, b, m))
+ gmp_die ("mpz_powm: Negative exponent and non-invertible base.");
+ }
+ else
+ {
+ mp_size_t bn;
+ mpz_abs (base, b);
+
+ bn = base->_mp_size;
+ if (bn >= mn)
+ {
+ mpn_div_qr_preinv (NULL, base->_mp_d, base->_mp_size, mp, mn, &minv);
+ bn = mn;
+ }
+
+ /* We have reduced the absolute value. Now take care of the
+ sign. Note that we get zero represented non-canonically as
+ m. */
+ if (b->_mp_size < 0)
+ {
+ mp_ptr bp = MPZ_REALLOC (base, mn);
+ gmp_assert_nocarry (mpn_sub (bp, mp, mn, bp, bn));
+ bn = mn;
+ }
+ base->_mp_size = mpn_normalized_size (base->_mp_d, bn);
+ }
+ mpz_init_set_ui (tr, 1);
+
+ while (--en >= 0)
+ {
+ mp_limb_t w = e->_mp_d[en];
+ mp_limb_t bit;
+
+ bit = GMP_LIMB_HIGHBIT;
+ do
+ {
+ mpz_mul (tr, tr, tr);
+ if (w & bit)
+ mpz_mul (tr, tr, base);
+ if (tr->_mp_size > mn)
+ {
+ mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+ tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+ }
+ bit >>= 1;
+ }
+ while (bit > 0);
+ }
+
+ /* Final reduction */
+ if (tr->_mp_size >= mn)
+ {
+ minv.shift = shift;
+ mpn_div_qr_preinv (NULL, tr->_mp_d, tr->_mp_size, mp, mn, &minv);
+ tr->_mp_size = mpn_normalized_size (tr->_mp_d, mn);
+ }
+ if (tp)
+ gmp_free (tp);
+
+ mpz_swap (r, tr);
+ mpz_clear (tr);
+ mpz_clear (base);
+}
+
+void
+mpz_powm_ui (mpz_t r, const mpz_t b, unsigned long elimb, const mpz_t m)
+{
+ mpz_t e;
+ mpz_powm (r, b, mpz_roinit_n (e, &elimb, 1), m);
+}
+
+/* x=trunc(y^(1/z)), r=y-x^z */
+void
+mpz_rootrem (mpz_t x, mpz_t r, const mpz_t y, unsigned long z)
+{
+ int sgn;
+ mpz_t t, u;
+
+ sgn = y->_mp_size < 0;
+ if ((~z & sgn) != 0)
+ gmp_die ("mpz_rootrem: Negative argument, with even root.");
+ if (z == 0)
+ gmp_die ("mpz_rootrem: Zeroth root.");
+
+ if (mpz_cmpabs_ui (y, 1) <= 0) {
+ if (x)
+ mpz_set (x, y);
+ if (r)
+ r->_mp_size = 0;
+ return;
+ }
+
+ mpz_init (u);
+ mpz_init (t);
+ mpz_setbit (t, mpz_sizeinbase (y, 2) / z + 1);
+
+ if (z == 2) /* simplify sqrt loop: z-1 == 1 */
+ do {
+ mpz_swap (u, t); /* u = x */
+ mpz_tdiv_q (t, y, u); /* t = y/x */
+ mpz_add (t, t, u); /* t = y/x + x */
+ mpz_tdiv_q_2exp (t, t, 1); /* x'= (y/x + x)/2 */
+ } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
+ else /* z != 2 */ {
+ mpz_t v;
+
+ mpz_init (v);
+ if (sgn)
+ mpz_neg (t, t);
+
+ do {
+ mpz_swap (u, t); /* u = x */
+ mpz_pow_ui (t, u, z - 1); /* t = x^(z-1) */
+ mpz_tdiv_q (t, y, t); /* t = y/x^(z-1) */
+ mpz_mul_ui (v, u, z - 1); /* v = x*(z-1) */
+ mpz_add (t, t, v); /* t = y/x^(z-1) + x*(z-1) */
+ mpz_tdiv_q_ui (t, t, z); /* x'=(y/x^(z-1) + x*(z-1))/z */
+ } while (mpz_cmpabs (t, u) < 0); /* |x'| < |x| */
+
+ mpz_clear (v);
+ }
+
+ if (r) {
+ mpz_pow_ui (t, u, z);
+ mpz_sub (r, y, t);
+ }
+ if (x)
+ mpz_swap (x, u);
+ mpz_clear (u);
+ mpz_clear (t);
+}
+
+int
+mpz_root (mpz_t x, const mpz_t y, unsigned long z)
+{
+ int res;
+ mpz_t r;
+
+ mpz_init (r);
+ mpz_rootrem (x, r, y, z);
+ res = r->_mp_size == 0;
+ mpz_clear (r);
+
+ return res;
+}
+
+/* Compute s = floor(sqrt(u)) and r = u - s^2. Allows r == NULL */
+void
+mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
+{
+ mpz_rootrem (s, r, u, 2);
+}
+
+void
+mpz_sqrt (mpz_t s, const mpz_t u)
+{
+ mpz_rootrem (s, NULL, u, 2);
+}
+
+int
+mpz_perfect_square_p (const mpz_t u)
+{
+ if (u->_mp_size <= 0)
+ return (u->_mp_size == 0);
+ else
+ return mpz_root (NULL, u, 2);
+}
+
+int
+mpn_perfect_square_p (mp_srcptr p, mp_size_t n)
+{
+ mpz_t t;
+
+ assert (n > 0);
+ assert (p [n-1] != 0);
+ return mpz_root (NULL, mpz_roinit_n (t, p, n), 2);
+}
+
+mp_size_t
+mpn_sqrtrem (mp_ptr sp, mp_ptr rp, mp_srcptr p, mp_size_t n)
+{
+ mpz_t s, r, u;
+ mp_size_t res;
+
+ assert (n > 0);
+ assert (p [n-1] != 0);
+
+ mpz_init (r);
+ mpz_init (s);
+ mpz_rootrem (s, r, mpz_roinit_n (u, p, n), 2);
+
+ assert (s->_mp_size == (n+1)/2);
+ mpn_copyd (sp, s->_mp_d, s->_mp_size);
+ mpz_clear (s);
+ res = r->_mp_size;
+ if (rp)
+ mpn_copyd (rp, r->_mp_d, res);
+ mpz_clear (r);
+ return res;
+}
+
+/* Combinatorics */
+
+void
+mpz_fac_ui (mpz_t x, unsigned long n)
+{
+ mpz_set_ui (x, n + (n == 0));
+ while (n > 2)
+ mpz_mul_ui (x, x, --n);
+}
+
+void
+mpz_bin_uiui (mpz_t r, unsigned long n, unsigned long k)
+{
+ mpz_t t;
+
+ mpz_set_ui (r, k <= n);
+
+ if (k > (n >> 1))
+ k = (k <= n) ? n - k : 0;
+
+ mpz_init (t);
+ mpz_fac_ui (t, k);
+
+ for (; k > 0; k--)
+ mpz_mul_ui (r, r, n--);
+
+ mpz_divexact (r, r, t);
+ mpz_clear (t);
+}
+
+
+/* Primality testing */
+static int
+gmp_millerrabin (const mpz_t n, const mpz_t nm1, mpz_t y,
+ const mpz_t q, mp_bitcnt_t k)
+{
+ assert (k > 0);
+
+ /* Caller must initialize y to the base. */
+ mpz_powm (y, y, q, n);
+
+ if (mpz_cmp_ui (y, 1) == 0 || mpz_cmp (y, nm1) == 0)
+ return 1;
+
+ while (--k > 0)
+ {
+ mpz_powm_ui (y, y, 2, n);
+ if (mpz_cmp (y, nm1) == 0)
+ return 1;
+ /* y == 1 means that the previous y was a non-trivial square root
+ of 1 (mod n). y == 0 means that n is a power of the base.
+ In either case, n is not prime. */
+ if (mpz_cmp_ui (y, 1) <= 0)
+ return 0;
+ }
+ return 0;
+}
+
+/* This product is 0xc0cfd797, and fits in 32 bits. */
+#define GMP_PRIME_PRODUCT \
+ (3UL*5UL*7UL*11UL*13UL*17UL*19UL*23UL*29UL)
+
+/* Bit (p+1)/2 is set, for each odd prime <= 61 */
+#define GMP_PRIME_MASK 0xc96996dcUL
+
+int
+mpz_probab_prime_p (const mpz_t n, int reps)
+{
+ mpz_t nm1;
+ mpz_t q;
+ mpz_t y;
+ mp_bitcnt_t k;
+ int is_prime;
+ int j;
+
+ /* Note that we use the absolute value of n only, for compatibility
+ with the real GMP. */
+ if (mpz_even_p (n))
+ return (mpz_cmpabs_ui (n, 2) == 0) ? 2 : 0;
+
+ /* Above test excludes n == 0 */
+ assert (n->_mp_size != 0);
+
+ if (mpz_cmpabs_ui (n, 64) < 0)
+ return (GMP_PRIME_MASK >> (n->_mp_d[0] >> 1)) & 2;
+
+ if (mpz_gcd_ui (NULL, n, GMP_PRIME_PRODUCT) != 1)
+ return 0;
+
+ /* All prime factors are >= 31. */
+ if (mpz_cmpabs_ui (n, 31*31) < 0)
+ return 2;
+
+ /* Use Miller-Rabin, with a deterministic sequence of bases, a[j] =
+ j^2 + j + 41 using Euler's polynomial. We potentially stop early,
+ if a[j] >= n - 1. Since n >= 31*31, this can happen only if reps >
+ 30 (a[30] == 971 > 31*31 == 961). */
+
+ mpz_init (nm1);
+ mpz_init (q);
+ mpz_init (y);
+
+ /* Find q and k, where q is odd and n = 1 + 2**k * q. */
+ nm1->_mp_size = mpz_abs_sub_ui (nm1, n, 1);
+ k = mpz_scan1 (nm1, 0);
+ mpz_tdiv_q_2exp (q, nm1, k);
+
+ for (j = 0, is_prime = 1; is_prime & (j < reps); j++)
+ {
+ mpz_set_ui (y, (unsigned long) j*j+j+41);
+ if (mpz_cmp (y, nm1) >= 0)
+ {
+ /* Don't try any further bases. This "early" break does not affect
+ the result for any reasonable reps value (<=5000 was tested) */
+ assert (j >= 30);
+ break;
+ }
+ is_prime = gmp_millerrabin (n, nm1, y, q, k);
+ }
+ mpz_clear (nm1);
+ mpz_clear (q);
+ mpz_clear (y);
+
+ return is_prime;
+}
+
+
+/* Logical operations and bit manipulation. */
+
+/* Numbers are treated as if represented in two's complement (and
+ infinitely sign extended). For a negative values we get the two's
+ complement from -x = ~x + 1, where ~ is bitwise complement.
+ Negation transforms
+
+ xxxx10...0
+
+ into
+
+ yyyy10...0
+
+ where yyyy is the bitwise complement of xxxx. So least significant
+ bits, up to and including the first one bit, are unchanged, and
+ the more significant bits are all complemented.
+
+ To change a bit from zero to one in a negative number, subtract the
+ corresponding power of two from the absolute value. This can never
+ underflow. To change a bit from one to zero, add the corresponding
+ power of two, and this might overflow. E.g., if x = -001111, the
+ two's complement is 110001. Clearing the least significant bit, we
+ get two's complement 110000, and -010000. */
+
+int
+mpz_tstbit (const mpz_t d, mp_bitcnt_t bit_index)
+{
+ mp_size_t limb_index;
+ unsigned shift;
+ mp_size_t ds;
+ mp_size_t dn;
+ mp_limb_t w;
+ int bit;
+
+ ds = d->_mp_size;
+ dn = GMP_ABS (ds);
+ limb_index = bit_index / GMP_LIMB_BITS;
+ if (limb_index >= dn)
+ return ds < 0;
+
+ shift = bit_index % GMP_LIMB_BITS;
+ w = d->_mp_d[limb_index];
+ bit = (w >> shift) & 1;
+
+ if (ds < 0)
+ {
+ /* d < 0. Check if any of the bits below is set: If so, our bit
+ must be complemented. */
+ if (shift > 0 && (w << (GMP_LIMB_BITS - shift)) > 0)
+ return bit ^ 1;
+ while (--limb_index >= 0)
+ if (d->_mp_d[limb_index] > 0)
+ return bit ^ 1;
+ }
+ return bit;
+}
+
+static void
+mpz_abs_add_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ mp_size_t dn, limb_index;
+ mp_limb_t bit;
+ mp_ptr dp;
+
+ dn = GMP_ABS (d->_mp_size);
+
+ limb_index = bit_index / GMP_LIMB_BITS;
+ bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+ if (limb_index >= dn)
+ {
+ mp_size_t i;
+ /* The bit should be set outside of the end of the number.
+ We have to increase the size of the number. */
+ dp = MPZ_REALLOC (d, limb_index + 1);
+
+ dp[limb_index] = bit;
+ for (i = dn; i < limb_index; i++)
+ dp[i] = 0;
+ dn = limb_index + 1;
+ }
+ else
+ {
+ mp_limb_t cy;
+
+ dp = d->_mp_d;
+
+ cy = mpn_add_1 (dp + limb_index, dp + limb_index, dn - limb_index, bit);
+ if (cy > 0)
+ {
+ dp = MPZ_REALLOC (d, dn + 1);
+ dp[dn++] = cy;
+ }
+ }
+
+ d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+static void
+mpz_abs_sub_bit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ mp_size_t dn, limb_index;
+ mp_ptr dp;
+ mp_limb_t bit;
+
+ dn = GMP_ABS (d->_mp_size);
+ dp = d->_mp_d;
+
+ limb_index = bit_index / GMP_LIMB_BITS;
+ bit = (mp_limb_t) 1 << (bit_index % GMP_LIMB_BITS);
+
+ assert (limb_index < dn);
+
+ gmp_assert_nocarry (mpn_sub_1 (dp + limb_index, dp + limb_index,
+ dn - limb_index, bit));
+ dn = mpn_normalized_size (dp, dn);
+ d->_mp_size = (d->_mp_size < 0) ? - dn : dn;
+}
+
+void
+mpz_setbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ if (!mpz_tstbit (d, bit_index))
+ {
+ if (d->_mp_size >= 0)
+ mpz_abs_add_bit (d, bit_index);
+ else
+ mpz_abs_sub_bit (d, bit_index);
+ }
+}
+
+void
+mpz_clrbit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ if (mpz_tstbit (d, bit_index))
+ {
+ if (d->_mp_size >= 0)
+ mpz_abs_sub_bit (d, bit_index);
+ else
+ mpz_abs_add_bit (d, bit_index);
+ }
+}
+
+void
+mpz_combit (mpz_t d, mp_bitcnt_t bit_index)
+{
+ if (mpz_tstbit (d, bit_index) ^ (d->_mp_size < 0))
+ mpz_abs_sub_bit (d, bit_index);
+ else
+ mpz_abs_add_bit (d, bit_index);
+}
+
+void
+mpz_com (mpz_t r, const mpz_t u)
+{
+ mpz_neg (r, u);
+ mpz_sub_ui (r, r, 1);
+}
+
+void
+mpz_and (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, rn, i;
+ mp_ptr up, vp, rp;
+
+ mp_limb_t ux, vx, rx;
+ mp_limb_t uc, vc, rc;
+ mp_limb_t ul, vl, rl;
+
+ un = GMP_ABS (u->_mp_size);
+ vn = GMP_ABS (v->_mp_size);
+ if (un < vn)
+ {
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (un, vn);
+ }
+ if (vn == 0)
+ {
+ r->_mp_size = 0;
+ return;
+ }
+
+ uc = u->_mp_size < 0;
+ vc = v->_mp_size < 0;
+ rc = uc & vc;
+
+ ux = -uc;
+ vx = -vc;
+ rx = -rc;
+
+ /* If the smaller input is positive, higher limbs don't matter. */
+ rn = vx ? un : vn;
+
+ rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ i = 0;
+ do
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ vx) + vc;
+ vc = vl < vc;
+
+ rl = ( (ul & vl) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ while (++i < vn);
+ assert (vc == 0);
+
+ for (; i < rn; i++)
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ rl = ( (ul & vx) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ if (rc)
+ rp[rn++] = rc;
+ else
+ rn = mpn_normalized_size (rp, rn);
+
+ r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_ior (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, rn, i;
+ mp_ptr up, vp, rp;
+
+ mp_limb_t ux, vx, rx;
+ mp_limb_t uc, vc, rc;
+ mp_limb_t ul, vl, rl;
+
+ un = GMP_ABS (u->_mp_size);
+ vn = GMP_ABS (v->_mp_size);
+ if (un < vn)
+ {
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (un, vn);
+ }
+ if (vn == 0)
+ {
+ mpz_set (r, u);
+ return;
+ }
+
+ uc = u->_mp_size < 0;
+ vc = v->_mp_size < 0;
+ rc = uc | vc;
+
+ ux = -uc;
+ vx = -vc;
+ rx = -rc;
+
+ /* If the smaller input is negative, by sign extension higher limbs
+ don't matter. */
+ rn = vx ? vn : un;
+
+ rp = MPZ_REALLOC (r, rn + (mp_size_t) rc);
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ i = 0;
+ do
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ vx) + vc;
+ vc = vl < vc;
+
+ rl = ( (ul | vl) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ while (++i < vn);
+ assert (vc == 0);
+
+ for (; i < rn; i++)
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ rl = ( (ul | vx) ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ if (rc)
+ rp[rn++] = rc;
+ else
+ rn = mpn_normalized_size (rp, rn);
+
+ r->_mp_size = rx ? -rn : rn;
+}
+
+void
+mpz_xor (mpz_t r, const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, i;
+ mp_ptr up, vp, rp;
+
+ mp_limb_t ux, vx, rx;
+ mp_limb_t uc, vc, rc;
+ mp_limb_t ul, vl, rl;
+
+ un = GMP_ABS (u->_mp_size);
+ vn = GMP_ABS (v->_mp_size);
+ if (un < vn)
+ {
+ MPZ_SRCPTR_SWAP (u, v);
+ MP_SIZE_T_SWAP (un, vn);
+ }
+ if (vn == 0)
+ {
+ mpz_set (r, u);
+ return;
+ }
+
+ uc = u->_mp_size < 0;
+ vc = v->_mp_size < 0;
+ rc = uc ^ vc;
+
+ ux = -uc;
+ vx = -vc;
+ rx = -rc;
+
+ rp = MPZ_REALLOC (r, un + (mp_size_t) rc);
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ i = 0;
+ do
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ vx) + vc;
+ vc = vl < vc;
+
+ rl = (ul ^ vl ^ rx) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ while (++i < vn);
+ assert (vc == 0);
+
+ for (; i < un; i++)
+ {
+ ul = (up[i] ^ ux) + uc;
+ uc = ul < uc;
+
+ rl = (ul ^ ux) + rc;
+ rc = rl < rc;
+ rp[i] = rl;
+ }
+ if (rc)
+ rp[un++] = rc;
+ else
+ un = mpn_normalized_size (rp, un);
+
+ r->_mp_size = rx ? -un : un;
+}
+
+static unsigned
+gmp_popcount_limb (mp_limb_t x)
+{
+ unsigned c;
+
+ /* Do 16 bits at a time, to avoid limb-sized constants. */
+ for (c = 0; x > 0; x >>= 16)
+ {
+ unsigned w = ((x >> 1) & 0x5555) + (x & 0x5555);
+ w = ((w >> 2) & 0x3333) + (w & 0x3333);
+ w = ((w >> 4) & 0x0f0f) + (w & 0x0f0f);
+ w = (w >> 8) + (w & 0x00ff);
+ c += w;
+ }
+ return c;
+}
+
+mp_bitcnt_t
+mpn_popcount (mp_srcptr p, mp_size_t n)
+{
+ mp_size_t i;
+ mp_bitcnt_t c;
+
+ for (c = 0, i = 0; i < n; i++)
+ c += gmp_popcount_limb (p[i]);
+
+ return c;
+}
+
+mp_bitcnt_t
+mpz_popcount (const mpz_t u)
+{
+ mp_size_t un;
+
+ un = u->_mp_size;
+
+ if (un < 0)
+ return ~(mp_bitcnt_t) 0;
+
+ return mpn_popcount (u->_mp_d, un);
+}
+
+mp_bitcnt_t
+mpz_hamdist (const mpz_t u, const mpz_t v)
+{
+ mp_size_t un, vn, i;
+ mp_limb_t uc, vc, ul, vl, comp;
+ mp_srcptr up, vp;
+ mp_bitcnt_t c;
+
+ un = u->_mp_size;
+ vn = v->_mp_size;
+
+ if ( (un ^ vn) < 0)
+ return ~(mp_bitcnt_t) 0;
+
+ comp = - (uc = vc = (un < 0));
+ if (uc)
+ {
+ assert (vn < 0);
+ un = -un;
+ vn = -vn;
+ }
+
+ up = u->_mp_d;
+ vp = v->_mp_d;
+
+ if (un < vn)
+ MPN_SRCPTR_SWAP (up, un, vp, vn);
+
+ for (i = 0, c = 0; i < vn; i++)
+ {
+ ul = (up[i] ^ comp) + uc;
+ uc = ul < uc;
+
+ vl = (vp[i] ^ comp) + vc;
+ vc = vl < vc;
+
+ c += gmp_popcount_limb (ul ^ vl);
+ }
+ assert (vc == 0);
+
+ for (; i < un; i++)
+ {
+ ul = (up[i] ^ comp) + uc;
+ uc = ul < uc;
+
+ c += gmp_popcount_limb (ul ^ comp);
+ }
+
+ return c;
+}
+
+mp_bitcnt_t
+mpz_scan1 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+ mp_ptr up;
+ mp_size_t us, un, i;
+ mp_limb_t limb, ux;
+
+ us = u->_mp_size;
+ un = GMP_ABS (us);
+ i = starting_bit / GMP_LIMB_BITS;
+
+ /* Past the end there's no 1 bits for u>=0, or an immediate 1 bit
+ for u<0. Notice this test picks up any u==0 too. */
+ if (i >= un)
+ return (us >= 0 ? ~(mp_bitcnt_t) 0 : starting_bit);
+
+ up = u->_mp_d;
+ ux = 0;
+ limb = up[i];
+
+ if (starting_bit != 0)
+ {
+ if (us < 0)
+ {
+ ux = mpn_zero_p (up, i);
+ limb = ~ limb + ux;
+ ux = - (mp_limb_t) (limb >= ux);
+ }
+
+ /* Mask to 0 all bits before starting_bit, thus ignoring them. */
+ limb &= (GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS));
+ }
+
+ return mpn_common_scan (limb, i, up, un, ux);
+}
+
+mp_bitcnt_t
+mpz_scan0 (const mpz_t u, mp_bitcnt_t starting_bit)
+{
+ mp_ptr up;
+ mp_size_t us, un, i;
+ mp_limb_t limb, ux;
+
+ us = u->_mp_size;
+ ux = - (mp_limb_t) (us >= 0);
+ un = GMP_ABS (us);
+ i = starting_bit / GMP_LIMB_BITS;
+
+ /* When past end, there's an immediate 0 bit for u>=0, or no 0 bits for
+ u<0. Notice this test picks up all cases of u==0 too. */
+ if (i >= un)
+ return (ux ? starting_bit : ~(mp_bitcnt_t) 0);
+
+ up = u->_mp_d;
+ limb = up[i] ^ ux;
+
+ if (ux == 0)
+ limb -= mpn_zero_p (up, i); /* limb = ~(~limb + zero_p) */
+
+ /* Mask all bits before starting_bit, thus ignoring them. */
+ limb &= (GMP_LIMB_MAX << (starting_bit % GMP_LIMB_BITS));
+
+ return mpn_common_scan (limb, i, up, un, ux);
+}
+
+
+/* MPZ base conversion. */
+
+size_t
+mpz_sizeinbase (const mpz_t u, int base)
+{
+ mp_size_t un;
+ mp_srcptr up;
+ mp_ptr tp;
+ mp_bitcnt_t bits;
+ struct gmp_div_inverse bi;
+ size_t ndigits;
+
+ assert (base >= 2);
+ assert (base <= 36);
+
+ un = GMP_ABS (u->_mp_size);
+ if (un == 0)
+ return 1;
+
+ up = u->_mp_d;
+
+ bits = (un - 1) * GMP_LIMB_BITS + mpn_limb_size_in_base_2 (up[un-1]);
+ switch (base)
+ {
+ case 2:
+ return bits;
+ case 4:
+ return (bits + 1) / 2;
+ case 8:
+ return (bits + 2) / 3;
+ case 16:
+ return (bits + 3) / 4;
+ case 32:
+ return (bits + 4) / 5;
+ /* FIXME: Do something more clever for the common case of base
+ 10. */
+ }
+
+ tp = gmp_xalloc_limbs (un);
+ mpn_copyi (tp, up, un);
+ mpn_div_qr_1_invert (&bi, base);
+
+ ndigits = 0;
+ do
+ {
+ ndigits++;
+ mpn_div_qr_1_preinv (tp, tp, un, &bi);
+ un -= (tp[un-1] == 0);
+ }
+ while (un > 0);
+
+ gmp_free (tp);
+ return ndigits;
+}
+
+char *
+mpz_get_str (char *sp, int base, const mpz_t u)
+{
+ unsigned bits;
+ const char *digits;
+ mp_size_t un;
+ size_t i, sn;
+
+ if (base >= 0)
+ {
+ digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+ }
+ else
+ {
+ base = -base;
+ digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ }
+ if (base <= 1)
+ base = 10;
+ if (base > 36)
+ return NULL;
+
+ sn = 1 + mpz_sizeinbase (u, base);
+ if (!sp)
+ sp = (char *) gmp_xalloc (1 + sn);
+
+ un = GMP_ABS (u->_mp_size);
+
+ if (un == 0)
+ {
+ sp[0] = '0';
+ sp[1] = '\0';
+ return sp;
+ }
+
+ i = 0;
+
+ if (u->_mp_size < 0)
+ sp[i++] = '-';
+
+ bits = mpn_base_power_of_two_p (base);
+
+ if (bits)
+ /* Not modified in this case. */
+ sn = i + mpn_get_str_bits ((unsigned char *) sp + i, bits, u->_mp_d, un);
+ else
+ {
+ struct mpn_base_info info;
+ mp_ptr tp;
+
+ mpn_get_base_info (&info, base);
+ tp = gmp_xalloc_limbs (un);
+ mpn_copyi (tp, u->_mp_d, un);
+
+ sn = i + mpn_get_str_other ((unsigned char *) sp + i, base, &info, tp, un);
+ gmp_free (tp);
+ }
+
+ for (; i < sn; i++)
+ sp[i] = digits[(unsigned char) sp[i]];
+
+ sp[sn] = '\0';
+ return sp;
+}
+
+int
+mpz_set_str (mpz_t r, const char *sp, int base)
+{
+ unsigned bits;
+ mp_size_t rn, alloc;
+ mp_ptr rp;
+ size_t dn;
+ int sign;
+ unsigned char *dp;
+
+ assert (base == 0 || (base >= 2 && base <= 36));
+
+ while (isspace( (unsigned char) *sp))
+ sp++;
+
+ sign = (*sp == '-');
+ sp += sign;
+
+ if (base == 0)
+ {
+ if (sp[0] == '0')
+ {
+ if (sp[1] == 'x' || sp[1] == 'X')
+ {
+ base = 16;
+ sp += 2;
+ }
+ else if (sp[1] == 'b' || sp[1] == 'B')
+ {
+ base = 2;
+ sp += 2;
+ }
+ else
+ base = 8;
+ }
+ else
+ base = 10;
+ }
+
+ if (!*sp)
+ {
+ r->_mp_size = 0;
+ return -1;
+ }
+ dp = (unsigned char *) gmp_xalloc (strlen (sp));
+
+ for (dn = 0; *sp; sp++)
+ {
+ unsigned digit;
+
+ if (isspace ((unsigned char) *sp))
+ continue;
+ else if (*sp >= '0' && *sp <= '9')
+ digit = *sp - '0';
+ else if (*sp >= 'a' && *sp <= 'z')
+ digit = *sp - 'a' + 10;
+ else if (*sp >= 'A' && *sp <= 'Z')
+ digit = *sp - 'A' + 10;
+ else
+ digit = base; /* fail */
+
+ if (digit >= (unsigned) base)
+ {
+ gmp_free (dp);
+ r->_mp_size = 0;
+ return -1;
+ }
+
+ dp[dn++] = digit;
+ }
+
+ if (!dn)
+ {
+ gmp_free (dp);
+ r->_mp_size = 0;
+ return -1;
+ }
+ bits = mpn_base_power_of_two_p (base);
+
+ if (bits > 0)
+ {
+ alloc = (dn * bits + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS;
+ rp = MPZ_REALLOC (r, alloc);
+ rn = mpn_set_str_bits (rp, dp, dn, bits);
+ }
+ else
+ {
+ struct mpn_base_info info;
+ mpn_get_base_info (&info, base);
+ alloc = (dn + info.exp - 1) / info.exp;
+ rp = MPZ_REALLOC (r, alloc);
+ rn = mpn_set_str_other (rp, dp, dn, base, &info);
+ /* Normalization, needed for all-zero input. */
+ assert (rn > 0);
+ rn -= rp[rn-1] == 0;
+ }
+ assert (rn <= alloc);
+ gmp_free (dp);
+
+ r->_mp_size = sign ? - rn : rn;
+
+ return 0;
+}
+
+int
+mpz_init_set_str (mpz_t r, const char *sp, int base)
+{
+ mpz_init (r);
+ return mpz_set_str (r, sp, base);
+}
+
+size_t
+mpz_out_str (FILE *stream, int base, const mpz_t x)
+{
+ char *str;
+ size_t len;
+
+ str = mpz_get_str (NULL, base, x);
+ len = strlen (str);
+ len = fwrite (str, 1, len, stream);
+ gmp_free (str);
+ return len;
+}
+
+
+static int
+gmp_detect_endian (void)
+{
+ static const int i = 2;
+ const unsigned char *p = (const unsigned char *) &i;
+ return 1 - *p;
+}
+
+/* Import and export. Does not support nails. */
+void
+mpz_import (mpz_t r, size_t count, int order, size_t size, int endian,
+ size_t nails, const void *src)
+{
+ const unsigned char *p;
+ ptrdiff_t word_step;
+ mp_ptr rp;
+ mp_size_t rn;
+
+ /* The current (partial) limb. */
+ mp_limb_t limb;
+ /* The number of bytes already copied to this limb (starting from
+ the low end). */
+ size_t bytes;
+ /* The index where the limb should be stored, when completed. */
+ mp_size_t i;
+
+ if (nails != 0)
+ gmp_die ("mpz_import: Nails not supported.");
+
+ assert (order == 1 || order == -1);
+ assert (endian >= -1 && endian <= 1);
+
+ if (endian == 0)
+ endian = gmp_detect_endian ();
+
+ p = (unsigned char *) src;
+
+ word_step = (order != endian) ? 2 * size : 0;
+
+ /* Process bytes from the least significant end, so point p at the
+ least significant word. */
+ if (order == 1)
+ {
+ p += size * (count - 1);
+ word_step = - word_step;
+ }
+
+ /* And at least significant byte of that word. */
+ if (endian == 1)
+ p += (size - 1);
+
+ rn = (size * count + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t);
+ rp = MPZ_REALLOC (r, rn);
+
+ for (limb = 0, bytes = 0, i = 0; count > 0; count--, p += word_step)
+ {
+ size_t j;
+ for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
+ {
+ limb |= (mp_limb_t) *p << (bytes++ * CHAR_BIT);
+ if (bytes == sizeof(mp_limb_t))
+ {
+ rp[i++] = limb;
+ bytes = 0;
+ limb = 0;
+ }
+ }
+ }
+ assert (i + (bytes > 0) == rn);
+ if (limb != 0)
+ rp[i++] = limb;
+ else
+ i = mpn_normalized_size (rp, i);
+
+ r->_mp_size = i;
+}
+
+void *
+mpz_export (void *r, size_t *countp, int order, size_t size, int endian,
+ size_t nails, const mpz_t u)
+{
+ size_t count;
+ mp_size_t un;
+
+ if (nails != 0)
+ gmp_die ("mpz_import: Nails not supported.");
+
+ assert (order == 1 || order == -1);
+ assert (endian >= -1 && endian <= 1);
+ assert (size > 0 || u->_mp_size == 0);
+
+ un = u->_mp_size;
+ count = 0;
+ if (un != 0)
+ {
+ size_t k;
+ unsigned char *p;
+ ptrdiff_t word_step;
+ /* The current (partial) limb. */
+ mp_limb_t limb;
+ /* The number of bytes left to to in this limb. */
+ size_t bytes;
+ /* The index where the limb was read. */
+ mp_size_t i;
+
+ un = GMP_ABS (un);
+
+ /* Count bytes in top limb. */
+ limb = u->_mp_d[un-1];
+ assert (limb != 0);
+
+ k = 0;
+ do {
+ k++; limb >>= CHAR_BIT;
+ } while (limb != 0);
+
+ count = (k + (un-1) * sizeof (mp_limb_t) + size - 1) / size;
+
+ if (!r)
+ r = gmp_xalloc (count * size);
+
+ if (endian == 0)
+ endian = gmp_detect_endian ();
+
+ p = (unsigned char *) r;
+
+ word_step = (order != endian) ? 2 * size : 0;
+
+ /* Process bytes from the least significant end, so point p at the
+ least significant word. */
+ if (order == 1)
+ {
+ p += size * (count - 1);
+ word_step = - word_step;
+ }
+
+ /* And at least significant byte of that word. */
+ if (endian == 1)
+ p += (size - 1);
+
+ for (bytes = 0, i = 0, k = 0; k < count; k++, p += word_step)
+ {
+ size_t j;
+ for (j = 0; j < size; j++, p -= (ptrdiff_t) endian)
+ {
+ if (bytes == 0)
+ {
+ if (i < un)
+ limb = u->_mp_d[i++];
+ bytes = sizeof (mp_limb_t);
+ }
+ *p = limb;
+ limb >>= CHAR_BIT;
+ bytes--;
+ }
+ }
+ assert (i == un);
+ assert (k == count);
+ }
+
+ if (countp)
+ *countp = count;
+
+ return r;
+}
diff --git a/src/misspell.c b/src/misspell.c
new file mode 100644
index 0000000..c1e58a0
--- /dev/null
+++ b/src/misspell.c
@@ -0,0 +1,114 @@
+/*
+ * 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>
+
+enum string_distance_function {
+ DELETION = 0, /* m1 */
+ INSERTION, /* m2 */
+ TRANSFORMATION, /* m3 */
+};
+#define DISTANCE_MAX (TRANSFORMATION + 1)
+
+static unsigned int min_distance(unsigned int *cost)
+{
+ unsigned int min = UINT_MAX;
+ int k;
+
+ for (k = 0; k < DISTANCE_MAX; k++) {
+ if (cost[k] < min)
+ min = cost[k];
+ }
+
+ return min;
+}
+
+/* A simple implementation of "The string-to-string correction problem (1974)"
+ * by Robert A. Wagner.
+ */
+static unsigned int string_distance(const char *a, const char *b)
+{
+ unsigned int len_a = strlen(a);
+ unsigned int len_b = strlen(b);
+ unsigned int *distance;
+ unsigned int i, j, ret;
+
+ distance = xzalloc((len_a + 1) * (len_b + 1) * sizeof(unsigned int));
+
+#define DISTANCE(__i, __j) distance[(__i) * len_b + (__j)]
+
+ for (i = 0; i <= len_a; i++)
+ DISTANCE(i, 0) = i;
+ for (j = 0; j <= len_b; j++)
+ DISTANCE(0, j) = j;
+
+ for (i = 1; i <= len_a; i++) {
+ for (j = 1; j <= len_b; j++) {
+ unsigned int subcost = (a[i] == b[j]) ? 0 : 1;
+ unsigned int cost[3];
+
+ cost[DELETION] = DISTANCE(i - 1, j) + 1;
+ cost[INSERTION] = DISTANCE(i, j - 1) + 1;
+ cost[TRANSFORMATION] = DISTANCE(i - 1, j - 1) + subcost;
+ DISTANCE(i, j) = min_distance(cost);
+
+ if (i > 1 && j > 1 &&
+ a[i] == b[j - 1] &&
+ a[i - 1] == b[j])
+ DISTANCE(i, j) =
+ min(DISTANCE(i, j),
+ DISTANCE(i - 2, j - 2) + subcost);
+ }
+ }
+
+ ret = DISTANCE(len_a, len_b);
+
+ xfree(distance);
+
+ return ret;
+}
+
+void string_misspell_init(struct string_misspell_state *st)
+{
+ st->obj = NULL;
+ st->min_distance = UINT_MAX;
+}
+
+int string_misspell_update(const char *a, const char *b,
+ void *obj, struct string_misspell_state *st)
+{
+ unsigned int len_a, len_b, max_len, min_len, distance, threshold;
+
+ len_a = strlen(a);
+ len_b = strlen(b);
+
+ max_len = max(len_a, len_b);
+ min_len = min(len_a, len_b);
+
+ if (max_len <= 1)
+ return 0;
+
+ if (max_len - min_len <= 1)
+ threshold = max(div_round_up(max_len, 3), 1);
+ else
+ threshold = div_round_up(max_len + 2, 3);
+
+ distance = string_distance(a, b);
+ if (distance > threshold)
+ return 0;
+ else if (distance < st->min_distance) {
+ st->min_distance = distance;
+ st->obj = obj;
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/mnl.c b/src/mnl.c
new file mode 100644
index 0000000..0fb36bd
--- /dev/null
+++ b/src/mnl.c
@@ -0,0 +1,2669 @@
+/*
+ * 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 (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>
+#include <libnftnl/table.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/set.h>
+#include <libnftnl/object.h>
+#include <libnftnl/flowtable.h>
+#include <libnftnl/batch.h>
+#include <libnftnl/udata.h>
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_hook.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <mnl.h>
+#include <cmd.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <utils.h>
+#include <nftables.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
+
+struct basehook {
+ struct list_head list;
+ const char *module_name;
+ const char *hookfn;
+ const char *table;
+ const char *chain;
+ int family;
+ int chain_family;
+ uint32_t num;
+ int prio;
+};
+
+struct mnl_socket *nft_mnl_socket_open(void)
+{
+ struct mnl_socket *nf_sock;
+ int one = 1;
+
+ nf_sock = mnl_socket_open(NETLINK_NETFILTER);
+ if (!nf_sock)
+ netlink_init_error();
+
+ if (fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK))
+ netlink_init_error();
+
+ mnl_socket_setsockopt(nf_sock, NETLINK_EXT_ACK, &one, sizeof(one));
+
+ return nf_sock;
+}
+
+uint32_t mnl_seqnum_alloc(unsigned int *seqnum)
+{
+ return (*seqnum)++;
+}
+
+/* The largest nf_tables netlink message is the set element message, which
+ * contains the NFTA_SET_ELEM_LIST_ELEMENTS attribute. This attribute is
+ * a nest that describes the set elements. Given that the netlink attribute
+ * length (nla_len) is 16 bits, the largest message is a bit larger than
+ * 64 KBytes.
+ */
+#define NFT_NLMSG_MAXSIZE (UINT16_MAX + getpagesize())
+
+static int
+nft_mnl_recv(struct netlink_ctx *ctx, uint32_t portid,
+ int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
+{
+ char buf[NFT_NLMSG_MAXSIZE];
+ bool eintr = false;
+ int ret;
+
+ ret = mnl_socket_recvfrom(ctx->nft->nf_sock, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, ctx->seqnum, portid, cb, cb_data);
+ if (ret == 0)
+ break;
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ ret = 0;
+ break;
+ }
+ if (errno != EINTR)
+ break;
+
+ /* process all pending messages before reporting EINTR */
+ eintr = true;
+ }
+ ret = mnl_socket_recvfrom(ctx->nft->nf_sock, buf, sizeof(buf));
+ }
+ if (eintr) {
+ ret = -1;
+ errno = EINTR;
+ }
+ return ret;
+}
+
+int
+nft_mnl_talk(struct netlink_ctx *ctx, const void *data, unsigned int len,
+ int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
+{
+ uint32_t portid = mnl_socket_get_portid(ctx->nft->nf_sock);
+
+ if (ctx->nft->debug_mask & NFT_DEBUG_MNL)
+ mnl_nlmsg_fprintf(ctx->nft->output.output_fp, data, len,
+ sizeof(struct nfgenmsg));
+
+ if (mnl_socket_sendto(ctx->nft->nf_sock, data, len) < 0)
+ return -1;
+
+ return nft_mnl_recv(ctx, portid, cb, cb_data);
+}
+
+/*
+ * Rule-set consistency check across several netlink dumps
+ */
+static uint32_t nft_genid;
+
+static int genid_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
+
+ nft_genid = ntohs(nfh->res_id);
+
+ return MNL_CB_OK;
+}
+
+uint32_t mnl_genid_get(struct netlink_ctx *ctx)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETGEN, AF_UNSPEC, 0, ctx->seqnum);
+ /* Skip error checking, old kernels sets res_id field to zero. */
+ nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, genid_cb, NULL);
+
+ return nft_genid;
+}
+
+static uint16_t nft_genid_u16(uint32_t genid)
+{
+ return genid & 0xffff;
+}
+
+static int check_genid(const struct nlmsghdr *nlh)
+{
+ struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
+
+ if (nft_genid_u16(nft_genid) != ntohs(nfh->res_id)) {
+ errno = EINTR;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Batching
+ */
+
+/* Selected batch page is 2 Mbytes long to support loading a ruleset of 3.5M
+ * rules matching on source and destination address as well as input and output
+ * interfaces. This is what legacy iptables supports.
+ */
+#define BATCH_PAGE_SIZE 2 * 1024 * 1024
+
+struct nftnl_batch *mnl_batch_init(void)
+{
+ struct nftnl_batch *batch;
+
+ batch = nftnl_batch_alloc(BATCH_PAGE_SIZE, NFT_NLMSG_MAXSIZE);
+ if (batch == NULL)
+ memory_allocation_error();
+
+ return batch;
+}
+
+static void mnl_nft_batch_continue(struct nftnl_batch *batch)
+{
+ if (nftnl_batch_update(batch) < 0)
+ memory_allocation_error();
+}
+
+uint32_t mnl_batch_begin(struct nftnl_batch *batch, uint32_t seqnum)
+{
+ nftnl_batch_begin(nftnl_batch_buffer(batch), seqnum);
+ mnl_nft_batch_continue(batch);
+
+ return seqnum;
+}
+
+void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum)
+{
+ nftnl_batch_end(nftnl_batch_buffer(batch), seqnum);
+ mnl_nft_batch_continue(batch);
+}
+
+bool mnl_batch_ready(struct nftnl_batch *batch)
+{
+ /* Check if the batch only contains the initial and trailing batch
+ * messages. In that case, the batch is empty.
+ */
+ return nftnl_batch_buffer_len(batch) !=
+ (NLMSG_HDRLEN + sizeof(struct nfgenmsg)) * 2;
+}
+
+void mnl_batch_reset(struct nftnl_batch *batch)
+{
+ nftnl_batch_free(batch);
+}
+
+static void mnl_err_list_node_add(struct list_head *err_list, int error,
+ int seqnum, uint32_t offset,
+ const char *errmsg)
+{
+ struct mnl_err *err = xmalloc(sizeof(struct mnl_err));
+
+ err->seqnum = seqnum;
+ err->offset = offset;
+ err->err = error;
+ list_add_tail(&err->head, err_list);
+}
+
+void mnl_err_list_free(struct mnl_err *err)
+{
+ list_del(&err->head);
+ xfree(err);
+}
+
+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;
+
+ getsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUF,
+ &sndnlbuffsiz, &len);
+
+ newbuffsiz = nftnl_batch_iovec_len(batch) * BATCH_PAGE_SIZE;
+ if (newbuffsiz <= sndnlbuffsiz)
+ 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) {
+ if (errno == EPERM)
+ ctx->maybe_emsgsize = newbuffsiz;
+ }
+}
+
+static unsigned int nlsndbufsiz;
+
+static int mnl_set_rcvbuffer(const struct mnl_socket *nl, socklen_t bufsiz)
+{
+ socklen_t len = sizeof(nlsndbufsiz);
+ int ret;
+
+ if (!nlsndbufsiz) {
+ getsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUF,
+ &nlsndbufsiz, &len);
+ }
+
+ if (nlsndbufsiz >= bufsiz)
+ return 0;
+
+ ret = setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUFFORCE,
+ &bufsiz, sizeof(socklen_t));
+ if (ret < 0) {
+ /* If this doesn't work, try to reach the system wide maximum
+ * (or whatever the user requested).
+ */
+ ret = setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_RCVBUF,
+ &bufsiz, sizeof(socklen_t));
+ }
+
+ return ret;
+}
+
+static void mnl_nft_batch_to_msg(struct netlink_ctx *ctx, struct msghdr *msg,
+ const struct sockaddr_nl *snl,
+ struct iovec *iov, unsigned int iov_len)
+{
+ msg->msg_name = (struct sockaddr_nl *)snl;
+ msg->msg_namelen = sizeof(*snl);
+ msg->msg_iov = iov;
+ msg->msg_iovlen = iov_len;
+
+ nftnl_batch_iovec(ctx->batch, iov, iov_len);
+}
+
+static ssize_t mnl_nft_socket_sendmsg(struct netlink_ctx *ctx,
+ const struct msghdr *msg)
+{
+ uint32_t iov_len = msg->msg_iovlen;
+ struct iovec *iov = msg->msg_iov;
+ unsigned int i;
+
+ if (ctx->nft->debug_mask & NFT_DEBUG_MNL) {
+ for (i = 0; i < iov_len; i++) {
+ mnl_nlmsg_fprintf(ctx->nft->output.output_fp,
+ iov[i].iov_base, iov[i].iov_len,
+ sizeof(struct nfgenmsg));
+ }
+ }
+
+ return sendmsg(mnl_socket_get_fd(ctx->nft->nf_sock), msg, 0);
+}
+
+static int err_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ uint16_t type;
+
+ if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0)
+ return MNL_CB_ERROR;
+
+ type = mnl_attr_get_type(attr);
+ switch (type) {
+ case NLMSGERR_ATTR_OFFS:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int mnl_batch_extack_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct netlink_cb_data *cb_data = data;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+ const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+ unsigned int hlen = sizeof(*err);
+ const char *msg = NULL;
+ uint32_t off = 0;
+ int errval;
+
+ if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr)))
+ return MNL_CB_ERROR;
+
+ if (err->error < 0)
+ errval = -err->error;
+ else
+ errval = err->error;
+
+ if (errval == 0)
+ return MNL_CB_STOP;
+
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ hlen += mnl_nlmsg_get_payload_len(&err->msg);
+
+ if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
+ return MNL_CB_ERROR;
+
+ if (tb[NLMSGERR_ATTR_OFFS])
+ off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
+
+ mnl_err_list_node_add(cb_data->err_list, errval,
+ nlh->nlmsg_seq, off, msg);
+ return MNL_CB_ERROR;
+}
+
+#define NFT_MNL_ECHO_RCVBUFF_DEFAULT (MNL_SOCKET_BUFFER_SIZE * 1024U)
+#define NFT_MNL_ACK_MAXSIZE ((sizeof(struct nlmsghdr) + \
+ sizeof(struct nfgenmsg) + (1 << 16)) + \
+ MNL_SOCKET_BUFFER_SIZE)
+
+int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
+ uint32_t num_cmds)
+{
+ struct mnl_socket *nl = ctx->nft->nf_sock;
+ int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
+ uint32_t iov_len = nftnl_batch_iovec_len(ctx->batch);
+ char rcv_buf[NFT_MNL_ACK_MAXSIZE];
+ const struct sockaddr_nl snl = {
+ .nl_family = AF_NETLINK
+ };
+ struct timeval tv = {
+ .tv_sec = 0,
+ .tv_usec = 0
+ };
+ struct iovec iov[iov_len];
+ struct msghdr msg = {};
+ unsigned int rcvbufsiz;
+ fd_set readfds;
+ static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = {
+ [NLMSG_ERROR] = mnl_batch_extack_cb,
+ };
+ struct netlink_cb_data cb_data = {
+ .err_list = err_list,
+ .nl_ctx = ctx,
+ };
+
+ mnl_set_sndbuffer(ctx);
+
+ mnl_nft_batch_to_msg(ctx, &msg, &snl, iov, iov_len);
+
+ rcvbufsiz = num_cmds * 1024;
+ if (nft_output_echo(&ctx->nft->output)) {
+ if (rcvbufsiz < NFT_MNL_ECHO_RCVBUFF_DEFAULT)
+ rcvbufsiz = NFT_MNL_ECHO_RCVBUFF_DEFAULT;
+ }
+
+ mnl_set_rcvbuffer(ctx->nft->nf_sock, rcvbufsiz);
+
+ ret = mnl_nft_socket_sendmsg(ctx, &msg);
+ if (ret == -1)
+ return -1;
+
+ /* receive and digest all the acknowledgments from the kernel. */
+ while (true) {
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ ret = select(fd + 1, &readfds, NULL, NULL, &tv);
+ if (ret == -1)
+ return -1;
+
+ if (!FD_ISSET(fd, &readfds))
+ break;
+
+ ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
+ if (ret == -1)
+ return -1;
+
+ /* Continue on error, make sure we get all acknowledgments */
+ ret = mnl_cb_run2(rcv_buf, ret, 0, portid,
+ netlink_echo_callback, &cb_data,
+ cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
+ }
+ return 0;
+}
+
+struct mnl_nft_rule_build_ctx {
+ struct netlink_linearize_ctx *lctx;
+ struct nlmsghdr *nlh;
+ struct cmd *cmd;
+};
+
+static int mnl_nft_expr_build_cb(struct nftnl_expr *nle, void *data)
+{
+ struct mnl_nft_rule_build_ctx *ctx = data;
+ struct nlmsghdr *nlh = ctx->nlh;
+ struct cmd *cmd = ctx->cmd;
+ struct nft_expr_loc *eloc;
+ struct nlattr *nest;
+
+ eloc = nft_expr_loc_find(nle, ctx->lctx);
+ if (eloc)
+ cmd_add_loc(cmd, nlh->nlmsg_len, eloc->loc);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
+ nftnl_expr_build_payload(nlh, nle);
+ mnl_attr_nest_end(nlh, nest);
+
+ nftnl_rule_del_expr(nle);
+ nftnl_expr_free(nle);
+
+ return 0;
+}
+
+static void mnl_nft_rule_build_ctx_init(struct mnl_nft_rule_build_ctx *rule_ctx,
+ struct nlmsghdr *nlh,
+ struct cmd *cmd,
+ struct netlink_linearize_ctx *lctx)
+{
+ memset(rule_ctx, 0, sizeof(*rule_ctx));
+ rule_ctx->nlh = nlh;
+ rule_ctx->cmd = cmd;
+ rule_ctx->lctx = lctx;
+}
+
+int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags)
+{
+ struct mnl_nft_rule_build_ctx rule_ctx;
+ struct netlink_linearize_ctx lctx;
+ struct rule *rule = cmd->rule;
+ struct handle *h = &rule->handle;
+ struct nftnl_rule *nlr;
+ struct nlmsghdr *nlh;
+ struct nlattr *nest;
+
+ nlr = nftnl_rule_alloc();
+ if (!nlr)
+ memory_allocation_error();
+
+ nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
+ if (h->position.id)
+ nftnl_rule_set_u64(nlr, NFTNL_RULE_POSITION, h->position.id);
+ if (h->rule_id)
+ nftnl_rule_set_u32(nlr, NFTNL_RULE_ID, h->rule_id);
+ if (h->position_id)
+ nftnl_rule_set_u32(nlr, NFTNL_RULE_POSITION_ID, h->position_id);
+
+ netlink_linearize_init(&lctx, nlr);
+ netlink_linearize_rule(ctx, rule, &lctx);
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWRULE,
+ cmd->handle.family,
+ NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+
+ if (h->chain_id)
+ mnl_attr_put_u32(nlh, NFTA_RULE_CHAIN_ID, htonl(h->chain_id));
+ else
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+
+ mnl_nft_rule_build_ctx_init(&rule_ctx, nlh, cmd, &lctx);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
+ nftnl_expr_foreach(nlr, mnl_nft_expr_build_cb, &rule_ctx);
+ mnl_attr_nest_end(nlh, nest);
+
+ nftnl_rule_nlmsg_build_payload(nlh, nlr);
+ nftnl_rule_free(nlr);
+ netlink_linearize_fini(&lctx);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct mnl_nft_rule_build_ctx rule_ctx;
+ struct netlink_linearize_ctx lctx;
+ struct rule *rule = cmd->rule;
+ struct handle *h = &rule->handle;
+ unsigned int flags = 0;
+ struct nftnl_rule *nlr;
+ struct nlmsghdr *nlh;
+ struct nlattr *nest;
+
+ if (nft_output_echo(&ctx->nft->output))
+ flags |= NLM_F_ECHO;
+
+ nlr = nftnl_rule_alloc();
+ if (!nlr)
+ memory_allocation_error();
+
+ nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
+
+ netlink_linearize_init(&lctx, nlr);
+ netlink_linearize_rule(ctx, rule, &lctx);
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWRULE,
+ cmd->handle.family,
+ NLM_F_REPLACE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location);
+ mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id));
+
+ mnl_nft_rule_build_ctx_init(&rule_ctx, nlh, cmd, &lctx);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
+ nftnl_expr_foreach(nlr, mnl_nft_expr_build_cb, &rule_ctx);
+ mnl_attr_nest_end(nlh, nest);
+
+ nftnl_rule_nlmsg_build_payload(nlh, nlr);
+ nftnl_rule_free(nlr);
+ netlink_linearize_fini(&lctx);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+int mnl_nft_rule_del(struct netlink_ctx *ctx, 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;
+
+ nlr = nftnl_rule_alloc();
+ if (!nlr)
+ memory_allocation_error();
+
+ 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),
+ msg_type,
+ nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY),
+ 0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ if (h->chain.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+ }
+ if (h->handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location);
+ mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id));
+ }
+
+ nftnl_rule_nlmsg_build_payload(nlh, nlr);
+ nftnl_rule_free(nlr);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+/*
+ * Rule
+ */
+
+static int rule_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_rule_list *nlr_list = data;
+ struct nftnl_rule *r;
+
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
+ r = nftnl_rule_alloc();
+ if (r == NULL)
+ memory_allocation_error();
+
+ if (nftnl_rule_nlmsg_parse(nlh, r) < 0)
+ goto err_free;
+
+ nftnl_rule_list_add_tail(r, nlr_list);
+ return MNL_CB_OK;
+
+err_free:
+ nftnl_rule_free(r);
+ return MNL_CB_OK;
+}
+
+struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *chain,
+ uint64_t rule_handle,
+ bool dump, bool reset)
+{
+ uint16_t nl_flags = dump ? NLM_F_DUMP : NLM_F_ACK;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nftnl_rule_list *nlr_list;
+ struct nftnl_rule *nlr = NULL;
+ struct nlmsghdr *nlh;
+ int msg_type, ret;
+
+ if (reset)
+ msg_type = NFT_MSG_GETRULE_RESET;
+ else
+ msg_type = NFT_MSG_GETRULE;
+
+ if (table) {
+ nlr = nftnl_rule_alloc();
+ if (!nlr)
+ memory_allocation_error();
+
+ nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, table);
+ if (chain)
+ nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, chain);
+ if (rule_handle)
+ nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, rule_handle);
+ }
+
+ nlr_list = nftnl_rule_list_alloc();
+ if (nlr_list == NULL)
+ memory_allocation_error();
+
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type, family,
+ nl_flags, ctx->seqnum);
+ if (nlr) {
+ nftnl_rule_nlmsg_build_payload(nlh, nlr);
+ nftnl_rule_free(nlr);
+ }
+
+ ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, rule_cb, nlr_list);
+ if (ret < 0)
+ goto err;
+
+ return nlr_list;
+err:
+ nftnl_rule_list_free(nlr_list);
+ return NULL;
+}
+
+/*
+ * 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)
+ xfree(dev_array[i++].ifname);
+
+ xfree(dev_array);
+}
+
+static void mnl_nft_chain_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
+{
+ const struct expr *dev_expr = cmd->chain->dev_expr;
+ const struct nft_dev *dev_array;
+ struct nlattr *nest_dev;
+ int i, num_devs = 0;
+
+ dev_array = nft_dev_array(dev_expr, &num_devs);
+ if (num_devs == 1) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[0].location);
+ mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, dev_array[0].ifname);
+ } else {
+ nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS);
+ for (i = 0; i < num_devs; i++) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[i].location);
+ mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
+ mnl_attr_nest_end(nlh, nest_dev);
+ }
+ }
+ nft_dev_array_free(dev_array);
+}
+
+int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags)
+{
+ struct nftnl_udata_buf *udbuf;
+ struct nftnl_chain *nlc;
+ struct nlmsghdr *nlh;
+ int priority, policy;
+
+ nlc = nftnl_chain_alloc();
+ if (nlc == NULL)
+ memory_allocation_error();
+
+ nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
+
+ if (cmd->chain) {
+ if (cmd->chain->flags & CHAIN_F_HW_OFFLOAD) {
+ nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FLAGS,
+ CHAIN_F_HW_OFFLOAD);
+ }
+ if (cmd->chain->comment) {
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_CHAIN_COMMENT, cmd->chain->comment))
+ memory_allocation_error();
+ nftnl_chain_set_data(nlc, NFTNL_CHAIN_USERDATA, nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
+ }
+ }
+ netlink_dump_chain(nlc, ctx);
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWCHAIN,
+ cmd->handle.family,
+ NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location);
+
+ if (!cmd->chain || !(cmd->chain->flags & CHAIN_F_BINDING)) {
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name);
+ } else {
+ if (cmd->handle.chain.name)
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME,
+ cmd->handle.chain.name);
+
+ mnl_attr_put_u32(nlh, NFTA_CHAIN_ID, htonl(cmd->handle.chain_id));
+ if (cmd->chain->flags)
+ nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FLAGS, cmd->chain->flags);
+ }
+
+ if (cmd->chain && cmd->chain->policy) {
+ mpz_export_data(&policy, cmd->chain->policy->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->policy->location);
+ mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(policy));
+ }
+
+ nftnl_chain_unset(nlc, NFTNL_CHAIN_TYPE);
+
+ nftnl_chain_nlmsg_build_payload(nlh, nlc);
+
+ if (cmd->chain && cmd->chain->flags & CHAIN_F_BASECHAIN) {
+ struct nlattr *nest;
+
+ if (cmd->chain->type.str) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->type.loc);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, cmd->chain->type.str);
+ }
+
+ nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
+
+ if (cmd->chain->type.str) {
+ mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(cmd->chain->hook.num));
+ mpz_export_data(&priority, cmd->chain->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(priority));
+ }
+
+ if (cmd->chain && cmd->chain->dev_expr)
+ mnl_nft_chain_devs_build(nlh, cmd);
+
+ mnl_attr_nest_end(nlh, nest);
+ }
+
+ nftnl_chain_free(nlc);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct chain *chain)
+{
+ const char *name = cmd->arg;
+ struct nftnl_chain *nlc;
+ struct nlmsghdr *nlh;
+
+ nlc = nftnl_chain_alloc();
+ if (nlc == NULL)
+ memory_allocation_error();
+
+ nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
+ nftnl_chain_set_u64(nlc, NFTNL_CHAIN_HANDLE, chain->handle.handle.id);
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, name);
+
+ netlink_dump_chain(nlc, ctx);
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWCHAIN,
+ cmd->handle.family,
+ 0, ctx->seqnum);
+ nftnl_chain_nlmsg_build_payload(nlh, nlc);
+ nftnl_chain_free(nlc);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+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;
+
+ nlc = nftnl_chain_alloc();
+ if (nlc == NULL)
+ memory_allocation_error();
+
+ 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),
+ msg_type,
+ cmd->handle.family,
+ 0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name);
+ if (cmd->handle.chain.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
+ if (cmd->op == CMD_DELETE &&
+ cmd->chain && cmd->chain->dev_expr) {
+ struct nlattr *nest;
+
+ nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
+ mnl_nft_chain_devs_build(nlh, cmd);
+ mnl_attr_nest_end(nlh, nest);
+ }
+
+ nftnl_chain_nlmsg_build_payload(nlh, nlc);
+ nftnl_chain_free(nlc);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+static int chain_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_chain_list *nlc_list = data;
+ struct nftnl_chain *c;
+
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
+ c = nftnl_chain_alloc();
+ if (c == NULL)
+ memory_allocation_error();
+
+ if (nftnl_chain_nlmsg_parse(nlh, c) < 0)
+ goto err_free;
+
+ nftnl_chain_list_add_tail(c, nlc_list);
+ return MNL_CB_OK;
+
+err_free:
+ nftnl_chain_free(c);
+ return MNL_CB_OK;
+}
+
+struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
+ int family, const char *table,
+ const char *chain)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nftnl_chain_list *nlc_list;
+ struct nftnl_chain *nlc = NULL;
+ struct nlmsghdr *nlh;
+ int ret;
+
+ nlc_list = nftnl_chain_list_alloc();
+ if (nlc_list == NULL)
+ memory_allocation_error();
+
+ if (table && chain) {
+ nlc = nftnl_chain_alloc();
+ if (!nlc)
+ memory_allocation_error();
+
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, table);
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, chain);
+ }
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family,
+ nlc ? NLM_F_ACK : NLM_F_DUMP, ctx->seqnum);
+ if (nlc) {
+ nftnl_chain_nlmsg_build_payload(nlh, nlc);
+ nftnl_chain_free(nlc);
+ }
+
+ ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, chain_cb, nlc_list);
+ if (ret < 0 && errno != ENOENT)
+ goto err;
+
+ return nlc_list;
+err:
+ nftnl_chain_list_free(nlc_list);
+ return NULL;
+}
+
+/*
+ * Table
+ */
+int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags)
+{
+ struct nftnl_udata_buf *udbuf;
+ struct nftnl_table *nlt;
+ struct nlmsghdr *nlh;
+
+ nlt = nftnl_table_alloc();
+ if (nlt == NULL)
+ memory_allocation_error();
+
+ nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
+ if (cmd->table) {
+ nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, cmd->table->flags);
+
+ if (cmd->table->comment) {
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_TABLE_COMMENT, cmd->table->comment))
+ memory_allocation_error();
+ nftnl_table_set_data(nlt, NFTNL_TABLE_USERDATA, nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
+ }
+ } else {
+ nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, 0);
+ }
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWTABLE,
+ cmd->handle.family,
+ flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
+ nftnl_table_nlmsg_build_payload(nlh, nlt);
+ nftnl_table_free(nlt);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+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;
+
+ nlt = nftnl_table_alloc();
+ if (nlt == NULL)
+ memory_allocation_error();
+
+ nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYTABLE;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch), msg_type,
+ cmd->handle.family, 0, ctx->seqnum);
+
+ if (cmd->handle.table.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_TABLE_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+ nftnl_table_nlmsg_build_payload(nlh, nlt);
+ nftnl_table_free(nlt);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+static int table_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_table_list *nlt_list = data;
+ struct nftnl_table *t;
+
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
+ t = nftnl_table_alloc();
+ if (t == NULL)
+ memory_allocation_error();
+
+ if (nftnl_table_nlmsg_parse(nlh, t) < 0)
+ goto err_free;
+
+ nftnl_table_list_add_tail(t, nlt_list);
+ return MNL_CB_OK;
+
+err_free:
+ nftnl_table_free(t);
+ return MNL_CB_OK;
+}
+
+struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
+ int family, const char *table)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nftnl_table_list *nlt_list;
+ struct nftnl_table *nlt = NULL;
+ int flags = NLM_F_DUMP;
+ struct nlmsghdr *nlh;
+ int ret;
+
+ nlt_list = nftnl_table_list_alloc();
+ if (nlt_list == NULL)
+ return NULL;
+
+ if (table) {
+ nlt = nftnl_table_alloc();
+ if (!nlt)
+ memory_allocation_error();
+
+ nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, family);
+ nftnl_table_set_str(nlt, NFTNL_TABLE_NAME, table);
+ flags = NLM_F_ACK;
+ }
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family,
+ flags, ctx->seqnum);
+ if (nlt) {
+ nftnl_table_nlmsg_build_payload(nlh, nlt);
+ nftnl_table_free(nlt);
+ }
+
+ ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, table_cb, nlt_list);
+ if (ret < 0 && errno != ENOENT)
+ goto err;
+
+ return nlt_list;
+err:
+ nftnl_table_list_free(nlt_list);
+ return NULL;
+}
+
+static void set_key_expression(struct netlink_ctx *ctx,
+ struct expr *expr, uint32_t set_flags,
+ struct nftnl_udata_buf *udbuf,
+ unsigned int type)
+{
+ struct nftnl_udata *nest1, *nest2;
+
+ if (!expr_ops(expr)->build_udata)
+ return;
+
+ nest1 = nftnl_udata_nest_start(udbuf, type);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_TYPEOF_EXPR, expr->etype);
+ nest2 = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_TYPEOF_DATA);
+ expr_ops(expr)->build_udata(udbuf, expr);
+ nftnl_udata_nest_end(udbuf, nest2);
+ nftnl_udata_nest_end(udbuf, nest1);
+}
+
+/*
+ * Set
+ */
+int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags)
+{
+ struct handle *h = &cmd->handle;
+ struct nftnl_udata_buf *udbuf;
+ struct set *set = cmd->set;
+ struct nftnl_set *nls;
+ struct nlmsghdr *nlh;
+ struct stmt *stmt;
+ int num_stmts = 0;
+
+ nls = nftnl_set_alloc();
+ if (!nls)
+ memory_allocation_error();
+
+ nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
+ nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
+ nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
+ nftnl_set_set_u32(nls, NFTNL_SET_ID, h->set_id);
+
+ nftnl_set_set_u32(nls, NFTNL_SET_FLAGS, set->flags);
+ nftnl_set_set_u32(nls, NFTNL_SET_KEY_TYPE,
+ dtype_map_to_kernel(set->key->dtype));
+ nftnl_set_set_u32(nls, NFTNL_SET_KEY_LEN,
+ div_round_up(set->key->len, BITS_PER_BYTE));
+ if (set_is_datamap(set->flags)) {
+ nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
+ dtype_map_to_kernel(set->data->dtype));
+ nftnl_set_set_u32(nls, NFTNL_SET_DATA_LEN,
+ div_round_up(set->data->len, BITS_PER_BYTE));
+ }
+ if (set_is_objmap(set->flags))
+ nftnl_set_set_u32(nls, NFTNL_SET_OBJ_TYPE, set->objtype);
+
+ if (set->timeout)
+ nftnl_set_set_u64(nls, NFTNL_SET_TIMEOUT, set->timeout);
+ if (set->gc_int)
+ nftnl_set_set_u32(nls, NFTNL_SET_GC_INTERVAL, set->gc_int);
+
+ nftnl_set_set_u32(nls, NFTNL_SET_ID, set->handle.set_id);
+
+ if (!(set->flags & NFT_SET_CONSTANT)) {
+ if (set->policy != NFT_SET_POL_PERFORMANCE)
+ nftnl_set_set_u32(nls, NFTNL_SET_POLICY, set->policy);
+
+ if (set->desc.size != 0)
+ nftnl_set_set_u32(nls, NFTNL_SET_DESC_SIZE,
+ set->desc.size);
+ } else if (set->init) {
+ nftnl_set_set_u32(nls, NFTNL_SET_DESC_SIZE, set->init->size);
+ }
+
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEYBYTEORDER,
+ set->key->byteorder))
+ memory_allocation_error();
+
+ if (set_is_datamap(set->flags) &&
+ !nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATABYTEORDER,
+ set->data->byteorder))
+ memory_allocation_error();
+
+ if (set->automerge &&
+ !nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_MERGE_ELEMENTS,
+ set->automerge))
+ memory_allocation_error();
+
+ set_key_expression(ctx, set->key, set->flags, udbuf, NFTNL_UDATA_SET_KEY_TYPEOF);
+ if (set->data) {
+ set_key_expression(ctx, set->data, set->flags, udbuf, NFTNL_UDATA_SET_DATA_TYPEOF);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATA_INTERVAL,
+ !!(set->data->flags & EXPR_F_INTERVAL));
+ }
+
+ if (set->desc.field_len[0]) {
+ nftnl_set_set_data(nls, NFTNL_SET_DESC_CONCAT,
+ set->desc.field_len,
+ set->desc.field_count *
+ sizeof(set->desc.field_len[0]));
+ }
+
+ if (set->comment) {
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_SET_COMMENT, set->comment))
+ memory_allocation_error();
+ }
+
+ nftnl_set_set_data(nls, NFTNL_SET_USERDATA, nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
+
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts == 1) {
+ list_for_each_entry(stmt, &set->stmt_list, list) {
+ nftnl_set_set_data(nls, NFTNL_SET_EXPR,
+ netlink_gen_stmt_stateful(stmt), 0);
+ break;
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ nftnl_set_add_expr(nls, netlink_gen_stmt_stateful(stmt));
+ }
+
+ netlink_dump_set(nls, ctx);
+
+ nftnl_set_unset(nls, NFTNL_SET_TABLE);
+ nftnl_set_unset(nls, NFTNL_SET_NAME);
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWSET,
+ h->family,
+ NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->set.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_NAME, h->set.name);
+
+ nftnl_set_nlmsg_build_payload(nlh, nls);
+ nftnl_set_free(nls);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+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;
+
+ nls = nftnl_set_alloc();
+ if (!nls)
+ memory_allocation_error();
+
+ 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),
+ msg_type,
+ h->family,
+ 0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_TABLE, cmd->handle.table.name);
+ if (h->set.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.set.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_NAME, cmd->handle.set.name);
+ } else if (h->handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_SET_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
+ nftnl_set_nlmsg_build_payload(nlh, nls);
+ nftnl_set_free(nls);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+static int set_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_set_list *nls_list = data;
+ struct nftnl_set *s;
+
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
+ s = nftnl_set_alloc();
+ if (s == NULL)
+ memory_allocation_error();
+
+ if (nftnl_set_nlmsg_parse(nlh, s) < 0)
+ goto err_free;
+
+ nftnl_set_list_add_tail(s, nls_list);
+ return MNL_CB_OK;
+
+err_free:
+ nftnl_set_free(s);
+ return MNL_CB_OK;
+}
+
+struct nftnl_set_list *
+mnl_nft_set_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *set)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nftnl_set_list *nls_list;
+ int flags = NLM_F_DUMP;
+ struct nlmsghdr *nlh;
+ struct nftnl_set *s;
+ int ret;
+
+ s = nftnl_set_alloc();
+ if (s == NULL)
+ memory_allocation_error();
+
+ if (table != NULL)
+ nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
+ if (set) {
+ nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ flags = NLM_F_ACK;
+ }
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
+ flags, ctx->seqnum);
+ nftnl_set_nlmsg_build_payload(nlh, s);
+ nftnl_set_free(s);
+
+ nls_list = nftnl_set_list_alloc();
+ if (nls_list == NULL)
+ memory_allocation_error();
+
+ ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_cb, nls_list);
+ if (ret < 0 && errno != ENOENT)
+ goto err;
+
+ return nls_list;
+err:
+ nftnl_set_list_free(nls_list);
+ return NULL;
+}
+
+int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags)
+{
+ struct obj *obj = cmd->object;
+ struct nftnl_udata_buf *udbuf;
+ struct nftnl_obj *nlo;
+ struct nlmsghdr *nlh;
+
+ nlo = nftnl_obj_alloc();
+ if (!nlo)
+ memory_allocation_error();
+
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, obj->type);
+
+ if (obj->comment) {
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_OBJ_COMMENT, obj->comment))
+ memory_allocation_error();
+ nftnl_obj_set_data(nlo, NFTNL_OBJ_USERDATA, nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
+ }
+
+ switch (obj->type) {
+ case NFT_OBJECT_COUNTER:
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_PKTS,
+ obj->counter.packets);
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_BYTES,
+ obj->counter.bytes);
+ break;
+ case NFT_OBJECT_QUOTA:
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_BYTES,
+ obj->quota.bytes);
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED,
+ obj->quota.used);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS,
+ obj->quota.flags);
+ break;
+ case NFT_OBJECT_LIMIT:
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_RATE, obj->limit.rate);
+ nftnl_obj_set_u64(nlo, NFTNL_OBJ_LIMIT_UNIT, obj->limit.unit);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_BURST, obj->limit.burst);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_TYPE, obj->limit.type);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_LIMIT_FLAGS, obj->limit.flags);
+ break;
+ case NFT_OBJECT_CT_HELPER:
+ nftnl_obj_set_str(nlo, NFTNL_OBJ_CT_HELPER_NAME,
+ obj->ct_helper.name);
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO,
+ obj->ct_helper.l4proto);
+ if (obj->ct_helper.l3proto)
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO,
+ obj->ct_helper.l3proto);
+ break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO,
+ obj->ct_timeout.l4proto);
+ if (obj->ct_timeout.l3proto)
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO,
+ obj->ct_timeout.l3proto);
+ nftnl_obj_set_data(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY,
+ obj->ct_timeout.timeout,
+ sizeof(obj->ct_timeout.timeout));
+ break;
+ case NFT_OBJECT_CT_EXPECT:
+ if (obj->ct_expect.l3proto)
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_EXPECT_L3PROTO,
+ obj->ct_expect.l3proto);
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_EXPECT_L4PROTO,
+ obj->ct_expect.l4proto);
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_EXPECT_DPORT,
+ obj->ct_expect.dport);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_CT_EXPECT_TIMEOUT,
+ obj->ct_expect.timeout);
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE,
+ obj->ct_expect.size);
+ break;
+ case NFT_OBJECT_SECMARK:
+ nftnl_obj_set_str(nlo, NFTNL_OBJ_SECMARK_CTX,
+ obj->secmark.ctx);
+ break;
+ case NFT_OBJECT_SYNPROXY:
+ nftnl_obj_set_u16(nlo, NFTNL_OBJ_SYNPROXY_MSS,
+ obj->synproxy.mss);
+ nftnl_obj_set_u8(nlo, NFTNL_OBJ_SYNPROXY_WSCALE,
+ obj->synproxy.wscale);
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_SYNPROXY_FLAGS,
+ obj->synproxy.flags);
+ break;
+ default:
+ BUG("Unknown type %d\n", obj->type);
+ break;
+ }
+ netlink_dump_obj(nlo, ctx);
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWOBJ, cmd->handle.family,
+ NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name);
+
+ nftnl_obj_nlmsg_build_payload(nlh, nlo);
+ nftnl_obj_free(nlo);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+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;
+
+ nlo = nftnl_obj_alloc();
+ if (!nlo)
+ memory_allocation_error();
+
+ 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),
+ msg_type, cmd->handle.family,
+ 0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name);
+
+ if (cmd->handle.obj.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_OBJ_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
+ nftnl_obj_nlmsg_build_payload(nlh, nlo);
+ nftnl_obj_free(nlo);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+static int obj_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_obj_list *nln_list = data;
+ struct nftnl_obj *n;
+
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
+ n = nftnl_obj_alloc();
+ if (n == NULL)
+ memory_allocation_error();
+
+ if (nftnl_obj_nlmsg_parse(nlh, n) < 0)
+ goto err_free;
+
+ nftnl_obj_list_add_tail(n, nln_list);
+ return MNL_CB_OK;
+
+err_free:
+ nftnl_obj_free(n);
+ return MNL_CB_OK;
+}
+
+
+struct nftnl_obj_list *
+mnl_nft_obj_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *name, uint32_t type, bool dump,
+ bool reset)
+{
+ uint16_t nl_flags = dump ? NLM_F_DUMP : NLM_F_ACK;
+ struct nftnl_obj_list *nln_list;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ struct nftnl_obj *n;
+ int msg_type, ret;
+
+ if (reset)
+ msg_type = NFT_MSG_GETOBJ_RESET;
+ else
+ msg_type = NFT_MSG_GETOBJ;
+
+ n = nftnl_obj_alloc();
+ if (n == NULL)
+ memory_allocation_error();
+
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type, family,
+ nl_flags, ctx->seqnum);
+ if (table != NULL)
+ nftnl_obj_set_str(n, NFTNL_OBJ_TABLE, table);
+ if (name != NULL)
+ nftnl_obj_set_str(n, NFTNL_OBJ_NAME, name);
+ if (type != NFT_OBJECT_UNSPEC)
+ nftnl_obj_set_u32(n, NFTNL_OBJ_TYPE, type);
+ nftnl_obj_nlmsg_build_payload(nlh, n);
+ nftnl_obj_free(n);
+
+ nln_list = nftnl_obj_list_alloc();
+ if (nln_list == NULL)
+ memory_allocation_error();
+
+ ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, obj_cb, nln_list);
+ if (ret < 0)
+ goto err;
+
+ return nln_list;
+err:
+ nftnl_obj_list_free(nln_list);
+ return NULL;
+}
+
+/*
+ * Set elements
+ */
+static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
+{
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
+ nftnl_set_elems_nlmsg_parse(nlh, data);
+ return MNL_CB_OK;
+}
+
+static bool mnl_nft_attr_nest_overflow(struct nlmsghdr *nlh,
+ const struct nlattr *from,
+ const struct nlattr *to)
+{
+ int len = (void *)to + to->nla_len - (void *)from;
+
+ /* The attribute length field is 16 bits long, thus the maximum payload
+ * that an attribute can convey is UINT16_MAX. In case of overflow,
+ * discard the last attribute that did not fit into the nest.
+ */
+ if (len > UINT16_MAX) {
+ nlh->nlmsg_len -= to->nla_len;
+ return true;
+ }
+ return false;
+}
+
+static void netlink_dump_setelem(const struct nftnl_set_elem *nlse,
+ struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+ char buf[4096];
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ nftnl_set_elem_snprintf(buf, sizeof(buf), nlse, NFTNL_OUTPUT_DEFAULT, 0);
+ fprintf(fp, "\t%s", buf);
+}
+
+static void netlink_dump_setelem_done(struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ fprintf(fp, "\n");
+}
+
+static int mnl_nft_setelem_batch(const struct nftnl_set *nls, struct cmd *cmd,
+ struct nftnl_batch *batch,
+ enum nf_tables_msg_types msg_type,
+ unsigned int flags, uint32_t seqnum,
+ const struct expr *set,
+ struct netlink_ctx *ctx)
+{
+ struct nlattr *nest1, *nest2;
+ struct nftnl_set_elem *nlse;
+ struct nlmsghdr *nlh;
+ struct expr *expr = NULL;
+ int i = 0;
+
+ 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), msg_type,
+ nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
+ flags, seqnum);
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_TABLE)) {
+ mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE,
+ nftnl_set_get_str(nls, NFTNL_SET_TABLE));
+ }
+ if (nftnl_set_is_set(nls, NFTNL_SET_NAME)) {
+ mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_SET,
+ nftnl_set_get_str(nls, NFTNL_SET_NAME));
+ }
+ if (nftnl_set_is_set(nls, NFTNL_SET_ID)) {
+ mnl_attr_put_u32(nlh, NFTA_SET_ELEM_LIST_SET_ID,
+ htonl(nftnl_set_get_u32(nls, NFTNL_SET_ID)));
+ }
+
+ if (!set || list_empty(&set->expressions))
+ return 0;
+
+ assert(expr);
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
+ list_for_each_entry_from(expr, &set->expressions, list) {
+ nlse = alloc_nftnl_setelem(set, expr);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &expr->location);
+ nest2 = mnl_attr_nest_start(nlh, ++i);
+ nftnl_set_elem_nlmsg_build_payload(nlh, nlse);
+ mnl_attr_nest_end(nlh, nest2);
+
+ netlink_dump_setelem(nlse, ctx);
+ nftnl_set_elem_free(nlse);
+ if (mnl_nft_attr_nest_overflow(nlh, nest1, nest2)) {
+ mnl_attr_nest_end(nlh, nest1);
+ mnl_nft_batch_continue(batch);
+ goto next;
+ }
+ }
+ mnl_attr_nest_end(nlh, nest1);
+ mnl_nft_batch_continue(batch);
+ netlink_dump_setelem_done(ctx);
+
+ return 0;
+}
+
+int mnl_nft_setelem_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ const struct set *set, const struct expr *expr,
+ unsigned int flags)
+{
+ const struct handle *h = &set->handle;
+ struct nftnl_set *nls;
+ int err;
+
+ nls = nftnl_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+
+ nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
+ nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
+ nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
+ if (h->set_id)
+ nftnl_set_set_u32(nls, NFTNL_SET_ID, h->set_id);
+ if (set_is_datamap(set->flags))
+ nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
+ dtype_map_to_kernel(set->data->dtype));
+
+ netlink_dump_set(nls, ctx);
+
+ err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, NFT_MSG_NEWSETELEM,
+ flags, ctx->seqnum, expr, ctx);
+ nftnl_set_free(nls);
+
+ return err;
+}
+
+int mnl_nft_setelem_flush(struct netlink_ctx *ctx, const struct cmd *cmd)
+{
+ const struct handle *h = &cmd->handle;
+ struct nftnl_set *nls;
+ struct nlmsghdr *nlh;
+
+ nls = nftnl_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+
+ nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
+ nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
+ nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
+ if (h->handle.id)
+ nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
+
+ netlink_dump_set(nls, ctx);
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_DELSETELEM,
+ h->family,
+ 0, ctx->seqnum);
+ nftnl_set_elems_nlmsg_build_payload(nlh, nls);
+ nftnl_set_free(nls);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+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;
+
+ nls = nftnl_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+
+ nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
+ nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
+ if (h->set.name)
+ nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
+ else if (h->handle.id)
+ nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
+
+ netlink_dump_set(nls, ctx);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYSETELEM;
+
+ err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, msg_type, 0,
+ ctx->seqnum, init, ctx);
+ nftnl_set_free(nls);
+
+ return err;
+}
+
+struct nftnl_set *mnl_nft_setelem_get_one(struct netlink_ctx *ctx,
+ struct nftnl_set *nls_in,
+ bool reset)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nftnl_set *nls_out;
+ struct nlmsghdr *nlh;
+ int msg_type;
+ int err;
+
+ 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);
+
+ nls_out = nftnl_set_alloc();
+ if (!nls_out)
+ return NULL;
+
+ nftnl_set_set_str(nls_out, NFTNL_SET_TABLE,
+ nftnl_set_get_str(nls_in, NFTNL_SET_TABLE));
+ nftnl_set_set_str(nls_out, NFTNL_SET_NAME,
+ nftnl_set_get_str(nls_in, NFTNL_SET_NAME));
+
+ err = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_elem_cb, nls_out);
+ if (err < 0) {
+ nftnl_set_free(nls_out);
+ return NULL;
+ }
+
+ return nls_out;
+}
+
+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, msg_type,
+ nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
+ NLM_F_DUMP, ctx->seqnum);
+ nftnl_set_elems_nlmsg_build_payload(nlh, nls);
+
+ return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_elem_cb, nls);
+}
+
+static int flowtable_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct nftnl_flowtable_list *nln_list = data;
+ struct nftnl_flowtable *n;
+
+ if (check_genid(nlh) < 0)
+ return MNL_CB_ERROR;
+
+ n = nftnl_flowtable_alloc();
+ if (n == NULL)
+ memory_allocation_error();
+
+ if (nftnl_flowtable_nlmsg_parse(nlh, n) < 0)
+ goto err_free;
+
+ nftnl_flowtable_list_add_tail(n, nln_list);
+ return MNL_CB_OK;
+
+err_free:
+ nftnl_flowtable_free(n);
+ return MNL_CB_OK;
+}
+
+struct nftnl_flowtable_list *
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *ft)
+{
+ struct nftnl_flowtable_list *nln_list;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nftnl_flowtable *n;
+ int flags = NLM_F_DUMP;
+ struct nlmsghdr *nlh;
+ int ret;
+
+ n = nftnl_flowtable_alloc();
+ if (n == NULL)
+ memory_allocation_error();
+
+ if (table != NULL)
+ nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_TABLE, table);
+ if (ft) {
+ nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_NAME, ft);
+ flags = NLM_F_ACK;
+ }
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
+ flags, ctx->seqnum);
+ nftnl_flowtable_nlmsg_build_payload(nlh, n);
+ nftnl_flowtable_free(n);
+
+ nln_list = nftnl_flowtable_list_alloc();
+ if (nln_list == NULL)
+ memory_allocation_error();
+
+ ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, flowtable_cb, nln_list);
+ if (ret < 0 && errno != ENOENT)
+ goto err;
+
+ return nln_list;
+err:
+ nftnl_flowtable_list_free(nln_list);
+ return NULL;
+}
+
+static void mnl_nft_ft_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
+{
+ const struct expr *dev_expr = cmd->flowtable->dev_expr;
+ const struct nft_dev *dev_array;
+ struct nlattr *nest_dev;
+ int i, num_devs= 0;
+
+ dev_array = nft_dev_array(dev_expr, &num_devs);
+ nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
+ for (i = 0; i < num_devs; i++) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[i].location);
+ mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
+ }
+
+ mnl_attr_nest_end(nlh, nest_dev);
+ nft_dev_array_free(dev_array);
+}
+
+int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ unsigned int flags)
+{
+ struct nftnl_flowtable *flo;
+ struct nlmsghdr *nlh;
+ struct nlattr *nest;
+ int priority;
+
+ flo = nftnl_flowtable_alloc();
+ if (!flo)
+ memory_allocation_error();
+
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
+ cmd->handle.family);
+
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FLAGS,
+ cmd->flowtable->flags);
+
+ netlink_dump_flowtable(flo, ctx);
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ NFT_MSG_NEWFLOWTABLE, cmd->handle.family,
+ NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.flowtable.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, cmd->handle.flowtable.name);
+
+ nftnl_flowtable_nlmsg_build_payload(nlh, flo);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
+
+ if (cmd->flowtable && cmd->flowtable->priority.expr) {
+ mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_NUM, htonl(cmd->flowtable->hook.num));
+ mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(priority));
+ }
+
+ if (cmd->flowtable->dev_expr)
+ mnl_nft_ft_devs_build(nlh, cmd);
+
+ mnl_attr_nest_end(nlh, nest);
+
+ nftnl_flowtable_free(flo);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELFLOWTABLE;
+ struct nftnl_flowtable *flo;
+ struct nlmsghdr *nlh;
+ struct nlattr *nest;
+
+ flo = nftnl_flowtable_alloc();
+ if (!flo)
+ memory_allocation_error();
+
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
+ cmd->handle.family);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYFLOWTABLE;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
+ msg_type, cmd->handle.family,
+ 0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name);
+
+ if (cmd->handle.flowtable.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len,
+ &cmd->handle.flowtable.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME,
+ cmd->handle.flowtable.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_FLOWTABLE_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
+ nftnl_flowtable_nlmsg_build_payload(nlh, flo);
+
+ if (cmd->op == CMD_DELETE &&
+ cmd->flowtable && cmd->flowtable->dev_expr) {
+ nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
+ mnl_nft_ft_devs_build(nlh, cmd);
+ mnl_attr_nest_end(nlh, nest);
+ }
+
+ nftnl_flowtable_free(flo);
+
+ mnl_nft_batch_continue(ctx->batch);
+
+ return 0;
+}
+
+/*
+ * events
+ */
+#define NFTABLES_NLEVENT_BUFSIZ (1 << 24)
+
+int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
+ struct output_ctx *octx,
+ int (*cb)(const struct nlmsghdr *nlh, void *data),
+ void *cb_data)
+{
+ /* Set netlink socket buffer size to 16 Mbytes to reduce chances of
+ * message loss due to ENOBUFS.
+ */
+ unsigned int bufsiz = NFTABLES_NLEVENT_BUFSIZ;
+ int fd = mnl_socket_get_fd(nf_sock);
+ char buf[NFT_NLMSG_MAXSIZE];
+ fd_set readfds;
+ int ret;
+
+ ret = mnl_set_rcvbuffer(nf_sock, bufsiz);
+ if (ret < 0)
+ nft_print(octx, "# Cannot set up netlink receive socket buffer size to %u bytes, falling back to %u bytes\n",
+ NFTABLES_NLEVENT_BUFSIZ, bufsiz);
+
+ while (1) {
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ ret = select(fd + 1, &readfds, NULL, NULL, NULL);
+ if (ret < 0)
+ return -1;
+
+ if (FD_ISSET(fd, &readfds)) {
+ ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
+ if (ret < 0) {
+ if (errno == ENOBUFS) {
+ nft_print(octx, "# ERROR: We lost some netlink events!\n");
+ continue;
+ }
+ nft_print(octx, "# ERROR: %s\n",
+ strerror(errno));
+ break;
+ }
+ }
+
+ if (debug_mask & NFT_DEBUG_MNL) {
+ mnl_nlmsg_fprintf(octx->output_fp, buf, sizeof(buf),
+ sizeof(struct nfgenmsg));
+ }
+ ret = mnl_cb_run(buf, ret, 0, 0, cb, cb_data);
+ if (ret <= 0)
+ break;
+ }
+ return ret;
+}
+
+static struct basehook *basehook_alloc(void)
+{
+ return xzalloc(sizeof(struct basehook));
+}
+
+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);
+}
+
+static void basehook_list_add_tail(struct basehook *b, struct list_head *head)
+{
+ struct basehook *hook;
+
+ list_for_each_entry(hook, head, list) {
+ if (hook->family != b->family)
+ continue;
+ if (hook->num != b->num)
+ continue;
+ if (hook->prio < b->prio)
+ continue;
+
+ list_add(&b->list, &hook->list);
+ return;
+ }
+
+ list_add_tail(&b->list, head);
+}
+
+static int dump_nf_attr_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_HOOK_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_HOOK_HOOKNUM:
+ case NFNLA_HOOK_PRIORITY:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_DEV:
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_MODULE_NAME:
+ case NFNLA_HOOK_FUNCTION_NAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_CHAIN_INFO:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int dump_nf_chain_info_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_HOOK_INFO_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_HOOK_INFO_DESC:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_INFO_TYPE:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int dump_nf_attr_chain_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_CHAIN_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_CHAIN_TABLE:
+ case NFNLA_CHAIN_NAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_CHAIN_FAMILY:
+ if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int dump_nf_attr_bpf_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_HOOK_BPF_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_HOOK_BPF_ID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+struct dump_nf_hook_data {
+ struct list_head *hook_list;
+ int family;
+};
+
+static int dump_nf_hooks(const struct nlmsghdr *nlh, void *_data)
+{
+ const struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *tb[NFNLA_HOOK_MAX + 1] = {};
+ struct dump_nf_hook_data *data = _data;
+ struct basehook *hook;
+
+ /* NB: Don't check the nft generation ID, this is not
+ * an nftables subsystem.
+ */
+ if (mnl_attr_parse(nlh, sizeof(*nfg), dump_nf_attr_cb, tb) < 0)
+ return -1;
+
+ if (!tb[NFNLA_HOOK_PRIORITY])
+ netlink_abi_error();
+
+ hook = basehook_alloc();
+ hook->prio = ntohl(mnl_attr_get_u32(tb[NFNLA_HOOK_PRIORITY]));
+
+ if (tb[NFNLA_HOOK_FUNCTION_NAME])
+ hook->hookfn = xstrdup(mnl_attr_get_str(tb[NFNLA_HOOK_FUNCTION_NAME]));
+
+ if (tb[NFNLA_HOOK_MODULE_NAME])
+ hook->module_name = xstrdup(mnl_attr_get_str(tb[NFNLA_HOOK_MODULE_NAME]));
+
+ if (tb[NFNLA_HOOK_CHAIN_INFO]) {
+ struct nlattr *nested[NFNLA_HOOK_INFO_MAX + 1] = {};
+ uint32_t type;
+
+ if (mnl_attr_parse_nested(tb[NFNLA_HOOK_CHAIN_INFO],
+ dump_nf_chain_info_cb, nested) < 0) {
+ basehook_free(hook);
+ return -1;
+ }
+
+ type = ntohl(mnl_attr_get_u32(nested[NFNLA_HOOK_INFO_TYPE]));
+ if (type == NFNL_HOOK_TYPE_NFTABLES) {
+ struct nlattr *info[NFNLA_CHAIN_MAX + 1] = {};
+ const char *tablename, *chainname;
+
+ if (mnl_attr_parse_nested(nested[NFNLA_HOOK_INFO_DESC],
+ dump_nf_attr_chain_cb,
+ info) < 0) {
+ basehook_free(hook);
+ return -1;
+ }
+
+ tablename = mnl_attr_get_str(info[NFNLA_CHAIN_TABLE]);
+ chainname = mnl_attr_get_str(info[NFNLA_CHAIN_NAME]);
+ if (tablename && chainname) {
+ hook->table = xstrdup(tablename);
+ hook->chain = xstrdup(chainname);
+ }
+ hook->chain_family = mnl_attr_get_u8(info[NFNLA_CHAIN_FAMILY]);
+ } else if (type == NFNL_HOOK_TYPE_BPF) {
+ struct nlattr *info[NFNLA_HOOK_BPF_MAX + 1] = {};
+
+ if (mnl_attr_parse_nested(nested[NFNLA_HOOK_INFO_DESC],
+ dump_nf_attr_bpf_cb, info) < 0) {
+ basehook_free(hook);
+ return -1;
+ }
+
+ if (info[NFNLA_HOOK_BPF_ID]) {
+ char tmpbuf[16];
+
+ snprintf(tmpbuf, sizeof(tmpbuf), "id %u",
+ ntohl(mnl_attr_get_u32(info[NFNLA_HOOK_BPF_ID])));
+
+ hook->chain = xstrdup(tmpbuf);
+ }
+ }
+ }
+ if (tb[NFNLA_HOOK_HOOKNUM])
+ hook->num = ntohl(mnl_attr_get_u32(tb[NFNLA_HOOK_HOOKNUM]));
+
+ hook->family = nfg->nfgen_family;
+
+ /* Netdev hooks potentially interfer with this family datapath. */
+ if (hook->family == NFPROTO_NETDEV) {
+ switch (data->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_INET:
+ case NFPROTO_BRIDGE:
+ hook->family = data->family;
+ hook->num = NF_INET_INGRESS;
+ break;
+ case NFPROTO_ARP:
+ if (hook->chain_family == NFPROTO_NETDEV) {
+ hook->family = data->family;
+ hook->num = __NF_ARP_INGRESS;
+ }
+ break;
+ }
+ }
+
+ basehook_list_add_tail(hook, data->hook_list);
+
+ return MNL_CB_OK;
+}
+
+static struct nlmsghdr *nf_hook_dump_request(char *buf, uint8_t family, uint32_t seq)
+{
+ struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+ struct nfgenmsg *nfg;
+
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_type = NFNL_SUBSYS_HOOK << 8;
+ nlh->nlmsg_seq = seq;
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = family;
+ nfg->version = NFNETLINK_V0;
+
+ return nlh;
+}
+
+static int __mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, uint8_t query_family,
+ uint8_t family, uint8_t hooknum,
+ const char *devname,
+ struct list_head *hook_list)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct dump_nf_hook_data data = {
+ .hook_list = hook_list,
+ .family = query_family,
+ };
+ struct nlmsghdr *nlh;
+
+ nlh = nf_hook_dump_request(buf, family, ctx->seqnum);
+ if (devname)
+ mnl_attr_put_strz(nlh, NFNLA_HOOK_DEV, devname);
+
+ mnl_attr_put_u32(nlh, NFNLA_HOOK_HOOKNUM, htonl(hooknum));
+
+ return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, dump_nf_hooks, &data);
+}
+
+static void print_hooks(struct netlink_ctx *ctx, int family, struct list_head *hook_list)
+{
+ struct basehook *hook, *tmp, *prev = NULL;
+ bool same, family_in_use = false;
+ int prio;
+ FILE *fp;
+
+ fp = ctx->nft->output.output_fp;
+
+ list_for_each_entry_safe(hook, tmp, hook_list, list) {
+ if (hook->family == family) {
+ family_in_use = true;
+ break;
+ }
+ }
+
+ if (!family_in_use)
+ return;
+
+ fprintf(fp, "family %s {\n", family2str(family));
+
+ list_for_each_entry_safe(hook, tmp, hook_list, list) {
+ if (hook->family != family)
+ continue;
+
+ if (prev) {
+ if (prev->num == hook->num) {
+ fprintf(fp, "\n");
+ same = true;
+ } else {
+ same = false;
+ fprintf(fp, "\n\t}\n");
+ }
+ } else {
+ same = false;
+ }
+ prev = hook;
+
+ if (!same) {
+ fprintf(fp, "\thook %s {\n",
+ hooknum2str(family, hook->num));
+ }
+
+ prio = hook->prio;
+ if (prio < 0)
+ fprintf(fp, "\t\t%011d", prio); /* outputs a '-' sign */
+ else if (prio == 0)
+ fprintf(fp, "\t\t %010u", prio);
+ else
+ fprintf(fp, "\t\t+%010u", prio);
+
+ if (hook->table && hook->chain)
+ fprintf(fp, " chain %s %s %s", family2str(hook->chain_family), hook->table, hook->chain);
+ else if (hook->hookfn && hook->chain)
+ fprintf(fp, " %s %s", hook->hookfn, hook->chain);
+ else if (hook->hookfn) {
+ fprintf(fp, " %s", hook->hookfn);
+ }
+ if (hook->module_name)
+ fprintf(fp, " [%s]", hook->module_name);
+ }
+
+ fprintf(fp, "\n\t}\n");
+ fprintf(fp, "}\n");
+}
+
+#define HOOK_FAMILY_MAX 5
+
+static uint8_t hook_family[HOOK_FAMILY_MAX] = {
+ NFPROTO_IPV4,
+ NFPROTO_IPV6,
+ NFPROTO_BRIDGE,
+ NFPROTO_ARP,
+};
+
+static int mnl_nft_dump_nf(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int i, err;
+
+ /* show ingress in first place in hook listing. */
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ for (i = 0; i <= NF_INET_POST_ROUTING; i++) {
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, i, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+ }
+
+ return err;
+}
+
+static int mnl_nft_dump_nf_arp(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int err;
+
+ /* show ingress in first place in hook listing. */
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, NF_ARP_IN, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, NF_ARP_OUT, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ return err;
+}
+
+static int mnl_nft_dump_nf_netdev(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int err;
+
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ return err;
+}
+
+static int mnl_nft_dump_nf_decnet(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int i, err;
+
+ /* show ingress in first place in hook listing. */
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+#define NF_DN_NUMHOOKS 7
+ for (i = 0; i < NF_DN_NUMHOOKS; i++) {
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, i, devname, hook_list);
+ if (err < 0) {
+ *ret = err;
+ return err;
+ }
+ }
+
+ return err;
+}
+
+static void release_hook_list(struct list_head *hook_list)
+{
+ struct basehook *hook, *next;
+
+ list_for_each_entry_safe(hook, next, hook_list, list)
+ basehook_free(hook);
+}
+
+int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, int hook, const char *devname)
+{
+ LIST_HEAD(hook_list);
+ unsigned int i;
+ int ret;
+
+ errno = 0;
+ ret = 0;
+
+ switch (family) {
+ case NFPROTO_UNSPEC:
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV4, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV6, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf(ctx, NFPROTO_BRIDGE, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf_decnet(ctx, NFPROTO_DECNET, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_INET:
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV4, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV6, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_BRIDGE:
+ mnl_nft_dump_nf(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_ARP:
+ mnl_nft_dump_nf_arp(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_NETDEV:
+ mnl_nft_dump_nf_netdev(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_DECNET:
+ mnl_nft_dump_nf_decnet(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ }
+
+ switch (family) {
+ case NFPROTO_UNSPEC:
+ for (i = 0; i < HOOK_FAMILY_MAX; i++)
+ print_hooks(ctx, hook_family[i], &hook_list);
+ break;
+ case NFPROTO_INET:
+ print_hooks(ctx, NFPROTO_IPV4, &hook_list);
+ print_hooks(ctx, NFPROTO_IPV6, &hook_list);
+ break;
+ default:
+ print_hooks(ctx, family, &hook_list);
+ break;
+ }
+
+ release_hook_list(&hook_list);
+ ret = 0;
+
+ return ret;
+}
diff --git a/src/monitor.c b/src/monitor.c
new file mode 100644
index 0000000..82762a0
--- /dev/null
+++ b/src/monitor.c
@@ -0,0 +1,1014 @@
+/*
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <libmnl/libmnl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+
+#include <libnftnl/table.h>
+#include <libnftnl/trace.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/object.h>
+#include <libnftnl/set.h>
+#include <libnftnl/flowtable.h>
+#include <libnftnl/udata.h>
+#include <libnftnl/ruleset.h>
+#include <libnftnl/common.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter.h>
+
+#include <nftables.h>
+#include <netlink.h>
+#include <mnl.h>
+#include <expression.h>
+#include <statement.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <erec.h>
+#include <iface.h>
+#include <json.h>
+
+enum {
+ NFT_OF_EVENT_ADD,
+ NFT_OF_EVENT_INSERT,
+ NFT_OF_EVENT_DEL,
+ NFT_OF_EVENT_CREATE,
+};
+
+#define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__)
+
+struct nftnl_table *netlink_table_alloc(const struct nlmsghdr *nlh)
+{
+ struct nftnl_table *nlt;
+
+ nlt = nftnl_table_alloc();
+ if (nlt == NULL)
+ memory_allocation_error();
+ if (nftnl_table_nlmsg_parse(nlh, nlt) < 0)
+ netlink_abi_error();
+
+ return nlt;
+}
+
+struct nftnl_chain *netlink_chain_alloc(const struct nlmsghdr *nlh)
+{
+ struct nftnl_chain *nlc;
+
+ nlc = nftnl_chain_alloc();
+ if (nlc == NULL)
+ memory_allocation_error();
+ if (nftnl_chain_nlmsg_parse(nlh, nlc) < 0)
+ netlink_abi_error();
+
+ return nlc;
+}
+
+struct nftnl_set *netlink_set_alloc(const struct nlmsghdr *nlh)
+{
+ struct nftnl_set *nls;
+
+ nls = nftnl_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+ if (nftnl_set_nlmsg_parse(nlh, nls) < 0)
+ netlink_abi_error();
+
+ return nls;
+}
+
+static struct nftnl_set *netlink_setelem_alloc(const struct nlmsghdr *nlh)
+{
+ struct nftnl_set *nls;
+
+ nls = nftnl_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+ if (nftnl_set_elems_nlmsg_parse(nlh, nls) < 0)
+ netlink_abi_error();
+
+ return nls;
+}
+
+struct nftnl_rule *netlink_rule_alloc(const struct nlmsghdr *nlh)
+{
+ struct nftnl_rule *nlr;
+
+ nlr = nftnl_rule_alloc();
+ if (nlr == NULL)
+ memory_allocation_error();
+ if (nftnl_rule_nlmsg_parse(nlh, nlr) < 0)
+ netlink_abi_error();
+
+ return nlr;
+}
+
+struct nftnl_obj *netlink_obj_alloc(const struct nlmsghdr *nlh)
+{
+ struct nftnl_obj *nlo;
+
+ nlo = nftnl_obj_alloc();
+ if (nlo == NULL)
+ memory_allocation_error();
+ if (nftnl_obj_nlmsg_parse(nlh, nlo) < 0)
+ netlink_abi_error();
+
+ return nlo;
+}
+
+static uint32_t netlink_msg2nftnl_of(uint32_t type, uint16_t flags)
+{
+ switch (type) {
+ case NFT_MSG_NEWRULE:
+ if (flags & NLM_F_APPEND)
+ return NFT_OF_EVENT_ADD;
+ else
+ return NFT_OF_EVENT_INSERT;
+ case NFT_MSG_NEWTABLE:
+ case NFT_MSG_NEWCHAIN:
+ case NFT_MSG_NEWSET:
+ case NFT_MSG_NEWSETELEM:
+ case NFT_MSG_NEWOBJ:
+ case NFT_MSG_NEWFLOWTABLE:
+ if (flags & NLM_F_EXCL)
+ return NFT_OF_EVENT_CREATE;
+ else
+ return NFT_OF_EVENT_ADD;
+ case NFT_MSG_DELTABLE:
+ case NFT_MSG_DELCHAIN:
+ case NFT_MSG_DELSET:
+ case NFT_MSG_DELSETELEM:
+ case NFT_MSG_DELRULE:
+ case NFT_MSG_DELOBJ:
+ case NFT_MSG_DELFLOWTABLE:
+ return NFTNL_OF_EVENT_DEL;
+ }
+
+ return 0;
+}
+
+static const char *nftnl_of2cmd(uint32_t of)
+{
+ switch (of) {
+ case NFT_OF_EVENT_ADD:
+ return "add";
+ case NFT_OF_EVENT_CREATE:
+ return "create";
+ case NFT_OF_EVENT_INSERT:
+ return "insert";
+ case NFT_OF_EVENT_DEL:
+ return "delete";
+ default:
+ return "???";
+ }
+}
+
+static const char *netlink_msg2cmd(uint32_t type, uint16_t flags)
+{
+ return nftnl_of2cmd(netlink_msg2nftnl_of(type, flags));
+}
+
+static void nlr_for_each_set(struct nftnl_rule *nlr,
+ void (*cb)(struct set *s, void *data),
+ void *data, struct nft_cache *cache)
+{
+ struct nftnl_expr_iter *nlrei;
+ struct nftnl_expr *nlre;
+ const char *set_name, *table;
+ const char *name;
+ struct set *s;
+ uint32_t family;
+
+ nlrei = nftnl_expr_iter_create(nlr);
+ if (nlrei == NULL)
+ memory_allocation_error();
+
+ family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
+ table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
+
+ nlre = nftnl_expr_iter_next(nlrei);
+ while (nlre != NULL) {
+ name = nftnl_expr_get_str(nlre, NFTNL_EXPR_NAME);
+ if (strcmp(name, "lookup") != 0)
+ goto next;
+
+ set_name = nftnl_expr_get_str(nlre, NFTNL_EXPR_LOOKUP_SET);
+ s = set_lookup_global(family, table, set_name, cache);
+ if (s == NULL)
+ goto next;
+
+ cb(s, data);
+next:
+ nlre = nftnl_expr_iter_next(nlrei);
+ }
+ nftnl_expr_iter_destroy(nlrei);
+}
+
+static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ struct nftnl_table *nlt;
+ struct table *t;
+ const char *cmd;
+
+ nlt = netlink_table_alloc(nlh);
+ t = netlink_delinearize_table(monh->ctx, nlt);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s table ", cmd);
+
+ nft_mon_print(monh, "%s %s", family2str(t->handle.family),
+ t->handle.table.name);
+
+ if (t->flags & TABLE_F_DORMANT)
+ nft_mon_print(monh, " { flags dormant; }");
+
+ if (nft_output_handle(&monh->ctx->nft->output))
+ nft_mon_print(monh, " # handle %" PRIu64 "",
+ t->handle.handle.id);
+ nft_mon_print(monh, "\n");
+ break;
+ case NFTNL_OUTPUT_JSON:
+ monitor_print_table_json(monh, cmd, t);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
+ break;
+ }
+ table_free(t);
+ nftnl_table_free(nlt);
+ return MNL_CB_OK;
+}
+
+static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ struct nftnl_chain *nlc;
+ struct chain *c;
+ const char *cmd;
+
+ nlc = netlink_chain_alloc(nlh);
+ c = netlink_delinearize_chain(monh->ctx, nlc);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s ", cmd);
+
+ switch (type) {
+ case NFT_MSG_NEWCHAIN:
+ chain_print_plain(c, &monh->ctx->nft->output);
+ break;
+ case NFT_MSG_DELCHAIN:
+ if (c->dev_array_len > 0)
+ chain_print_plain(c, &monh->ctx->nft->output);
+ else
+ nft_mon_print(monh, "chain %s %s %s",
+ family2str(c->handle.family),
+ c->handle.table.name,
+ c->handle.chain.name);
+ break;
+ }
+ nft_mon_print(monh, "\n");
+ break;
+ case NFTNL_OUTPUT_JSON:
+ monitor_print_chain_json(monh, cmd, c);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
+ break;
+ }
+ chain_free(c);
+ nftnl_chain_free(nlc);
+ return MNL_CB_OK;
+}
+
+static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ struct nftnl_set *nls;
+ const char *family, *cmd;
+ struct set *set;
+ uint32_t flags;
+
+ nls = netlink_set_alloc(nlh);
+ flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+ if (set_is_anonymous(flags))
+ goto out;
+
+ set = netlink_delinearize_set(monh->ctx, nls);
+ if (set == NULL) {
+ nftnl_set_free(nls);
+ return MNL_CB_ERROR;
+ }
+ family = family2str(set->handle.family);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s ", cmd);
+
+ switch (type) {
+ case NFT_MSG_NEWSET:
+ set_print_plain(set, &monh->ctx->nft->output);
+ break;
+ case NFT_MSG_DELSET:
+ nft_mon_print(monh, "set %s %s %s", family,
+ set->handle.table.name,
+ set->handle.set.name);
+ break;
+ }
+ nft_mon_print(monh, "\n");
+ break;
+ case NFTNL_OUTPUT_JSON:
+ monitor_print_set_json(monh, cmd, set);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
+ break;
+ }
+ set_free(set);
+out:
+ nftnl_set_free(nls);
+ return MNL_CB_OK;
+}
+
+/* returns true if the event should be ignored (i.e. null element) */
+static bool netlink_event_ignore_range_event(struct nftnl_set_elem *nlse)
+{
+ uint32_t flags = 0;
+
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS))
+ flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
+ if (!(flags & NFT_SET_ELEM_INTERVAL_END))
+ return false;
+
+ if (nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_KEY) != 0)
+ return false;
+
+ return true;
+}
+
+static bool set_elem_is_open_interval(struct expr *elem)
+{
+ switch (elem->etype) {
+ case EXPR_SET_ELEM:
+ return elem->elem_flags & NFTNL_SET_ELEM_F_INTERVAL_OPEN;
+ case EXPR_MAPPING:
+ return set_elem_is_open_interval(elem->left);
+ default:
+ return false;
+ }
+}
+
+/* returns true if the we cached the range element */
+static bool netlink_event_range_cache(struct set *cached_set,
+ struct set *dummyset)
+{
+ struct expr *elem;
+
+ /* not an interval ? */
+ if (!(cached_set->flags & NFT_SET_INTERVAL))
+ return false;
+
+ /* if cache exists, dummyset must contain the other end of the range */
+ if (cached_set->rg_cache) {
+ compound_expr_add(dummyset->init, cached_set->rg_cache);
+ cached_set->rg_cache = NULL;
+ goto out_decompose;
+ }
+
+ /* don't cache half-open range elements */
+ elem = list_entry(dummyset->init->expressions.prev, struct expr, list);
+ if (!set_elem_is_open_interval(elem)) {
+ cached_set->rg_cache = expr_clone(elem);
+ return true;
+ }
+
+out_decompose:
+ interval_map_decompose(dummyset->init);
+ return false;
+}
+
+static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ struct nftnl_set_elems_iter *nlsei;
+ struct nftnl_set_elem *nlse;
+ struct nftnl_set *nls;
+ struct set *dummyset;
+ struct set *set;
+ const char *setname, *table, *cmd;
+ uint32_t family;
+
+ nls = netlink_setelem_alloc(nlh);
+ table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
+ setname = nftnl_set_get_str(nls, NFTNL_SET_NAME);
+ family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
+
+ set = set_lookup_global(family, table, setname, &monh->ctx->nft->cache);
+ if (set == NULL) {
+ fprintf(stderr, "W: Received event for an unknown set.\n");
+ goto out;
+ }
+
+ if (set_is_anonymous(set->flags))
+ goto out;
+
+ /* we want to 'delinearize' the set_elem, but don't
+ * modify the original cached set. This path is only
+ * 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);
+
+ nlsei = nftnl_set_elems_iter_create(nls);
+ if (nlsei == NULL)
+ memory_allocation_error();
+
+ nlse = nftnl_set_elems_iter_next(nlsei);
+ while (nlse != NULL) {
+ if (netlink_event_ignore_range_event(nlse)) {
+ set_free(dummyset);
+ nftnl_set_elems_iter_destroy(nlsei);
+ goto out;
+ }
+ if (netlink_delinearize_setelem(nlse, dummyset,
+ &monh->ctx->nft->cache) < 0) {
+ set_free(dummyset);
+ nftnl_set_elems_iter_destroy(nlsei);
+ goto out;
+ }
+ nlse = nftnl_set_elems_iter_next(nlsei);
+ }
+ nftnl_set_elems_iter_destroy(nlsei);
+
+ if (netlink_event_range_cache(set, dummyset)) {
+ set_free(dummyset);
+ goto out;
+ }
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s element %s %s %s ",
+ cmd, family2str(family), table, setname);
+ expr_print(dummyset->init, &monh->ctx->nft->output);
+ nft_mon_print(monh, "\n");
+ break;
+ case NFTNL_OUTPUT_JSON:
+ dummyset->handle.family = family;
+ dummyset->handle.set.name = setname;
+ dummyset->handle.table.name = table;
+ monitor_print_element_json(monh, cmd, dummyset);
+ /* prevent set_free() from trying to free those */
+ dummyset->handle.set.name = NULL;
+ dummyset->handle.table.name = NULL;
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
+ break;
+ }
+ set_free(dummyset);
+out:
+ nftnl_set_free(nls);
+ return MNL_CB_OK;
+}
+
+static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ const char *family, *cmd;
+ struct nftnl_obj *nlo;
+ struct obj *obj;
+
+ nlo = netlink_obj_alloc(nlh);
+
+ obj = netlink_delinearize_obj(monh->ctx, nlo);
+ if (!obj) {
+ nftnl_obj_free(nlo);
+ return MNL_CB_ERROR;
+ }
+ family = family2str(obj->handle.family);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ nft_mon_print(monh, "%s ", cmd);
+
+ switch (type) {
+ case NFT_MSG_NEWOBJ:
+ obj_print_plain(obj, &monh->ctx->nft->output);
+ break;
+ case NFT_MSG_DELOBJ:
+ nft_mon_print(monh, "%s %s %s %s",
+ obj_type_name(obj->type),
+ family,
+ obj->handle.table.name,
+ obj->handle.obj.name);
+ break;
+ }
+ nft_mon_print(monh, "\n");
+ break;
+ case NFTNL_OUTPUT_JSON:
+ monitor_print_obj_json(monh, cmd, obj);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
+ break;
+ }
+ obj_free(obj);
+ nftnl_obj_free(nlo);
+ return MNL_CB_OK;
+}
+
+static void rule_map_decompose_cb(struct set *s, void *data)
+{
+ if (!set_is_anonymous(s->flags))
+ return;
+
+ if (set_is_non_concat_range(s))
+ interval_map_decompose(s->init);
+ else if (set_is_interval(s->flags))
+ concat_range_aggregate(s->init);
+}
+
+static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ const char *family, *cmd;
+ struct nftnl_rule *nlr;
+ struct rule *r;
+
+ 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);
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ family = family2str(r->handle.family);
+
+ nft_mon_print(monh, "%s rule %s %s %s ",
+ cmd,
+ family,
+ r->handle.table.name,
+ r->handle.chain.name);
+ if (r->handle.position.id) {
+ nft_mon_print(monh, "handle %" PRIu64" ",
+ r->handle.position.id);
+ }
+ switch (type) {
+ case NFT_MSG_NEWRULE:
+ rule_print(r, &monh->ctx->nft->output);
+
+ break;
+ case NFT_MSG_DELRULE:
+ nft_mon_print(monh, "handle %" PRIu64,
+ r->handle.handle.id);
+ break;
+ }
+ nft_mon_print(monh, "\n");
+ break;
+ case NFTNL_OUTPUT_JSON:
+ monitor_print_rule_json(monh, cmd, r);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
+ break;
+ }
+ rule_free(r);
+out_free_nlr:
+ nftnl_rule_free(nlr);
+ return MNL_CB_OK;
+}
+
+static void netlink_events_cache_addtable(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh)
+{
+ struct nftnl_table *nlt;
+ struct table *t;
+
+ nlt = netlink_table_alloc(nlh);
+ t = netlink_delinearize_table(monh->ctx, nlt);
+ nftnl_table_free(nlt);
+
+ table_cache_add(t, &monh->ctx->nft->cache);
+}
+
+static void netlink_events_cache_deltable(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh)
+{
+ struct nftnl_table *nlt;
+ struct table *t;
+ struct handle h;
+
+ nlt = netlink_table_alloc(nlh);
+ h.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
+ h.table.name = nftnl_table_get_str(nlt, NFTNL_TABLE_NAME);
+
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ h.table.name, h.family);
+ if (t == NULL)
+ goto out;
+
+ table_cache_del(t);
+ table_free(t);
+out:
+ nftnl_table_free(nlt);
+}
+
+static void netlink_events_cache_addset(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh)
+{
+ struct netlink_ctx set_tmpctx;
+ struct nftnl_set *nls;
+ struct table *t;
+ struct set *s;
+ LIST_HEAD(msgs);
+
+ 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);
+ s = netlink_delinearize_set(&set_tmpctx, nls);
+ if (s == NULL)
+ goto out;
+ s->init = set_expr_alloc(monh->loc, s);
+
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ s->handle.table.name, s->handle.family);
+ if (t == NULL) {
+ fprintf(stderr, "W: Unable to cache set: table not found.\n");
+ set_free(s);
+ goto out;
+ }
+
+ if (nft_output_echo(&monh->ctx->nft->output) &&
+ !set_is_anonymous(s->flags)) {
+ set_free(s);
+ goto out;
+ }
+
+ set_cache_add(s, t);
+out:
+ nftnl_set_free(nls);
+}
+
+static void netlink_events_cache_addsetelem(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh)
+{
+ struct nftnl_set_elems_iter *nlsei;
+ struct nftnl_set_elem *nlse;
+ struct nftnl_set *nls;
+ struct set *set;
+ const char *table, *setname;
+ uint32_t family;
+
+ nls = netlink_setelem_alloc(nlh);
+ family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
+ table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
+ setname = nftnl_set_get_str(nls, NFTNL_SET_NAME);
+
+ set = set_lookup_global(family, table, setname, &monh->ctx->nft->cache);
+ if (set == NULL) {
+ fprintf(stderr,
+ "W: Unable to cache set_elem. Set not found.\n");
+ goto out;
+ }
+
+ if (nft_output_echo(&monh->ctx->nft->output) &&
+ !set_is_anonymous(set->flags))
+ goto out;
+
+ nlsei = nftnl_set_elems_iter_create(nls);
+ if (nlsei == NULL)
+ memory_allocation_error();
+
+ nlse = nftnl_set_elems_iter_next(nlsei);
+ while (nlse != NULL) {
+ if (netlink_delinearize_setelem(nlse, set,
+ &monh->ctx->nft->cache) < 0) {
+ fprintf(stderr,
+ "W: Unable to cache set_elem. "
+ "Delinearize failed.\n");
+ nftnl_set_elems_iter_destroy(nlsei);
+ goto out;
+ }
+ nlse = nftnl_set_elems_iter_next(nlsei);
+ }
+ nftnl_set_elems_iter_destroy(nlsei);
+out:
+ nftnl_set_free(nls);
+}
+
+static void netlink_events_cache_delset_cb(struct set *s,
+ void *data)
+{
+ set_cache_del(s);
+ set_free(s);
+}
+
+static void netlink_events_cache_delsets(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh)
+{
+ struct nftnl_rule *nlr = netlink_rule_alloc(nlh);
+
+ nlr_for_each_set(nlr, netlink_events_cache_delset_cb, NULL,
+ &monh->ctx->nft->cache);
+ nftnl_rule_free(nlr);
+}
+
+static void netlink_events_cache_addobj(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh)
+{
+ struct netlink_ctx obj_tmpctx;
+ struct nftnl_obj *nlo;
+ struct table *t;
+ struct obj *obj;
+ LIST_HEAD(msgs);
+
+ memset(&obj_tmpctx, 0, sizeof(obj_tmpctx));
+ init_list_head(&obj_tmpctx.list);
+ init_list_head(&msgs);
+ obj_tmpctx.msgs = &msgs;
+
+ nlo = netlink_obj_alloc(nlh);
+ obj = netlink_delinearize_obj(&obj_tmpctx, nlo);
+ if (obj == NULL)
+ goto out;
+
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ obj->handle.table.name, obj->handle.family);
+ if (t == NULL) {
+ fprintf(stderr, "W: Unable to cache object: table not found.\n");
+ obj_free(obj);
+ goto out;
+ }
+
+ obj_cache_add(obj, t);
+out:
+ nftnl_obj_free(nlo);
+}
+
+static void netlink_events_cache_delobj(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh)
+{
+ struct nftnl_obj *nlo;
+ const char *name;
+ struct obj *obj;
+ struct handle h;
+ struct table *t;
+ uint32_t type;
+
+ nlo = netlink_obj_alloc(nlh);
+ h.family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
+ h.table.name = nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE);
+
+ name = nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME);
+ type = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE);
+ h.handle.id = nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
+
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ h.table.name, h.family);
+ if (t == NULL) {
+ fprintf(stderr, "W: Unable to cache object: table not found.\n");
+ goto out;
+ }
+
+ obj = obj_cache_find(t, name, type);
+ if (obj == NULL) {
+ fprintf(stderr, "W: Unable to find object in cache\n");
+ goto out;
+ }
+
+ obj_cache_del(obj);
+ obj_free(obj);
+out:
+ nftnl_obj_free(nlo);
+}
+
+static void netlink_events_cache_update(struct netlink_mon_handler *monh,
+ const struct nlmsghdr *nlh, int type)
+{
+ if (nft_output_echo(&monh->ctx->nft->output) &&
+ type != NFT_MSG_NEWSET && type != NFT_MSG_NEWSETELEM)
+ return;
+
+ switch (type) {
+ case NFT_MSG_NEWTABLE:
+ netlink_events_cache_addtable(monh, nlh);
+ break;
+ case NFT_MSG_DELTABLE:
+ netlink_events_cache_deltable(monh, nlh);
+ break;
+ case NFT_MSG_NEWSET:
+ netlink_events_cache_addset(monh, nlh);
+ break;
+ case NFT_MSG_NEWSETELEM:
+ netlink_events_cache_addsetelem(monh, nlh);
+ break;
+ case NFT_MSG_DELRULE:
+ /* there are no notification for anon-set deletion */
+ netlink_events_cache_delsets(monh, nlh);
+ break;
+ case NFT_MSG_NEWOBJ:
+ netlink_events_cache_addobj(monh, nlh);
+ break;
+ case NFT_MSG_DELOBJ:
+ netlink_events_cache_delobj(monh, nlh);
+ break;
+ }
+}
+
+/* only those which could be useful listening to events */
+static const char *const nftnl_msg_types[NFT_MSG_MAX] = {
+ [NFT_MSG_NEWTABLE] = "NFT_MSG_NEWTABLE",
+ [NFT_MSG_DELTABLE] = "NFT_MSG_DELTABLE",
+ [NFT_MSG_NEWCHAIN] = "NFT_MSG_NEWCHAIN",
+ [NFT_MSG_DELCHAIN] = "NFT_MSG_DELCHAIN",
+ [NFT_MSG_NEWSET] = "NFT_MSG_NEWSET",
+ [NFT_MSG_DELSET] = "NFT_MSG_DELSET",
+ [NFT_MSG_NEWSETELEM] = "NFT_MSG_NEWSETELEM",
+ [NFT_MSG_DELSETELEM] = "NFT_MSG_DELSETELEM",
+ [NFT_MSG_NEWRULE] = "NFT_MSG_NEWRULE",
+ [NFT_MSG_DELRULE] = "NFT_MSG_DELRULE",
+ [NFT_MSG_TRACE] = "NFT_MSG_TRACE",
+ [NFT_MSG_NEWGEN] = "NFT_MSG_NEWGEN",
+ [NFT_MSG_NEWOBJ] = "NFT_MSG_NEWOBJ",
+ [NFT_MSG_DELOBJ] = "NFT_MSG_DELOBJ",
+};
+
+static const char *nftnl_msgtype2str(uint16_t type)
+{
+ if (type >= NFT_MSG_MAX || !nftnl_msg_types[type])
+ return "unknown";
+
+ return nftnl_msg_types[type];
+}
+
+static void netlink_events_debug(uint16_t type, unsigned int debug_mask)
+{
+ if (!(debug_mask & NFT_DEBUG_NETLINK))
+ return;
+
+ printf("netlink event: %s\n", nftnl_msgtype2str(type));
+}
+
+static int netlink_events_newgen_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ const struct nlattr *attr;
+ char name[256] = "";
+ int genid = -1, pid = -1;
+
+ if (monh->format != NFTNL_OUTPUT_DEFAULT)
+ return MNL_CB_OK;
+
+ mnl_attr_for_each(attr, nlh, sizeof(struct nfgenmsg)) {
+ switch (mnl_attr_get_type(attr)) {
+ case NFTA_GEN_ID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ break;
+ genid = ntohl(mnl_attr_get_u32(attr));
+ break;
+ case NFTA_GEN_PROC_NAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+ break;
+ snprintf(name, sizeof(name), "%s", mnl_attr_get_str(attr));
+ break;
+ case NFTA_GEN_PROC_PID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ break;
+ pid = ntohl(mnl_attr_get_u32(attr));
+ break;
+ }
+ }
+ if (genid >= 0) {
+ nft_mon_print(monh, "# new generation %d", genid);
+ if (pid >= 0)
+ nft_mon_print(monh, " by process %d (%s)", pid, name);
+
+ nft_mon_print(monh, "\n");
+ }
+
+ return MNL_CB_OK;
+}
+
+static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
+{
+ int ret = MNL_CB_OK;
+ uint16_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
+ struct netlink_mon_handler *monh = (struct netlink_mon_handler *)data;
+
+ netlink_events_debug(type, monh->ctx->nft->debug_mask);
+ netlink_events_cache_update(monh, nlh, type);
+
+ if (!(monh->monitor_flags & (1 << type)))
+ return ret;
+
+ switch (type) {
+ case NFT_MSG_NEWTABLE:
+ case NFT_MSG_DELTABLE:
+ ret = netlink_events_table_cb(nlh, type, monh);
+ break;
+ case NFT_MSG_NEWCHAIN:
+ case NFT_MSG_DELCHAIN:
+ ret = netlink_events_chain_cb(nlh, type, monh);
+ break;
+ case NFT_MSG_NEWSET:
+ case NFT_MSG_DELSET: /* nft {add|delete} set */
+ ret = netlink_events_set_cb(nlh, type, monh);
+ break;
+ case NFT_MSG_NEWSETELEM:
+ case NFT_MSG_DELSETELEM: /* nft {add|delete} element */
+ ret = netlink_events_setelem_cb(nlh, type, monh);
+ break;
+ case NFT_MSG_NEWRULE:
+ case NFT_MSG_DELRULE:
+ ret = netlink_events_rule_cb(nlh, type, monh);
+ break;
+ case NFT_MSG_TRACE:
+ ret = netlink_events_trace_cb(nlh, type, monh);
+ break;
+ case NFT_MSG_NEWOBJ:
+ case NFT_MSG_DELOBJ:
+ ret = netlink_events_obj_cb(nlh, type, monh);
+ break;
+ case NFT_MSG_NEWGEN:
+ ret = netlink_events_newgen_cb(nlh, type, monh);
+ break;
+ }
+
+ return ret;
+}
+
+int netlink_echo_callback(const struct nlmsghdr *nlh, void *data)
+{
+ struct netlink_cb_data *nl_cb_data = data;
+ struct netlink_ctx *ctx = nl_cb_data->nl_ctx;
+ struct nft_ctx *nft = ctx->nft;
+
+ struct netlink_mon_handler echo_monh = {
+ .format = NFTNL_OUTPUT_DEFAULT,
+ .ctx = ctx,
+ .loc = &netlink_location,
+ .monitor_flags = 0xffffffff,
+ };
+
+ if (!nft_output_echo(&echo_monh.ctx->nft->output))
+ return MNL_CB_OK;
+
+ if (nft_output_json(&nft->output)) {
+ if (nft->json_root)
+ return json_events_cb(nlh, &echo_monh);
+ if (!nft->json_echo)
+ json_alloc_echo(nft);
+ echo_monh.format = NFTNL_OUTPUT_JSON;
+ }
+
+ return netlink_events_cb(nlh, &echo_monh);
+}
+
+int netlink_monitor(struct netlink_mon_handler *monhandler,
+ struct mnl_socket *nf_sock)
+{
+ int group;
+
+ if (monhandler->monitor_flags & (1 << NFT_MSG_TRACE)) {
+ group = NFNLGRP_NFTRACE;
+ if (mnl_socket_setsockopt(nf_sock, NETLINK_ADD_MEMBERSHIP,
+ &group, sizeof(int)) < 0)
+ return -1;
+ }
+ if (monhandler->monitor_flags & ~(1 << NFT_MSG_TRACE)) {
+ group = NFNLGRP_NFTABLES;
+ if (mnl_socket_setsockopt(nf_sock, NETLINK_ADD_MEMBERSHIP,
+ &group, sizeof(int)) < 0)
+ return -1;
+ }
+
+ return mnl_nft_event_listener(nf_sock, monhandler->ctx->nft->debug_mask,
+ &monhandler->ctx->nft->output,
+ netlink_events_cb, monhandler);
+}
diff --git a/src/netlink.c b/src/netlink.c
new file mode 100644
index 0000000..120a8ba
--- /dev/null
+++ b/src/netlink.c
@@ -0,0 +1,2240 @@
+/*
+ * Copyright (c) 2008-2012 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2013 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.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <errno.h>
+#include <libmnl/libmnl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+
+#include <libnftnl/table.h>
+#include <libnftnl/trace.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/object.h>
+#include <libnftnl/set.h>
+#include <libnftnl/flowtable.h>
+#include <libnftnl/udata.h>
+#include <libnftnl/ruleset.h>
+#include <libnftnl/common.h>
+#include <libnftnl/udata.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter.h>
+
+#include <nftables.h>
+#include <parser.h>
+#include <netlink.h>
+#include <mnl.h>
+#include <expression.h>
+#include <statement.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <erec.h>
+#include <iface.h>
+
+#define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__)
+
+const struct input_descriptor indesc_netlink = {
+ .name = "netlink",
+ .type = INDESC_NETLINK,
+};
+
+const struct location netlink_location = {
+ .indesc = &indesc_netlink,
+};
+
+void __noreturn __netlink_abi_error(const char *file, int line,
+ const char *reason)
+{
+ fprintf(stderr, "E: Contact urgently your Linux kernel vendor. "
+ "Netlink ABI is broken: %s:%d %s\n", file, line, reason);
+ abort();
+}
+
+int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ if (loc == NULL)
+ loc = &netlink_location;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, loc, fmt, ap);
+ va_end(ap);
+ erec_queue(erec, ctx->msgs);
+ return -1;
+}
+
+void __noreturn __netlink_init_error(const char *filename, int line,
+ const char *reason)
+{
+ fprintf(stderr, "%s:%d: Unable to initialize Netlink socket: %s\n",
+ filename, line, reason);
+ exit(NFT_EXIT_NONL);
+}
+
+struct nftnl_expr *alloc_nft_expr(const char *name)
+{
+ struct nftnl_expr *nle;
+
+ nle = nftnl_expr_alloc(name);
+ if (nle == NULL)
+ memory_allocation_error();
+
+ return nle;
+}
+static void netlink_gen_key(const struct expr *expr,
+ struct nft_data_linearize *data);
+static void __netlink_gen_data(const struct expr *expr,
+ struct nft_data_linearize *data, bool expand);
+
+struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
+ const struct expr *expr)
+{
+ const struct expr *elem, *data;
+ struct nftnl_set_elem *nlse;
+ struct nft_data_linearize nld;
+ struct nftnl_udata_buf *udbuf = NULL;
+ uint32_t flags = 0;
+ int num_exprs = 0;
+ struct stmt *stmt;
+ struct expr *key;
+
+ nlse = nftnl_set_elem_alloc();
+ if (nlse == NULL)
+ memory_allocation_error();
+
+ data = NULL;
+ if (expr->etype == EXPR_MAPPING) {
+ elem = expr->left;
+ if (!(expr->flags & EXPR_F_INTERVAL_END))
+ data = expr->right;
+ } else {
+ elem = expr;
+ }
+ if (elem->etype != EXPR_SET_ELEM)
+ BUG("Unexpected expression type: got %d\n", elem->etype);
+
+ key = elem->key;
+
+ switch (key->etype) {
+ case EXPR_SET_ELEM_CATCHALL:
+ break;
+ default:
+ if (set->set_flags & NFT_SET_INTERVAL &&
+ key->etype == EXPR_CONCAT && key->field_count > 1) {
+ key->flags |= EXPR_F_INTERVAL;
+ netlink_gen_key(key, &nld);
+ key->flags &= ~EXPR_F_INTERVAL;
+
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
+
+ key->flags |= EXPR_F_INTERVAL_END;
+ netlink_gen_key(key, &nld);
+ key->flags &= ~EXPR_F_INTERVAL_END;
+
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY_END,
+ &nld.value, nld.len);
+ } else {
+ netlink_gen_key(key, &nld);
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
+ }
+ break;
+ }
+
+ if (elem->timeout)
+ nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_TIMEOUT,
+ elem->timeout);
+ if (elem->expiration)
+ nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_EXPIRATION,
+ elem->expiration);
+ list_for_each_entry(stmt, &elem->stmt_list, list)
+ num_exprs++;
+
+ if (num_exprs == 1) {
+ list_for_each_entry(stmt, &elem->stmt_list, list) {
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_EXPR,
+ netlink_gen_stmt_stateful(stmt), 0);
+ }
+ } else if (num_exprs > 1) {
+ list_for_each_entry(stmt, &elem->stmt_list, list) {
+ nftnl_set_elem_add_expr(nlse,
+ netlink_gen_stmt_stateful(stmt));
+ }
+ }
+ if (elem->comment || expr->elem_flags) {
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ }
+ if (elem->comment) {
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_SET_ELEM_COMMENT,
+ elem->comment))
+ memory_allocation_error();
+ }
+ if (expr->elem_flags) {
+ if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_ELEM_FLAGS,
+ expr->elem_flags))
+ memory_allocation_error();
+ }
+ if (udbuf) {
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_USERDATA,
+ nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
+ }
+ if (set_is_datamap(set->set_flags) && data != NULL) {
+ __netlink_gen_data(data, &nld, !(data->flags & EXPR_F_SINGLETON));
+ switch (data->etype) {
+ case EXPR_VERDICT:
+ nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_VERDICT,
+ data->verdict);
+ if (data->chain != NULL)
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_CHAIN,
+ nld.chain, strlen(nld.chain));
+ break;
+ case EXPR_CONCAT:
+ assert(nld.len > 0);
+ /* fallthrough */
+ case EXPR_VALUE:
+ case EXPR_RANGE:
+ case EXPR_PREFIX:
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_DATA,
+ nld.value, nld.len);
+ break;
+ default:
+ BUG("unexpected set element expression\n");
+ break;
+ }
+ }
+ if (set_is_objmap(set->set_flags) && data != NULL) {
+ netlink_gen_data(data, &nld);
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_OBJREF,
+ nld.value, nld.len);
+ }
+
+ if (expr->flags & EXPR_F_INTERVAL_END)
+ flags |= NFT_SET_ELEM_INTERVAL_END;
+ if (key->etype == EXPR_SET_ELEM_CATCHALL)
+ flags |= NFT_SET_ELEM_CATCHALL;
+
+ if (flags)
+ nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS, flags);
+
+ return nlse;
+}
+
+void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
+ unsigned int len, struct nft_data_linearize *data)
+{
+ assert(len > 0);
+ mpz_export_data(data->value, value, byteorder, len);
+ data->len = len;
+}
+
+static int netlink_export_pad(unsigned char *data, const mpz_t v,
+ const struct expr *i)
+{
+ mpz_export_data(data, v, i->byteorder,
+ div_round_up(i->len, BITS_PER_BYTE));
+
+ return netlink_padded_len(i->len) / BITS_PER_BYTE;
+}
+
+static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i,
+ unsigned char *data)
+{
+ struct expr *expr;
+
+ switch (i->etype) {
+ case EXPR_RANGE:
+ if (flags & EXPR_F_INTERVAL_END)
+ expr = i->right;
+ else
+ expr = i->left;
+
+ if (expr_basetype(expr)->type == TYPE_INTEGER &&
+ expr->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+ i = expr;
+ break;
+ case EXPR_PREFIX:
+ if (flags & EXPR_F_INTERVAL_END) {
+ int count;
+ mpz_t v;
+
+ mpz_init_bitmask(v, i->len - i->prefix_len);
+
+ if (i->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(v, i->len / BITS_PER_BYTE);
+
+ mpz_add(v, i->prefix->value, v);
+ count = netlink_export_pad(data, v, i);
+ mpz_clear(v);
+ return count;
+ }
+ return netlink_export_pad(data, i->prefix->value, i);
+ case EXPR_VALUE:
+ /* Switch byteorder only once for singleton values when the set
+ * contains concatenation of intervals.
+ */
+ if (!(flags & EXPR_F_INTERVAL))
+ break;
+
+ expr = (struct expr *)i;
+ if (expr_basetype(expr)->type == TYPE_INTEGER &&
+ expr->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+ 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_key(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = expr->len / BITS_PER_BYTE, offset = 0;
+ unsigned char data[len];
+ const struct expr *i;
+
+ memset(data, 0, len);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += __netlink_gen_concat_key(expr->flags, i, data + offset);
+
+ memcpy(nld->value, data, len);
+ nld->len = len;
+}
+
+static int __netlink_gen_concat_data(int end, const struct expr *i,
+ unsigned char *data)
+{
+ switch (i->etype) {
+ case EXPR_RANGE:
+ i = end ? i->right : i->left;
+ break;
+ case EXPR_PREFIX:
+ if (end) {
+ int count;
+ mpz_t v;
+
+ mpz_init_bitmask(v, i->len - i->prefix_len);
+ mpz_add(v, i->prefix->value, v);
+ count = netlink_export_pad(data, v, i);
+ mpz_clear(v);
+ return count;
+ }
+ return netlink_export_pad(data, i->prefix->value, i);
+ case EXPR_VALUE:
+ break;
+ default:
+ BUG("invalid expression type '%s' in set", expr_ops(i)->name);
+ }
+
+ return netlink_export_pad(data, i->value, i);
+}
+
+static void __netlink_gen_concat_expand(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2, offset = 0;
+ unsigned char data[len];
+ const struct expr *i;
+
+ memset(data, 0, len);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += __netlink_gen_concat_data(false, i, data + offset);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += __netlink_gen_concat_data(true, i, data + offset);
+
+ memcpy(nld->value, data, len);
+ nld->len = 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);
+
+ memcpy(nld->value, data, len);
+ nld->len = len;
+}
+
+static void netlink_gen_concat_data(const struct expr *expr,
+ struct nft_data_linearize *nld, bool expand)
+{
+ if (expand)
+ __netlink_gen_concat_expand(expr, nld);
+ else
+ __netlink_gen_concat(expr, nld);
+}
+
+static void netlink_gen_constant_data(const struct expr *expr,
+ struct nft_data_linearize *data)
+{
+ assert(expr->etype == EXPR_VALUE);
+ netlink_gen_raw_data(expr->value, expr->byteorder,
+ div_round_up(expr->len, BITS_PER_BYTE), data);
+}
+
+static void netlink_gen_chain(const struct expr *expr,
+ struct nft_data_linearize *data)
+{
+ char chain[NFT_CHAIN_MAXNAMELEN];
+ unsigned int len;
+
+ len = expr->chain->len / BITS_PER_BYTE;
+
+ if (!len)
+ BUG("chain length is 0");
+
+ if (len > sizeof(chain))
+ BUG("chain is too large (%u, %u max)",
+ len, (unsigned int)sizeof(chain));
+
+ memset(chain, 0, sizeof(chain));
+
+ mpz_export_data(chain, expr->chain->value,
+ BYTEORDER_HOST_ENDIAN, len);
+ snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", chain);
+}
+
+static void netlink_gen_verdict(const struct expr *expr,
+ struct nft_data_linearize *data)
+{
+
+ data->verdict = expr->verdict;
+
+ switch (expr->verdict) {
+ case NFT_JUMP:
+ case NFT_GOTO:
+ if (expr->chain)
+ netlink_gen_chain(expr, data);
+ else
+ data->chain_id = expr->chain_id;
+ break;
+ }
+}
+
+static void netlink_gen_range(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = div_round_up(expr->left->len, BITS_PER_BYTE) * 2;
+ unsigned char data[len];
+ unsigned int offset = 0;
+
+ memset(data, 0, len);
+ offset = netlink_export_pad(data, expr->left->value, expr->left);
+ netlink_export_pad(data + offset, expr->right->value, expr->right);
+ memcpy(nld->value, data, len);
+ nld->len = 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];
+ int offset;
+ mpz_t v;
+
+ 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;
+}
+
+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));
+ }
+}
+
+static void __netlink_gen_data(const struct expr *expr,
+ struct nft_data_linearize *data, bool expand)
+{
+ switch (expr->etype) {
+ case EXPR_VALUE:
+ return netlink_gen_constant_data(expr, data);
+ case EXPR_CONCAT:
+ return netlink_gen_concat_data(expr, data, expand);
+ case EXPR_VERDICT:
+ return netlink_gen_verdict(expr, data);
+ case EXPR_RANGE:
+ return netlink_gen_range(expr, data);
+ case EXPR_PREFIX:
+ return netlink_gen_prefix(expr, data);
+ default:
+ BUG("invalid data expression type %s\n", expr_name(expr));
+ }
+}
+
+void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data)
+{
+ __netlink_gen_data(expr, data, false);
+}
+
+struct expr *netlink_alloc_value(const struct location *loc,
+ const struct nft_data_delinearize *nld)
+{
+ return constant_expr_alloc(loc, &invalid_type, BYTEORDER_INVALID,
+ nld->len * BITS_PER_BYTE, nld->value);
+}
+
+static struct expr *netlink_alloc_verdict(const struct location *loc,
+ const struct nft_data_delinearize *nld)
+{
+ struct expr *chain;
+
+ switch (nld->verdict) {
+ case NFT_JUMP:
+ case NFT_GOTO:
+ chain = constant_expr_alloc(loc, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(nld->chain) * BITS_PER_BYTE,
+ nld->chain);
+ break;
+ default:
+ chain = NULL;
+ break;
+ }
+
+ return verdict_expr_alloc(loc, nld->verdict, chain);
+}
+
+struct expr *netlink_alloc_data(const struct location *loc,
+ const struct nft_data_delinearize *nld,
+ enum nft_registers dreg)
+{
+ switch (dreg) {
+ case NFT_REG_VERDICT:
+ return netlink_alloc_verdict(loc, nld);
+ default:
+ return netlink_alloc_value(loc, nld);
+ }
+}
+
+void netlink_dump_rule(const struct nftnl_rule *nlr, struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ nftnl_rule_fprintf(fp, nlr, 0, 0);
+ fprintf(fp, "\n");
+}
+
+void netlink_dump_expr(const struct nftnl_expr *nle,
+ FILE *fp, unsigned int debug_mask)
+{
+ if (!(debug_mask & NFT_DEBUG_NETLINK))
+ return;
+
+ nftnl_expr_fprintf(fp, nle, 0, 0);
+ fprintf(fp, "\n");
+}
+
+void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ nftnl_chain_fprintf(fp, nlc, 0, 0);
+ fprintf(fp, "\n");
+}
+
+static int chain_parse_udata_cb(const struct nftnl_udata *attr, void *data)
+{
+ unsigned char *value = nftnl_udata_get(attr);
+ uint8_t type = nftnl_udata_type(attr);
+ const struct nftnl_udata **tb = data;
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_CHAIN_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+static int qsort_device_cmp(const void *a, const void *b)
+{
+ const char **x = (const char **)a;
+ const char **y = (const char **)b;
+
+ return strcmp(*x, *y);
+}
+
+struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
+ const struct nftnl_chain *nlc)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_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();
+ chain->handle.family =
+ nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
+ chain->handle.table.name =
+ xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE));
+ chain->handle.chain.name =
+ xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
+ chain->handle.handle.id =
+ nftnl_chain_get_u64(nlc, NFTNL_CHAIN_HANDLE);
+ if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_FLAGS))
+ chain->flags = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FLAGS);
+
+ if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_HOOKNUM) &&
+ nftnl_chain_is_set(nlc, NFTNL_CHAIN_PRIO) &&
+ nftnl_chain_is_set(nlc, NFTNL_CHAIN_TYPE) &&
+ nftnl_chain_is_set(nlc, NFTNL_CHAIN_POLICY)) {
+ chain->hook.num =
+ nftnl_chain_get_u32(nlc, NFTNL_CHAIN_HOOKNUM);
+ chain->hook.name =
+ hooknum2str(chain->handle.family, chain->hook.num);
+ priority = nftnl_chain_get_s32(nlc, NFTNL_CHAIN_PRIO);
+ chain->priority.expr =
+ constant_expr_alloc(&netlink_location,
+ &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE,
+ &priority);
+ chain->type.str =
+ xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TYPE));
+ policy = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
+ chain->policy = constant_expr_alloc(&netlink_location,
+ &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE,
+ &policy);
+ nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
+ if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) {
+ chain->dev_array = xmalloc(sizeof(char *) * 2);
+ chain->dev_array_len = 1;
+ chain->dev_array[0] =
+ xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_DEV));
+ chain->dev_array[1] = NULL;
+ } else if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEVICES)) {
+ dev_array = nftnl_chain_get(nlc, NFTNL_CHAIN_DEVICES);
+ while (dev_array[len])
+ len++;
+
+ chain->dev_array = xmalloc((len + 1)* sizeof(char *));
+ for (i = 0; i < len; i++)
+ chain->dev_array[i] = xstrdup(dev_array[i]);
+
+ chain->dev_array[i] = NULL;
+ chain->dev_array_len = len;
+ }
+ chain->flags |= CHAIN_F_BASECHAIN;
+
+ if (chain->dev_array_len) {
+ qsort(chain->dev_array, chain->dev_array_len,
+ sizeof(char *), qsort_device_cmp);
+ }
+ }
+
+ if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_USERDATA)) {
+ udata = nftnl_chain_get_data(nlc, NFTNL_CHAIN_USERDATA, &ulen);
+ if (nftnl_udata_parse(udata, ulen, chain_parse_udata_cb, ud) < 0) {
+ netlink_io_error(ctx, NULL, "Cannot parse userdata");
+ chain_free(chain);
+ return NULL;
+ }
+ if (ud[NFTNL_UDATA_CHAIN_COMMENT])
+ chain->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_CHAIN_COMMENT]));
+ }
+
+ return chain;
+}
+
+static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data)
+{
+ unsigned char *value = nftnl_udata_get(attr);
+ const struct nftnl_udata **tb = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_TABLE_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+struct table *netlink_delinearize_table(struct netlink_ctx *ctx,
+ const struct nftnl_table *nlt)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_TABLE_MAX + 1] = {};
+ struct table *table;
+ const char *udata;
+ uint32_t ulen;
+
+ table = table_alloc();
+ table->handle.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
+ table->handle.table.name = xstrdup(nftnl_table_get_str(nlt, NFTNL_TABLE_NAME));
+ table->flags = nftnl_table_get_u32(nlt, NFTNL_TABLE_FLAGS);
+ table->handle.handle.id = nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE);
+ table->owner = nftnl_table_get_u32(nlt, NFTNL_TABLE_OWNER);
+
+ if (nftnl_table_is_set(nlt, NFTNL_TABLE_USERDATA)) {
+ udata = nftnl_table_get_data(nlt, NFTNL_TABLE_USERDATA, &ulen);
+ if (nftnl_udata_parse(udata, ulen, table_parse_udata_cb, ud) < 0) {
+ netlink_io_error(ctx, NULL, "Cannot parse userdata");
+ table_free(table);
+ return NULL;
+ }
+ if (ud[NFTNL_UDATA_TABLE_COMMENT])
+ table->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_TABLE_COMMENT]));
+ }
+
+ return table;
+}
+
+static int list_table_cb(struct nftnl_table *nlt, void *arg)
+{
+ struct netlink_ctx *ctx = arg;
+ struct table *table;
+
+ table = netlink_delinearize_table(ctx, nlt);
+ list_add_tail(&table->list, &ctx->list);
+
+ return 0;
+}
+
+int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter)
+{
+ struct nftnl_table_list *table_cache;
+ uint32_t family = h->family;
+ const char *table = NULL;
+
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ }
+
+ table_cache = mnl_nft_table_dump(ctx, family, table);
+ if (table_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return -1;
+ }
+
+ ctx->data = h;
+ nftnl_table_list_foreach(table_cache, list_table_cb, ctx);
+ nftnl_table_list_free(table_cache);
+ return 0;
+}
+
+enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
+{
+ switch (dtype->type) {
+ case TYPE_VERDICT:
+ return NFT_DATA_VERDICT;
+ default:
+ return dtype->type;
+ }
+}
+
+static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
+{
+ /* The function always returns ownership of a reference. But for
+ * &verdict_Type and datatype_lookup(), those are static instances,
+ * we can omit the datatype_get() call.
+ */
+ switch (type) {
+ case NFT_DATA_VERDICT:
+ return &verdict_type;
+ default:
+ if (type & ~TYPE_MASK)
+ return concat_type_alloc(type);
+ return datatype_lookup((enum datatypes) type);
+ }
+}
+
+void netlink_dump_set(const struct nftnl_set *nls, struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ nftnl_set_fprintf(fp, nls, 0, 0);
+ fprintf(fp, "\n");
+}
+
+static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data)
+{
+ unsigned char *value = nftnl_udata_get(attr);
+ const struct nftnl_udata **tb = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_KEYBYTEORDER:
+ case NFTNL_UDATA_SET_DATABYTEORDER:
+ case NFTNL_UDATA_SET_MERGE_ELEMENTS:
+ case NFTNL_UDATA_SET_DATA_INTERVAL:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_KEY_TYPEOF:
+ case NFTNL_UDATA_SET_DATA_TYPEOF:
+ if (len < 3)
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+static int set_key_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **tb = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_TYPEOF_EXPR:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_TYPEOF_DATA:
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+static struct expr *set_make_key(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_TYPEOF_MAX + 1] = {};
+ const struct expr_ops *ops;
+ struct expr *expr;
+ uint32_t etype;
+ int err;
+
+ if (!attr)
+ return NULL;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ set_key_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_SET_TYPEOF_EXPR] ||
+ !ud[NFTNL_UDATA_SET_TYPEOF_DATA])
+ return NULL;
+
+ etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_TYPEOF_EXPR]);
+ ops = expr_ops_by_type_u32(etype);
+ if (!ops)
+ return NULL;
+
+ expr = ops->parse_udata(ud[NFTNL_UDATA_SET_TYPEOF_DATA]);
+ if (!expr)
+ return NULL;
+
+ return expr;
+}
+
+static bool set_udata_key_valid(const struct expr *e, uint32_t len)
+{
+ if (!e)
+ return false;
+
+ return div_round_up(e->len, BITS_PER_BYTE) == len / BITS_PER_BYTE;
+}
+
+struct setelem_parse_ctx {
+ struct set *set;
+ struct nft_cache *cache;
+ struct list_head stmt_list;
+};
+
+static int set_elem_parse_expressions(struct nftnl_expr *e, void *data)
+{
+ struct setelem_parse_ctx *setelem_parse_ctx = data;
+ struct nft_cache *cache = setelem_parse_ctx->cache;
+ struct set *set = setelem_parse_ctx->set;
+ struct stmt *stmt;
+
+ stmt = netlink_parse_set_expr(set, cache, e);
+ list_add_tail(&stmt->list, &setelem_parse_ctx->stmt_list);
+
+ return 0;
+}
+
+struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
+ const struct nftnl_set *nls)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {};
+ enum byteorder keybyteorder = BYTEORDER_INVALID;
+ enum byteorder databyteorder = BYTEORDER_INVALID;
+ struct setelem_parse_ctx set_parse_ctx;
+ const struct datatype *datatype = NULL;
+ const struct datatype *keytype = NULL;
+ const struct datatype *dtype2 = NULL;
+ const struct datatype *dtype = NULL;
+ struct expr *typeof_expr_data = NULL;
+ struct expr *typeof_expr_key = NULL;
+ const char *udata, *comment = NULL;
+ uint32_t flags, key, objtype = 0;
+ uint32_t data_interval = 0;
+ bool automerge = false;
+ struct set *set;
+ uint32_t ulen;
+ uint32_t klen;
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_USERDATA)) {
+ udata = nftnl_set_get_data(nls, NFTNL_SET_USERDATA, &ulen);
+ if (nftnl_udata_parse(udata, ulen, set_parse_udata_cb, ud) < 0) {
+ netlink_io_error(ctx, NULL, "Cannot parse userdata");
+ return NULL;
+ }
+
+#define GET_U32_UDATA(var, attr) \
+ if (ud[attr]) \
+ var = nftnl_udata_get_u32(ud[attr])
+
+ GET_U32_UDATA(keybyteorder, NFTNL_UDATA_SET_KEYBYTEORDER);
+ GET_U32_UDATA(databyteorder, NFTNL_UDATA_SET_DATABYTEORDER);
+ GET_U32_UDATA(automerge, NFTNL_UDATA_SET_MERGE_ELEMENTS);
+ GET_U32_UDATA(data_interval, NFTNL_UDATA_SET_DATA_INTERVAL);
+
+#undef GET_U32_UDATA
+ typeof_expr_key = set_make_key(ud[NFTNL_UDATA_SET_KEY_TYPEOF]);
+ if (ud[NFTNL_UDATA_SET_DATA_TYPEOF])
+ typeof_expr_data = set_make_key(ud[NFTNL_UDATA_SET_DATA_TYPEOF]);
+ if (ud[NFTNL_UDATA_SET_COMMENT])
+ comment = nftnl_udata_get(ud[NFTNL_UDATA_SET_COMMENT]);
+ }
+
+ key = nftnl_set_get_u32(nls, NFTNL_SET_KEY_TYPE);
+ keytype = dtype_map_from_kernel(key);
+ if (keytype == NULL) {
+ netlink_io_error(ctx, NULL, "Unknown data type in set key %u",
+ key);
+ return NULL;
+ }
+
+ flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+ if (set_is_datamap(flags)) {
+ uint32_t data;
+
+ data = nftnl_set_get_u32(nls, NFTNL_SET_DATA_TYPE);
+ datatype = dtype_map_from_kernel(data);
+ if (datatype == NULL) {
+ netlink_io_error(ctx, NULL,
+ "Unknown data type in set key %u",
+ data);
+ set = NULL;
+ goto out;
+ }
+ }
+
+ if (set_is_objmap(flags)) {
+ objtype = nftnl_set_get_u32(nls, NFTNL_SET_OBJ_TYPE);
+ assert(!datatype);
+ datatype = &string_type;
+ }
+
+ set = set_alloc(&netlink_location);
+ set->handle.family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
+ set->handle.table.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_TABLE));
+ set->handle.set.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_NAME));
+ set->automerge = automerge;
+ if (comment)
+ set->comment = xstrdup(comment);
+
+ init_list_head(&set_parse_ctx.stmt_list);
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_EXPR)) {
+ const struct nftnl_expr *nle;
+ struct stmt *stmt;
+
+ nle = nftnl_set_get(nls, NFTNL_SET_EXPR);
+ stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle);
+ list_add_tail(&stmt->list, &set_parse_ctx.stmt_list);
+ } else if (nftnl_set_is_set(nls, NFTNL_SET_EXPRESSIONS)) {
+ set_parse_ctx.cache = &ctx->nft->cache;
+ set_parse_ctx.set = set;
+ nftnl_set_expr_foreach(nls, set_elem_parse_expressions,
+ &set_parse_ctx);
+ }
+ list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list);
+
+ if (datatype) {
+ uint32_t dlen;
+
+ dtype2 = set_datatype_alloc(datatype, databyteorder);
+ klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE;
+
+ dlen = data_interval ? klen / 2 : klen;
+
+ if (set_udata_key_valid(typeof_expr_data, dlen)) {
+ typeof_expr_data->len = klen;
+ set->data = typeof_expr_data;
+ typeof_expr_data = NULL;
+ } else {
+ set->data = constant_expr_alloc(&netlink_location,
+ dtype2,
+ databyteorder, klen,
+ NULL);
+
+ /* Can't use 'typeof' keyword, so discard key too */
+ expr_free(typeof_expr_key);
+ typeof_expr_key = NULL;
+ }
+
+ if (data_interval)
+ set->data->flags |= EXPR_F_INTERVAL;
+ }
+
+ dtype = set_datatype_alloc(keytype, keybyteorder);
+ klen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE;
+
+ if (set_udata_key_valid(typeof_expr_key, klen)) {
+ set->key = typeof_expr_key;
+ typeof_expr_key = NULL;
+ set->key_typeof_valid = true;
+ } else {
+ set->key = constant_expr_alloc(&netlink_location, dtype,
+ keybyteorder, klen,
+ NULL);
+ }
+
+ set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+ set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
+
+ set->objtype = objtype;
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_TIMEOUT))
+ set->timeout = nftnl_set_get_u64(nls, NFTNL_SET_TIMEOUT);
+ if (nftnl_set_is_set(nls, NFTNL_SET_GC_INTERVAL))
+ set->gc_int = nftnl_set_get_u32(nls, NFTNL_SET_GC_INTERVAL);
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_POLICY))
+ set->policy = nftnl_set_get_u32(nls, NFTNL_SET_POLICY);
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_DESC_SIZE))
+ set->desc.size = nftnl_set_get_u32(nls, NFTNL_SET_DESC_SIZE);
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_DESC_CONCAT)) {
+ uint32_t len = NFT_REG32_COUNT;
+ const uint8_t *data;
+
+ data = nftnl_set_get_data(nls, NFTNL_SET_DESC_CONCAT, &len);
+ if (data) {
+ memcpy(set->desc.field_len, data, len);
+ set->desc.field_count = len;
+ }
+ }
+
+out:
+ expr_free(typeof_expr_data);
+ expr_free(typeof_expr_key);
+ datatype_free(datatype);
+ datatype_free(keytype);
+ datatype_free(dtype2);
+ datatype_free(dtype);
+ return set;
+}
+
+void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
+{
+ struct nftnl_set_elem *nlse;
+ const struct expr *expr;
+
+ list_for_each_entry(expr, &set->expressions, list) {
+ nlse = alloc_nftnl_setelem(set, expr);
+ nftnl_set_elem_add(nls, nlse);
+ }
+}
+
+static bool range_expr_is_prefix(const struct expr *range, uint32_t *prefix_len)
+{
+ const struct expr *right = range->right;
+ const struct expr *left = range->left;
+ uint32_t len = left->len;
+ unsigned long n1, n2;
+ uint32_t plen;
+ mpz_t bitmask;
+
+ mpz_init2(bitmask, left->len);
+ mpz_xor(bitmask, left->value, right->value);
+
+ n1 = mpz_scan0(bitmask, 0);
+ if (n1 == ULONG_MAX)
+ goto not_a_prefix;
+
+ n2 = mpz_scan1(bitmask, n1 + 1);
+ if (n2 < len)
+ goto not_a_prefix;
+
+ plen = len - n1;
+
+ if (mpz_scan1(left->value, 0) < len - plen)
+ goto not_a_prefix;
+
+ mpz_clear(bitmask);
+ *prefix_len = plen;
+
+ return true;
+
+not_a_prefix:
+ mpz_clear(bitmask);
+
+ return false;
+}
+
+struct expr *range_expr_to_prefix(struct expr *range)
+{
+ struct expr *prefix;
+ uint32_t prefix_len;
+
+ if (range_expr_is_prefix(range, &prefix_len)) {
+ prefix = prefix_expr_alloc(&range->location,
+ expr_get(range->left),
+ prefix_len);
+ expr_free(range);
+ return prefix;
+ }
+
+ return range;
+}
+
+static struct expr *range_expr_reduce(struct expr *range)
+{
+ struct expr *expr;
+
+ if (!mpz_cmp(range->left->value, range->right->value)) {
+ expr = expr_get(range->left);
+ expr_free(range);
+ return expr;
+ }
+
+ if (range->left->dtype->type != TYPE_IPADDR &&
+ range->left->dtype->type != TYPE_IP6ADDR)
+ return range;
+
+ return range_expr_to_prefix(range);
+}
+
+static struct expr *netlink_parse_interval_elem(const struct set *set,
+ struct expr *expr)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ const struct datatype *dtype = set->data->dtype;
+ struct expr *range, *left, *right;
+ char data[len];
+
+ mpz_export_data(data, expr->value, dtype->byteorder, len);
+ left = constant_expr_alloc(&internal_location, dtype,
+ dtype->byteorder,
+ (len / 2) * BITS_PER_BYTE, &data[0]);
+ right = constant_expr_alloc(&internal_location, dtype,
+ dtype->byteorder,
+ (len / 2) * BITS_PER_BYTE, &data[len / 2]);
+ range = range_expr_alloc(&expr->location, left, right);
+ expr_free(expr);
+
+ return range_expr_to_prefix(range);
+}
+
+static struct expr *concat_elem_expr(const struct set *set, struct expr *key,
+ const struct datatype *dtype,
+ struct expr *data, int *off)
+{
+ const struct datatype *subtype;
+ unsigned int sub_length;
+ struct expr *expr;
+
+ if (key) {
+ (*off)--;
+ sub_length = round_up(key->len, BITS_PER_BYTE);
+
+ expr = constant_expr_splice(data, sub_length);
+ expr->dtype = datatype_get(key->dtype);
+ expr->byteorder = key->byteorder;
+ expr->len = key->len;
+ } else {
+ subtype = concat_subtype_lookup(dtype->type, --(*off));
+ sub_length = round_up(subtype->size, BITS_PER_BYTE);
+ expr = constant_expr_splice(data, sub_length);
+ expr->dtype = subtype;
+ expr->byteorder = subtype->byteorder;
+ }
+
+ if (expr_basetype(expr)->type == TYPE_STRING ||
+ (!(set->flags & NFT_SET_INTERVAL) &&
+ expr->byteorder == BYTEORDER_HOST_ENDIAN))
+ mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+ if (expr->dtype->basetype != NULL &&
+ expr->dtype->basetype->type == TYPE_BITMASK)
+ expr = bitmask_expr_to_binops(expr);
+
+ data->len -= netlink_padding_len(sub_length);
+
+ return expr;
+}
+
+static struct expr *netlink_parse_concat_elem_key(const struct set *set,
+ struct expr *data)
+{
+ const struct datatype *dtype = set->key->dtype;
+ struct expr *concat, *expr, *n = NULL;
+ int off = dtype->subtypes;
+
+ if (set->key->etype == EXPR_CONCAT)
+ n = list_first_entry(&set->key->expressions, struct expr, list);
+
+ concat = concat_expr_alloc(&data->location);
+ while (off > 0) {
+ expr = concat_elem_expr(set, n, dtype, data, &off);
+ compound_expr_add(concat, expr);
+ if (set->key->etype == EXPR_CONCAT)
+ n = list_next_entry(n, list);
+ }
+
+ expr_free(data);
+
+ return concat;
+}
+
+static struct expr *netlink_parse_concat_elem(const struct set *set,
+ struct expr *data)
+{
+ const struct datatype *dtype = set->data->dtype;
+ struct expr *concat, *expr, *left, *range;
+ struct list_head expressions;
+ int off = dtype->subtypes;
+
+ init_list_head(&expressions);
+
+ concat = concat_expr_alloc(&data->location);
+ while (off > 0) {
+ expr = concat_elem_expr(set, NULL, dtype, data, &off);
+ list_add_tail(&expr->list, &expressions);
+ }
+
+ if (set->data->flags & EXPR_F_INTERVAL) {
+ assert(!list_empty(&expressions));
+
+ off = dtype->subtypes;
+
+ while (off > 0) {
+ left = list_first_entry(&expressions, struct expr, list);
+
+ expr = concat_elem_expr(set, NULL, dtype, data, &off);
+ list_del(&left->list);
+
+ range = range_expr_alloc(&data->location, left, expr);
+ range = range_expr_reduce(range);
+ compound_expr_add(concat, range);
+ }
+ assert(list_empty(&expressions));
+ } else {
+ list_splice_tail(&expressions, &concat->expressions);
+ }
+
+ expr_free(data);
+
+ return concat;
+}
+
+static int set_elem_parse_udata_cb(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **tb = data;
+ unsigned char *value = nftnl_udata_get(attr);
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_ELEM_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_ELEM_FLAGS:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+static void set_elem_parse_udata(struct nftnl_set_elem *nlse,
+ struct expr *expr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_ELEM_MAX + 1] = {};
+ const void *data;
+ uint32_t len;
+
+ data = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_USERDATA, &len);
+ if (nftnl_udata_parse(data, len, set_elem_parse_udata_cb, ud))
+ return;
+
+ if (ud[NFTNL_UDATA_SET_ELEM_COMMENT])
+ expr->comment =
+ xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_SET_ELEM_COMMENT]));
+ if (ud[NFTNL_UDATA_SET_ELEM_FLAGS])
+ expr->elem_flags =
+ nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_ELEM_FLAGS]);
+}
+
+int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
+ struct set *set, struct nft_cache *cache)
+{
+ struct setelem_parse_ctx setelem_parse_ctx = {
+ .set = set,
+ .cache = cache,
+ };
+ struct nft_data_delinearize nld;
+ struct expr *expr, *key, *data;
+ uint32_t flags = 0;
+
+ init_list_head(&setelem_parse_ctx.stmt_list);
+
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY))
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY, &nld.len);
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS))
+ flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
+
+key_end:
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY)) {
+ key = netlink_alloc_value(&netlink_location, &nld);
+ datatype_set(key, set->key->dtype);
+ key->byteorder = set->key->byteorder;
+ if (set->key->dtype->subtypes)
+ key = netlink_parse_concat_elem_key(set, key);
+
+ if (!(set->flags & NFT_SET_INTERVAL) &&
+ key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
+
+ if (key->dtype->basetype != NULL &&
+ key->dtype->basetype->type == TYPE_BITMASK)
+ key = bitmask_expr_to_binops(key);
+ } else if (flags & NFT_SET_ELEM_CATCHALL) {
+ key = set_elem_catchall_expr_alloc(&netlink_location);
+ datatype_set(key, set->key->dtype);
+ key->byteorder = set->key->byteorder;
+ key->len = set->key->len;
+ } else {
+ BUG("Unexpected set element with no key\n");
+ }
+
+ expr = set_elem_expr_alloc(&netlink_location, key);
+ expr->flags |= EXPR_F_KERNEL;
+
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT))
+ expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT);
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION))
+ expr->expiration = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_EXPIRATION);
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_USERDATA))
+ set_elem_parse_udata(nlse, expr);
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) {
+ const struct nftnl_expr *nle;
+ struct stmt *stmt;
+
+ nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL);
+ stmt = netlink_parse_set_expr(set, cache, nle);
+ list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list);
+ } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) {
+ nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions,
+ &setelem_parse_ctx);
+ }
+ list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list);
+
+ if (flags & NFT_SET_ELEM_INTERVAL_END) {
+ expr->flags |= EXPR_F_INTERVAL_END;
+ if (mpz_cmp_ui(set->key->value, 0) == 0)
+ set->root = true;
+ }
+
+ if (set_is_datamap(set->flags)) {
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_DATA)) {
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_DATA,
+ &nld.len);
+ } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_CHAIN)) {
+ nld.chain = nftnl_set_elem_get_str(nlse, NFTNL_SET_ELEM_CHAIN);
+ nld.verdict = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_VERDICT);
+ } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_VERDICT)) {
+ nld.verdict = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_VERDICT);
+ } else
+ goto out;
+
+ data = netlink_alloc_data(&netlink_location, &nld,
+ set->data->dtype->type == TYPE_VERDICT ?
+ NFT_REG_VERDICT : NFT_REG_1);
+ datatype_set(data, set->data->dtype);
+ data->byteorder = set->data->byteorder;
+
+ if (set->data->dtype->subtypes) {
+ data = netlink_parse_concat_elem(set, data);
+ } else if (set->data->flags & EXPR_F_INTERVAL)
+ data = netlink_parse_interval_elem(set, data);
+
+ if (data->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
+
+ expr = mapping_expr_alloc(&netlink_location, expr, data);
+ }
+ if (set_is_objmap(set->flags)) {
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_OBJREF)) {
+ nld.value = nftnl_set_elem_get(nlse,
+ NFTNL_SET_ELEM_OBJREF,
+ &nld.len);
+ } else
+ goto out;
+
+ data = netlink_alloc_value(&netlink_location, &nld);
+ data->dtype = &string_type;
+ data->byteorder = BYTEORDER_HOST_ENDIAN;
+ mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
+ expr = mapping_expr_alloc(&netlink_location, expr, data);
+ }
+out:
+ compound_expr_add(set->init, expr);
+
+ if (!(flags & NFT_SET_ELEM_INTERVAL_END) &&
+ nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY_END)) {
+ flags |= NFT_SET_ELEM_INTERVAL_END;
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY_END,
+ &nld.len);
+ goto key_end;
+ }
+
+ return 0;
+}
+
+static int list_setelem_cb(struct nftnl_set_elem *nlse, void *arg)
+{
+ struct netlink_ctx *ctx = arg;
+ return netlink_delinearize_setelem(nlse, ctx->set, &ctx->nft->cache);
+}
+
+static int list_setelem_debug_cb(struct nftnl_set_elem *nlse, void *arg)
+{
+ int r;
+
+ r = list_setelem_cb(nlse, arg);
+ if (r == 0) {
+ struct netlink_ctx *ctx = arg;
+ FILE *fp = ctx->nft->output.output_fp;
+
+ fprintf(fp, "\t");
+ nftnl_set_elem_fprintf(fp, nlse, 0, 0);
+ fprintf(fp, "\n");
+ }
+
+ return r;
+}
+
+static int list_setelements(struct nftnl_set *s, struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (fp && (ctx->nft->debug_mask & NFT_DEBUG_NETLINK)) {
+ const char *table, *name;
+ uint32_t family = nftnl_set_get_u32(s, NFTNL_SET_FAMILY);
+
+ table = nftnl_set_get_str(s, NFTNL_SET_TABLE);
+ name = nftnl_set_get_str(s, NFTNL_SET_NAME);
+
+ fprintf(fp, "%s %s @%s\n", family2str(family), table, name);
+
+ return nftnl_set_elem_foreach(s, list_setelem_debug_cb, ctx);
+ }
+
+ return nftnl_set_elem_foreach(s, list_setelem_cb, ctx);
+}
+
+int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h,
+ struct set *set, bool reset)
+{
+ struct nftnl_set *nls;
+ int err;
+
+ nls = nftnl_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+
+ nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
+ nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
+ nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
+ if (h->handle.id)
+ nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
+
+ err = mnl_nft_setelem_get(ctx, nls, reset);
+ if (err < 0) {
+ nftnl_set_free(nls);
+ if (errno == EINTR)
+ return -1;
+
+ return 0;
+ }
+
+ ctx->set = set;
+ set->init = set_expr_alloc(&internal_location, set);
+ list_setelements(nls, ctx);
+
+ if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
+ concat_range_aggregate(set->init);
+ else if (set->flags & NFT_SET_INTERVAL)
+ interval_map_decompose(set->init);
+ else
+ list_expr_sort(&ctx->set->init->expressions);
+
+ nftnl_set_free(nls);
+ ctx->set = NULL;
+
+ return 0;
+}
+
+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, bool reset)
+{
+ struct nftnl_set *nls, *nls_out = NULL;
+ int err = 0;
+
+ nls = nftnl_set_alloc();
+ if (nls == NULL)
+ memory_allocation_error();
+
+ nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
+ nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
+ nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
+ if (h->handle.id)
+ nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
+
+ alloc_setelem_cache(init, nls);
+
+ netlink_dump_set(nls, ctx);
+
+ nls_out = mnl_nft_setelem_get_one(ctx, nls, reset);
+ if (!nls_out) {
+ nftnl_set_free(nls);
+ return -1;
+ }
+
+ ctx->set = set;
+ set->init = set_expr_alloc(loc, set);
+ list_setelements(nls_out, ctx);
+
+ if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
+ concat_range_aggregate(set->init);
+ else if (set->flags & NFT_SET_INTERVAL)
+ err = get_set_decompose(cache_set, set);
+ else
+ list_expr_sort(&ctx->set->init->expressions);
+
+ nftnl_set_free(nls);
+ nftnl_set_free(nls_out);
+ ctx->set = NULL;
+
+ return err;
+}
+
+void netlink_dump_obj(struct nftnl_obj *nln, struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ nftnl_obj_fprintf(fp, nln, 0, 0);
+ fprintf(fp, "\n");
+}
+
+static int obj_parse_udata_cb(const struct nftnl_udata *attr, void *data)
+{
+ unsigned char *value = nftnl_udata_get(attr);
+ uint8_t type = nftnl_udata_type(attr);
+ const struct nftnl_udata **tb = data;
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_OBJ_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
+ struct nftnl_obj *nlo)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {};
+ const char *udata;
+ struct obj *obj;
+ uint32_t type;
+ uint32_t ulen;
+
+ obj = obj_alloc(&netlink_location);
+ obj->handle.family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
+ obj->handle.table.name =
+ xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE));
+ obj->handle.obj.name =
+ xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME));
+ obj->handle.handle.id =
+ nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_USERDATA)) {
+ udata = nftnl_obj_get_data(nlo, NFTNL_OBJ_USERDATA, &ulen);
+ if (nftnl_udata_parse(udata, ulen, obj_parse_udata_cb, ud) < 0) {
+ netlink_io_error(ctx, NULL, "Cannot parse userdata");
+ obj_free(obj);
+ return NULL;
+ }
+ if (ud[NFTNL_UDATA_OBJ_COMMENT])
+ obj->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_OBJ_COMMENT]));
+ }
+
+ type = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE);
+ switch (type) {
+ case NFT_OBJECT_COUNTER:
+ obj->counter.packets =
+ nftnl_obj_get_u64(nlo, NFTNL_OBJ_CTR_PKTS);
+ obj->counter.bytes =
+ nftnl_obj_get_u64(nlo, NFTNL_OBJ_CTR_BYTES);
+ break;
+ case NFT_OBJECT_QUOTA:
+ obj->quota.bytes =
+ nftnl_obj_get_u64(nlo, NFTNL_OBJ_QUOTA_BYTES);
+ obj->quota.used =
+ nftnl_obj_get_u64(nlo, NFTNL_OBJ_QUOTA_CONSUMED);
+ obj->quota.flags =
+ nftnl_obj_get_u32(nlo, NFTNL_OBJ_QUOTA_FLAGS);
+ break;
+ case NFT_OBJECT_SECMARK:
+ snprintf(obj->secmark.ctx, sizeof(obj->secmark.ctx), "%s",
+ nftnl_obj_get_str(nlo, NFTNL_OBJ_SECMARK_CTX));
+ break;
+ case NFT_OBJECT_CT_HELPER:
+ snprintf(obj->ct_helper.name, sizeof(obj->ct_helper.name), "%s",
+ nftnl_obj_get_str(nlo, NFTNL_OBJ_CT_HELPER_NAME));
+ obj->ct_helper.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO);
+ obj->ct_helper.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO);
+ break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ init_list_head(&obj->ct_timeout.timeout_list);
+ obj->ct_timeout.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO);
+ obj->ct_timeout.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO);
+ memcpy(obj->ct_timeout.timeout,
+ nftnl_obj_get(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY),
+ NFTNL_CTTIMEOUT_ARRAY_MAX * sizeof(uint32_t));
+ break;
+ case NFT_OBJECT_LIMIT:
+ obj->limit.rate =
+ nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_RATE);
+ obj->limit.unit =
+ nftnl_obj_get_u64(nlo, NFTNL_OBJ_LIMIT_UNIT);
+ obj->limit.burst =
+ nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_BURST);
+ obj->limit.type =
+ nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_TYPE);
+ obj->limit.flags =
+ nftnl_obj_get_u32(nlo, NFTNL_OBJ_LIMIT_FLAGS);
+ break;
+ case NFT_OBJECT_CT_EXPECT:
+ obj->ct_expect.l3proto =
+ nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_L3PROTO);
+ obj->ct_expect.l4proto =
+ nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_L4PROTO);
+ obj->ct_expect.dport =
+ nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_EXPECT_DPORT);
+ obj->ct_expect.timeout =
+ nftnl_obj_get_u32(nlo, NFTNL_OBJ_CT_EXPECT_TIMEOUT);
+ obj->ct_expect.size =
+ nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_EXPECT_SIZE);
+ break;
+ case NFT_OBJECT_SYNPROXY:
+ obj->synproxy.mss =
+ nftnl_obj_get_u16(nlo, NFTNL_OBJ_SYNPROXY_MSS);
+ obj->synproxy.wscale =
+ nftnl_obj_get_u8(nlo, NFTNL_OBJ_SYNPROXY_WSCALE);
+ obj->synproxy.flags =
+ nftnl_obj_get_u32(nlo, NFTNL_OBJ_SYNPROXY_FLAGS);
+ break;
+ }
+ obj->type = type;
+
+ return obj;
+}
+
+void netlink_dump_flowtable(struct nftnl_flowtable *flo,
+ struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ nftnl_flowtable_fprintf(fp, flo, 0, 0);
+ fprintf(fp, "\n");
+}
+
+static int list_obj_cb(struct nftnl_obj *nls, void *arg)
+{
+ struct netlink_ctx *ctx = arg;
+ struct obj *obj;
+
+ obj = netlink_delinearize_obj(ctx, nls);
+ if (obj == NULL)
+ return -1;
+ list_add_tail(&obj->list, &ctx->list);
+ return 0;
+}
+
+int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
+ uint32_t type, bool dump)
+{
+ const struct handle *h = &cmd->handle;
+ struct nftnl_obj_list *obj_cache;
+ int err;
+
+ obj_cache = mnl_nft_obj_dump(ctx, h->family,
+ h->table.name, h->obj.name, type, dump, true);
+ if (obj_cache == NULL)
+ return -1;
+
+ err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx);
+ nftnl_obj_list_free(obj_cache);
+ 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)
+{
+ struct flowtable *flowtable;
+ const char * const *dev_array;
+ int len = 0, i, priority;
+
+ flowtable = flowtable_alloc(&netlink_location);
+ flowtable->handle.family =
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FAMILY);
+ flowtable->handle.table.name =
+ xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_TABLE));
+ flowtable->handle.flowtable.name =
+ xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_NAME));
+ flowtable->handle.handle.id =
+ nftnl_flowtable_get_u64(nlo, NFTNL_FLOWTABLE_HANDLE);
+ if (nftnl_flowtable_is_set(nlo, NFTNL_FLOWTABLE_FLAGS))
+ flowtable->flags = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS);
+ dev_array = nftnl_flowtable_get(nlo, NFTNL_FLOWTABLE_DEVICES);
+ while (dev_array[len])
+ len++;
+
+ if (len)
+ flowtable->dev_array = xmalloc(len * sizeof(char *));
+ for (i = 0; i < len; i++)
+ flowtable->dev_array[i] = xstrdup(dev_array[i]);
+
+ flowtable->dev_array_len = len;
+
+ if (flowtable->dev_array_len) {
+ qsort(flowtable->dev_array, flowtable->dev_array_len,
+ sizeof(char *), qsort_device_cmp);
+ }
+
+ priority = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_PRIO);
+ flowtable->priority.expr =
+ constant_expr_alloc(&netlink_location,
+ &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) *
+ BITS_PER_BYTE,
+ &priority);
+ flowtable->hook.num =
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_HOOKNUM);
+ flowtable->flags =
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS);
+
+ return flowtable;
+}
+
+static int list_flowtable_cb(struct nftnl_flowtable *nls, void *arg)
+{
+ struct netlink_ctx *ctx = arg;
+ struct flowtable *flowtable;
+
+ flowtable = netlink_delinearize_flowtable(ctx, nls);
+ if (flowtable == NULL)
+ return -1;
+ list_add_tail(&flowtable->list, &ctx->list);
+ return 0;
+}
+
+int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h)
+{
+ struct nftnl_flowtable_list *flowtable_cache;
+ int err;
+
+ flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family,
+ h->table.name, NULL);
+ if (flowtable_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return 0;
+ }
+
+ err = nftnl_flowtable_list_foreach(flowtable_cache, list_flowtable_cb, ctx);
+ nftnl_flowtable_list_free(flowtable_cache);
+ return err;
+}
+
+static void trace_print_hdr(const struct nftnl_trace *nlt,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "trace id %08x %s ",
+ nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
+ family2str(nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY)));
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_TABLE))
+ nft_print(octx, "%s ",
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE));
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_CHAIN))
+ nft_print(octx, "%s ",
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
+}
+
+static void trace_print_expr(const struct nftnl_trace *nlt, unsigned int attr,
+ struct expr *lhs, struct output_ctx *octx)
+{
+ struct expr *rhs, *rel;
+ const void *data;
+ uint32_t len;
+
+ data = nftnl_trace_get_data(nlt, attr, &len);
+ rhs = constant_expr_alloc(&netlink_location,
+ lhs->dtype, lhs->byteorder,
+ len * BITS_PER_BYTE, data);
+ rel = relational_expr_alloc(&netlink_location, OP_EQ, lhs, rhs);
+
+ expr_print(rel, octx);
+ nft_print(octx, " ");
+ expr_free(rel);
+}
+
+static void trace_print_verdict(const struct nftnl_trace *nlt,
+ struct output_ctx *octx)
+{
+ struct expr *chain_expr = NULL;
+ const char *chain = NULL;
+ unsigned int verdict;
+ struct expr *expr;
+
+ verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT);
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_JUMP_TARGET)) {
+ chain = xstrdup(nftnl_trace_get_str(nlt, NFTNL_TRACE_JUMP_TARGET));
+ chain_expr = constant_expr_alloc(&netlink_location,
+ &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(chain) * BITS_PER_BYTE,
+ chain);
+ }
+ expr = verdict_expr_alloc(&netlink_location, verdict, chain_expr);
+
+ nft_print(octx, "verdict ");
+ expr_print(expr, octx);
+ expr_free(expr);
+}
+
+static void trace_print_policy(const struct nftnl_trace *nlt,
+ struct output_ctx *octx)
+{
+ unsigned int policy;
+ struct expr *expr;
+
+ policy = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY);
+
+ expr = verdict_expr_alloc(&netlink_location, policy, NULL);
+
+ nft_print(octx, "policy ");
+ expr_print(expr, octx);
+ expr_free(expr);
+}
+
+static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt,
+ uint64_t rule_handle,
+ struct nft_cache *cache)
+{
+ struct chain *chain;
+ struct table *table;
+ struct handle h;
+
+ h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
+ h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
+ h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
+
+ if (!h.table.name)
+ return NULL;
+
+ table = table_cache_find(&cache->table_cache, h.table.name, h.family);
+ if (!table)
+ return NULL;
+
+ chain = chain_cache_find(table, h.chain.name);
+ if (!chain)
+ return NULL;
+
+ return rule_lookup(chain, rule_handle);
+}
+
+static void trace_print_rule(const struct nftnl_trace *nlt,
+ struct output_ctx *octx, struct nft_cache *cache)
+{
+ uint64_t rule_handle;
+ struct rule *rule;
+
+ rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE);
+ rule = trace_lookup_rule(nlt, rule_handle, cache);
+
+ trace_print_hdr(nlt, octx);
+
+ if (rule) {
+ nft_print(octx, "rule ");
+ rule_print(rule, octx);
+ } else {
+ nft_print(octx, "unknown rule handle %" PRIu64, rule_handle);
+ }
+
+ nft_print(octx, " (");
+ trace_print_verdict(nlt, octx);
+ nft_print(octx, ")\n");
+}
+
+static void trace_gen_stmts(struct list_head *stmts,
+ struct proto_ctx *ctx, struct payload_dep_ctx *pctx,
+ const struct nftnl_trace *nlt, unsigned int attr,
+ enum proto_bases base)
+{
+ struct list_head unordered = LIST_HEAD_INIT(unordered);
+ struct list_head list;
+ struct expr *rel, *lhs, *rhs, *tmp, *nexpr;
+ struct stmt *stmt;
+ const struct proto_desc *desc;
+ const void *hdr;
+ uint32_t hlen;
+ unsigned int n;
+
+ if (!nftnl_trace_is_set(nlt, attr))
+ return;
+ hdr = nftnl_trace_get_data(nlt, attr, &hlen);
+
+ lhs = payload_expr_alloc(&netlink_location, NULL, 0);
+ payload_init_raw(lhs, base, 0, hlen * BITS_PER_BYTE);
+ rhs = constant_expr_alloc(&netlink_location,
+ &invalid_type, BYTEORDER_INVALID,
+ hlen * BITS_PER_BYTE, hdr);
+
+restart:
+ init_list_head(&list);
+ payload_expr_expand(&list, lhs, ctx);
+ expr_free(lhs);
+
+ desc = NULL;
+ list_for_each_entry_safe(lhs, nexpr, &list, list) {
+ if (desc && desc != ctx->protocol[base].desc) {
+ /* Chained protocols */
+ lhs->payload.offset = 0;
+ if (ctx->protocol[base].desc == NULL)
+ break;
+ goto restart;
+ }
+
+ tmp = constant_expr_splice(rhs, lhs->len);
+ expr_set_type(tmp, lhs->dtype, lhs->byteorder);
+ if (tmp->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(tmp->value, tmp->len / BITS_PER_BYTE);
+
+ /* Skip unknown and filtered expressions */
+ desc = lhs->payload.desc;
+ if (lhs->dtype == &invalid_type ||
+ desc->checksum_key == payload_hdr_field(lhs) ||
+ desc->format.filter & (1 << payload_hdr_field(lhs))) {
+ expr_free(lhs);
+ expr_free(tmp);
+ continue;
+ }
+
+ rel = relational_expr_alloc(&lhs->location, OP_EQ, lhs, tmp);
+ stmt = expr_stmt_alloc(&rel->location, rel);
+ list_add_tail(&stmt->list, &unordered);
+
+ desc = ctx->protocol[base].desc;
+ relational_expr_pctx_update(ctx, rel);
+ }
+
+ expr_free(rhs);
+
+ n = 0;
+next:
+ list_for_each_entry(stmt, &unordered, list) {
+ enum proto_bases b = base;
+
+ rel = stmt->expr;
+ lhs = rel->left;
+
+ /* Move statements to result list in defined order */
+ desc = lhs->payload.desc;
+ if (desc->format.order[n] &&
+ desc->format.order[n] != payload_hdr_field(lhs))
+ continue;
+
+ list_move_tail(&stmt->list, stmts);
+ n++;
+
+ if (payload_is_stacked(desc, rel))
+ b--;
+
+ /* Don't strip 'icmp type' from payload dump. */
+ if (pctx->icmp_type == 0)
+ payload_dependency_kill(pctx, lhs, ctx->family);
+ if (lhs->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(pctx, stmt, b);
+
+ goto next;
+ }
+}
+
+static void trace_print_packet(const struct nftnl_trace *nlt,
+ struct output_ctx *octx)
+{
+ struct list_head stmts = LIST_HEAD_INIT(stmts);
+ const struct proto_desc *ll_desc;
+ struct payload_dep_ctx pctx = {};
+ struct proto_ctx ctx;
+ uint16_t dev_type;
+ uint32_t nfproto;
+ struct stmt *stmt, *next;
+
+ trace_print_hdr(nlt, octx);
+
+ nft_print(octx, "packet: ");
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
+ trace_print_expr(nlt, NFTNL_TRACE_IIF,
+ meta_expr_alloc(&netlink_location,
+ NFT_META_IIF), octx);
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
+ trace_print_expr(nlt, NFTNL_TRACE_OIF,
+ meta_expr_alloc(&netlink_location,
+ NFT_META_OIF), octx);
+
+ 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)) {
+ nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO);
+
+ proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location, NULL);
+ proto_ctx_update(&ctx, PROTO_BASE_NETWORK_HDR, &netlink_location,
+ proto_find_upper(ll_desc, nfproto));
+ }
+ if (ctx.protocol[PROTO_BASE_LL_HDR].desc == NULL &&
+ nftnl_trace_is_set(nlt, NFTNL_TRACE_IIFTYPE)) {
+ dev_type = nftnl_trace_get_u16(nlt, NFTNL_TRACE_IIFTYPE);
+ proto_ctx_update(&ctx, PROTO_BASE_LL_HDR, &netlink_location,
+ proto_dev_desc(dev_type));
+ }
+
+ trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_LL_HEADER,
+ PROTO_BASE_LL_HDR);
+ trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_NETWORK_HEADER,
+ PROTO_BASE_NETWORK_HDR);
+ trace_gen_stmts(&stmts, &ctx, &pctx, nlt, NFTNL_TRACE_TRANSPORT_HEADER,
+ PROTO_BASE_TRANSPORT_HDR);
+
+ list_for_each_entry_safe(stmt, next, &stmts, list) {
+ stmt_print(stmt, octx);
+ nft_print(octx, " ");
+ stmt_free(stmt);
+ }
+ nft_print(octx, "\n");
+}
+
+int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ struct nftnl_trace *nlt;
+
+ assert(type == NFT_MSG_TRACE);
+
+ nlt = nftnl_trace_alloc();
+ if (!nlt)
+ memory_allocation_error();
+
+ if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
+ netlink_abi_error();
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
+ nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
+ trace_print_packet(nlt, &monh->ctx->nft->output);
+
+ switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) {
+ case NFT_TRACETYPE_RULE:
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE))
+ trace_print_rule(nlt, &monh->ctx->nft->output,
+ &monh->ctx->nft->cache);
+ break;
+ case NFT_TRACETYPE_POLICY:
+ trace_print_hdr(nlt, &monh->ctx->nft->output);
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_POLICY)) {
+ trace_print_policy(nlt, &monh->ctx->nft->output);
+ nft_mon_print(monh, " ");
+ }
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK))
+ trace_print_expr(nlt, NFTNL_TRACE_MARK,
+ meta_expr_alloc(&netlink_location,
+ NFT_META_MARK),
+ &monh->ctx->nft->output);
+ nft_mon_print(monh, "\n");
+ break;
+ case NFT_TRACETYPE_RETURN:
+ trace_print_hdr(nlt, &monh->ctx->nft->output);
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_VERDICT)) {
+ trace_print_verdict(nlt, &monh->ctx->nft->output);
+ nft_mon_print(monh, " ");
+ }
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_MARK))
+ trace_print_expr(nlt, NFTNL_TRACE_MARK,
+ meta_expr_alloc(&netlink_location,
+ NFT_META_MARK),
+ &monh->ctx->nft->output);
+ nft_mon_print(monh, "\n");
+ break;
+ }
+
+ nftnl_trace_free(nlt);
+ return MNL_CB_OK;
+}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
new file mode 100644
index 0000000..e214510
--- /dev/null
+++ b/src/netlink_delinearize.c
@@ -0,0 +1,3512 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2013 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.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <limits.h>
+#include <linux/netfilter/nf_tables.h>
+#include <arpa/inet.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter.h>
+#include <net/ethernet.h>
+#include <netlink.h>
+#include <rule.h>
+#include <statement.h>
+#include <expression.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <erec.h>
+#include <sys/socket.h>
+#include <libnftnl/udata.h>
+#include <cache.h>
+#include <xt.h>
+
+struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx)
+{
+ return ctx->dl;
+}
+
+static struct dl_proto_ctx *dl_proto_ctx_outer(struct rule_pp_ctx *ctx)
+{
+ return &ctx->_dl[0];
+}
+
+static int netlink_parse_expr(const struct nftnl_expr *nle,
+ struct netlink_parse_ctx *ctx);
+
+static void __fmtstring(3, 4) netlink_error(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, loc, fmt, ap);
+ va_end(ap);
+ erec_queue(erec, ctx->msgs);
+}
+
+static unsigned int netlink_parse_register(const struct nftnl_expr *nle,
+ unsigned int attr)
+{
+ unsigned int reg;
+
+ reg = nftnl_expr_get_u32(nle, attr);
+ /* Translate 128bit registers to corresponding 32bit registers */
+ if (reg >= NFT_REG_1 && reg <= NFT_REG_4)
+ reg = 1 + (reg - NFT_REG_1) * (NFT_REG_SIZE / NFT_REG32_SIZE);
+ else if (reg >= NFT_REG32_00)
+ reg = 1 + reg - NFT_REG32_00;
+
+ return reg;
+}
+
+static void netlink_set_register(struct netlink_parse_ctx *ctx,
+ enum nft_registers reg,
+ struct expr *expr)
+{
+ if (reg == NFT_REG_VERDICT || reg > MAX_REGS) {
+ netlink_error(ctx, &expr->location,
+ "Invalid destination register %u", reg);
+ expr_free(expr);
+ return;
+ }
+
+ expr_free(ctx->registers[reg]);
+
+ ctx->registers[reg] = expr;
+}
+
+static struct expr *netlink_get_register(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ enum nft_registers reg)
+{
+ struct expr *expr;
+
+ if (reg == NFT_REG_VERDICT || reg > MAX_REGS) {
+ netlink_error(ctx, loc, "Invalid source register %u", reg);
+ return NULL;
+ }
+
+ expr = ctx->registers[reg];
+ if (expr != NULL)
+ expr = expr_clone(expr);
+
+ return expr;
+}
+
+static void netlink_release_registers(struct netlink_parse_ctx *ctx)
+{
+ int i;
+
+ for (i = 0; i <= MAX_REGS; i++)
+ expr_free(ctx->registers[i]);
+}
+
+static struct expr *netlink_parse_concat_expr(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ unsigned int reg,
+ unsigned int len)
+{
+ struct expr *concat, *expr;
+ unsigned int consumed;
+
+ concat = concat_expr_alloc(loc);
+ while (len > 0) {
+ expr = netlink_get_register(ctx, loc, reg);
+ if (expr == NULL) {
+ netlink_error(ctx, loc,
+ "Relational expression size mismatch");
+ goto err;
+ }
+ compound_expr_add(concat, expr);
+
+ consumed = netlink_padded_len(expr->len);
+ assert(consumed > 0);
+ len -= consumed;
+ reg += netlink_register_space(expr->len);
+ }
+ return concat;
+
+err:
+ expr_free(concat);
+ return NULL;
+}
+
+static struct expr *netlink_parse_concat_key(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ unsigned int reg,
+ const struct expr *key)
+{
+ uint32_t type = key->dtype->type;
+ unsigned int n, len = key->len;
+ struct expr *concat, *expr;
+ unsigned int consumed;
+
+ concat = concat_expr_alloc(loc);
+ n = div_round_up(fls(type), TYPE_BITS);
+
+ while (len > 0) {
+ const struct datatype *i;
+
+ expr = netlink_get_register(ctx, loc, reg);
+ if (expr == NULL) {
+ netlink_error(ctx, loc,
+ "Concat expression size mismatch");
+ goto err;
+ }
+
+ if (n > 0 && concat_subtype_id(type, --n)) {
+ i = concat_subtype_lookup(type, n);
+
+ expr_set_type(expr, i, i->byteorder);
+ }
+
+ compound_expr_add(concat, expr);
+
+ consumed = netlink_padded_len(expr->len);
+ assert(consumed > 0);
+ len -= consumed;
+ reg += netlink_register_space(expr->len);
+ }
+
+ return concat;
+
+err:
+ expr_free(concat);
+ return NULL;
+}
+
+static struct expr *netlink_parse_concat_data(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ unsigned int reg,
+ unsigned int len,
+ struct expr *data)
+{
+ struct expr *concat, *expr, *i;
+
+ concat = concat_expr_alloc(loc);
+ while (len > 0) {
+ expr = netlink_get_register(ctx, loc, reg);
+ if (expr == NULL) {
+ netlink_error(ctx, loc,
+ "Relational expression size mismatch");
+ goto err;
+ }
+ i = constant_expr_splice(data, expr->len);
+ data->len -= netlink_padding_len(expr->len);
+ compound_expr_add(concat, i);
+
+ len -= netlink_padded_len(expr->len);
+ reg += netlink_register_space(expr->len);
+ expr_free(expr);
+ }
+ return concat;
+
+err:
+ expr_free(concat);
+ return NULL;
+}
+
+static void netlink_parse_chain_verdict(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ struct expr *expr,
+ enum nft_verdicts verdict)
+{
+ char chain_name[NFT_CHAIN_MAXNAMELEN] = {};
+ struct chain *chain;
+
+ expr_chain_export(expr->chain, chain_name);
+ chain = chain_binding_lookup(ctx->table, chain_name);
+
+ /* Special case: 'nft list chain x y' needs to pull in implicit chains */
+ if (!chain && !strncmp(chain_name, "__chain", strlen("__chain"))) {
+ nft_chain_cache_update(ctx->nlctx, ctx->table, chain_name);
+ chain = chain_binding_lookup(ctx->table, chain_name);
+ }
+
+ if (chain) {
+ ctx->stmt = chain_stmt_alloc(loc, chain, verdict);
+ expr_free(expr);
+ } else {
+ ctx->stmt = verdict_stmt_alloc(loc, expr);
+ }
+}
+
+static void netlink_parse_immediate(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct nft_data_delinearize nld;
+ enum nft_registers dreg;
+ struct expr *expr;
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_VERDICT)) {
+ nld.verdict = nftnl_expr_get_u32(nle, NFTNL_EXPR_IMM_VERDICT);
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_CHAIN)) {
+ nld.chain = nftnl_expr_get(nle, NFTNL_EXPR_IMM_CHAIN,
+ &nld.len);
+ }
+ } else if (nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_DATA)) {
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_IMM_DATA, &nld.len);
+ }
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_IMM_DREG);
+ expr = netlink_alloc_data(loc, &nld, dreg);
+
+ if (dreg == NFT_REG_VERDICT) {
+ switch (expr->verdict) {
+ case NFT_JUMP:
+ netlink_parse_chain_verdict(ctx, loc, expr, NFT_JUMP);
+ break;
+ case NFT_GOTO:
+ netlink_parse_chain_verdict(ctx, loc, expr, NFT_GOTO);
+ break;
+ default:
+ ctx->stmt = verdict_stmt_alloc(loc, expr);
+ break;
+ }
+ } else {
+ netlink_set_register(ctx, dreg, expr);
+ }
+}
+
+static void netlink_parse_xfrm(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers dreg;
+ enum nft_xfrm_keys key;
+ struct expr *expr;
+ uint32_t spnum;
+ uint8_t dir;
+
+ key = nftnl_expr_get_u32(nle, NFTNL_EXPR_XFRM_KEY);
+ dir = nftnl_expr_get_u8(nle, NFTNL_EXPR_XFRM_DIR);
+ spnum = nftnl_expr_get_u32(nle, NFTNL_EXPR_XFRM_SPNUM);
+ expr = xfrm_expr_alloc(loc, dir, spnum, key);
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_XFRM_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static enum ops netlink_parse_range_op(const struct nftnl_expr *nle)
+{
+ switch (nftnl_expr_get_u32(nle, NFTNL_EXPR_RANGE_OP)) {
+ case NFT_RANGE_EQ:
+ return OP_EQ;
+ case NFT_RANGE_NEQ:
+ return OP_NEQ;
+ default:
+ return OP_INVALID;
+ }
+}
+
+static void netlink_parse_range(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct expr *expr, *left, *right, *from, *to;
+ struct nft_data_delinearize nld;
+ enum nft_registers sreg;
+ enum ops op;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_RANGE_SREG);
+ left = netlink_get_register(ctx, loc, sreg);
+ if (left == NULL)
+ return netlink_error(ctx, loc,
+ "Relational expression has no left hand side");
+
+ op = netlink_parse_range_op(nle);
+
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_RANGE_FROM_DATA, &nld.len);
+ from = netlink_alloc_value(loc, &nld);
+
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_RANGE_TO_DATA, &nld.len);
+ to = netlink_alloc_value(loc, &nld);
+
+ right = range_expr_alloc(loc, from, to);
+ expr = relational_expr_alloc(loc, op, left, right);
+ ctx->stmt = expr_stmt_alloc(loc, expr);
+}
+
+static enum ops netlink_parse_cmp_op(const struct nftnl_expr *nle)
+{
+ switch (nftnl_expr_get_u32(nle, NFTNL_EXPR_CMP_OP)) {
+ case NFT_CMP_EQ:
+ return OP_EQ;
+ case NFT_CMP_NEQ:
+ return OP_NEQ;
+ case NFT_CMP_LT:
+ return OP_LT;
+ case NFT_CMP_LTE:
+ return OP_LTE;
+ case NFT_CMP_GT:
+ return OP_GT;
+ case NFT_CMP_GTE:
+ return OP_GTE;
+ default:
+ return OP_INVALID;
+ }
+}
+
+static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct nft_data_delinearize nld;
+ enum nft_registers sreg;
+ struct expr *expr, *left, *right, *tmp;
+ enum ops op;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_CMP_SREG);
+ left = netlink_get_register(ctx, loc, sreg);
+ if (left == NULL)
+ return netlink_error(ctx, loc,
+ "Relational expression has no left "
+ "hand side");
+
+ op = netlink_parse_cmp_op(nle);
+
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_CMP_DATA, &nld.len);
+ right = netlink_alloc_value(loc, &nld);
+
+ if (left->len > right->len &&
+ expr_basetype(left) != &string_type) {
+ mpz_lshift_ui(right->value, left->len - right->len);
+ right = prefix_expr_alloc(loc, right, right->len);
+ right->prefix->len = left->len;
+ } else if (left->len > 0 && left->len < right->len) {
+ expr_free(left);
+ left = netlink_parse_concat_expr(ctx, loc, sreg, right->len);
+ if (left == NULL)
+ goto err_free;
+ tmp = netlink_parse_concat_data(ctx, loc, sreg, right->len, right);
+ if (tmp == NULL)
+ goto err_free;
+ expr_free(right);
+ right = tmp;
+ }
+
+ expr = relational_expr_alloc(loc, op, left, right);
+ ctx->stmt = expr_stmt_alloc(loc, expr);
+ return;
+err_free:
+ expr_free(left);
+ expr_free(right);
+}
+
+static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers sreg, dreg;
+ const char *name;
+ struct expr *expr, *left, *right;
+ struct set *set;
+ uint32_t flag;
+
+ name = nftnl_expr_get_str(nle, NFTNL_EXPR_LOOKUP_SET);
+ set = set_cache_find(ctx->table, name);
+ if (set == NULL)
+ return netlink_error(ctx, loc,
+ "Unknown set '%s' in lookup expression",
+ name);
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_LOOKUP_SREG);
+ left = netlink_get_register(ctx, loc, sreg);
+ if (left == NULL)
+ return netlink_error(ctx, loc,
+ "Lookup expression has no left hand side");
+
+ if (left->len < set->key->len) {
+ expr_free(left);
+ left = netlink_parse_concat_expr(ctx, loc, sreg, set->key->len);
+ if (left == NULL)
+ return;
+ }
+
+ right = set_ref_expr_alloc(loc, set);
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOOKUP_DREG)) {
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_LOOKUP_DREG);
+ expr = map_expr_alloc(loc, left, right);
+ if (dreg != NFT_REG_VERDICT)
+ return netlink_set_register(ctx, dreg, expr);
+ } else {
+ expr = relational_expr_alloc(loc, OP_EQ, left, right);
+ }
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOOKUP_FLAGS)) {
+ flag = nftnl_expr_get_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS);
+ if (flag & NFT_LOOKUP_F_INV)
+ expr->op = OP_NEQ;
+ }
+
+ ctx->stmt = expr_stmt_alloc(loc, expr);
+}
+
+static struct expr *netlink_parse_bitwise_bool(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle,
+ enum nft_registers sreg,
+ struct expr *left)
+
+{
+ struct nft_data_delinearize nld;
+ struct expr *expr, *mask, *xor, *or;
+ mpz_t m, x, o;
+
+ expr = left;
+
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_MASK, &nld.len);
+ mask = netlink_alloc_value(loc, &nld);
+ mpz_init_set(m, mask->value);
+
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_XOR, &nld.len);
+ xor = netlink_alloc_value(loc, &nld);
+ mpz_init_set(x, xor->value);
+
+ mpz_init_set_ui(o, 0);
+ if (mpz_scan0(m, 0) != mask->len || mpz_cmp_ui(x, 0)) {
+ /* o = (m & x) ^ x */
+ mpz_and(o, m, x);
+ mpz_xor(o, o, x);
+ /* x &= m */
+ mpz_and(x, x, m);
+ /* m |= o */
+ mpz_ior(m, m, o);
+ }
+
+ if (left->len > 0 && mpz_scan0(m, 0) >= left->len) {
+ /* mask encompasses the entire value */
+ expr_free(mask);
+ } else {
+ mpz_set(mask->value, m);
+ expr = binop_expr_alloc(loc, OP_AND, expr, mask);
+ expr->len = left->len;
+ }
+
+ if (mpz_cmp_ui(x, 0)) {
+ mpz_set(xor->value, x);
+ expr = binop_expr_alloc(loc, OP_XOR, expr, xor);
+ expr->len = left->len;
+ } else
+ expr_free(xor);
+
+ if (mpz_cmp_ui(o, 0)) {
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_XOR,
+ &nld.len);
+
+ or = netlink_alloc_value(loc, &nld);
+ mpz_set(or->value, o);
+ expr = binop_expr_alloc(loc, OP_OR, expr, or);
+ expr->len = left->len;
+ }
+
+ mpz_clear(m);
+ mpz_clear(x);
+ mpz_clear(o);
+
+ return expr;
+}
+
+static struct expr *netlink_parse_bitwise_shift(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle,
+ enum ops op,
+ enum nft_registers sreg,
+ struct expr *left)
+{
+ struct nft_data_delinearize nld;
+ struct expr *expr, *right;
+
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_DATA, &nld.len);
+ right = netlink_alloc_value(loc, &nld);
+ right->byteorder = BYTEORDER_HOST_ENDIAN;
+
+ expr = binop_expr_alloc(loc, op, left, right);
+ expr->len = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_LEN) * BITS_PER_BYTE;
+
+ return expr;
+}
+
+static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers sreg, dreg;
+ struct expr *expr, *left;
+ enum nft_bitwise_ops op;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_SREG);
+ left = netlink_get_register(ctx, loc, sreg);
+ if (left == NULL)
+ return netlink_error(ctx, loc,
+ "Bitwise expression has no left "
+ "hand side");
+
+ op = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_OP);
+
+ switch (op) {
+ case NFT_BITWISE_BOOL:
+ expr = netlink_parse_bitwise_bool(ctx, loc, nle, sreg,
+ left);
+ break;
+ case NFT_BITWISE_LSHIFT:
+ expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_LSHIFT,
+ sreg, left);
+ break;
+ case NFT_BITWISE_RSHIFT:
+ expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_RSHIFT,
+ sreg, left);
+ break;
+ default:
+ BUG("invalid bitwise operation %u\n", op);
+ }
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_byteorder(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers sreg, dreg;
+ struct expr *expr, *arg;
+ enum ops op;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_BYTEORDER_SREG);
+ arg = netlink_get_register(ctx, loc, sreg);
+ if (arg == NULL)
+ return netlink_error(ctx, loc,
+ "Byteorder expression has no left "
+ "hand side");
+
+ switch (nftnl_expr_get_u32(nle, NFTNL_EXPR_BYTEORDER_OP)) {
+ case NFT_BYTEORDER_NTOH:
+ op = OP_NTOH;
+ break;
+ case NFT_BYTEORDER_HTON:
+ op = OP_HTON;
+ break;
+ default:
+ BUG("invalid byteorder operation %u\n",
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_BYTEORDER_OP));
+ }
+
+ expr = unary_expr_alloc(loc, op, arg);
+ expr->len = arg->len;
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_BYTEORDER_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_payload_expr(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers dreg;
+ uint32_t base, offset, len;
+ 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;
+
+ expr = payload_expr_alloc(loc, NULL, 0);
+ 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)
+{
+ enum nft_registers sreg;
+ uint32_t base, offset, len;
+ struct expr *expr, *val;
+ struct stmt *stmt;
+
+ base = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_BASE) + 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;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_PAYLOAD_SREG);
+ val = netlink_get_register(ctx, loc, sreg);
+ if (val == NULL)
+ return netlink_error(ctx, loc,
+ "payload statement has no expression");
+
+ expr = payload_expr_alloc(loc, NULL, 0);
+ payload_init_raw(expr, base, offset, len);
+
+ stmt = payload_stmt_alloc(loc, expr, val);
+ rule_stmt_append(ctx->rule, stmt);
+}
+
+static void netlink_parse_payload(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_PAYLOAD_DREG))
+ netlink_parse_payload_expr(ctx, loc, nle);
+ else
+ netlink_parse_payload_stmt(ctx, loc, nle);
+}
+
+static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ uint32_t offset, len, flags;
+ enum nft_registers dreg;
+ enum nft_exthdr_op op;
+ uint8_t type;
+ struct expr *expr;
+
+ type = nftnl_expr_get_u8(nle, NFTNL_EXPR_EXTHDR_TYPE);
+ offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET) * BITS_PER_BYTE;
+ len = nftnl_expr_get_u32(nle, NFTNL_EXPR_EXTHDR_LEN) * BITS_PER_BYTE;
+ op = nftnl_expr_get_u32(nle, NFTNL_EXPR_EXTHDR_OP);
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_EXTHDR_FLAGS);
+
+ expr = exthdr_expr_alloc(loc, NULL, 0);
+ exthdr_init_raw(expr, type, offset, len, op, flags);
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_EXTHDR_DREG)) {
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_DREG);
+ netlink_set_register(ctx, dreg, expr);
+ } else if (nftnl_expr_is_set(nle, NFTNL_EXPR_EXTHDR_SREG)) {
+ enum nft_registers sreg;
+ struct stmt *stmt;
+ struct expr *val;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_SREG);
+ val = netlink_get_register(ctx, loc, sreg);
+ if (val == NULL) {
+ expr_free(expr);
+ return netlink_error(ctx, loc,
+ "exthdr statement has no expression");
+ }
+
+ expr_set_type(val, expr->dtype, expr->byteorder);
+
+ stmt = exthdr_stmt_alloc(loc, expr, val);
+ rule_stmt_append(ctx->rule, stmt);
+ } else {
+ struct stmt *stmt = optstrip_stmt_alloc(loc, expr);
+
+ rule_stmt_append(ctx->rule, stmt);
+ }
+}
+
+static void netlink_parse_hash(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers sreg, dreg;
+ struct expr *expr, *hexpr;
+ uint32_t mod, seed, len, offset;
+ enum nft_hash_types type;
+ bool seed_set;
+
+ type = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_TYPE);
+ offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_OFFSET);
+ seed_set = nftnl_expr_is_set(nle, NFTNL_EXPR_HASH_SEED);
+ seed = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_SEED);
+ mod = nftnl_expr_get_u32(nle, NFTNL_EXPR_HASH_MODULUS);
+
+ expr = hash_expr_alloc(loc, mod, seed_set, seed, offset, type);
+
+ if (type != NFT_HASH_SYM) {
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_SREG);
+ hexpr = netlink_get_register(ctx, loc, sreg);
+
+ if (hexpr == NULL) {
+ netlink_error(ctx, loc,
+ "hash statement has no expression");
+ goto out_err;
+ }
+ len = nftnl_expr_get_u32(nle,
+ NFTNL_EXPR_HASH_LEN) * BITS_PER_BYTE;
+ if (hexpr->len < len) {
+ expr_free(hexpr);
+ hexpr = netlink_parse_concat_expr(ctx, loc, sreg, len);
+ if (hexpr == NULL)
+ goto out_err;
+ }
+ expr->hash.expr = hexpr;
+ }
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_HASH_DREG);
+ netlink_set_register(ctx, dreg, expr);
+ return;
+out_err:
+ expr_free(expr);
+}
+
+static void netlink_parse_fib(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers dreg;
+ struct expr *expr;
+ uint32_t flags, result;
+
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_FIB_FLAGS);
+ result = nftnl_expr_get_u32(nle, NFTNL_EXPR_FIB_RESULT);
+
+ expr = fib_expr_alloc(loc, flags, result);
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_FIB_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_meta_expr(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers dreg;
+ uint32_t key;
+ struct expr *expr;
+
+ key = nftnl_expr_get_u32(nle, NFTNL_EXPR_META_KEY);
+ 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);
+}
+
+static void netlink_parse_socket(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers dreg;
+ uint32_t key, level;
+ struct expr * expr;
+
+ key = nftnl_expr_get_u32(nle, NFTNL_EXPR_SOCKET_KEY);
+ level = nftnl_expr_get_u32(nle, NFTNL_EXPR_SOCKET_LEVEL);
+ expr = socket_expr_alloc(loc, key, level);
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_SOCKET_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_osf(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers dreg;
+ struct expr *expr;
+ uint32_t flags;
+ uint8_t ttl;
+
+ ttl = nftnl_expr_get_u8(nle, NFTNL_EXPR_OSF_TTL);
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_OSF_FLAGS);
+ expr = osf_expr_alloc(loc, ttl, flags);
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_OSF_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_meta_stmt(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers sreg;
+ uint32_t key;
+ struct stmt *stmt;
+ struct expr *expr;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_META_SREG);
+ expr = netlink_get_register(ctx, loc, sreg);
+ if (expr == NULL)
+ return netlink_error(ctx, loc,
+ "meta statement has no expression");
+
+ key = nftnl_expr_get_u32(nle, NFTNL_EXPR_META_KEY);
+ stmt = meta_stmt_alloc(loc, key, expr);
+
+ if (stmt->meta.tmpl)
+ expr_set_type(expr, stmt->meta.tmpl->dtype, stmt->meta.tmpl->byteorder);
+
+ ctx->stmt = stmt;
+}
+
+static void netlink_parse_meta(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_META_DREG))
+ netlink_parse_meta_expr(ctx, loc, nle);
+ else
+ netlink_parse_meta_stmt(ctx, loc, nle);
+}
+
+static void netlink_parse_rt(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers dreg;
+ uint32_t key;
+ struct expr *expr;
+
+ key = nftnl_expr_get_u32(nle, NFTNL_EXPR_RT_KEY);
+ expr = rt_expr_alloc(loc, key, false);
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_RT_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_numgen(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ uint32_t type, until, offset;
+ enum nft_registers dreg;
+ struct expr *expr;
+
+ type = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_TYPE);
+ until = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_MODULUS);
+ offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_OFFSET);
+
+ expr = numgen_expr_alloc(loc, type, until, offset);
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_NG_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_notrack(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ ctx->stmt = notrack_stmt_alloc(loc);
+}
+
+static void netlink_parse_flow_offload(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ const char *table_name;
+
+ table_name = xstrdup(nftnl_expr_get_str(nle, NFTNL_EXPR_FLOW_TABLE_NAME));
+ ctx->stmt = flow_offload_stmt_alloc(loc, table_name);
+}
+
+static void netlink_parse_ct_stmt(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers sreg;
+ uint32_t key;
+ struct stmt *stmt;
+ struct expr *expr;
+ int8_t dir = -1;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_CT_SREG);
+ expr = netlink_get_register(ctx, loc, sreg);
+ if (expr == NULL)
+ return netlink_error(ctx, loc,
+ "ct statement has no expression");
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_CT_DIR))
+ dir = nftnl_expr_get_u8(nle, NFTNL_EXPR_CT_DIR);
+
+ key = nftnl_expr_get_u32(nle, NFTNL_EXPR_CT_KEY);
+ stmt = ct_stmt_alloc(loc, key, dir, expr);
+ expr_set_type(expr, stmt->ct.tmpl->dtype, stmt->ct.tmpl->byteorder);
+
+ ctx->stmt = stmt;
+}
+
+static void netlink_parse_ct_expr(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct expr *expr = NULL;
+ enum nft_registers dreg;
+ int8_t dir = -1;
+ uint32_t key;
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_CT_DIR))
+ dir = nftnl_expr_get_u8(nle, NFTNL_EXPR_CT_DIR);
+
+ key = nftnl_expr_get_u32(nle, NFTNL_EXPR_CT_KEY);
+ expr = ct_expr_alloc(loc, key, dir);
+
+ dreg = netlink_parse_register(nle, NFTNL_EXPR_CT_DREG);
+ netlink_set_register(ctx, dreg, expr);
+}
+
+static void netlink_parse_ct(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_CT_DREG))
+ netlink_parse_ct_expr(ctx, loc, nle);
+ else
+ netlink_parse_ct_stmt(ctx, loc, nle);
+}
+
+static void netlink_parse_connlimit(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = connlimit_stmt_alloc(loc);
+ stmt->connlimit.count =
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_CONNLIMIT_COUNT);
+ stmt->connlimit.flags =
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_CONNLIMIT_FLAGS);
+
+ ctx->stmt = stmt;
+}
+
+static void netlink_parse_counter(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = counter_stmt_alloc(loc);
+ stmt->counter.packets = nftnl_expr_get_u64(nle, NFTNL_EXPR_CTR_PACKETS);
+ stmt->counter.bytes = nftnl_expr_get_u64(nle, NFTNL_EXPR_CTR_BYTES);
+
+ 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)
+{
+ struct stmt *stmt;
+ const char *prefix;
+
+ stmt = log_stmt_alloc(loc);
+ prefix = nftnl_expr_get_str(nle, NFTNL_EXPR_LOG_PREFIX);
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_PREFIX)) {
+ stmt->log.prefix = constant_expr_alloc(&internal_location,
+ &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(prefix) + 1) * BITS_PER_BYTE,
+ prefix);
+ stmt->log.flags |= STMT_LOG_PREFIX;
+ }
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_GROUP)) {
+ stmt->log.group = nftnl_expr_get_u16(nle, NFTNL_EXPR_LOG_GROUP);
+ stmt->log.flags |= STMT_LOG_GROUP;
+ }
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_SNAPLEN)) {
+ stmt->log.snaplen =
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_LOG_SNAPLEN);
+ stmt->log.flags |= STMT_LOG_SNAPLEN;
+ }
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_QTHRESHOLD)) {
+ stmt->log.qthreshold =
+ nftnl_expr_get_u16(nle, NFTNL_EXPR_LOG_QTHRESHOLD);
+ stmt->log.flags |= STMT_LOG_QTHRESHOLD;
+ }
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_LEVEL)) {
+ stmt->log.level =
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_LOG_LEVEL);
+ stmt->log.flags |= STMT_LOG_LEVEL;
+ }
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_FLAGS)) {
+ stmt->log.logflags =
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_LOG_FLAGS);
+ }
+
+ ctx->stmt = stmt;
+}
+
+static void netlink_parse_limit(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = limit_stmt_alloc(loc);
+ stmt->limit.rate = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_RATE);
+ stmt->limit.unit = nftnl_expr_get_u64(nle, NFTNL_EXPR_LIMIT_UNIT);
+ stmt->limit.type = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_TYPE);
+ stmt->limit.burst = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_BURST);
+ stmt->limit.flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_LIMIT_FLAGS);
+
+ ctx->stmt = stmt;
+}
+
+static void netlink_parse_quota(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = quota_stmt_alloc(loc);
+ stmt->quota.bytes = nftnl_expr_get_u64(nle, NFTNL_EXPR_QUOTA_BYTES);
+ stmt->quota.used =
+ nftnl_expr_get_u64(nle, NFTNL_EXPR_QUOTA_CONSUMED);
+ stmt->quota.flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_QUOTA_FLAGS);
+
+ ctx->stmt = stmt;
+}
+
+static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *expr)
+{
+ struct stmt *stmt;
+ uint8_t icmp_code;
+
+ stmt = reject_stmt_alloc(loc);
+ stmt->reject.type = nftnl_expr_get_u32(expr, NFTNL_EXPR_REJECT_TYPE);
+ icmp_code = nftnl_expr_get_u8(expr, NFTNL_EXPR_REJECT_CODE);
+ stmt->reject.icmp_code = icmp_code;
+ stmt->reject.expr = constant_expr_alloc(loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN, 8,
+ &icmp_code);
+ ctx->stmt = stmt;
+}
+
+static bool is_nat_addr_map(const struct expr *addr, uint8_t family,
+ struct stmt *stmt)
+{
+ const struct expr *mappings, *data;
+ const struct set *set;
+
+ if (!addr ||
+ expr_ops(addr)->type != EXPR_MAP)
+ return false;
+
+ mappings = addr->right;
+ if (expr_ops(mappings)->type != EXPR_SET_REF)
+ return false;
+
+ set = mappings->set;
+ data = set->data;
+
+ if (!(data->flags & EXPR_F_INTERVAL))
+ return false;
+
+ stmt->nat.family = family;
+
+ /* if we're dealing with an address:address map,
+ * the length will be bit_sizeof(addr) + 32 (one register).
+ */
+ switch (family) {
+ case NFPROTO_IPV4:
+ if (data->len == 32 + 32) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+ return true;
+ } else if (data->len == 32 + 32 + 32 + 32) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL |
+ STMT_NAT_F_CONCAT;
+ return true;
+ }
+ break;
+ case NFPROTO_IPV6:
+ if (data->len == 128 + 128) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+ return true;
+ } else if (data->len == 128 + 32 + 128 + 32) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL |
+ STMT_NAT_F_CONCAT;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool is_nat_proto_map(const struct expr *addr, uint8_t family)
+{
+ const struct expr *mappings, *data;
+ const struct set *set;
+
+ if (!addr ||
+ expr_ops(addr)->type != EXPR_MAP)
+ return false;
+
+ mappings = addr->right;
+ if (expr_ops(mappings)->type != EXPR_SET_REF)
+ return false;
+
+ set = mappings->set;
+ data = set->data;
+
+ /* if we're dealing with an address:inet_service map,
+ * the length will be bit_sizeof(addr) + 32 (one register).
+ */
+ switch (family) {
+ case NFPROTO_IPV4:
+ return data->len == 32 + 32;
+ case NFPROTO_IPV6:
+ return data->len == 128 + 32;
+ }
+
+ return false;
+}
+
+static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+ struct expr *addr, *proto;
+ enum nft_registers reg1, reg2;
+ int family;
+
+ stmt = nat_stmt_alloc(loc,
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_TYPE));
+
+ family = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FAMILY);
+
+ if (ctx->table->handle.family == NFPROTO_INET)
+ stmt->nat.family = family;
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_NAT_FLAGS))
+ stmt->nat.flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FLAGS);
+
+ if (stmt->nat.flags & NF_NAT_RANGE_NETMAP)
+ stmt->nat.type_flags |= STMT_NAT_F_PREFIX;
+
+ addr = NULL;
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN);
+ if (reg1) {
+ addr = netlink_get_register(ctx, loc, reg1);
+ if (addr == NULL) {
+ netlink_error(ctx, loc,
+ "NAT statement has no address expression");
+ goto out_err;
+ }
+
+ if (family == NFPROTO_IPV4)
+ expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN);
+ else
+ expr_set_type(addr, &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN);
+ stmt->nat.addr = addr;
+ }
+
+ if (is_nat_addr_map(addr, family, stmt)) {
+ stmt->nat.family = family;
+ ctx->stmt = stmt;
+ return;
+ }
+
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX);
+ if (reg2 && reg2 != reg1) {
+ addr = netlink_get_register(ctx, loc, reg2);
+ if (addr == NULL) {
+ netlink_error(ctx, loc,
+ "NAT statement has no address expression");
+ goto out_err;
+ }
+
+ if (family == NFPROTO_IPV4)
+ expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN);
+ else
+ expr_set_type(addr, &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN);
+ if (stmt->nat.addr != NULL) {
+ addr = range_expr_alloc(loc, stmt->nat.addr, addr);
+ addr = range_expr_to_prefix(addr);
+ }
+ stmt->nat.addr = addr;
+ }
+
+ if (is_nat_proto_map(addr, family)) {
+ stmt->nat.family = family;
+ stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
+ ctx->stmt = stmt;
+ return;
+ }
+
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN);
+ if (reg1) {
+ proto = netlink_get_register(ctx, loc, reg1);
+ if (proto == NULL) {
+ netlink_error(ctx, loc,
+ "NAT statement has no proto expression");
+ goto out_err;
+ }
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ stmt->nat.proto = proto;
+ }
+
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MAX);
+ if (reg2 && reg2 != reg1) {
+ proto = netlink_get_register(ctx, loc, reg2);
+ if (proto == NULL) {
+ netlink_error(ctx, loc,
+ "NAT statement has no proto expression");
+ goto out_err;
+ }
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ if (stmt->nat.proto != NULL)
+ proto = range_expr_alloc(loc, stmt->nat.proto, proto);
+ stmt->nat.proto = proto;
+ }
+
+ ctx->stmt = stmt;
+ return;
+out_err:
+ stmt_free(stmt);
+}
+
+static void netlink_parse_synproxy(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = synproxy_stmt_alloc(loc);
+ stmt->synproxy.mss = nftnl_expr_get_u16(nle, NFTNL_EXPR_SYNPROXY_MSS);
+ stmt->synproxy.wscale = nftnl_expr_get_u8(nle,
+ NFTNL_EXPR_SYNPROXY_WSCALE);
+ stmt->synproxy.flags = nftnl_expr_get_u32(nle,
+ NFTNL_EXPR_SYNPROXY_FLAGS);
+
+ ctx->stmt = stmt;
+}
+
+static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+ struct expr *addr, *port;
+ enum nft_registers reg;
+
+ stmt = tproxy_stmt_alloc(loc);
+ stmt->tproxy.family = nftnl_expr_get_u32(nle, NFTNL_EXPR_TPROXY_FAMILY);
+ stmt->tproxy.table_family = ctx->table->handle.family;
+
+ reg = netlink_parse_register(nle, NFTNL_EXPR_TPROXY_REG_ADDR);
+ if (reg) {
+ addr = netlink_get_register(ctx, loc, reg);
+ if (addr == NULL)
+ goto err;
+
+ switch (stmt->tproxy.family) {
+ case NFPROTO_IPV4:
+ expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN);
+ break;
+ case NFPROTO_IPV6:
+ expr_set_type(addr, &ip6addr_type, BYTEORDER_BIG_ENDIAN);
+ break;
+ default:
+ netlink_error(ctx, loc,
+ "tproxy address must be IPv4 or IPv6");
+ goto err;
+ }
+ stmt->tproxy.addr = addr;
+ }
+
+ reg = netlink_parse_register(nle, NFTNL_EXPR_TPROXY_REG_PORT);
+ if (reg) {
+ port = netlink_get_register(ctx, loc, reg);
+ if (port == NULL)
+ goto err;
+ expr_set_type(port, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ stmt->tproxy.port = port;
+ }
+
+ ctx->stmt = stmt;
+ return;
+err:
+ stmt_free(stmt);
+}
+
+static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers reg1, reg2;
+ struct expr *proto;
+ struct stmt *stmt;
+ uint32_t flags = 0;
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_MASQ_FLAGS))
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_MASQ_FLAGS);
+
+ stmt = nat_stmt_alloc(loc, NFT_NAT_MASQ);
+ stmt->nat.flags = flags;
+
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MIN);
+ if (reg1) {
+ proto = netlink_get_register(ctx, loc, reg1);
+ if (proto == NULL) {
+ netlink_error(ctx, loc,
+ "MASQUERADE statement has no proto expression");
+ goto out_err;
+ }
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ stmt->nat.proto = proto;
+ }
+
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MAX);
+ if (reg2 && reg2 != reg1) {
+ proto = netlink_get_register(ctx, loc, reg2);
+ if (proto == NULL) {
+ netlink_error(ctx, loc,
+ "MASQUERADE statement has no proto expression");
+ goto out_err;
+ }
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ if (stmt->nat.proto != NULL)
+ proto = range_expr_alloc(loc, stmt->nat.proto, proto);
+ stmt->nat.proto = proto;
+ }
+
+ ctx->stmt = stmt;
+ return;
+out_err:
+ stmt_free(stmt);
+}
+
+static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+ struct expr *proto;
+ enum nft_registers reg1, reg2;
+ uint32_t flags;
+
+ stmt = nat_stmt_alloc(loc, NFT_NAT_REDIR);
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_REDIR_FLAGS)) {
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_REDIR_FLAGS);
+ stmt->nat.flags = flags;
+ }
+
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MIN);
+ if (reg1) {
+ proto = netlink_get_register(ctx, loc, reg1);
+ if (proto == NULL) {
+ netlink_error(ctx, loc,
+ "redirect statement has no proto expression");
+ goto out_err;
+ }
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ stmt->nat.proto = proto;
+ }
+
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MAX);
+ if (reg2 && reg2 != reg1) {
+ proto = netlink_get_register(ctx, loc, reg2);
+ if (proto == NULL) {
+ netlink_error(ctx, loc,
+ "redirect statement has no proto expression");
+ goto out_err;
+ }
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ if (stmt->nat.proto != NULL)
+ proto = range_expr_alloc(loc, stmt->nat.proto,
+ proto);
+ stmt->nat.proto = proto;
+ }
+
+ ctx->stmt = stmt;
+ return;
+out_err:
+ stmt_free(stmt);
+}
+
+static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers reg1, reg2;
+ struct expr *addr, *dev;
+ struct stmt *stmt;
+
+ stmt = dup_stmt_alloc(loc);
+
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_DUP_SREG_ADDR);
+ if (reg1) {
+ addr = netlink_get_register(ctx, loc, reg1);
+ if (addr == NULL) {
+ netlink_error(ctx, loc,
+ "DUP statement has no destination expression");
+ goto out_err;
+ }
+
+ switch (ctx->table->handle.family) {
+ case NFPROTO_IPV4:
+ expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN);
+ break;
+ case NFPROTO_IPV6:
+ expr_set_type(addr, &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN);
+ break;
+ }
+ stmt->dup.to = addr;
+ }
+
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_DUP_SREG_DEV);
+ if (reg2) {
+ dev = netlink_get_register(ctx, loc, reg2);
+ if (dev == NULL) {
+ netlink_error(ctx, loc,
+ "DUP statement has no output expression");
+ goto out_err;
+ }
+
+ expr_set_type(dev, &ifindex_type, BYTEORDER_HOST_ENDIAN);
+ if (stmt->dup.to == NULL)
+ stmt->dup.to = dev;
+ else
+ stmt->dup.dev = dev;
+ }
+
+ ctx->stmt = stmt;
+ return;
+out_err:
+ stmt_free(stmt);
+}
+
+static void netlink_parse_fwd(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers reg1, reg2;
+ struct expr *dev, *addr;
+ struct stmt *stmt;
+
+ stmt = fwd_stmt_alloc(loc);
+
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_FWD_SREG_DEV);
+ if (reg1) {
+ dev = netlink_get_register(ctx, loc, reg1);
+ if (dev == NULL) {
+ netlink_error(ctx, loc,
+ "fwd statement has no output expression");
+ goto out_err;
+ }
+
+ expr_set_type(dev, &ifindex_type, BYTEORDER_HOST_ENDIAN);
+ stmt->fwd.dev = dev;
+ }
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_FWD_NFPROTO)) {
+ stmt->fwd.family =
+ nftnl_expr_get_u32(nle, NFTNL_EXPR_FWD_NFPROTO);
+ }
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_FWD_SREG_ADDR)) {
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_FWD_SREG_ADDR);
+ if (reg2) {
+ addr = netlink_get_register(ctx, loc, reg2);
+ if (addr == NULL) {
+ netlink_error(ctx, loc,
+ "fwd statement has no output expression");
+ goto out_err;
+ }
+
+ switch (stmt->fwd.family) {
+ case AF_INET:
+ expr_set_type(addr, &ipaddr_type,
+ BYTEORDER_BIG_ENDIAN);
+ break;
+ case AF_INET6:
+ expr_set_type(addr, &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN);
+ break;
+ default:
+ netlink_error(ctx, loc,
+ "fwd statement has no family");
+ goto out_err;
+ }
+ stmt->fwd.addr = addr;
+ }
+ }
+
+ ctx->stmt = stmt;
+ return;
+out_err:
+ stmt_free(stmt);
+}
+
+static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct expr *expr;
+ uint16_t flags;
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_QUEUE_SREG_QNUM)) {
+ enum nft_registers reg = netlink_parse_register(nle, NFTNL_EXPR_QUEUE_SREG_QNUM);
+
+ expr = netlink_get_register(ctx, loc, reg);
+ if (!expr) {
+ netlink_error(ctx, loc, "queue statement has no sreg expression");
+ return;
+ }
+ } else {
+ uint16_t total = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_TOTAL);
+ uint16_t num = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_NUM);
+
+ expr = constant_expr_alloc(loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN, 16, &num);
+
+ if (total > 1) {
+ struct expr *high;
+
+ total += num - 1;
+ high = constant_expr_alloc(loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN, 16, &total);
+ expr = range_expr_alloc(loc, expr, high);
+ }
+ }
+
+ flags = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_FLAGS);
+ ctx->stmt = queue_stmt_alloc(loc, expr, flags);
+}
+
+struct dynset_parse_ctx {
+ struct netlink_parse_ctx *nlctx;
+ const struct location *loc;
+ struct list_head stmt_list;
+};
+
+static int dynset_parse_expressions(struct nftnl_expr *e, void *data)
+{
+ struct dynset_parse_ctx *dynset_parse_ctx = data;
+ struct netlink_parse_ctx *ctx = dynset_parse_ctx->nlctx;
+ const struct location *loc = dynset_parse_ctx->loc;
+ struct stmt *stmt;
+
+ if (netlink_parse_expr(e, ctx) < 0 || !ctx->stmt) {
+ netlink_error(ctx, loc, "Could not parse dynset stmt");
+ return -1;
+ }
+ stmt = ctx->stmt;
+
+ list_add_tail(&stmt->list, &dynset_parse_ctx->stmt_list);
+
+ return 0;
+}
+
+static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct dynset_parse_ctx dynset_parse_ctx = {
+ .nlctx = ctx,
+ .loc = loc,
+ };
+ struct expr *expr, *expr_data = NULL;
+ enum nft_registers sreg, sreg_data;
+ struct stmt *stmt, *dstmt, *next;
+ const struct nftnl_expr *dnle;
+ struct set *set;
+ const char *name;
+
+ init_list_head(&dynset_parse_ctx.stmt_list);
+
+ name = nftnl_expr_get_str(nle, NFTNL_EXPR_DYNSET_SET_NAME);
+ set = set_cache_find(ctx->table, name);
+ if (set == NULL)
+ return netlink_error(ctx, loc,
+ "Unknown set '%s' in dynset statement",
+ name);
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY);
+ expr = netlink_get_register(ctx, loc, sreg);
+ if (expr == NULL)
+ return netlink_error(ctx, loc,
+ "Dynset statement has no key expression");
+
+ if (expr->len < set->key->len) {
+ expr_free(expr);
+ expr = netlink_parse_concat_key(ctx, loc, sreg, set->key);
+ if (expr == NULL)
+ return;
+ } else if (expr->dtype == &invalid_type) {
+ expr_set_type(expr, datatype_get(set->key->dtype), set->key->byteorder);
+ }
+
+ expr = set_elem_expr_alloc(&expr->location, expr);
+ expr->timeout = nftnl_expr_get_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT);
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_EXPR)) {
+ dstmt = NULL;
+ dnle = nftnl_expr_get(nle, NFTNL_EXPR_DYNSET_EXPR, NULL);
+ if (dnle != NULL) {
+ if (netlink_parse_expr(dnle, ctx) < 0)
+ goto out_err;
+ if (ctx->stmt == NULL) {
+ netlink_error(ctx, loc,
+ "Could not parse dynset stmt");
+ goto out_err;
+ }
+ dstmt = ctx->stmt;
+ list_add_tail(&dstmt->list,
+ &dynset_parse_ctx.stmt_list);
+ }
+ } else if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS)) {
+ if (nftnl_expr_expr_foreach(nle, dynset_parse_expressions,
+ &dynset_parse_ctx) < 0)
+ goto out_err;
+ }
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_SREG_DATA)) {
+ sreg_data = netlink_parse_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA);
+ expr_data = netlink_get_register(ctx, loc, sreg_data);
+
+ if (expr_data && expr_data->len < set->data->len) {
+ expr_free(expr_data);
+ expr_data = netlink_parse_concat_expr(ctx, loc, sreg_data, set->data->len);
+ if (expr_data == NULL)
+ netlink_error(ctx, loc,
+ "Could not parse dynset map data expressions");
+ }
+ }
+
+ if (expr_data != NULL) {
+ expr_set_type(expr_data, set->data->dtype, set->data->byteorder);
+ stmt = map_stmt_alloc(loc);
+ stmt->map.set = set_ref_expr_alloc(loc, set);
+ stmt->map.key = expr;
+ stmt->map.data = expr_data;
+ stmt->map.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
+ list_splice_tail(&dynset_parse_ctx.stmt_list,
+ &stmt->map.stmt_list);
+ } else {
+ if (!list_empty(&dynset_parse_ctx.stmt_list) &&
+ set_is_anonymous(set->flags)) {
+ stmt = meter_stmt_alloc(loc);
+ stmt->meter.set = set_ref_expr_alloc(loc, set);
+ stmt->meter.key = expr;
+ stmt->meter.stmt = list_first_entry(&dynset_parse_ctx.stmt_list,
+ struct stmt, list);
+ stmt->meter.size = set->desc.size;
+ } else {
+ stmt = set_stmt_alloc(loc);
+ stmt->set.set = set_ref_expr_alloc(loc, set);
+ stmt->set.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
+ stmt->set.key = expr;
+ list_splice_tail(&dynset_parse_ctx.stmt_list,
+ &stmt->set.stmt_list);
+ }
+ }
+
+ ctx->stmt = stmt;
+ return;
+out_err:
+ list_for_each_entry_safe(dstmt, next, &dynset_parse_ctx.stmt_list, list)
+ stmt_free(dstmt);
+
+ expr_free(expr);
+}
+
+static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ uint32_t type = nftnl_expr_get_u32(nle, NFTNL_EXPR_OBJREF_IMM_TYPE);
+ struct expr *expr;
+ struct stmt *stmt;
+
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_OBJREF_IMM_NAME)) {
+ struct nft_data_delinearize nld;
+
+ type = nftnl_expr_get_u32(nle, NFTNL_EXPR_OBJREF_IMM_TYPE);
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_OBJREF_IMM_NAME,
+ &nld.len);
+ expr = netlink_alloc_value(&netlink_location, &nld);
+ datatype_set(expr, &string_type);
+ expr->byteorder = BYTEORDER_HOST_ENDIAN;
+ } else if (nftnl_expr_is_set(nle, NFTNL_EXPR_OBJREF_SET_SREG)) {
+ struct expr *left, *right;
+ enum nft_registers sreg;
+ const char *name;
+ struct set *set;
+
+ name = nftnl_expr_get_str(nle, NFTNL_EXPR_OBJREF_SET_NAME);
+ set = set_cache_find(ctx->table, name);
+ if (set == NULL)
+ return netlink_error(ctx, loc,
+ "Unknown set '%s' in objref expression",
+ name);
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_OBJREF_SET_SREG);
+ left = netlink_get_register(ctx, loc, sreg);
+ if (left == NULL)
+ return netlink_error(ctx, loc,
+ "objref expression has no left hand side");
+
+ if (left->len < set->key->len) {
+ expr_free(left);
+ left = netlink_parse_concat_expr(ctx, loc, sreg, set->key->len);
+ if (left == NULL)
+ return;
+ }
+
+ right = set_ref_expr_alloc(loc, set);
+ expr = map_expr_alloc(loc, left, right);
+ expr_set_type(expr, &string_type, BYTEORDER_HOST_ENDIAN);
+ type = set->objtype;
+ } else {
+ netlink_error(ctx, loc, "unknown objref expression type %u",
+ type);
+ return;
+ }
+
+ stmt = objref_stmt_alloc(loc);
+ stmt->objref.type = type;
+ stmt->objref.expr = expr;
+ ctx->stmt = stmt;
+}
+
+struct expr_handler {
+ const char *name;
+ void (*parse)(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle);
+};
+
+static const struct expr_handler netlink_parsers[] = {
+ { .name = "immediate", .parse = netlink_parse_immediate },
+ { .name = "cmp", .parse = netlink_parse_cmp },
+ { .name = "lookup", .parse = netlink_parse_lookup },
+ { .name = "bitwise", .parse = netlink_parse_bitwise },
+ { .name = "byteorder", .parse = netlink_parse_byteorder },
+ { .name = "payload", .parse = netlink_parse_payload },
+ { .name = "inner", .parse = netlink_parse_inner },
+ { .name = "exthdr", .parse = netlink_parse_exthdr },
+ { .name = "meta", .parse = netlink_parse_meta },
+ { .name = "socket", .parse = netlink_parse_socket },
+ { .name = "osf", .parse = netlink_parse_osf },
+ { .name = "rt", .parse = netlink_parse_rt },
+ { .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 },
+ { .name = "reject", .parse = netlink_parse_reject },
+ { .name = "nat", .parse = netlink_parse_nat },
+ { .name = "tproxy", .parse = netlink_parse_tproxy },
+ { .name = "notrack", .parse = netlink_parse_notrack },
+ { .name = "masq", .parse = netlink_parse_masq },
+ { .name = "redir", .parse = netlink_parse_redir },
+ { .name = "dup", .parse = netlink_parse_dup },
+ { .name = "queue", .parse = netlink_parse_queue },
+ { .name = "dynset", .parse = netlink_parse_dynset },
+ { .name = "fwd", .parse = netlink_parse_fwd },
+ { .name = "target", .parse = netlink_parse_target },
+ { .name = "match", .parse = netlink_parse_match },
+ { .name = "objref", .parse = netlink_parse_objref },
+ { .name = "quota", .parse = netlink_parse_quota },
+ { .name = "numgen", .parse = netlink_parse_numgen },
+ { .name = "hash", .parse = netlink_parse_hash },
+ { .name = "fib", .parse = netlink_parse_fib },
+ { .name = "tcpopt", .parse = netlink_parse_exthdr },
+ { .name = "flow_offload", .parse = netlink_parse_flow_offload },
+ { .name = "xfrm", .parse = netlink_parse_xfrm },
+ { .name = "synproxy", .parse = netlink_parse_synproxy },
+};
+
+static int netlink_parse_expr(const struct nftnl_expr *nle,
+ struct netlink_parse_ctx *ctx)
+{
+ const char *type = nftnl_expr_get_str(nle, NFTNL_EXPR_NAME);
+ struct location loc;
+ unsigned int i;
+
+ memset(&loc, 0, sizeof(loc));
+ loc.indesc = &indesc_netlink;
+ loc.nle = nle;
+
+ for (i = 0; i < array_size(netlink_parsers); i++) {
+ if (strcmp(type, netlink_parsers[i].name))
+ continue;
+
+ netlink_parsers[i].parse(ctx, &loc, nle);
+
+ return 0;
+ }
+ netlink_error(ctx, &loc, "unknown expression type '%s'", type);
+
+ return 0;
+}
+
+static int netlink_parse_rule_expr(struct nftnl_expr *nle, void *arg)
+{
+ struct netlink_parse_ctx *ctx = arg;
+ int err;
+
+ err = netlink_parse_expr(nle, ctx);
+ if (err < 0)
+ return err;
+ if (ctx->stmt != NULL) {
+ rule_stmt_append(ctx->rule, ctx->stmt);
+ ctx->stmt = NULL;
+ }
+ return 0;
+}
+
+struct stmt *netlink_parse_set_expr(const struct set *set,
+ const struct nft_cache *cache,
+ const struct nftnl_expr *nle)
+{
+ struct netlink_parse_ctx ctx, *pctx = &ctx;
+ struct handle h = {};
+
+ handle_merge(&h, &set->handle);
+ pctx->rule = rule_alloc(&netlink_location, &h);
+ pctx->table = table_cache_find(&cache->table_cache,
+ set->handle.table.name,
+ set->handle.family);
+ assert(pctx->table != NULL);
+
+ if (netlink_parse_expr(nle, pctx) < 0)
+ return NULL;
+
+ init_list_head(&pctx->rule->stmts);
+ rule_free(pctx->rule);
+
+ return pctx->stmt;
+}
+
+static bool meta_outer_may_dependency_kill(struct rule_pp_ctx *ctx,
+ const struct expr *expr)
+{
+ struct dl_proto_ctx *dl_outer = dl_proto_ctx_outer(ctx);
+ struct stmt *stmt = dl_outer->pdctx.pdeps[expr->payload.inner_desc->base];
+ struct expr *dep;
+ uint8_t l4proto;
+
+ if (!stmt)
+ return false;
+
+ dep = stmt->expr;
+
+ if (dep->left->meta.key != NFT_META_L4PROTO)
+ return false;
+
+ l4proto = mpz_get_uint8(dep->right->value);
+
+ switch (l4proto) {
+ case IPPROTO_GRE:
+ if (expr->payload.inner_desc == &proto_gre ||
+ expr->payload.inner_desc == &proto_gretap)
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp);
+
+static void payload_match_expand(struct rule_pp_ctx *ctx,
+ struct expr *expr,
+ struct expr *payload)
+{
+ struct expr *left = payload, *right = expr->right, *tmp;
+ struct list_head list = LIST_HEAD_INIT(list);
+ 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, &dl->pctx);
+
+ list_for_each_entry(left, &list, list) {
+ tmp = constant_expr_splice(right, left->len);
+ expr_set_type(tmp, left->dtype, left->byteorder);
+
+ if (left->payload.tmpl && (left->len < left->payload.tmpl->len)) {
+ mpz_lshift_ui(tmp->value, left->payload.tmpl->len - left->len);
+ tmp->len = left->payload.tmpl->len;
+ tmp = prefix_expr_alloc(&tmp->location, tmp, left->len);
+ }
+
+ nexpr = relational_expr_alloc(&expr->location, expr->op,
+ left, tmp);
+ if (expr->op == OP_EQ)
+ relational_expr_pctx_update(&dl->pctx, nexpr);
+
+ nstmt = expr_stmt_alloc(&ctx->stmt->location, nexpr);
+ list_add_tail(&nstmt->list, &ctx->stmt->list);
+
+ assert(left->etype == EXPR_PAYLOAD);
+ assert(left->payload.base);
+ assert(base == left->payload.base);
+
+ 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(&dl->pdctx, nexpr->left,
+ dl->pctx.family);
+ if (expr->op == OP_EQ && left->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(&dl->pdctx, nstmt, base);
+ }
+ list_del(&ctx->stmt->list);
+ stmt_free(ctx->stmt);
+ ctx->stmt = NULL;
+}
+
+static void payload_icmp_check(struct rule_pp_ctx *rctx, struct expr *expr, const struct expr *value)
+{
+ struct dl_proto_ctx *dl = dl_proto_ctx(rctx);
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *desc;
+ uint8_t icmp_type;
+ unsigned int i;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+ assert(value->etype == EXPR_VALUE);
+
+ if (expr->payload.base != PROTO_BASE_TRANSPORT_HDR)
+ return;
+
+ /* icmp(v6) type is 8 bit, if value is smaller or larger, this is not
+ * a protocol dependency.
+ */
+ if (expr->len != 8 || value->len != 8 || dl->pctx.th_dep.icmp.type)
+ return;
+
+ desc = dl->pctx.protocol[expr->payload.base].desc;
+ if (desc == NULL)
+ return;
+
+ /* not icmp? ignore. */
+ if (desc != &proto_icmp && desc != &proto_icmp6)
+ return;
+
+ assert(desc->base == expr->payload.base);
+
+ icmp_type = mpz_get_uint8(value->value);
+
+ for (i = 1; i < array_size(desc->templates); i++) {
+ tmpl = &desc->templates[i];
+
+ if (tmpl->len == 0)
+ return;
+
+ if (tmpl->offset != expr->payload.offset ||
+ tmpl->len != expr->len)
+ continue;
+
+ /* Matches but doesn't load a protocol key -> ignore. */
+ if (desc->protocol_key != i)
+ return;
+
+ expr->payload.desc = desc;
+ expr->payload.tmpl = tmpl;
+ dl->pctx.th_dep.icmp.type = icmp_type;
+ return;
+ }
+}
+
+static void payload_match_postprocess(struct rule_pp_ctx *ctx,
+ struct expr *expr,
+ struct expr *payload)
+{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
+
+ switch (expr->op) {
+ case OP_EQ:
+ case OP_NEQ:
+ if (expr->right->etype == EXPR_VALUE) {
+ payload_match_expand(ctx, expr, payload);
+ break;
+ } else if (expr->right->etype == EXPR_SET_REF) {
+ struct set *set = expr->right->set;
+
+ if (set_is_anonymous(set->flags) &&
+ set->init &&
+ !list_empty(&set->init->expressions)) {
+ struct expr *elem;
+
+ elem = list_first_entry(&set->init->expressions, struct expr, list);
+
+ if (elem->etype == EXPR_SET_ELEM &&
+ elem->key->etype == EXPR_VALUE)
+ payload_icmp_check(ctx, payload, elem->key);
+ }
+ }
+ /* Fall through */
+ default:
+ payload_expr_complete(payload, &dl->pctx);
+ expr_set_type(expr->right, payload->dtype,
+ payload->byteorder);
+ payload_dependency_kill(&dl->pdctx, payload, dl->pctx.family);
+ break;
+ }
+}
+
+static uint8_t ether_type_to_nfproto(uint16_t l3proto)
+{
+ switch(l3proto) {
+ case ETH_P_IP:
+ return NFPROTO_IPV4;
+ case ETH_P_IPV6:
+ return NFPROTO_IPV6;
+ default:
+ break;
+ }
+
+ return NFPROTO_UNSPEC;
+}
+
+static bool __meta_dependency_may_kill(const struct expr *dep, uint8_t *nfproto)
+{
+ uint16_t l3proto;
+
+ switch (dep->left->etype) {
+ case EXPR_META:
+ switch (dep->left->meta.key) {
+ case NFT_META_NFPROTO:
+ *nfproto = mpz_get_uint8(dep->right->value);
+ break;
+ case NFT_META_PROTOCOL:
+ l3proto = mpz_get_uint16(dep->right->value);
+ *nfproto = ether_type_to_nfproto(l3proto);
+ break;
+ default:
+ return true;
+ }
+ break;
+ case EXPR_PAYLOAD:
+ if (dep->left->payload.base != PROTO_BASE_LL_HDR)
+ return true;
+
+ if (dep->left->dtype != &ethertype_type)
+ return true;
+
+ l3proto = mpz_get_uint16(dep->right->value);
+ *nfproto = ether_type_to_nfproto(l3proto);
+ break;
+ default:
+ return true;
+ }
+
+ return false;
+}
+
+/* We have seen a protocol key expression that restricts matching at the network
+ * base, leave it in place since this is meaningful in bridge, inet and netdev
+ * families. Exceptions are ICMP and ICMPv6 where this code assumes that can
+ * only happen with IPv4 and IPv6.
+ */
+static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx,
+ unsigned int family,
+ const struct expr *expr)
+{
+ uint8_t l4proto, nfproto = NFPROTO_UNSPEC;
+ struct expr *dep = payload_dependency_get(ctx, PROTO_BASE_NETWORK_HDR);
+
+ if (!dep)
+ return true;
+
+ if (__meta_dependency_may_kill(dep, &nfproto))
+ return true;
+
+ switch (family) {
+ case NFPROTO_INET:
+ case NFPROTO_NETDEV:
+ case NFPROTO_BRIDGE:
+ break;
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ return family == nfproto;
+ default:
+ return true;
+ }
+
+ if (expr->left->meta.key != NFT_META_L4PROTO)
+ return true;
+
+ l4proto = mpz_get_uint8(expr->right->value);
+
+ switch (l4proto) {
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ break;
+ default:
+ return false;
+ }
+
+ if ((nfproto == NFPROTO_IPV4 && l4proto == IPPROTO_ICMPV6) ||
+ (nfproto == NFPROTO_IPV6 && l4proto == IPPROTO_ICMP))
+ return false;
+
+ return true;
+}
+
+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;
+
+ if (right->etype == EXPR_SET || right->etype == EXPR_SET_REF)
+ expr_set_type(right, left->dtype, left->byteorder);
+
+ switch (expr->op) {
+ case OP_EQ:
+ if (expr->right->etype == EXPR_RANGE ||
+ expr->right->etype == EXPR_SET ||
+ expr->right->etype == EXPR_SET_REF)
+ break;
+
+ relational_expr_pctx_update(&dl->pctx, expr);
+
+ if (base < PROTO_BASE_TRANSPORT_HDR) {
+ if (payload_dependency_exists(&dl->pdctx, base) &&
+ meta_may_dependency_kill(&dl->pdctx,
+ dl->pctx.family, expr))
+ payload_dependency_release(&dl->pdctx, base);
+
+ if (left->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(&dl->pdctx, ctx->stmt, base);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void meta_match_postprocess(struct rule_pp_ctx *ctx,
+ const struct expr *expr)
+{
+ const struct expr *left = expr->left;
+
+ ct_meta_common_postprocess(ctx, expr, left->meta.base);
+}
+
+static void ct_match_postprocess(struct rule_pp_ctx *ctx,
+ const struct expr *expr)
+{
+ const struct expr *left = expr->left;
+
+ ct_meta_common_postprocess(ctx, expr, left->ct.base);
+}
+
+/* Convert a bitmask to a prefix length */
+static unsigned int expr_mask_to_prefix(const struct expr *expr)
+{
+ unsigned long n;
+
+ n = mpz_scan1(expr->value, 0);
+ if (n == ULONG_MAX)
+ return 0;
+ return mpz_scan0(expr->value, n + 1) - n;
+}
+
+/* Return true if a bitmask can be expressed as a prefix length */
+static bool expr_mask_is_prefix(const struct expr *expr)
+{
+ unsigned long n1, n2;
+
+ n1 = mpz_scan1(expr->value, 0);
+ if (n1 == ULONG_MAX)
+ return true;
+ n2 = mpz_scan0(expr->value, n1 + 1);
+ if (n2 < expr->len || n2 == ULONG_MAX)
+ return false;
+ return true;
+}
+
+/* Convert a series of inclusive OR expressions into a list */
+static struct expr *binop_tree_to_list(struct expr *list, struct expr *expr)
+{
+ if (expr->etype == EXPR_BINOP && expr->op == OP_OR) {
+ if (list == NULL)
+ list = list_expr_alloc(&expr->location);
+ list = binop_tree_to_list(list, expr->left);
+ list = binop_tree_to_list(list, expr->right);
+ } else {
+ if (list == NULL)
+ return expr_get(expr);
+ compound_expr_add(list, expr_get(expr));
+ }
+
+ return list;
+}
+
+static void binop_adjust_one(const struct expr *binop, struct expr *value,
+ unsigned int shift)
+{
+ struct expr *left = binop->left;
+
+ assert(value->len >= binop->right->len);
+
+ mpz_rshift_ui(value->value, shift);
+ switch (left->etype) {
+ case EXPR_PAYLOAD:
+ case EXPR_EXTHDR:
+ value->len = left->len;
+ break;
+ default:
+ BUG("unknown expression type %s\n", expr_name(left));
+ break;
+ }
+}
+
+static void binop_adjust(const struct expr *binop, struct expr *right,
+ unsigned int shift)
+{
+ struct expr *i;
+
+ switch (right->etype) {
+ case EXPR_VALUE:
+ 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:
+ binop_adjust_one(binop, i->key, shift);
+ break;
+ case EXPR_RANGE:
+ binop_adjust_one(binop, i->key->left, shift);
+ binop_adjust_one(binop, i->key->right, shift);
+ break;
+ case EXPR_SET_ELEM:
+ binop_adjust(binop, i->key->key, shift);
+ break;
+ default:
+ BUG("unknown expression type %s\n", expr_name(i->key));
+ }
+ }
+ break;
+ case EXPR_RANGE:
+ binop_adjust_one(binop, right->left, shift);
+ binop_adjust_one(binop, right->right, shift);
+ break;
+ default:
+ BUG("unknown expression type %s\n", expr_name(right));
+ break;
+ }
+}
+
+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;
+ unsigned int shift;
+
+ assert(binop->etype == EXPR_BINOP);
+
+ if ((left->etype == EXPR_PAYLOAD &&
+ payload_expr_trim(left, mask, &dl->pctx, &shift)) ||
+ (left->etype == EXPR_EXTHDR &&
+ exthdr_find_template(left, mask, &shift))) {
+ struct expr *right = NULL;
+
+ /* mask is implicit, binop needs to be removed.
+ *
+ * Fix all values of the expression according to the mask
+ * and then process the payload instruction using the real
+ * sizes and offsets we're interested in.
+ *
+ * Finally, convert the expression to 1) by replacing
+ * the binop with the binop payload/exthdr expression.
+ */
+ switch (expr->etype) {
+ case EXPR_BINOP:
+ case EXPR_RELATIONAL:
+ right = expr->right;
+ binop_adjust(binop, right, shift);
+ break;
+ case EXPR_MAP:
+ right = expr->mappings;
+ binop_adjust(binop, right, shift);
+ break;
+ default:
+ break;
+ }
+
+ assert(binop->left == left);
+ *expr_binop = expr_get(left);
+
+ 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;
+
+ if (binop->op != OP_AND)
+ return;
+
+ if (binop->left->etype == EXPR_PAYLOAD &&
+ binop->right->etype == EXPR_VALUE)
+ binop_postprocess(ctx, expr, &expr->map);
+}
+
+static bool is_shift_by_zero(const struct expr *binop)
+{
+ struct expr *rhs;
+
+ if (binop->op != OP_RSHIFT && binop->op != OP_LSHIFT)
+ return false;
+
+ rhs = binop->right;
+ if (rhs->etype != EXPR_VALUE || rhs->len > 64)
+ return false;
+
+ return mpz_get_uint64(rhs->value) == 0;
+}
+
+static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr **exprp)
+{
+ struct expr *expr = *exprp, *binop = expr->left, *right = expr->right;
+
+ 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);
+ }
+ 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);
+ break;
+ default:
+ break;
+ }
+ } else if (binop->left->dtype->flags & DTYPE_F_PREFIX &&
+ binop->op == OP_AND && expr->right->etype == EXPR_VALUE &&
+ expr_mask_is_prefix(binop->right)) {
+ expr->left = expr_get(binop->left);
+ expr->right = prefix_expr_alloc(&expr->location,
+ expr_get(right),
+ expr_mask_to_prefix(binop->right));
+ expr_free(right);
+ expr_free(binop);
+ } else if (binop->op == OP_AND &&
+ binop->right->etype == EXPR_VALUE) {
+ /*
+ * This *might* be a payload match testing header fields that
+ * have non byte divisible offsets and/or bit lengths.
+ *
+ * Thus we need to deal with two different cases.
+ *
+ * 1 the simple version:
+ * relation
+ * payload value|setlookup
+ *
+ * expr: relation, left: payload, right: value, e.g. tcp dport == 22.
+ *
+ * 2. The '&' version (this is what we're looking at now).
+ * relation
+ * binop value1|setlookup
+ * payload value2
+ *
+ * expr: relation, left: binop, right: value, e.g.
+ * ip saddr 10.0.0.0/8
+ *
+ * payload_expr_trim will figure out if the mask is needed to match
+ * templates.
+ */
+ binop_postprocess(ctx, expr, &expr->left);
+ } else if (binop->op == OP_RSHIFT && binop->left->op == OP_AND &&
+ binop->right->etype == EXPR_VALUE && binop->left->right->etype == EXPR_VALUE) {
+ /* Handle 'ip version @s4' and similar, i.e. set lookups where the lhs needs
+ * fixups to mask out unwanted bits AND a shift.
+ */
+
+ binop_postprocess(ctx, binop, &binop->left);
+ if (is_shift_by_zero(binop)) {
+ struct expr *lhs = binop->left;
+
+ expr_get(lhs);
+ expr_free(binop);
+ expr->left = lhs;
+ }
+ }
+}
+
+static bool payload_binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+
+ if (expr->op != OP_RSHIFT)
+ return false;
+
+ if (expr->left->etype == EXPR_UNARY) {
+ /*
+ * If the payload value was originally in a different byte-order
+ * from the payload expression, there will be a byte-order
+ * conversion to remove.
+ */
+ struct expr *left = expr_get(expr->left->arg);
+ expr_free(expr->left);
+ expr->left = left;
+ }
+
+ if (expr->left->etype != EXPR_BINOP || expr->left->op != OP_AND)
+ return false;
+
+ if (expr->left->left->etype != EXPR_PAYLOAD)
+ return false;
+
+ expr_set_type(expr->right, &integer_type,
+ BYTEORDER_HOST_ENDIAN);
+ expr_postprocess(ctx, &expr->right);
+
+ binop_postprocess(ctx, expr, &expr->left);
+ *exprp = expr_get(expr->left);
+ expr_free(expr);
+
+ return true;
+}
+
+static struct expr *string_wildcard_expr_alloc(struct location *loc,
+ const struct expr *mask,
+ const struct expr *expr)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ char data[len + 2];
+ int pos;
+
+ mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
+ pos = div_round_up(expr_mask_to_prefix(mask), BITS_PER_BYTE);
+ data[pos] = '*';
+ data[pos + 1] = '\0';
+
+ return constant_expr_alloc(loc, expr->dtype, BYTEORDER_HOST_ENDIAN,
+ expr->len + BITS_PER_BYTE, data);
+}
+
+/* This calculates the string length and checks if it is nul-terminated, this
+ * function is quite a hack :)
+ */
+static bool __expr_postprocess_string(struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ char data[len + 1];
+
+ mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
+
+ if (data[len - 1] != '\0')
+ return false;
+
+ len = strlen(data);
+ if (len && data[len - 1] == '*') {
+ data[len - 1] = '\\';
+ data[len] = '*';
+ data[len + 1] = '\0';
+ expr = constant_expr_alloc(&expr->location, expr->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (len + 2) * BITS_PER_BYTE, data);
+ expr_free(*exprp);
+ *exprp = expr;
+ }
+
+ return true;
+}
+
+static struct expr *expr_postprocess_string(struct expr *expr)
+{
+ struct expr *mask, *out;
+
+ assert(expr_basetype(expr)->type == TYPE_STRING);
+ if (__expr_postprocess_string(&expr))
+ return expr;
+
+ mask = constant_expr_alloc(&expr->location, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ expr->len + BITS_PER_BYTE, NULL);
+ mpz_clear(mask->value);
+ mpz_init_bitmask(mask->value, expr->len);
+ out = string_wildcard_expr_alloc(&expr->location, mask, expr);
+ expr_free(expr);
+ expr_free(mask);
+ return out;
+}
+
+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) {
+ case EXPR_MAP:
+ switch (expr->map->etype) {
+ case EXPR_BINOP:
+ map_binop_postprocess(ctx, expr);
+ break;
+ default:
+ break;
+ }
+
+ expr_postprocess(ctx, &expr->map);
+ expr_postprocess(ctx, &expr->mappings);
+ break;
+ case EXPR_MAPPING:
+ expr_postprocess(ctx, &expr->left);
+ expr_postprocess(ctx, &expr->right);
+ break;
+ case EXPR_SET:
+ 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_HEAD(tmp);
+ struct expr *n;
+
+ 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));
+ 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:
+ case OP_RSHIFT:
+ expr_set_type(expr->right, &integer_type,
+ BYTEORDER_HOST_ENDIAN);
+ break;
+ case OP_AND:
+ if (expr->right->len > expr->left->len) {
+ expr_set_type(expr->right, expr->left->dtype,
+ BYTEORDER_HOST_ENDIAN);
+ } else {
+ expr_set_type(expr->right, expr->left->dtype,
+ expr->left->byteorder);
+ }
+
+ /* Do not process OP_AND in ordinary rule context.
+ *
+ * Removal needs to be performed as part of the relational
+ * operation because the RHS constant might need to be adjusted
+ * (shifted).
+ *
+ * This is different in set element context or concatenations:
+ * There is no relational operation (eq, neq and so on), thus
+ * it needs to be processed right away.
+ */
+ if ((ctx->flags & RULE_PP_REMOVE_OP_AND) &&
+ expr->left->etype == EXPR_PAYLOAD &&
+ expr->right->etype == EXPR_VALUE) {
+ __binop_postprocess(ctx, expr, expr->left, expr->right, exprp);
+ return;
+ }
+ break;
+ default:
+ if (expr->right->len > expr->left->len) {
+ expr_set_type(expr->right, expr->left->dtype,
+ BYTEORDER_HOST_ENDIAN);
+ } else {
+ expr_set_type(expr->right, expr->left->dtype,
+ expr->left->byteorder);
+ }
+ }
+ expr_postprocess(ctx, &expr->right);
+
+ 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);
+ }
+ expr_postprocess(ctx, &expr->left);
+ break;
+ default:
+ expr_postprocess(ctx, &expr->left);
+ break;
+ }
+
+ expr_set_type(expr->right, expr->left->dtype, expr->left->byteorder);
+ expr_postprocess(ctx, &expr->right);
+
+ switch (expr->left->etype) {
+ case EXPR_CT:
+ ct_match_postprocess(ctx, expr);
+ break;
+ case EXPR_META:
+ meta_match_postprocess(ctx, expr);
+ break;
+ case EXPR_BINOP:
+ relational_binop_postprocess(ctx, exprp);
+ break;
+ default:
+ break;
+ }
+ break;
+ case EXPR_PAYLOAD:
+ 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);
+
+ break;
+ case EXPR_RANGE:
+ expr_postprocess(ctx, &expr->left);
+ expr_postprocess(ctx, &expr->right);
+ break;
+ case EXPR_PREFIX:
+ expr_postprocess(ctx, &expr->prefix);
+ break;
+ case EXPR_SET_ELEM:
+ ctx->flags |= RULE_PP_IN_SET_ELEM;
+ expr_postprocess(ctx, &expr->key);
+ ctx->flags &= ~RULE_PP_IN_SET_ELEM;
+ break;
+ case EXPR_EXTHDR:
+ exthdr_dependency_kill(&dl->pdctx, expr, dl->pctx.family);
+ break;
+ case EXPR_SET_REF:
+ case EXPR_META:
+ case EXPR_RT:
+ case EXPR_VERDICT:
+ case EXPR_NUMGEN:
+ case EXPR_FIB:
+ case EXPR_SOCKET:
+ case EXPR_OSF:
+ case EXPR_XFRM:
+ break;
+ case EXPR_HASH:
+ if (expr->hash.expr)
+ expr_postprocess(ctx, &expr->hash.expr);
+ break;
+ case EXPR_CT:
+ ct_expr_update_type(&dl->pctx, expr);
+ break;
+ default:
+ BUG("unknown expression type %s\n", expr_name(expr));
+ }
+}
+
+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 (dl->pctx.family) {
+ case NFPROTO_IPV4:
+ 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(&dl->pdctx,
+ PROTO_BASE_TRANSPORT_HDR))
+ payload_dependency_release(&dl->pdctx,
+ PROTO_BASE_TRANSPORT_HDR);
+ break;
+ case NFPROTO_IPV6:
+ 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(&dl->pdctx,
+ PROTO_BASE_TRANSPORT_HDR))
+ payload_dependency_release(&dl->pdctx,
+ PROTO_BASE_TRANSPORT_HDR);
+ break;
+ case NFPROTO_INET:
+ case NFPROTO_BRIDGE:
+ case NFPROTO_NETDEV:
+ if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH) {
+ datatype_set(stmt->reject.expr, &icmpx_code_type);
+ break;
+ }
+
+ /* always print full icmp(6) name, simple 'reject' might be ambiguious
+ * because ipv4 vs. ipv6 info might be lost
+ */
+ stmt->reject.verbose_print = 1;
+
+ 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 */
+ case __constant_htons(ETH_P_IP): /* BRIDGE, NETDEV */
+ stmt->reject.family = NFPROTO_IPV4;
+ datatype_set(stmt->reject.expr, &icmp_code_type);
+ break;
+ case NFPROTO_IPV6: /* INET */
+ case __constant_htons(ETH_P_IPV6): /* BRIDGE, NETDEV */
+ stmt->reject.family = NFPROTO_IPV6;
+ datatype_set(stmt->reject.expr, &icmpv6_code_type);
+ break;
+ default:
+ break;
+ }
+
+ if (payload_dependency_exists(&dl->pdctx, PROTO_BASE_NETWORK_HDR))
+ payload_dependency_release(&dl->pdctx,
+ PROTO_BASE_NETWORK_HDR);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool expr_may_merge_range(struct expr *expr, struct expr *prev,
+ enum ops *op)
+{
+ struct expr *left, *prev_left;
+
+ if (prev->etype == EXPR_RELATIONAL &&
+ expr->etype == EXPR_RELATIONAL) {
+ /* ct and meta needs an unary to swap byteorder, in this case
+ * we have to explore the inner branch in this tree.
+ */
+ if (expr->left->etype == EXPR_UNARY)
+ left = expr->left->arg;
+ else
+ left = expr->left;
+
+ if (prev->left->etype == EXPR_UNARY)
+ prev_left = prev->left->arg;
+ else
+ prev_left = prev->left;
+
+ if (left->etype == prev_left->etype) {
+ if (expr->op == OP_LTE && prev->op == OP_GTE) {
+ *op = OP_EQ;
+ return true;
+ } else if (expr->op == OP_GT && prev->op == OP_LT) {
+ *op = OP_NEQ;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+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(&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(&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(&dl->pdctx.prev->list);
+ stmt_free(dl->pdctx.prev);
+
+ list_del(&stmt->list);
+ stmt_free(stmt);
+ ctx->stmt = nstmt;
+}
+
+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 (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, &dl->pctx, &shift)) {
+ binop_adjust(binop, mask, shift);
+ payload_expr_complete(payload, &dl->pctx);
+ expr_set_type(mask, payload->dtype,
+ payload->byteorder);
+ }
+}
+
+/**
+ * stmt_payload_binop_postprocess - decode payload set binop
+ *
+ * @ctx: rule postprocessing context
+ *
+ * This helper has to be called if expr_postprocess() failed to
+ * decode the payload operation.
+ *
+ * Usually a failure to decode means that userspace had to munge
+ * the original payload expression because it has an odd size or
+ * a non-byte divisible offset/length.
+ *
+ * If that was the case, the 'value' expression is not a value but
+ * a binop expression with a munged payload expression on the left
+ * and a mask to clear the real payload offset/length.
+ *
+ * So chech if we have one of the following binops:
+ * I)
+ * binop (|)
+ * binop(&) value/set
+ * payload value(mask)
+ *
+ * This is the normal case, the | RHS is the value the user wants
+ * to set, the & RHS is the mask value that discards bits we need
+ * to clear but retains everything unrelated to the set operation.
+ *
+ * IIa)
+ * binop (&)
+ * payload mask
+ *
+ * User specified a zero set value -- netlink bitwise decoding
+ * discarded the redundant "| 0" part. This is identical to I),
+ * we can just set value to 0 after we inferred the real payload size.
+ *
+ * IIb)
+ * binop (|)
+ * payload value/set
+ *
+ * This happens when user wants to set all bits, netlink bitwise
+ * decoding changed '(payload & mask) ^ bits_to_set' into
+ * 'payload | bits_to_set', discarding the redundant "& 0xfff...".
+ */
+static void stmt_payload_binop_postprocess(struct rule_pp_ctx *ctx)
+{
+ struct expr *expr, *binop, *payload, *value, *mask;
+ struct stmt *stmt = ctx->stmt;
+ mpz_t bitmask;
+
+ expr = stmt->payload.val;
+
+ if (expr->etype != EXPR_BINOP)
+ return;
+
+ switch (expr->left->etype) {
+ case EXPR_BINOP: {/* I? */
+ mpz_t tmp;
+
+ if (expr->op != OP_OR)
+ return;
+
+ value = expr->right;
+ if (value->etype != EXPR_VALUE)
+ return;
+
+ binop = expr->left;
+ if (binop->op != OP_AND)
+ return;
+
+ payload = binop->left;
+ if (payload->etype != EXPR_PAYLOAD)
+ return;
+
+ if (!payload_expr_cmp(stmt->payload.expr, payload))
+ return;
+
+ mask = binop->right;
+ if (mask->etype != EXPR_VALUE)
+ return;
+
+ mpz_init(tmp);
+ mpz_set(tmp, mask->value);
+
+ mpz_init_bitmask(bitmask, payload->len);
+ mpz_xor(bitmask, bitmask, mask->value);
+ mpz_xor(bitmask, bitmask, value->value);
+ mpz_set(mask->value, bitmask);
+ mpz_clear(bitmask);
+
+ binop_postprocess(ctx, expr, &expr->left);
+ if (!payload_is_known(payload)) {
+ mpz_set(mask->value, tmp);
+ mpz_clear(tmp);
+ return;
+ }
+
+ mpz_clear(tmp);
+ expr_free(stmt->payload.expr);
+ stmt->payload.expr = expr_get(payload);
+ stmt->payload.val = expr_get(expr->right);
+ expr_free(expr);
+ break;
+ }
+ case EXPR_PAYLOAD: /* II? */
+ value = expr->right;
+ if (value->etype != EXPR_VALUE)
+ return;
+
+ switch (expr->op) {
+ case OP_AND: /* IIa */
+ payload = expr->left;
+ mpz_init_bitmask(bitmask, payload->len);
+ mpz_xor(bitmask, bitmask, value->value);
+ mpz_set(value->value, bitmask);
+ mpz_clear(bitmask);
+ break;
+ case OP_OR: /* IIb */
+ break;
+ default: /* No idea */
+ return;
+ }
+
+ stmt_payload_binop_pp(ctx, expr);
+ if (!payload_is_known(expr->left))
+ return;
+
+ expr_free(stmt->payload.expr);
+
+ switch (expr->op) {
+ case OP_AND:
+ /* Mask was used to match payload, i.e.
+ * user asked to set zero value.
+ */
+ mpz_set_ui(value->value, 0);
+ break;
+ default:
+ break;
+ }
+
+ stmt->payload.expr = expr_get(expr->left);
+ stmt->payload.val = expr_get(expr->right);
+ expr_free(expr);
+ break;
+ default: /* No idea */
+ break;
+ }
+}
+
+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);
+
+ expr_postprocess(ctx, &stmt->payload.val);
+}
+
+static void stmt_queue_postprocess(struct rule_pp_ctx *ctx)
+{
+ struct stmt *stmt = ctx->stmt;
+ struct expr *e = stmt->queue.queue;
+
+ if (e == NULL || e->etype == EXPR_VALUE ||
+ e->etype == EXPR_RANGE)
+ return;
+
+ expr_postprocess(ctx, &stmt->queue.queue);
+}
+
+/*
+ * We can only remove payload dependencies if they occur without
+ * a statement with side effects in between.
+ *
+ * For instance:
+ * 'ip protocol tcp tcp dport 22 counter' is same as
+ * 'tcp dport 22 counter'.
+ *
+ * 'ip protocol tcp counter tcp dport 22' cannot be written as
+ * 'counter tcp dport 22' (that would be counter ip protocol tcp, but
+ * that counts every packet, not just ip/tcp).
+ */
+static void
+rule_maybe_reset_payload_deps(struct payload_dep_ctx *pdctx, enum stmt_types t)
+{
+ if (t == STMT_EXPRESSION)
+ return;
+
+ 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._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:
+ stmt_expr_postprocess(&rctx);
+ break;
+ case STMT_PAYLOAD:
+ stmt_payload_postprocess(&rctx);
+ break;
+ case STMT_METER:
+ expr_postprocess(&rctx, &stmt->meter.key);
+ break;
+ case STMT_META:
+ if (stmt->meta.expr != NULL)
+ expr_postprocess(&rctx, &stmt->meta.expr);
+ break;
+ case STMT_CT:
+ if (stmt->ct.expr != NULL) {
+ expr_postprocess(&rctx, &stmt->ct.expr);
+
+ if (stmt->ct.expr->etype == EXPR_BINOP &&
+ stmt->ct.key == NFT_CT_EVENTMASK) {
+ expr = binop_tree_to_list(NULL, stmt->ct.expr);
+ expr_free(stmt->ct.expr);
+ stmt->ct.expr = expr;
+ }
+ }
+ break;
+ case STMT_NAT:
+ if (stmt->nat.addr != NULL)
+ expr_postprocess(&rctx, &stmt->nat.addr);
+ if (stmt->nat.proto != NULL)
+ 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(&dl->pdctx);
+ expr_postprocess(&rctx, &stmt->tproxy.port);
+ }
+ break;
+ case STMT_REJECT:
+ stmt_reject_postprocess(&rctx);
+ break;
+ case STMT_SET:
+ expr_postprocess(&rctx, &stmt->set.key);
+ break;
+ case STMT_MAP:
+ expr_postprocess(&rctx, &stmt->map.key);
+ expr_postprocess(&rctx, &stmt->map.data);
+ break;
+ case STMT_DUP:
+ if (stmt->dup.to != NULL)
+ expr_postprocess(&rctx, &stmt->dup.to);
+ if (stmt->dup.dev != NULL)
+ expr_postprocess(&rctx, &stmt->dup.dev);
+ break;
+ case STMT_FWD:
+ expr_postprocess(&rctx, &stmt->fwd.dev);
+ if (stmt->fwd.addr != NULL)
+ expr_postprocess(&rctx, &stmt->fwd.addr);
+ break;
+ case STMT_XT:
+ stmt_xt_postprocess(&rctx, stmt, rule);
+ break;
+ case STMT_OBJREF:
+ expr_postprocess(&rctx, &stmt->objref.expr);
+ break;
+ case STMT_QUEUE:
+ stmt_queue_postprocess(&rctx);
+ break;
+ default:
+ break;
+ }
+
+ dl->pdctx.prev = rctx.stmt;
+
+ rule_maybe_reset_payload_deps(&dl->pdctx, type);
+ }
+}
+
+static int parse_rule_udata_cb(const struct nftnl_udata *attr, void *data)
+{
+ unsigned char *value = nftnl_udata_get(attr);
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+ const struct nftnl_udata **tb = data;
+
+ switch (type) {
+ case NFTNL_UDATA_RULE_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+static char *nftnl_rule_get_comment(const struct nftnl_rule *nlr)
+{
+ const struct nftnl_udata *tb[NFTNL_UDATA_RULE_MAX + 1] = {};
+ const void *data;
+ uint32_t len;
+
+ if (!nftnl_rule_is_set(nlr, NFTNL_RULE_USERDATA))
+ return NULL;
+
+ data = nftnl_rule_get_data(nlr, NFTNL_RULE_USERDATA, &len);
+
+ if (nftnl_udata_parse(data, len, parse_rule_udata_cb, tb) < 0)
+ return NULL;
+
+ if (!tb[NFTNL_UDATA_RULE_COMMENT])
+ return NULL;
+
+ return xstrdup(nftnl_udata_get(tb[NFTNL_UDATA_RULE_COMMENT]));
+}
+
+struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
+ struct nftnl_rule *nlr)
+{
+ struct netlink_parse_ctx _ctx, *pctx = &_ctx;
+ struct handle h;
+
+ memset(&_ctx, 0, sizeof(_ctx));
+ _ctx.msgs = ctx->msgs;
+ _ctx.debug_mask = ctx->nft->debug_mask;
+ _ctx.nlctx = ctx;
+
+ memset(&h, 0, sizeof(h));
+ h.family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
+ h.table.name = xstrdup(nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE));
+ h.chain.name = xstrdup(nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN));
+ h.handle.id = nftnl_rule_get_u64(nlr, NFTNL_RULE_HANDLE);
+
+ if (nftnl_rule_is_set(nlr, NFTNL_RULE_POSITION))
+ h.position.id = nftnl_rule_get_u64(nlr, NFTNL_RULE_POSITION);
+
+ pctx->rule = rule_alloc(&netlink_location, &h);
+ pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
+ h.table.name, h.family);
+ if (!pctx->table) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ pctx->rule->comment = nftnl_rule_get_comment(nlr);
+
+ nftnl_expr_foreach(nlr, netlink_parse_rule_expr, pctx);
+
+ rule_parse_postprocess(pctx, pctx->rule);
+ netlink_release_registers(pctx);
+ return pctx->rule;
+}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
new file mode 100644
index 0000000..0c62341
--- /dev/null
+++ b/src/netlink_linearize.c
@@ -0,0 +1,1789 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2013 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.
+ *
+ * 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 <rule.h>
+#include <statement.h>
+#include <expression.h>
+#include <netlink.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <netinet/in.h>
+
+#include <linux/netfilter.h>
+#include <libnftnl/udata.h>
+
+struct nft_expr_loc *nft_expr_loc_find(const struct nftnl_expr *nle,
+ struct netlink_linearize_ctx *ctx)
+{
+ struct nft_expr_loc *eloc;
+ uint32_t hash;
+
+ hash = (uint64_t)nle % NFT_EXPR_LOC_HSIZE;
+ list_for_each_entry(eloc, &ctx->expr_loc_htable[hash], hlist) {
+ if (eloc->nle == nle)
+ return eloc;
+ }
+
+ return NULL;
+}
+
+static void nft_expr_loc_add(const struct nftnl_expr *nle,
+ const struct location *loc,
+ struct netlink_linearize_ctx *ctx)
+{
+ struct nft_expr_loc *eloc;
+ uint32_t hash;
+
+ eloc = xmalloc(sizeof(*eloc));
+ eloc->nle = nle;
+ eloc->loc = loc;
+ hash = (uint64_t)nle % NFT_EXPR_LOC_HSIZE;
+ list_add_tail(&eloc->hlist, &ctx->expr_loc_htable[hash]);
+}
+
+static void netlink_put_register(struct nftnl_expr *nle,
+ uint32_t attr, uint32_t reg)
+{
+ /* Convert to 128 bit register numbers if possible for compatibility */
+ if (reg != NFT_REG_VERDICT) {
+ reg -= NFT_REG_1;
+ if (reg % (NFT_REG_SIZE / NFT_REG32_SIZE) == 0)
+ reg = NFT_REG_1 + reg / (NFT_REG_SIZE / NFT_REG32_SIZE);
+ else
+ reg += NFT_REG32_00;
+ }
+
+ nftnl_expr_set_u32(nle, attr, reg);
+}
+
+static enum nft_registers __get_register(struct netlink_linearize_ctx *ctx,
+ unsigned int size)
+{
+ unsigned int reg, n;
+
+ n = netlink_register_space(size);
+ if (ctx->reg_low + n > NFT_REG_1 + NFT_REG32_15 - NFT_REG32_00 + 1)
+ BUG("register reg_low %u invalid\n", ctx->reg_low);
+
+ reg = ctx->reg_low;
+ ctx->reg_low += n;
+ return reg;
+}
+
+static void __release_register(struct netlink_linearize_ctx *ctx,
+ unsigned int size)
+{
+ unsigned int n;
+
+ n = netlink_register_space(size);
+ if (ctx->reg_low < NFT_REG_1 + n)
+ BUG("register reg_low %u invalid\n", ctx->reg_low);
+
+ ctx->reg_low -= n;
+}
+
+static enum nft_registers get_register(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr)
+{
+ if (expr && expr->etype == EXPR_CONCAT)
+ return __get_register(ctx, expr->len);
+ else
+ return __get_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
+}
+
+static void release_register(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr)
+{
+ if (expr && expr->etype == EXPR_CONCAT)
+ __release_register(ctx, expr->len);
+ else
+ __release_register(ctx, NFT_REG_SIZE * BITS_PER_BYTE);
+}
+
+static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg);
+
+static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ const struct expr *i;
+
+ list_for_each_entry(i, &expr->expressions, list) {
+ netlink_gen_expr(ctx, i, dreg);
+ dreg += netlink_register_space(i->len);
+ }
+}
+
+static void nft_rule_add_expr(struct netlink_linearize_ctx *ctx,
+ struct nftnl_expr *nle,
+ const struct location *loc)
+{
+ nft_expr_loc_add(nle, loc, ctx);
+ nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
+static void netlink_gen_fib(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("fib");
+ netlink_put_register(nle, NFTNL_EXPR_FIB_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_RESULT, expr->fib.result);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_FLAGS, expr->fib.flags);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ enum nft_registers sreg;
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("hash");
+
+ if (expr->hash.expr) {
+ sreg = get_register(ctx, expr->hash.expr);
+ netlink_gen_expr(ctx, expr->hash.expr, sreg);
+ release_register(ctx, expr->hash.expr);
+ netlink_put_register(nle, NFTNL_EXPR_HASH_SREG, sreg);
+
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_LEN,
+ div_round_up(expr->hash.expr->len,
+ BITS_PER_BYTE));
+ }
+ netlink_put_register(nle, NFTNL_EXPR_HASH_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_MODULUS, expr->hash.mod);
+ if (expr->hash.seed_set)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_SEED, expr->hash.seed);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_OFFSET, expr->hash.offset);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_TYPE, expr->hash.type);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static struct nftnl_expr *
+__netlink_gen_payload(const struct expr *expr, enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("payload");
+ netlink_put_register(nle, NFTNL_EXPR_PAYLOAD_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_BASE,
+ expr->payload.base - 1);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET,
+ expr->payload.offset / BITS_PER_BYTE);
+ 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);
+}
+
+static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ unsigned int offset = expr->exthdr.offset;
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("exthdr");
+ netlink_put_register(nle, NFTNL_EXPR_EXTHDR_DREG, dreg);
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
+ expr->exthdr.raw_type);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
+ div_round_up(expr->len, BITS_PER_BYTE));
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_FLAGS, expr->exthdr.flags);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_meta(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ if (expr->meta.inner_desc) {
+ netlink_gen_inner(ctx, expr, dreg, expr->meta.inner_desc);
+ return;
+ }
+
+ nle = __netlink_gen_meta(expr, dreg);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_rt(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("rt");
+ netlink_put_register(nle, NFTNL_EXPR_RT_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_RT_KEY, expr->rt.key);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_socket(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("socket");
+ netlink_put_register(nle, NFTNL_EXPR_SOCKET_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_KEY, expr->socket.key);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_LEVEL, expr->socket.level);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_osf(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("osf");
+ netlink_put_register(nle, NFTNL_EXPR_OSF_DREG, dreg);
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_OSF_TTL, expr->osf.ttl);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_OSF_FLAGS, expr->osf.flags);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("numgen");
+ netlink_put_register(nle, NFTNL_EXPR_NG_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_TYPE, expr->numgen.type);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_MODULUS, expr->numgen.mod);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_OFFSET, expr->numgen.offset);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_ct(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("ct");
+ netlink_put_register(nle, NFTNL_EXPR_CT_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CT_KEY, expr->ct.key);
+ if (expr->ct.direction >= 0)
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
+ expr->ct.direction);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers sreg;
+ int regspace = 0;
+
+ assert(expr->mappings->etype == EXPR_SET_REF);
+
+ if (dreg == NFT_REG_VERDICT)
+ sreg = get_register(ctx, expr->map);
+ else
+ sreg = dreg;
+
+ /* suppress assert in netlink_gen_expr */
+ if (expr->map->etype == EXPR_CONCAT) {
+ regspace = netlink_register_space(expr->map->len);
+ ctx->reg_low += regspace;
+ }
+
+ netlink_gen_expr(ctx, expr->map, sreg);
+ ctx->reg_low -= regspace;
+
+ nle = alloc_nft_expr("lookup");
+ netlink_put_register(nle, NFTNL_EXPR_LOOKUP_SREG, sreg);
+ netlink_put_register(nle, NFTNL_EXPR_LOOKUP_DREG, dreg);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_LOOKUP_SET,
+ expr->mappings->set->handle.set.name);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID,
+ expr->mappings->set->handle.set_id);
+
+ if (dreg == NFT_REG_VERDICT)
+ release_register(ctx, expr->map);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers sreg;
+
+ assert(expr->right->etype == EXPR_SET_REF);
+ assert(dreg == NFT_REG_VERDICT);
+
+ sreg = get_register(ctx, expr->left);
+ netlink_gen_expr(ctx, expr->left, sreg);
+
+ nle = alloc_nft_expr("lookup");
+ netlink_put_register(nle, NFTNL_EXPR_LOOKUP_SREG, sreg);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_LOOKUP_SET,
+ expr->right->set->handle.set.name);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_SET_ID,
+ expr->right->set->handle.set_id);
+ if (expr->op == OP_NEQ)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS, NFT_LOOKUP_F_INV);
+
+ release_register(ctx, expr->left);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static enum nft_cmp_ops netlink_gen_cmp_op(enum ops op)
+{
+ switch (op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ return NFT_CMP_EQ;
+ case OP_NEQ:
+ return NFT_CMP_NEQ;
+ case OP_LT:
+ return NFT_CMP_LT;
+ case OP_GT:
+ return NFT_CMP_GT;
+ case OP_LTE:
+ return NFT_CMP_LTE;
+ case OP_GTE:
+ return NFT_CMP_GTE;
+ default:
+ BUG("invalid comparison operation %u\n", op);
+ }
+}
+
+static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers sreg)
+{
+ struct nft_data_linearize nld, zero = {};
+ struct nftnl_expr *nle;
+ mpz_t mask;
+
+ 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);
+ mpz_clear(mask);
+
+ zero.len = nld.len;
+
+ nle = alloc_nft_expr("bitwise");
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, nld.len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld.value, nld.len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &zero.value, zero.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+
+ return expr->right->prefix;
+}
+
+static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct expr *range = expr->right;
+ struct nftnl_expr *nle;
+ enum nft_registers sreg;
+ struct nft_data_linearize nld;
+
+ assert(dreg == NFT_REG_VERDICT);
+
+ sreg = get_register(ctx, expr->left);
+ netlink_gen_expr(ctx, expr->left, sreg);
+
+ switch (expr->op) {
+ case OP_NEQ:
+ nle = alloc_nft_expr("range");
+ netlink_put_register(nle, NFTNL_EXPR_RANGE_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_RANGE_OP, NFT_RANGE_NEQ);
+ netlink_gen_data(range->left, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_RANGE_FROM_DATA,
+ nld.value, nld.len);
+ netlink_gen_data(range->right, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_RANGE_TO_DATA,
+ nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ break;
+ case OP_EQ:
+ case OP_IMPLICIT:
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP,
+ netlink_gen_cmp_op(OP_GTE));
+ netlink_gen_data(range->left, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP,
+ netlink_gen_cmp_op(OP_LTE));
+ netlink_gen_data(range->right, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ break;
+ default:
+ BUG("invalid range operation %u\n", expr->op);
+
+ }
+
+ release_register(ctx, expr->left);
+}
+
+static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+ struct nft_data_linearize nld, nld2;
+ enum nft_registers sreg;
+ unsigned int len;
+ mpz_t zero;
+
+ assert(dreg == NFT_REG_VERDICT);
+
+ sreg = get_register(ctx, expr->left);
+ netlink_gen_expr(ctx, expr->left, sreg);
+ len = div_round_up(expr->left->len, BITS_PER_BYTE);
+
+ mpz_init_set_ui(zero, 0);
+
+ netlink_gen_raw_data(zero, expr->right->byteorder, len, &nld);
+ netlink_gen_data(expr->right, &nld2);
+
+ if (expr->left->etype == EXPR_BINOP) {
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld2.value, nld2.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ } else {
+ nle = alloc_nft_expr("bitwise");
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ if (expr->op == OP_NEG)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
+ else
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
+
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ }
+
+ mpz_clear(zero);
+ release_register(ctx, expr->left);
+}
+
+static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
+ enum nft_registers sreg;
+ struct expr *right;
+ int len;
+
+ assert(dreg == NFT_REG_VERDICT);
+
+ switch (expr->op) {
+ case OP_IMPLICIT:
+ case OP_EQ:
+ case OP_NEQ:
+ case OP_LT:
+ case OP_GT:
+ case OP_LTE:
+ case OP_GTE:
+ case OP_NEG:
+ break;
+ default:
+ BUG("invalid relational operation %u\n", expr->op);
+ }
+
+ switch (expr->right->etype) {
+ case EXPR_RANGE:
+ return netlink_gen_range(ctx, expr, dreg);
+ case EXPR_SET:
+ case EXPR_SET_REF:
+ return netlink_gen_lookup(ctx, expr, dreg);
+ case EXPR_LIST:
+ return netlink_gen_flagcmp(ctx, expr, dreg);
+ case EXPR_PREFIX:
+ sreg = get_register(ctx, expr->left);
+ if (expr_basetype(expr->left)->type != TYPE_STRING &&
+ (expr->right->byteorder != BYTEORDER_BIG_ENDIAN ||
+ !expr->right->prefix_len ||
+ expr->right->prefix_len % BITS_PER_BYTE)) {
+ len = div_round_up(expr->right->len, BITS_PER_BYTE);
+ netlink_gen_expr(ctx, expr->left, sreg);
+ right = netlink_gen_prefix(ctx, expr, sreg);
+ } else {
+ len = div_round_up(expr->right->prefix_len, BITS_PER_BYTE);
+ right = expr->right->prefix;
+ expr->left->len = expr->right->prefix_len;
+ netlink_gen_expr(ctx, expr->left, sreg);
+ }
+ break;
+ default:
+ if ((expr->op == OP_IMPLICIT || expr->op == OP_NEG) &&
+ expr->right->dtype->basetype != NULL &&
+ expr->right->dtype->basetype->type == TYPE_BITMASK)
+ return netlink_gen_flagcmp(ctx, expr, dreg);
+
+ sreg = get_register(ctx, expr->left);
+ len = div_round_up(expr->right->len, BITS_PER_BYTE);
+ right = expr->right;
+ netlink_gen_expr(ctx, expr->left, sreg);
+ break;
+ }
+
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP,
+ netlink_gen_cmp_op(expr->op));
+ netlink_gen_data(right, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, len);
+ release_register(ctx, expr->left);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x)
+{
+ /* xor = x ^ (xor & m) */
+ mpz_and(xor, xor, m);
+ mpz_xor(xor, x, xor);
+ /* mask &= m */
+ mpz_and(mask, mask, m);
+}
+
+static void netlink_gen_shift(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ enum nft_bitwise_ops op = expr->op == OP_LSHIFT ?
+ NFT_BITWISE_LSHIFT : NFT_BITWISE_RSHIFT;
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
+
+ netlink_gen_expr(ctx, expr->left, dreg);
+
+ nle = alloc_nft_expr("bitwise");
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg);
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, op);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
+
+ netlink_gen_raw_data(expr->right->value, expr->right->byteorder,
+ sizeof(uint32_t), &nld);
+
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_DATA, nld.value,
+ nld.len);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct 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;
+
+ mpz_init(mask);
+ mpz_init(xor);
+ mpz_init(val);
+ mpz_init(tmp);
+
+ 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))
+ binops[n++] = left = left->left;
+ n--;
+
+ netlink_gen_expr(ctx, binops[n--], dreg);
+
+ mpz_bitmask(mask, expr->len);
+ mpz_set_ui(xor, 0);
+ for (; n >= 0; n--) {
+ i = binops[n];
+ mpz_set(val, i->right->value);
+
+ switch (i->op) {
+ case OP_AND:
+ mpz_set_ui(tmp, 0);
+ combine_binop(mask, xor, val, tmp);
+ break;
+ case OP_OR:
+ mpz_com(tmp, val);
+ combine_binop(mask, xor, tmp, val);
+ break;
+ case OP_XOR:
+ mpz_bitmask(tmp, expr->len);
+ combine_binop(mask, xor, tmp, val);
+ break;
+ default:
+ BUG("invalid binary operation %u\n", i->op);
+ }
+ }
+
+ len = div_round_up(expr->len, BITS_PER_BYTE);
+
+ nle = alloc_nft_expr("bitwise");
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg);
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_BOOL);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
+
+ netlink_gen_raw_data(mask, expr->byteorder, len, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, nld.value, nld.len);
+ netlink_gen_raw_data(xor, expr->byteorder, len, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, nld.value, nld.len);
+
+ mpz_clear(tmp);
+ mpz_clear(val);
+ mpz_clear(xor);
+ mpz_clear(mask);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ switch(expr->op) {
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ netlink_gen_shift(ctx, expr, dreg);
+ break;
+ default:
+ netlink_gen_bitwise(ctx, expr, dreg);
+ break;
+ }
+}
+
+static enum nft_byteorder_ops netlink_gen_unary_op(enum ops op)
+{
+ switch (op) {
+ case OP_HTON:
+ return NFT_BYTEORDER_HTON;
+ case OP_NTOH:
+ return NFT_BYTEORDER_NTOH;
+ default:
+ BUG("invalid unary operation %u\n", op);
+ }
+}
+
+static void netlink_gen_unary(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+ int byte_size;
+
+ if ((expr->arg->len % 64) == 0)
+ byte_size = 8;
+ else if ((expr->arg->len % 32) == 0)
+ byte_size = 4;
+ else
+ byte_size = 2;
+
+ netlink_gen_expr(ctx, expr->arg, dreg);
+
+ nle = alloc_nft_expr("byteorder");
+ 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,
+ div_round_up(expr->len, BITS_PER_BYTE));
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_SIZE,
+ byte_size);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_OP,
+ netlink_gen_unary_op(expr->op));
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_immediate(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ const struct location *loc = &expr->location;
+ struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("immediate");
+ netlink_put_register(nle, NFTNL_EXPR_IMM_DREG, dreg);
+ netlink_gen_data(expr, &nld);
+ switch (expr->etype) {
+ case EXPR_VALUE:
+ nftnl_expr_set(nle, NFTNL_EXPR_IMM_DATA, nld.value, nld.len);
+ break;
+ case EXPR_VERDICT:
+ if (expr->chain) {
+ nftnl_expr_set_str(nle, NFTNL_EXPR_IMM_CHAIN,
+ nld.chain);
+ loc = &expr->chain->location;
+ } else if (expr->chain_id) {
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_IMM_CHAIN_ID,
+ nld.chain_id);
+ }
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_IMM_VERDICT, nld.verdict);
+ break;
+ default:
+ break;
+ }
+ nft_rule_add_expr(ctx, nle, loc);
+}
+
+static void netlink_gen_xfrm(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("xfrm");
+ netlink_put_register(nle, NFTNL_EXPR_XFRM_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_KEY, expr->xfrm.key);
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_XFRM_DIR, expr->xfrm.direction);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_SPNUM, expr->xfrm.spnum);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ assert(dreg < ctx->reg_low);
+
+ switch (expr->etype) {
+ case EXPR_VERDICT:
+ case EXPR_VALUE:
+ return netlink_gen_immediate(ctx, expr, dreg);
+ case EXPR_UNARY:
+ return netlink_gen_unary(ctx, expr, dreg);
+ case EXPR_BINOP:
+ return netlink_gen_binop(ctx, expr, dreg);
+ case EXPR_RELATIONAL:
+ return netlink_gen_relational(ctx, expr, dreg);
+ case EXPR_CONCAT:
+ return netlink_gen_concat(ctx, expr, dreg);
+ case EXPR_MAP:
+ return netlink_gen_map(ctx, expr, dreg);
+ case EXPR_PAYLOAD:
+ return netlink_gen_payload(ctx, expr, dreg);
+ case EXPR_EXTHDR:
+ return netlink_gen_exthdr(ctx, expr, dreg);
+ case EXPR_META:
+ return netlink_gen_meta(ctx, expr, dreg);
+ case EXPR_RT:
+ return netlink_gen_rt(ctx, expr, dreg);
+ case EXPR_CT:
+ return netlink_gen_ct(ctx, expr, dreg);
+ case EXPR_SET_ELEM:
+ return netlink_gen_expr(ctx, expr->key, dreg);
+ case EXPR_NUMGEN:
+ return netlink_gen_numgen(ctx, expr, dreg);
+ case EXPR_HASH:
+ return netlink_gen_hash(ctx, expr, dreg);
+ case EXPR_FIB:
+ return netlink_gen_fib(ctx, expr, dreg);
+ case EXPR_SOCKET:
+ return netlink_gen_socket(ctx, expr, dreg);
+ case EXPR_OSF:
+ return netlink_gen_osf(ctx, expr, dreg);
+ case EXPR_XFRM:
+ return netlink_gen_xfrm(ctx, expr, dreg);
+ default:
+ BUG("unknown expression type %s\n", expr_name(expr));
+ }
+}
+
+static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct expr *expr = stmt->objref.expr;
+ struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
+ uint32_t sreg_key;
+
+ nle = alloc_nft_expr("objref");
+ switch (expr->etype) {
+ case EXPR_MAP:
+ sreg_key = get_register(ctx, expr->map);
+ netlink_gen_expr(ctx, expr->map, sreg_key);
+ release_register(ctx, expr->map);
+
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_OBJREF_SET_SREG, sreg_key);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_OBJREF_SET_NAME,
+ expr->mappings->set->handle.set.name);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_OBJREF_SET_ID,
+ expr->mappings->set->handle.set_id);
+ break;
+ case EXPR_VALUE:
+ netlink_gen_data(stmt->objref.expr, &nld);
+ nftnl_expr_set(nle, NFTNL_EXPR_OBJREF_IMM_NAME,
+ nld.value, nld.len);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_OBJREF_IMM_TYPE,
+ stmt->objref.type);
+ break;
+ default:
+ BUG("unsupported expression %u\n", expr->etype);
+ }
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static struct nftnl_expr *netlink_gen_connlimit_stmt(const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("connlimit");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CONNLIMIT_COUNT,
+ stmt->connlimit.count);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CONNLIMIT_FLAGS,
+ stmt->connlimit.flags);
+
+ return nle;
+}
+
+static struct nftnl_expr *netlink_gen_counter_stmt(const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("counter");
+ if (stmt->counter.packets) {
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_PACKETS,
+ stmt->counter.packets);
+ }
+ if (stmt->counter.bytes) {
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_CTR_BYTES,
+ stmt->counter.bytes);
+ }
+
+ return nle;
+}
+
+static struct nftnl_expr *netlink_gen_limit_stmt(const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("limit");
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_RATE, stmt->limit.rate);
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_LIMIT_UNIT, stmt->limit.unit);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_TYPE, stmt->limit.type);
+ if (stmt->limit.burst > 0)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_BURST,
+ stmt->limit.burst);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LIMIT_FLAGS, stmt->limit.flags);
+
+ return nle;
+}
+
+static struct nftnl_expr *netlink_gen_quota_stmt(const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("quota");
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_QUOTA_BYTES, stmt->quota.bytes);
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_QUOTA_CONSUMED, stmt->quota.used);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_QUOTA_FLAGS, stmt->quota.flags);
+
+ 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) {
+ case STMT_CONNLIMIT:
+ return netlink_gen_connlimit_stmt(stmt);
+ case STMT_COUNTER:
+ return netlink_gen_counter_stmt(stmt);
+ case STMT_LIMIT:
+ 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);
+ }
+}
+
+static void netlink_gen_verdict_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
+}
+
+static bool payload_needs_l4csum_update_pseudohdr(const struct expr *expr,
+ const struct proto_desc *desc)
+{
+ int i;
+
+ for (i = 0; i < PROTO_HDRS_MAX; i++) {
+ if (payload_hdr_field(expr) == desc->pseudohdr[i])
+ return true;
+ }
+ return false;
+}
+
+static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ const struct expr *expr;
+ enum nft_registers sreg;
+ unsigned int offset;
+
+ sreg = get_register(ctx, stmt->exthdr.val);
+ netlink_gen_expr(ctx, stmt->exthdr.val, sreg);
+ release_register(ctx, stmt->exthdr.val);
+
+ expr = stmt->exthdr.expr;
+
+ offset = expr->exthdr.offset;
+
+ nle = alloc_nft_expr("exthdr");
+ netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg);
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
+ expr->exthdr.raw_type);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
+ div_round_up(expr->len, BITS_PER_BYTE));
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ const struct proto_desc *desc;
+ const struct expr *expr;
+ enum nft_registers sreg;
+ unsigned int csum_off;
+
+ sreg = get_register(ctx, stmt->payload.val);
+ netlink_gen_expr(ctx, stmt->payload.val, sreg);
+ release_register(ctx, stmt->payload.val);
+
+ expr = stmt->payload.expr;
+
+ csum_off = 0;
+ desc = expr->payload.desc;
+ if (desc != NULL && desc->checksum_key)
+ csum_off = desc->templates[desc->checksum_key].offset;
+
+ nle = alloc_nft_expr("payload");
+ netlink_put_register(nle, NFTNL_EXPR_PAYLOAD_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_BASE,
+ expr->payload.base - 1);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET,
+ expr->payload.offset / BITS_PER_BYTE);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_LEN,
+ expr->len / BITS_PER_BYTE);
+ if (csum_off) {
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_TYPE,
+ desc->checksum_type);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_OFFSET,
+ csum_off / BITS_PER_BYTE);
+ }
+ if ((expr->payload.base == PROTO_BASE_NETWORK_HDR && desc &&
+ payload_needs_l4csum_update_pseudohdr(expr, desc)) ||
+ expr->payload.base == PROTO_BASE_INNER_HDR)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS,
+ NFT_PAYLOAD_L4CSUM_PSEUDOHDR);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers sreg;
+
+ sreg = get_register(ctx, stmt->meta.expr);
+ netlink_gen_expr(ctx, stmt->meta.expr, sreg);
+ release_register(ctx, stmt->meta.expr);
+
+ nle = alloc_nft_expr("meta");
+ netlink_put_register(nle, NFTNL_EXPR_META_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, stmt->meta.key);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("log");
+ if (stmt->log.prefix != NULL) {
+ char prefix[NF_LOG_PREFIXLEN] = {};
+
+ expr_to_string(stmt->log.prefix, prefix);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX, prefix);
+ }
+ if (stmt->log.flags & STMT_LOG_GROUP) {
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_LOG_GROUP, stmt->log.group);
+ if (stmt->log.flags & STMT_LOG_SNAPLEN)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_SNAPLEN,
+ stmt->log.snaplen);
+ if (stmt->log.flags & STMT_LOG_QTHRESHOLD)
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_LOG_QTHRESHOLD,
+ stmt->log.qthreshold);
+ } else {
+ if (stmt->log.flags & STMT_LOG_LEVEL)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_LEVEL,
+ stmt->log.level);
+ if (stmt->log.logflags)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_FLAGS,
+ stmt->log.logflags);
+ }
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("reject");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_REJECT_TYPE, stmt->reject.type);
+ if (stmt->reject.icmp_code != -1)
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_REJECT_CODE,
+ stmt->reject.icmp_code);
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static unsigned int nat_addrlen(uint8_t family)
+{
+ switch (family) {
+ case NFPROTO_IPV4: return 32;
+ case NFPROTO_IPV6: return 128;
+ }
+
+ BUG("invalid nat family %u\n", family);
+ return 0;
+}
+
+static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers amin_reg, amax_reg;
+ enum nft_registers pmin_reg, pmax_reg;
+ uint8_t family = 0;
+ int registers = 0;
+ int nftnl_flag_attr;
+ int nftnl_reg_pmin, nftnl_reg_pmax;
+
+ switch (stmt->nat.type) {
+ case NFT_NAT_SNAT:
+ case NFT_NAT_DNAT:
+ nle = alloc_nft_expr("nat");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_TYPE, stmt->nat.type);
+
+ family = stmt->nat.family;
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_FAMILY, family);
+
+ nftnl_flag_attr = NFTNL_EXPR_NAT_FLAGS;
+ nftnl_reg_pmin = NFTNL_EXPR_NAT_REG_PROTO_MIN;
+ nftnl_reg_pmax = NFTNL_EXPR_NAT_REG_PROTO_MAX;
+ break;
+ case NFT_NAT_MASQ:
+ nle = alloc_nft_expr("masq");
+
+ nftnl_flag_attr = NFTNL_EXPR_MASQ_FLAGS;
+ nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN;
+ nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX;
+ break;
+ case NFT_NAT_REDIR:
+ nle = alloc_nft_expr("redir");
+
+ nftnl_flag_attr = NFTNL_EXPR_REDIR_FLAGS;
+ nftnl_reg_pmin = NFTNL_EXPR_REDIR_REG_PROTO_MIN;
+ nftnl_reg_pmax = NFTNL_EXPR_REDIR_REG_PROTO_MAX;
+ break;
+ default:
+ BUG("unknown nat type %d\n", stmt->nat.type);
+ break;
+ }
+
+ if (stmt->nat.flags != 0)
+ nftnl_expr_set_u32(nle, nftnl_flag_attr, stmt->nat.flags);
+
+ if (stmt->nat.addr) {
+ amin_reg = get_register(ctx, NULL);
+ registers++;
+
+ if (stmt->nat.addr->etype == EXPR_RANGE) {
+ amax_reg = get_register(ctx, NULL);
+ registers++;
+
+ netlink_gen_expr(ctx, stmt->nat.addr->left, amin_reg);
+ netlink_gen_expr(ctx, stmt->nat.addr->right, amax_reg);
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN,
+ amin_reg);
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ amax_reg);
+ } else {
+ netlink_gen_expr(ctx, stmt->nat.addr, amin_reg);
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN,
+ amin_reg);
+ if (stmt->nat.addr->etype == EXPR_MAP &&
+ stmt->nat.addr->mappings->set->data->flags & EXPR_F_INTERVAL) {
+ amin_reg += netlink_register_space(nat_addrlen(family));
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+ netlink_put_register(nle, nftnl_reg_pmin,
+ amin_reg);
+ } else {
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ amin_reg);
+ }
+ }
+ }
+
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+ /* nat_stmt evaluation step doesn't allow
+ * STMT_NAT_F_CONCAT && stmt->nat.proto.
+ */
+ assert(stmt->nat.proto == NULL);
+
+ pmin_reg = amin_reg;
+
+ if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL) {
+ pmin_reg += netlink_register_space(nat_addrlen(family));
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ pmin_reg);
+ }
+
+ /* if STMT_NAT_F_CONCAT is set, the mapped type is a
+ * concatenation of 'addr . inet_service'.
+ * The map lookup will then return the
+ * concatenated value, so we need to skip
+ * the address and use the register that
+ * will hold the inet_service part.
+ */
+ pmin_reg += netlink_register_space(nat_addrlen(family));
+ if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL)
+ netlink_put_register(nle, nftnl_reg_pmax, pmin_reg);
+ else
+ netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
+ }
+ }
+
+ if (stmt->nat.proto) {
+ pmin_reg = get_register(ctx, NULL);
+ registers++;
+
+ if (stmt->nat.proto->etype == EXPR_RANGE) {
+ pmax_reg = get_register(ctx, NULL);
+ registers++;
+
+ netlink_gen_expr(ctx, stmt->nat.proto->left, pmin_reg);
+ netlink_gen_expr(ctx, stmt->nat.proto->right, pmax_reg);
+ netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
+ netlink_put_register(nle, nftnl_reg_pmax, pmax_reg);
+ } else {
+ netlink_gen_expr(ctx, stmt->nat.proto, pmin_reg);
+ netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
+ }
+ }
+
+ while (registers > 0) {
+ release_register(ctx, NULL);
+ registers--;
+ }
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers addr_reg;
+ enum nft_registers port_reg;
+ int registers = 0;
+ const int family = stmt->tproxy.family;
+ int nftnl_reg_port;
+
+ nle = alloc_nft_expr("tproxy");
+
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_TPROXY_FAMILY, family);
+
+ nftnl_reg_port = NFTNL_EXPR_TPROXY_REG_PORT;
+
+ if (stmt->tproxy.addr) {
+ addr_reg = get_register(ctx, NULL);
+ registers++;
+ netlink_gen_expr(ctx, stmt->tproxy.addr, addr_reg);
+ netlink_put_register(nle, NFTNL_EXPR_TPROXY_REG_ADDR,
+ addr_reg);
+ }
+
+ if (stmt->tproxy.port) {
+ port_reg = get_register(ctx, NULL);
+ registers++;
+ netlink_gen_expr(ctx, stmt->tproxy.port, port_reg);
+ netlink_put_register(nle, nftnl_reg_port, port_reg);
+ }
+
+ while (registers > 0) {
+ release_register(ctx, NULL);
+ registers--;
+ }
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("synproxy");
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_SYNPROXY_MSS, stmt->synproxy.mss);
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_SYNPROXY_WSCALE,
+ stmt->synproxy.wscale);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS,
+ stmt->synproxy.flags);
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers sreg1, sreg2;
+
+ nle = alloc_nft_expr("dup");
+
+ if (stmt->dup.to != NULL) {
+ if (stmt->dup.to->dtype == &ifindex_type) {
+ sreg1 = get_register(ctx, stmt->dup.to);
+ netlink_gen_expr(ctx, stmt->dup.to, sreg1);
+ netlink_put_register(nle, NFTNL_EXPR_DUP_SREG_DEV, sreg1);
+ } else {
+ sreg1 = get_register(ctx, stmt->dup.to);
+ netlink_gen_expr(ctx, stmt->dup.to, sreg1);
+ netlink_put_register(nle, NFTNL_EXPR_DUP_SREG_ADDR, sreg1);
+ }
+ }
+ if (stmt->dup.dev != NULL) {
+ sreg2 = get_register(ctx, stmt->dup.dev);
+ netlink_gen_expr(ctx, stmt->dup.dev, sreg2);
+ netlink_put_register(nle, NFTNL_EXPR_DUP_SREG_DEV, sreg2);
+ release_register(ctx, stmt->dup.dev);
+ }
+ if (stmt->dup.to != NULL)
+ release_register(ctx, stmt->dup.to);
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ enum nft_registers sreg1, sreg2;
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("fwd");
+
+ sreg1 = get_register(ctx, stmt->fwd.dev);
+ netlink_gen_expr(ctx, stmt->fwd.dev, sreg1);
+ netlink_put_register(nle, NFTNL_EXPR_FWD_SREG_DEV, sreg1);
+
+ if (stmt->fwd.addr != NULL) {
+ sreg2 = get_register(ctx, stmt->fwd.addr);
+ netlink_gen_expr(ctx, stmt->fwd.addr, sreg2);
+ netlink_put_register(nle, NFTNL_EXPR_FWD_SREG_ADDR, sreg2);
+ release_register(ctx, stmt->fwd.addr);
+ }
+ release_register(ctx, stmt->fwd.dev);
+
+ if (stmt->fwd.family)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_FWD_NFPROTO,
+ stmt->fwd.family);
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_optstrip_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle = alloc_nft_expr("exthdr");
+ struct expr *expr = stmt->optstrip.expr;
+
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
+ expr->exthdr.raw_type);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ enum nft_registers sreg = 0;
+ struct nftnl_expr *nle;
+ uint16_t total_queues;
+ struct expr *expr;
+ mpz_t low, high;
+
+ mpz_init2(low, 16);
+ mpz_init2(high, 16);
+
+ expr = stmt->queue.queue;
+
+ if (expr) {
+ if (expr->etype == EXPR_RANGE || expr->etype == EXPR_VALUE) {
+ range_expr_value_low(low, stmt->queue.queue);
+ range_expr_value_high(high, stmt->queue.queue);
+ } else {
+ sreg = get_register(ctx, expr);
+ netlink_gen_expr(ctx, expr, sreg);
+ release_register(ctx, expr);
+ }
+ }
+
+ total_queues = mpz_get_uint16(high) - mpz_get_uint16(low) + 1;
+
+ nle = alloc_nft_expr("queue");
+
+ if (sreg) {
+ netlink_put_register(nle, NFTNL_EXPR_QUEUE_SREG_QNUM, sreg);
+ } else {
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low));
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues);
+ }
+
+ if (stmt->queue.flags)
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_FLAGS,
+ stmt->queue.flags);
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+
+ mpz_clear(low);
+ mpz_clear(high);
+}
+
+static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers sreg;
+
+ sreg = get_register(ctx, stmt->ct.expr);
+ netlink_gen_expr(ctx, stmt->ct.expr, sreg);
+ release_register(ctx, stmt->ct.expr);
+
+ nle = alloc_nft_expr("ct");
+ netlink_put_register(nle, NFTNL_EXPR_CT_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CT_KEY, stmt->ct.key);
+ if (stmt->ct.direction >= 0)
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
+ stmt->ct.direction);
+
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_notrack_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("notrack");
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("flow_offload");
+ nftnl_expr_set_str(nle, NFTNL_EXPR_FLOW_TABLE_NAME,
+ stmt->flow.table_name);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct set *set = stmt->meter.set->set;
+ enum nft_registers sreg_key;
+ struct nftnl_expr *nle;
+ int num_stmts = 0;
+ struct stmt *this;
+
+ sreg_key = get_register(ctx, stmt->set.key->key);
+ netlink_gen_expr(ctx, stmt->set.key->key, sreg_key);
+ release_register(ctx, stmt->set.key->key);
+
+ nle = alloc_nft_expr("dynset");
+ netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key);
+ if (stmt->set.key->timeout > 0)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
+ stmt->set.key->timeout);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->set.op);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+
+ list_for_each_entry(this, &stmt->set.stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts == 1) {
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
+ netlink_gen_stmt_stateful(this), 0);
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ nftnl_expr_add_expr(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS,
+ netlink_gen_stmt_stateful(this));
+ }
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_FLAGS,
+ NFT_DYNSET_F_EXPR);
+ }
+}
+
+static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct set *set = stmt->map.set->set;
+ enum nft_registers sreg_data;
+ enum nft_registers sreg_key;
+ struct nftnl_expr *nle;
+ int num_stmts = 0;
+ struct stmt *this;
+
+ sreg_key = get_register(ctx, stmt->map.key->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->key);
+ release_register(ctx, stmt->map.data);
+
+ nle = alloc_nft_expr("dynset");
+ netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key);
+ netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA, sreg_data);
+
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->map.op);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+
+ if (stmt->map.key->timeout > 0)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
+ stmt->map.key->timeout);
+
+ list_for_each_entry(this, &stmt->map.stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts == 1) {
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
+ netlink_gen_stmt_stateful(this), 0);
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ nftnl_expr_add_expr(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS,
+ netlink_gen_stmt_stateful(this));
+ }
+ }
+}
+
+static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+ enum nft_registers sreg_key;
+ enum nft_dynset_ops op;
+ struct set *set;
+
+ sreg_key = get_register(ctx, stmt->meter.key->key);
+ netlink_gen_expr(ctx, stmt->meter.key->key, sreg_key);
+ release_register(ctx, stmt->meter.key->key);
+
+ set = stmt->meter.set->set;
+ if (stmt->meter.key->timeout)
+ op = NFT_DYNSET_OP_UPDATE;
+ else
+ op = NFT_DYNSET_OP_ADD;
+
+ nle = alloc_nft_expr("dynset");
+ netlink_put_register(nle, NFTNL_EXPR_DYNSET_SREG_KEY, sreg_key);
+ if (stmt->meter.key->timeout)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
+ stmt->meter.key->timeout);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, op);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
+ nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
+ netlink_gen_stmt_stateful(stmt->meter.stmt), 0);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_chain_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ return netlink_gen_expr(ctx, stmt->chain.expr, NFT_REG_VERDICT);
+}
+
+static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ switch (stmt->ops->type) {
+ case STMT_EXPRESSION:
+ return netlink_gen_expr(ctx, stmt->expr, NFT_REG_VERDICT);
+ case STMT_VERDICT:
+ return netlink_gen_verdict_stmt(ctx, stmt);
+ case STMT_METER:
+ return netlink_gen_meter_stmt(ctx, stmt);
+ case STMT_EXTHDR:
+ return netlink_gen_exthdr_stmt(ctx, stmt);
+ case STMT_PAYLOAD:
+ return netlink_gen_payload_stmt(ctx, stmt);
+ case STMT_META:
+ return netlink_gen_meta_stmt(ctx, stmt);
+ case STMT_LOG:
+ return netlink_gen_log_stmt(ctx, stmt);
+ case STMT_REJECT:
+ return netlink_gen_reject_stmt(ctx, stmt);
+ case STMT_NAT:
+ return netlink_gen_nat_stmt(ctx, stmt);
+ case STMT_TPROXY:
+ return netlink_gen_tproxy_stmt(ctx, stmt);
+ case STMT_SYNPROXY:
+ return netlink_gen_synproxy_stmt(ctx, stmt);
+ case STMT_DUP:
+ return netlink_gen_dup_stmt(ctx, stmt);
+ case STMT_QUEUE:
+ return netlink_gen_queue_stmt(ctx, stmt);
+ case STMT_CT:
+ return netlink_gen_ct_stmt(ctx, stmt);
+ case STMT_SET:
+ return netlink_gen_set_stmt(ctx, stmt);
+ case STMT_FWD:
+ return netlink_gen_fwd_stmt(ctx, stmt);
+ case STMT_CONNLIMIT:
+ 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;
+ case STMT_NOTRACK:
+ return netlink_gen_notrack_stmt(ctx, stmt);
+ case STMT_FLOW_OFFLOAD:
+ return netlink_gen_flow_offload_stmt(ctx, stmt);
+ case STMT_OBJREF:
+ return netlink_gen_objref_stmt(ctx, stmt);
+ case STMT_MAP:
+ return netlink_gen_map_stmt(ctx, stmt);
+ case STMT_CHAIN:
+ return netlink_gen_chain_stmt(ctx, stmt);
+ case STMT_OPTSTRIP:
+ return netlink_gen_optstrip_stmt(ctx, stmt);
+ default:
+ BUG("unknown statement type %s\n", stmt->ops->name);
+ }
+}
+
+void netlink_linearize_init(struct netlink_linearize_ctx *lctx,
+ struct nftnl_rule *nlr)
+{
+ int i;
+
+ memset(lctx, 0, sizeof(*lctx));
+ lctx->reg_low = NFT_REG_1;
+ lctx->nlr = nlr;
+ lctx->expr_loc_htable =
+ xmalloc(sizeof(struct list_head) * NFT_EXPR_LOC_HSIZE);
+ for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++)
+ init_list_head(&lctx->expr_loc_htable[i]);
+}
+
+void netlink_linearize_fini(struct netlink_linearize_ctx *lctx)
+{
+ struct nft_expr_loc *eloc, *next;
+ int i;
+
+ for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++) {
+ list_for_each_entry_safe(eloc, next, &lctx->expr_loc_htable[i], hlist)
+ xfree(eloc);
+ }
+ xfree(lctx->expr_loc_htable);
+}
+
+void netlink_linearize_rule(struct netlink_ctx *ctx,
+ const struct rule *rule,
+ struct netlink_linearize_ctx *lctx)
+{
+ const struct stmt *stmt;
+
+ list_for_each_entry(stmt, &rule->stmts, list)
+ netlink_gen_stmt(lctx, stmt);
+
+ if (rule->comment) {
+ struct nftnl_udata_buf *udata;
+
+ udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udata)
+ memory_allocation_error();
+
+ if (!nftnl_udata_put_strz(udata, NFTNL_UDATA_RULE_COMMENT,
+ rule->comment))
+ memory_allocation_error();
+ nftnl_rule_set_data(lctx->nlr, NFTNL_RULE_USERDATA,
+ nftnl_udata_buf_data(udata),
+ nftnl_udata_buf_len(udata));
+
+ nftnl_udata_buf_free(udata);
+ }
+
+ if (ctx->nft->debug_mask & NFT_DEBUG_NETLINK) {
+ nftnl_rule_set_str(lctx->nlr, NFTNL_RULE_TABLE,
+ rule->handle.table.name);
+ if (rule->handle.chain.name)
+ nftnl_rule_set_str(lctx->nlr, NFTNL_RULE_CHAIN,
+ rule->handle.chain.name);
+
+ netlink_dump_rule(lctx->nlr, ctx);
+
+ nftnl_rule_unset(lctx->nlr, NFTNL_RULE_CHAIN);
+ nftnl_rule_unset(lctx->nlr, NFTNL_RULE_TABLE);
+ }
+}
diff --git a/src/nfnl_osf.c b/src/nfnl_osf.c
new file mode 100644
index 0000000..20a1bfe
--- /dev/null
+++ b/src/nfnl_osf.c
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2005 Evgeniy Polyakov <johnpol@2ka.mxt.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * Based on iptables/utils/nfnl_osf.c.
+ */
+
+#include <nft.h>
+
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <linux/unistd.h>
+
+#include <libmnl/libmnl.h>
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_osf.h>
+#include <mnl.h>
+#include <osf.h>
+
+#define OPTDEL ','
+#define OSFPDEL ':'
+#define MAXOPTSTRLEN 128
+
+static struct nf_osf_opt IANA_opts[] = {
+ { .kind = 0, .length = 1,},
+ { .kind=1, .length=1,},
+ { .kind=2, .length=4,},
+ { .kind=3, .length=3,},
+ { .kind=4, .length=2,},
+ { .kind=5, .length=1,}, /* SACK length is not defined */
+ { .kind=6, .length=6,},
+ { .kind=7, .length=6,},
+ { .kind=8, .length=10,},
+ { .kind=9, .length=2,},
+ { .kind=10, .length=3,},
+ { .kind=11, .length=1,}, /* CC: Suppose 1 */
+ { .kind=12, .length=1,}, /* the same */
+ { .kind=13, .length=1,}, /* and here too */
+ { .kind=14, .length=3,},
+ { .kind=15, .length=1,}, /* TCP Alternate Checksum Data. Length is not defined */
+ { .kind=16, .length=1,},
+ { .kind=17, .length=1,},
+ { .kind=18, .length=3,},
+ { .kind=19, .length=18,},
+ { .kind=20, .length=1,},
+ { .kind=21, .length=1,},
+ { .kind=22, .length=1,},
+ { .kind=23, .length=1,},
+ { .kind=24, .length=1,},
+ { .kind=25, .length=1,},
+ { .kind=26, .length=1,},
+};
+
+static char *nf_osf_strchr(char *ptr, char c)
+{
+ char *tmp;
+
+ tmp = strchr(ptr, c);
+ if (tmp)
+ *tmp = '\0';
+
+ while (tmp && isspace(*(tmp + 1)))
+ tmp++;
+
+ return tmp;
+}
+
+static void nf_osf_parse_opt(struct nf_osf_opt *opt, __u16 *optnum, char *obuf,
+ int olen)
+{
+ int i, op;
+ char *ptr, wc;
+ unsigned long val;
+
+ ptr = &obuf[0];
+ i = 0;
+ while (ptr != NULL && i < olen && *ptr != 0) {
+ val = 0;
+ wc = OSF_WSS_PLAIN;
+ switch (obuf[i]) {
+ case 'N':
+ op = OSFOPT_NOP;
+ ptr = nf_osf_strchr(&obuf[i], OPTDEL);
+ if (ptr) {
+ *ptr = '\0';
+ ptr++;
+ i += (int)(ptr - &obuf[i]);
+ } else
+ i++;
+ break;
+ case 'S':
+ op = OSFOPT_SACKP;
+ ptr = nf_osf_strchr(&obuf[i], OPTDEL);
+ if (ptr) {
+ *ptr = '\0';
+ ptr++;
+ i += (int)(ptr - &obuf[i]);
+ } else
+ i++;
+ break;
+ case 'T':
+ op = OSFOPT_TS;
+ ptr = nf_osf_strchr(&obuf[i], OPTDEL);
+ if (ptr) {
+ *ptr = '\0';
+ ptr++;
+ i += (int)(ptr - &obuf[i]);
+ } else
+ i++;
+ break;
+ case 'W':
+ op = OSFOPT_WSO;
+ ptr = nf_osf_strchr(&obuf[i], OPTDEL);
+ if (ptr) {
+ switch (obuf[i + 1]) {
+ case '%':
+ wc = OSF_WSS_MODULO;
+ break;
+ case 'S':
+ wc = OSF_WSS_MSS;
+ break;
+ case 'T':
+ wc = OSF_WSS_MTU;
+ break;
+ default:
+ wc = OSF_WSS_PLAIN;
+ break;
+ }
+
+ *ptr = '\0';
+ ptr++;
+ if (wc)
+ val = strtoul(&obuf[i + 2], NULL, 10);
+ else
+ val = strtoul(&obuf[i + 1], NULL, 10);
+ i += (int)(ptr - &obuf[i]);
+
+ } else
+ i++;
+ break;
+ case 'M':
+ op = OSFOPT_MSS;
+ ptr = nf_osf_strchr(&obuf[i], OPTDEL);
+ if (ptr) {
+ if (obuf[i + 1] == '%')
+ wc = OSF_WSS_MODULO;
+ *ptr = '\0';
+ ptr++;
+ if (wc)
+ val = strtoul(&obuf[i + 2], NULL, 10);
+ else
+ val = strtoul(&obuf[i + 1], NULL, 10);
+ i += (int)(ptr - &obuf[i]);
+ } else
+ i++;
+ break;
+ case 'E':
+ op = OSFOPT_EOL;
+ ptr = nf_osf_strchr(&obuf[i], OPTDEL);
+ if (ptr) {
+ *ptr = '\0';
+ ptr++;
+ i += (int)(ptr - &obuf[i]);
+ } else
+ i++;
+ break;
+ default:
+ op = OSFOPT_EMPTY;
+ ptr = nf_osf_strchr(&obuf[i], OPTDEL);
+ if (ptr) {
+ ptr++;
+ i += (int)(ptr - &obuf[i]);
+ } else
+ i++;
+ break;
+ }
+
+ if (op != OSFOPT_EMPTY) {
+ opt[*optnum].kind = IANA_opts[op].kind;
+ opt[*optnum].length = IANA_opts[op].length;
+ opt[*optnum].wc.wc = wc;
+ opt[*optnum].wc.val = val;
+ (*optnum)++;
+ }
+ }
+}
+
+static int osf_load_line(char *buffer, int len, int del,
+ struct netlink_ctx *ctx)
+{
+ int i, cnt = 0;
+ char obuf[MAXOPTSTRLEN];
+ struct nf_osf_user_finger f;
+ char *pbeg, *pend;
+ struct nlmsghdr *nlh;
+ struct nfgenmsg *nfg;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+
+ memset(&f, 0, sizeof(struct nf_osf_user_finger));
+
+ if (ctx->nft->debug_mask & NFT_DEBUG_MNL)
+ nft_print(&ctx->nft->output, "Loading '%s'.\n", buffer);
+
+ for (i = 0; i < len && buffer[i] != '\0'; ++i) {
+ if (buffer[i] == ':')
+ cnt++;
+ }
+
+ if (cnt != 8) {
+ if (ctx->nft->debug_mask & NFT_DEBUG_MNL)
+ nft_print(&ctx->nft->output, "Wrong input line '%s': cnt: %d, must be 8, i: %d, must be %d.\n", buffer, cnt, i, len);
+ return -EINVAL;
+ }
+
+ memset(obuf, 0, sizeof(obuf));
+
+ pbeg = buffer;
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ if (pbeg[0] == 'S') {
+ f.wss.wc = OSF_WSS_MSS;
+ if (pbeg[1] == '%')
+ f.wss.val = strtoul(&pbeg[2], NULL, 10);
+ else if (pbeg[1] == '*')
+ f.wss.val = 0;
+ else
+ f.wss.val = strtoul(&pbeg[1], NULL, 10);
+ } else if (pbeg[0] == 'T') {
+ f.wss.wc = OSF_WSS_MTU;
+ if (pbeg[1] == '%')
+ f.wss.val = strtoul(&pbeg[2], NULL, 10);
+ else if (pbeg[1] == '*')
+ f.wss.val = 0;
+ else
+ f.wss.val = strtoul(&pbeg[1], NULL, 10);
+ } else if (pbeg[0] == '%') {
+ f.wss.wc = OSF_WSS_MODULO;
+ f.wss.val = strtoul(&pbeg[1], NULL, 10);
+ } else if (isdigit(pbeg[0])) {
+ f.wss.wc = OSF_WSS_PLAIN;
+ f.wss.val = strtoul(&pbeg[0], NULL, 10);
+ }
+
+ pbeg = pend + 1;
+ }
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ f.ttl = strtoul(pbeg, NULL, 10);
+ pbeg = pend + 1;
+ }
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ f.df = strtoul(pbeg, NULL, 10);
+ pbeg = pend + 1;
+ }
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ f.ss = strtoul(pbeg, NULL, 10);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ i = sizeof(obuf);
+ snprintf(obuf, i, "%.*s,", i - 2, pbeg);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ i = sizeof(f.genre);
+ if (pbeg[0] == '@' || pbeg[0] == '*')
+ pbeg++;
+ snprintf(f.genre, i, "%.*s", i - 1, pbeg);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ i = sizeof(f.version);
+ snprintf(f.version, i, "%.*s", i - 1, pbeg);
+ pbeg = pend + 1;
+ }
+
+ pend = nf_osf_strchr(pbeg, OSFPDEL);
+ if (pend) {
+ *pend = '\0';
+ i = sizeof(f.subtype);
+ snprintf(f.subtype, i, "%.*s", i - 1, pbeg);
+ pbeg = pend + 1;
+ }
+
+ nf_osf_parse_opt(f.opt, &f.opt_num, obuf, sizeof(obuf));
+
+ memset(buf, 0, sizeof(buf));
+
+ if (del) {
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_OSF << 8) | OSF_MSG_REMOVE;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_seq = ctx->seqnum;
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = AF_UNSPEC;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = 0;
+ } else {
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_OSF << 8) | OSF_MSG_ADD;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
+ nlh->nlmsg_seq = ctx->seqnum;
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = AF_UNSPEC;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = 0;
+
+ mnl_attr_put(nlh, OSF_ATTR_FINGER, sizeof(struct nf_osf_user_finger), &f);
+ }
+
+ return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, 0, NULL);
+}
+
+#define OS_SIGNATURES DEFAULT_INCLUDE_PATH "/nftables/osf/pf.os"
+
+int nfnl_osf_load_fingerprints(struct netlink_ctx *ctx, int del)
+{
+ FILE *inf;
+ int err = 0;
+ char buf[1024];
+
+ if (ctx->nft->debug_mask & NFT_DEBUG_MNL)
+ nft_print(&ctx->nft->output, "Opening OS signature file '%s'\n",
+ OS_SIGNATURES);
+
+ inf = fopen(OS_SIGNATURES, "r");
+ if (!inf) {
+ if (ctx->nft->debug_mask & NFT_DEBUG_MNL)
+ nft_print(&ctx->nft->output, "Failed to open file '%s'\n",
+ OS_SIGNATURES);
+
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), inf)) {
+ int len;
+
+ if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
+ continue;
+
+ len = strlen(buf) - 1;
+
+ if (len <= 0)
+ continue;
+
+ buf[len] = '\0';
+
+ err = osf_load_line(buf, len, del, ctx);
+ if (err)
+ break;
+
+ memset(buf, 0, sizeof(buf));
+ }
+
+ fclose(inf);
+ return err;
+}
diff --git a/src/nftutils.c b/src/nftutils.c
new file mode 100644
index 0000000..ca178aa
--- /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 0000000..7db56f4
--- /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
new file mode 100644
index 0000000..3029fa5
--- /dev/null
+++ b/src/numgen.c
@@ -0,0 +1,140 @@
+/*
+ * Number generator expression definitions.
+ *
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <nftables.h>
+#include <expression.h>
+#include <datatype.h>
+#include <gmputil.h>
+#include <numgen.h>
+#include <utils.h>
+
+static const char *numgen_type[NFT_NG_RANDOM + 1] = {
+ [NFT_NG_INCREMENTAL] = "inc",
+ [NFT_NG_RANDOM] = "random",
+};
+
+static const char *numgen_type_str(enum nft_ng_types type)
+{
+ if (type > NFT_NG_RANDOM)
+ return "[unknown numgen]";
+
+ return numgen_type[type];
+}
+
+static void numgen_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_print(octx, "numgen %s mod %u",
+ numgen_type_str(expr->numgen.type),
+ expr->numgen.mod);
+ if (expr->numgen.offset)
+ nft_print(octx, " offset %u", expr->numgen.offset);
+}
+
+static bool numgen_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->numgen.type == e2->numgen.type &&
+ e1->numgen.mod == e2->numgen.mod &&
+ e1->numgen.offset == e2->numgen.offset;
+}
+
+static void numgen_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->numgen.type = expr->numgen.type;
+ new->numgen.mod = expr->numgen.mod;
+ new->numgen.offset = expr->numgen.offset;
+}
+
+#define NFTNL_UDATA_NUMGEN_TYPE 0
+#define NFTNL_UDATA_NUMGEN_MOD 1
+#define NFTNL_UDATA_NUMGEN_OFFSET 2
+#define NFTNL_UDATA_NUMGEN_MAX 3
+
+static int numgen_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_NUMGEN_TYPE, expr->numgen.type);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_NUMGEN_MOD, expr->numgen.mod);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_NUMGEN_OFFSET, expr->numgen.offset);
+
+ return 0;
+}
+
+static int numgen_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_NUMGEN_TYPE:
+ case NFTNL_UDATA_NUMGEN_MOD:
+ case NFTNL_UDATA_NUMGEN_OFFSET:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *numgen_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_NUMGEN_MAX + 1] = {};
+ enum nft_ng_types type;
+ uint32_t mod, offset;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ numgen_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_NUMGEN_TYPE] ||
+ !ud[NFTNL_UDATA_NUMGEN_MOD] ||
+ !ud[NFTNL_UDATA_NUMGEN_OFFSET])
+ return NULL;
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_NUMGEN_TYPE]);
+ mod = nftnl_udata_get_u32(ud[NFTNL_UDATA_NUMGEN_MOD]);
+ offset = nftnl_udata_get_u32(ud[NFTNL_UDATA_NUMGEN_OFFSET]);
+
+ return numgen_expr_alloc(&internal_location, type, mod, offset);
+}
+
+const struct expr_ops numgen_expr_ops = {
+ .type = EXPR_NUMGEN,
+ .name = "numgen",
+ .print = numgen_expr_print,
+ .json = numgen_expr_json,
+ .cmp = numgen_expr_cmp,
+ .clone = numgen_expr_clone,
+ .parse_udata = numgen_expr_parse_udata,
+ .build_udata = numgen_expr_build_udata,
+};
+
+struct expr *numgen_expr_alloc(const struct location *loc,
+ enum nft_ng_types type, uint32_t mod,
+ uint32_t offset)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_NUMGEN, &integer_type,
+ BYTEORDER_HOST_ENDIAN, 4 * BITS_PER_BYTE);
+ expr->numgen.type = type;
+ expr->numgen.mod = mod;
+ expr->numgen.offset = offset;
+
+ return expr;
+}
diff --git a/src/optimize.c b/src/optimize.c
new file mode 100644
index 0000000..27e0ffe
--- /dev/null
+++ b/src/optimize.c
@@ -0,0 +1,1406 @@
+/*
+ * Copyright (c) 2021 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+/* Funded through the NGI0 PET Fund established by NLnet (https://nlnet.nl)
+ * with support from the European Commission's Next Generation Internet
+ * programme.
+ */
+
+#include <nft.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <nftables.h>
+#include <parser.h>
+#include <expression.h>
+#include <statement.h>
+#include <utils.h>
+#include <erec.h>
+#include <linux/netfilter.h>
+
+#define MAX_STMTS 32
+
+struct optimize_ctx {
+ struct stmt *stmt[MAX_STMTS];
+ uint32_t num_stmts;
+
+ struct stmt ***stmt_matrix;
+ struct rule **rule;
+ uint32_t num_rules;
+};
+
+static bool __expr_cmp(const struct expr *expr_a, const struct expr *expr_b)
+{
+ if (expr_a->etype != expr_b->etype)
+ return false;
+
+ switch (expr_a->etype) {
+ case EXPR_PAYLOAD:
+ if (expr_a->payload.base != expr_b->payload.base)
+ return false;
+ if (expr_a->payload.offset != expr_b->payload.offset)
+ return false;
+ if (expr_a->payload.desc != expr_b->payload.desc)
+ return false;
+ if (expr_a->payload.inner_desc != expr_b->payload.inner_desc)
+ return false;
+ if (expr_a->payload.tmpl != expr_b->payload.tmpl)
+ return false;
+ break;
+ case EXPR_EXTHDR:
+ if (expr_a->exthdr.desc != expr_b->exthdr.desc)
+ return false;
+ if (expr_a->exthdr.tmpl != expr_b->exthdr.tmpl)
+ return false;
+ break;
+ case EXPR_META:
+ if (expr_a->meta.key != expr_b->meta.key)
+ return false;
+ if (expr_a->meta.base != expr_b->meta.base)
+ return false;
+ break;
+ case EXPR_CT:
+ if (expr_a->ct.key != expr_b->ct.key)
+ return false;
+ if (expr_a->ct.base != expr_b->ct.base)
+ return false;
+ if (expr_a->ct.direction != expr_b->ct.direction)
+ return false;
+ if (expr_a->ct.nfproto != expr_b->ct.nfproto)
+ return false;
+ break;
+ case EXPR_RT:
+ if (expr_a->rt.key != expr_b->rt.key)
+ return false;
+ break;
+ case EXPR_SOCKET:
+ if (expr_a->socket.key != expr_b->socket.key)
+ return false;
+ if (expr_a->socket.level != expr_b->socket.level)
+ return false;
+ break;
+ case EXPR_OSF:
+ if (expr_a->osf.ttl != expr_b->osf.ttl)
+ return false;
+ if (expr_a->osf.flags != expr_b->osf.flags)
+ return false;
+ break;
+ case EXPR_XFRM:
+ if (expr_a->xfrm.key != expr_b->xfrm.key)
+ return false;
+ if (expr_a->xfrm.direction != expr_b->xfrm.direction)
+ return false;
+ break;
+ case EXPR_FIB:
+ if (expr_a->fib.flags != expr_b->fib.flags)
+ return false;
+ if (expr_a->fib.result != expr_b->fib.result)
+ return false;
+ break;
+ case EXPR_NUMGEN:
+ if (expr_a->numgen.type != expr_b->numgen.type)
+ return false;
+ if (expr_a->numgen.mod != expr_b->numgen.mod)
+ return false;
+ if (expr_a->numgen.offset != expr_b->numgen.offset)
+ return false;
+ break;
+ case EXPR_HASH:
+ if (expr_a->hash.mod != expr_b->hash.mod)
+ return false;
+ if (expr_a->hash.seed_set != expr_b->hash.seed_set)
+ return false;
+ if (expr_a->hash.seed != expr_b->hash.seed)
+ return false;
+ if (expr_a->hash.offset != expr_b->hash.offset)
+ return false;
+ if (expr_a->hash.type != expr_b->hash.type)
+ return false;
+ break;
+ case EXPR_BINOP:
+ return __expr_cmp(expr_a->left, expr_b->left);
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static bool stmt_expr_supported(const struct expr *expr)
+{
+ switch (expr->right->etype) {
+ case EXPR_SYMBOL:
+ case EXPR_RANGE:
+ case EXPR_PREFIX:
+ case EXPR_SET:
+ case EXPR_LIST:
+ case EXPR_VALUE:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool expr_symbol_set(const struct expr *expr)
+{
+ return expr->right->etype == EXPR_SYMBOL &&
+ expr->right->symtype == SYMBOL_SET;
+}
+
+static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b,
+ bool fully_compare)
+{
+ struct expr *expr_a, *expr_b;
+
+ if (stmt_a->ops->type != stmt_b->ops->type)
+ return false;
+
+ switch (stmt_a->ops->type) {
+ case STMT_EXPRESSION:
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+
+ if (expr_a->op != expr_b->op)
+ return false;
+ if (expr_a->op != OP_IMPLICIT && expr_a->op != OP_EQ)
+ return false;
+
+ if (fully_compare) {
+ if (!stmt_expr_supported(expr_a) ||
+ !stmt_expr_supported(expr_b))
+ return false;
+
+ if (expr_symbol_set(expr_a) ||
+ expr_symbol_set(expr_b))
+ return false;
+ }
+
+ return __expr_cmp(expr_a->left, expr_b->left);
+ case STMT_COUNTER:
+ case STMT_NOTRACK:
+ break;
+ case STMT_VERDICT:
+ if (!fully_compare)
+ break;
+
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+
+ if (expr_a->etype != expr_b->etype)
+ return false;
+
+ if (expr_a->etype == EXPR_MAP &&
+ expr_b->etype == EXPR_MAP)
+ return __expr_cmp(expr_a->map, expr_b->map);
+ break;
+ case STMT_LOG:
+ if (stmt_a->log.snaplen != stmt_b->log.snaplen ||
+ stmt_a->log.group != stmt_b->log.group ||
+ stmt_a->log.qthreshold != stmt_b->log.qthreshold ||
+ stmt_a->log.level != stmt_b->log.level ||
+ stmt_a->log.logflags != stmt_b->log.logflags ||
+ stmt_a->log.flags != stmt_b->log.flags)
+ return false;
+
+ if (!!stmt_a->log.prefix ^ !!stmt_b->log.prefix)
+ return false;
+
+ if (!stmt_a->log.prefix)
+ return true;
+
+ if (stmt_a->log.prefix->etype != EXPR_VALUE ||
+ stmt_b->log.prefix->etype != EXPR_VALUE ||
+ mpz_cmp(stmt_a->log.prefix->value, stmt_b->log.prefix->value))
+ return false;
+ break;
+ case STMT_REJECT:
+ if (stmt_a->reject.family != stmt_b->reject.family ||
+ stmt_a->reject.type != stmt_b->reject.type ||
+ stmt_a->reject.icmp_code != stmt_b->reject.icmp_code)
+ return false;
+
+ if (!!stmt_a->reject.expr ^ !!stmt_b->reject.expr)
+ return false;
+
+ if (!stmt_a->reject.expr)
+ return true;
+
+ if (__expr_cmp(stmt_a->reject.expr, stmt_b->reject.expr))
+ return false;
+ break;
+ case STMT_NAT:
+ if (stmt_a->nat.type != stmt_b->nat.type ||
+ stmt_a->nat.flags != stmt_b->nat.flags ||
+ stmt_a->nat.family != stmt_b->nat.family ||
+ stmt_a->nat.type_flags != stmt_b->nat.type_flags)
+ return false;
+
+ switch (stmt_a->nat.type) {
+ case NFT_NAT_SNAT:
+ case NFT_NAT_DNAT:
+ if ((stmt_a->nat.addr &&
+ stmt_a->nat.addr->etype != EXPR_SYMBOL &&
+ stmt_a->nat.addr->etype != EXPR_RANGE) ||
+ (stmt_b->nat.addr &&
+ stmt_b->nat.addr->etype != EXPR_SYMBOL &&
+ stmt_b->nat.addr->etype != EXPR_RANGE) ||
+ (stmt_a->nat.proto &&
+ stmt_a->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_a->nat.proto->etype != EXPR_RANGE) ||
+ (stmt_b->nat.proto &&
+ stmt_b->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_b->nat.proto->etype != EXPR_RANGE))
+ return false;
+ break;
+ case NFT_NAT_MASQ:
+ break;
+ case NFT_NAT_REDIR:
+ if ((stmt_a->nat.proto &&
+ stmt_a->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_a->nat.proto->etype != EXPR_RANGE) ||
+ (stmt_b->nat.proto &&
+ stmt_b->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_b->nat.proto->etype != EXPR_RANGE))
+ return false;
+
+ /* it should be possible to infer implicit redirections
+ * such as:
+ *
+ * tcp dport 1234 redirect
+ * tcp dport 3456 redirect to :7890
+ * merge:
+ * redirect to tcp dport map { 1234 : 1234, 3456 : 7890 }
+ *
+ * currently not implemented.
+ */
+ if (fully_compare &&
+ stmt_a->nat.type == NFT_NAT_REDIR &&
+ stmt_b->nat.type == NFT_NAT_REDIR &&
+ (!!stmt_a->nat.proto ^ !!stmt_b->nat.proto))
+ return false;
+
+ break;
+ default:
+ assert(0);
+ }
+
+ return true;
+ default:
+ /* ... Merging anything else is yet unsupported. */
+ return false;
+ }
+
+ return true;
+}
+
+static bool expr_verdict_eq(const struct expr *expr_a, const struct expr *expr_b)
+{
+ if (expr_a->verdict != expr_b->verdict)
+ return false;
+ if (expr_a->chain && expr_b->chain) {
+ if (expr_a->chain->etype != expr_b->chain->etype)
+ return false;
+ if (expr_a->chain->etype == EXPR_VALUE &&
+ strcmp(expr_a->chain->identifier, expr_b->chain->identifier))
+ return false;
+ } else if (expr_a->chain || expr_b->chain) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool stmt_verdict_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ struct expr *expr_a, *expr_b;
+
+ assert (stmt_a->ops->type == STMT_VERDICT);
+
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+ if (expr_a->etype == EXPR_VERDICT &&
+ expr_b->etype == EXPR_VERDICT)
+ return expr_verdict_eq(expr_a, expr_b);
+
+ if (expr_a->etype == EXPR_MAP &&
+ expr_b->etype == EXPR_MAP)
+ return __expr_cmp(expr_a->map, expr_b->map);
+
+ return false;
+}
+
+static bool stmt_type_find(struct optimize_ctx *ctx, const struct stmt *stmt)
+{
+ bool unsupported_exists = false;
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type == STMT_INVALID)
+ unsupported_exists = true;
+
+ if (__stmt_type_eq(stmt, ctx->stmt[i], false))
+ return true;
+ }
+
+ switch (stmt->ops->type) {
+ case STMT_EXPRESSION:
+ case STMT_VERDICT:
+ case STMT_COUNTER:
+ case STMT_NOTRACK:
+ case STMT_LOG:
+ case STMT_NAT:
+ case STMT_REJECT:
+ break;
+ default:
+ /* add unsupported statement only once to statement matrix. */
+ if (unsupported_exists)
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+static struct stmt_ops unsupported_stmt_ops = {
+ .type = STMT_INVALID,
+ .name = "unsupported",
+};
+
+static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
+{
+ struct stmt *stmt, *clone;
+
+ list_for_each_entry(stmt, &rule->stmts, list) {
+ if (stmt_type_find(ctx, stmt))
+ continue;
+
+ /* No refcounter available in statement objects, clone it to
+ * to store in the array of selectors.
+ */
+ clone = stmt_alloc(&internal_location, stmt->ops);
+ switch (stmt->ops->type) {
+ case STMT_EXPRESSION:
+ if (stmt->expr->op != OP_IMPLICIT &&
+ stmt->expr->op != OP_EQ) {
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+ if (stmt->expr->left->etype == EXPR_CONCAT) {
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+ /* fall-through */
+ case STMT_VERDICT:
+ clone->expr = expr_get(stmt->expr);
+ break;
+ case STMT_COUNTER:
+ case STMT_NOTRACK:
+ break;
+ case STMT_LOG:
+ memcpy(&clone->log, &stmt->log, sizeof(clone->log));
+ if (stmt->log.prefix)
+ clone->log.prefix = expr_get(stmt->log.prefix);
+ break;
+ case STMT_NAT:
+ if ((stmt->nat.addr &&
+ stmt->nat.addr->etype == EXPR_MAP) ||
+ (stmt->nat.proto &&
+ stmt->nat.proto->etype == EXPR_MAP)) {
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+ clone->nat.type = stmt->nat.type;
+ clone->nat.family = stmt->nat.family;
+ if (stmt->nat.addr)
+ clone->nat.addr = expr_clone(stmt->nat.addr);
+ if (stmt->nat.proto)
+ clone->nat.proto = expr_clone(stmt->nat.proto);
+ clone->nat.flags = stmt->nat.flags;
+ clone->nat.type_flags = stmt->nat.type_flags;
+ break;
+ case STMT_REJECT:
+ if (stmt->reject.expr)
+ clone->reject.expr = expr_get(stmt->reject.expr);
+ clone->reject.type = stmt->reject.type;
+ clone->reject.icmp_code = stmt->reject.icmp_code;
+ clone->reject.family = stmt->reject.family;
+ break;
+ default:
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+
+ ctx->stmt[ctx->num_stmts++] = clone;
+ if (ctx->num_stmts >= MAX_STMTS)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int unsupported_in_stmt_matrix(const struct optimize_ctx *ctx)
+{
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type == STMT_INVALID)
+ return i;
+ }
+ /* this should not happen. */
+ return -1;
+}
+
+static int cmd_stmt_find_in_stmt_matrix(struct optimize_ctx *ctx, struct stmt *stmt)
+{
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (__stmt_type_eq(stmt, ctx->stmt[i], false))
+ return i;
+ }
+
+ return -1;
+}
+
+static struct stmt unsupported_stmt = {
+ .ops = &unsupported_stmt_ops,
+};
+
+static void rule_build_stmt_matrix_stmts(struct optimize_ctx *ctx,
+ struct rule *rule, uint32_t *i)
+{
+ struct stmt *stmt;
+ int k;
+
+ list_for_each_entry(stmt, &rule->stmts, list) {
+ k = cmd_stmt_find_in_stmt_matrix(ctx, stmt);
+ if (k < 0) {
+ k = unsupported_in_stmt_matrix(ctx);
+ assert(k >= 0);
+ ctx->stmt_matrix[*i][k] = &unsupported_stmt;
+ continue;
+ }
+ ctx->stmt_matrix[*i][k] = stmt;
+ }
+ ctx->rule[(*i)++] = rule;
+}
+
+static int stmt_verdict_find(const struct optimize_ctx *ctx)
+{
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type != STMT_VERDICT)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+struct merge {
+ /* interval of rules to be merged */
+ uint32_t rule_from;
+ uint32_t num_rules;
+ /* statements to be merged (index relative to statement matrix) */
+ uint32_t stmt[MAX_STMTS];
+ uint32_t num_stmts;
+};
+
+static void merge_expr_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct stmt *stmt_a)
+{
+ struct expr *expr_a, *expr_b, *set, *elem;
+ struct stmt *stmt_b;
+ uint32_t i;
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ expr_a = stmt_a->expr->right;
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr_a));
+ compound_expr_add(set, elem);
+
+ for (i = from + 1; i <= to; i++) {
+ stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
+ expr_b = stmt_b->expr->right;
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr_b));
+ compound_expr_add(set, elem);
+ }
+
+ expr_free(stmt_a->expr->right);
+ stmt_a->expr->right = set;
+}
+
+static void merge_vmap(const struct optimize_ctx *ctx,
+ struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ struct expr *mappings, *mapping, *expr;
+
+ mappings = stmt_b->expr->mappings;
+ list_for_each_entry(expr, &mappings->expressions, list) {
+ mapping = expr_clone(expr);
+ compound_expr_add(stmt_a->expr->mappings, mapping);
+ }
+}
+
+static void merge_verdict_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct stmt *stmt_a)
+{
+ struct stmt *stmt_b;
+ uint32_t i;
+
+ for (i = from + 1; i <= to; i++) {
+ stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
+ switch (stmt_b->ops->type) {
+ case STMT_VERDICT:
+ switch (stmt_b->expr->etype) {
+ case EXPR_MAP:
+ merge_vmap(ctx, stmt_a, stmt_b);
+ break;
+ default:
+ assert(0);
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+static void merge_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to, const struct merge *merge)
+{
+ struct stmt *stmt_a = ctx->stmt_matrix[from][merge->stmt[0]];
+
+ switch (stmt_a->ops->type) {
+ case STMT_EXPRESSION:
+ merge_expr_stmts(ctx, from, to, merge, stmt_a);
+ break;
+ case STMT_VERDICT:
+ merge_verdict_stmts(ctx, from, to, merge, stmt_a);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+static void __merge_concat(const struct optimize_ctx *ctx, uint32_t i,
+ const struct merge *merge, struct list_head *concat_list)
+{
+ struct expr *concat, *next, *expr, *concat_clone, *clone;
+ LIST_HEAD(pending_list);
+ struct stmt *stmt_a;
+ uint32_t k;
+
+ concat = concat_expr_alloc(&internal_location);
+ list_add(&concat->list, concat_list);
+
+ for (k = 0; k < merge->num_stmts; k++) {
+ list_for_each_entry_safe(concat, next, concat_list, list) {
+ stmt_a = ctx->stmt_matrix[i][merge->stmt[k]];
+ switch (stmt_a->expr->right->etype) {
+ case EXPR_SET:
+ list_for_each_entry(expr, &stmt_a->expr->right->expressions, list) {
+ concat_clone = expr_clone(concat);
+ clone = expr_clone(expr->key);
+ compound_expr_add(concat_clone, clone);
+ list_add_tail(&concat_clone->list, &pending_list);
+ }
+ list_del(&concat->list);
+ expr_free(concat);
+ break;
+ case EXPR_SYMBOL:
+ case EXPR_VALUE:
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ clone = expr_clone(stmt_a->expr->right);
+ compound_expr_add(concat, clone);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ list_splice_init(&pending_list, concat_list);
+ }
+}
+
+static void __merge_concat_stmts(const struct optimize_ctx *ctx, uint32_t i,
+ const struct merge *merge, struct expr *set)
+{
+ struct expr *concat, *next, *elem;
+ LIST_HEAD(concat_list);
+
+ __merge_concat(ctx, i, merge, &concat_list);
+
+ list_for_each_entry_safe(concat, next, &concat_list, list) {
+ list_del(&concat->list);
+ elem = set_elem_expr_alloc(&internal_location, concat);
+ compound_expr_add(set, elem);
+ }
+}
+
+static void merge_concat_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct stmt *stmt, *stmt_a;
+ struct expr *concat, *set;
+ uint32_t i, k;
+
+ stmt = ctx->stmt_matrix[from][merge->stmt[0]];
+ /* build concatenation of selectors, eg. ifname . ip daddr . tcp dport */
+ concat = concat_expr_alloc(&internal_location);
+
+ for (k = 0; k < merge->num_stmts; k++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[k]];
+ compound_expr_add(concat, expr_get(stmt_a->expr->left));
+ }
+ expr_free(stmt->expr->left);
+ stmt->expr->left = concat;
+
+ /* build set data contenation, eg. { eth0 . 1.1.1.1 . 22 } */
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++)
+ __merge_concat_stmts(ctx, i, merge, set);
+
+ expr_free(stmt->expr->right);
+ stmt->expr->right = set;
+
+ for (k = 1; k < merge->num_stmts; k++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[k]];
+ list_del(&stmt_a->list);
+ stmt_free(stmt_a);
+ }
+}
+
+static void build_verdict_map(struct expr *expr, struct stmt *verdict,
+ struct expr *set, struct stmt *counter)
+{
+ struct expr *item, *elem, *mapping;
+
+ switch (expr->etype) {
+ case EXPR_LIST:
+ list_for_each_entry(item, &expr->expressions, list) {
+ elem = set_elem_expr_alloc(&internal_location, expr_get(item));
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ }
+ break;
+ case EXPR_SET:
+ list_for_each_entry(item, &expr->expressions, list) {
+ elem = set_elem_expr_alloc(&internal_location, expr_get(item->key));
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ }
+ break;
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ case EXPR_VALUE:
+ case EXPR_SYMBOL:
+ case EXPR_CONCAT:
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr));
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+static void remove_counter(const struct optimize_ctx *ctx, uint32_t from)
+{
+ struct stmt *stmt;
+ uint32_t i;
+
+ /* remove counter statement */
+ for (i = 0; i < ctx->num_stmts; i++) {
+ stmt = ctx->stmt_matrix[from][i];
+ if (!stmt)
+ continue;
+
+ if (stmt->ops->type == STMT_COUNTER) {
+ list_del(&stmt->list);
+ stmt_free(stmt);
+ }
+ }
+}
+
+static struct stmt *zap_counter(const struct optimize_ctx *ctx, uint32_t from)
+{
+ struct stmt *stmt;
+ uint32_t i;
+
+ /* remove counter statement */
+ for (i = 0; i < ctx->num_stmts; i++) {
+ stmt = ctx->stmt_matrix[from][i];
+ if (!stmt)
+ continue;
+
+ if (stmt->ops->type == STMT_COUNTER) {
+ list_del(&stmt->list);
+ return stmt;
+ }
+ }
+
+ return NULL;
+}
+
+static void merge_stmts_vmap(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct stmt *stmt_a = ctx->stmt_matrix[from][merge->stmt[0]];
+ struct stmt *stmt_b, *verdict_a, *verdict_b, *stmt;
+ struct expr *expr_a, *expr_b, *expr, *left, *set;
+ struct stmt *counter;
+ uint32_t i;
+ int k;
+
+ k = stmt_verdict_find(ctx);
+ assert(k >= 0);
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ expr_a = stmt_a->expr->right;
+ verdict_a = ctx->stmt_matrix[from][k];
+ counter = zap_counter(ctx, from);
+ build_verdict_map(expr_a, verdict_a, set, counter);
+
+ for (i = from + 1; i <= to; i++) {
+ stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
+ expr_b = stmt_b->expr->right;
+ verdict_b = ctx->stmt_matrix[i][k];
+ counter = zap_counter(ctx, i);
+ build_verdict_map(expr_b, verdict_b, set, counter);
+ }
+
+ left = expr_get(stmt_a->expr->left);
+ expr = map_expr_alloc(&internal_location, left, set);
+ stmt = verdict_stmt_alloc(&internal_location, expr);
+
+ list_add(&stmt->list, &stmt_a->list);
+ list_del(&stmt_a->list);
+ stmt_free(stmt_a);
+ list_del(&verdict_a->list);
+ stmt_free(verdict_a);
+}
+
+static void __merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
+ uint32_t i, const struct merge *merge,
+ struct expr *set, struct stmt *verdict)
+{
+ struct expr *concat, *next, *elem, *mapping;
+ LIST_HEAD(concat_list);
+ struct stmt *counter;
+
+ counter = zap_counter(ctx, i);
+ __merge_concat(ctx, i, merge, &concat_list);
+
+ list_for_each_entry_safe(concat, next, &concat_list, list) {
+ list_del(&concat->list);
+ elem = set_elem_expr_alloc(&internal_location, concat);
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ }
+}
+
+static void merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct stmt *orig_stmt = ctx->stmt_matrix[from][merge->stmt[0]];
+ struct stmt *stmt, *stmt_a, *verdict;
+ struct expr *concat_a, *expr, *set;
+ uint32_t i;
+ int k;
+
+ k = stmt_verdict_find(ctx);
+ assert(k >= 0);
+
+ /* build concatenation of selectors, eg. ifname . ip daddr . tcp dport */
+ concat_a = concat_expr_alloc(&internal_location);
+ for (i = 0; i < merge->num_stmts; i++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[i]];
+ compound_expr_add(concat_a, expr_get(stmt_a->expr->left));
+ }
+
+ /* build set data contenation, eg. { eth0 . 1.1.1.1 . 22 : accept } */
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++) {
+ verdict = ctx->stmt_matrix[i][k];
+ __merge_concat_stmts_vmap(ctx, i, merge, set, verdict);
+ }
+
+ expr = map_expr_alloc(&internal_location, concat_a, set);
+ stmt = verdict_stmt_alloc(&internal_location, expr);
+
+ list_add(&stmt->list, &orig_stmt->list);
+ list_del(&orig_stmt->list);
+ stmt_free(orig_stmt);
+
+ for (i = 1; i < merge->num_stmts; i++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[i]];
+ list_del(&stmt_a->list);
+ stmt_free(stmt_a);
+ }
+
+ verdict = ctx->stmt_matrix[from][k];
+ list_del(&verdict->list);
+ stmt_free(verdict);
+}
+
+static bool stmt_verdict_cmp(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to)
+{
+ struct stmt *stmt_a, *stmt_b;
+ uint32_t i;
+ int k;
+
+ k = stmt_verdict_find(ctx);
+ if (k < 0)
+ return true;
+
+ for (i = from; i + 1 <= to; i++) {
+ stmt_a = ctx->stmt_matrix[i][k];
+ stmt_b = ctx->stmt_matrix[i + 1][k];
+ if (!stmt_a && !stmt_b)
+ continue;
+ if (!stmt_a || !stmt_b)
+ return false;
+ if (!stmt_verdict_eq(stmt_a, stmt_b))
+ return false;
+ }
+
+ return true;
+}
+
+static int stmt_nat_type(const struct optimize_ctx *ctx, int from,
+ enum nft_nat_etypes *nat_type)
+{
+ uint32_t j;
+
+ for (j = 0; j < ctx->num_stmts; j++) {
+ if (!ctx->stmt_matrix[from][j])
+ continue;
+
+ if (ctx->stmt_matrix[from][j]->ops->type == STMT_NAT) {
+ *nat_type = ctx->stmt_matrix[from][j]->nat.type;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int stmt_nat_find(const struct optimize_ctx *ctx, int from)
+{
+ enum nft_nat_etypes nat_type;
+ uint32_t i;
+
+ if (stmt_nat_type(ctx, from, &nat_type) < 0)
+ return -1;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type != STMT_NAT ||
+ ctx->stmt[i]->nat.type != nat_type)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+static struct expr *stmt_nat_expr(struct stmt *nat_stmt)
+{
+ struct expr *nat_expr;
+
+ assert(nat_stmt->ops->type == STMT_NAT);
+
+ if (nat_stmt->nat.proto) {
+ if (nat_stmt->nat.addr) {
+ nat_expr = concat_expr_alloc(&internal_location);
+ compound_expr_add(nat_expr, expr_get(nat_stmt->nat.addr));
+ compound_expr_add(nat_expr, expr_get(nat_stmt->nat.proto));
+ } else {
+ nat_expr = expr_get(nat_stmt->nat.proto);
+ }
+ expr_free(nat_stmt->nat.proto);
+ nat_stmt->nat.proto = NULL;
+ } else {
+ nat_expr = expr_get(nat_stmt->nat.addr);
+ }
+
+ assert(nat_expr);
+
+ return nat_expr;
+}
+
+static void merge_nat(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct expr *expr, *set, *elem, *nat_expr, *mapping, *left;
+ int k, family = NFPROTO_UNSPEC;
+ struct stmt *stmt, *nat_stmt;
+ uint32_t i;
+
+ k = stmt_nat_find(ctx, from);
+ assert(k >= 0);
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++) {
+ stmt = ctx->stmt_matrix[i][merge->stmt[0]];
+ expr = stmt->expr->right;
+
+ nat_stmt = ctx->stmt_matrix[i][k];
+ nat_expr = stmt_nat_expr(nat_stmt);
+
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr));
+ mapping = mapping_expr_alloc(&internal_location, elem, nat_expr);
+ compound_expr_add(set, mapping);
+ }
+
+ stmt = ctx->stmt_matrix[from][merge->stmt[0]];
+ left = expr_get(stmt->expr->left);
+ if (left->etype == EXPR_PAYLOAD) {
+ if (left->payload.desc == &proto_ip)
+ family = NFPROTO_IPV4;
+ else if (left->payload.desc == &proto_ip6)
+ family = NFPROTO_IPV6;
+ }
+ expr = map_expr_alloc(&internal_location, left, set);
+
+ nat_stmt = ctx->stmt_matrix[from][k];
+ if (nat_stmt->nat.family == NFPROTO_UNSPEC)
+ nat_stmt->nat.family = family;
+
+ expr_free(nat_stmt->nat.addr);
+ if (nat_stmt->nat.type == NFT_NAT_REDIR)
+ nat_stmt->nat.proto = expr;
+ else
+ nat_stmt->nat.addr = expr;
+
+ remove_counter(ctx, from);
+ list_del(&stmt->list);
+ stmt_free(stmt);
+}
+
+static void merge_concat_nat(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct expr *expr, *set, *elem, *nat_expr, *mapping, *left, *concat;
+ int k, family = NFPROTO_UNSPEC;
+ struct stmt *stmt, *nat_stmt;
+ uint32_t i, j;
+
+ k = stmt_nat_find(ctx, from);
+ assert(k >= 0);
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++) {
+
+ concat = concat_expr_alloc(&internal_location);
+ for (j = 0; j < merge->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[i][merge->stmt[j]];
+ expr = stmt->expr->right;
+ compound_expr_add(concat, expr_get(expr));
+ }
+
+ nat_stmt = ctx->stmt_matrix[i][k];
+ nat_expr = stmt_nat_expr(nat_stmt);
+
+ elem = set_elem_expr_alloc(&internal_location, concat);
+ mapping = mapping_expr_alloc(&internal_location, elem, nat_expr);
+ compound_expr_add(set, mapping);
+ }
+
+ concat = concat_expr_alloc(&internal_location);
+ for (j = 0; j < merge->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[from][merge->stmt[j]];
+ left = stmt->expr->left;
+ if (left->etype == EXPR_PAYLOAD) {
+ if (left->payload.desc == &proto_ip)
+ family = NFPROTO_IPV4;
+ else if (left->payload.desc == &proto_ip6)
+ family = NFPROTO_IPV6;
+ }
+ compound_expr_add(concat, expr_get(left));
+ }
+ expr = map_expr_alloc(&internal_location, concat, set);
+
+ nat_stmt = ctx->stmt_matrix[from][k];
+ if (nat_stmt->nat.family == NFPROTO_UNSPEC)
+ nat_stmt->nat.family = family;
+
+ expr_free(nat_stmt->nat.addr);
+ nat_stmt->nat.addr = expr;
+
+ remove_counter(ctx, from);
+ for (j = 0; j < merge->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[from][merge->stmt[j]];
+ list_del(&stmt->list);
+ stmt_free(stmt);
+ }
+}
+
+static void rule_optimize_print(struct output_ctx *octx,
+ const struct rule *rule)
+{
+ const struct location *loc = &rule->location;
+ const struct input_descriptor *indesc = loc->indesc;
+ const char *line = "";
+ char buf[1024];
+
+ switch (indesc->type) {
+ case INDESC_BUFFER:
+ case INDESC_CLI:
+ line = indesc->data;
+ *strchrnul(line, '\n') = '\0';
+ break;
+ case INDESC_STDIN:
+ line = indesc->data;
+ line += loc->line_offset;
+ *strchrnul(line, '\n') = '\0';
+ break;
+ case INDESC_FILE:
+ line = line_location(indesc, loc, buf, sizeof(buf));
+ break;
+ case INDESC_INTERNAL:
+ case INDESC_NETLINK:
+ break;
+ default:
+ BUG("invalid input descriptor type %u\n", indesc->type);
+ }
+
+ print_location(octx->error_fp, indesc, loc);
+ fprintf(octx->error_fp, "%s\n", line);
+}
+
+enum {
+ MERGE_BY_VERDICT,
+ MERGE_BY_NAT_MAP,
+ MERGE_BY_NAT,
+};
+
+static uint32_t merge_stmt_type(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to)
+{
+ const struct stmt *stmt;
+ uint32_t i, j;
+
+ for (i = from; i <= to; i++) {
+ for (j = 0; j < ctx->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[i][j];
+ if (!stmt)
+ continue;
+ if (stmt->ops->type == STMT_NAT) {
+ if ((stmt->nat.type == NFT_NAT_REDIR &&
+ !stmt->nat.proto) ||
+ stmt->nat.type == NFT_NAT_MASQ)
+ return MERGE_BY_NAT;
+
+ return MERGE_BY_NAT_MAP;
+ }
+ }
+ }
+
+ /* merge by verdict, even if no verdict is specified. */
+ return MERGE_BY_VERDICT;
+}
+
+static void merge_rules(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct output_ctx *octx)
+{
+ uint32_t merge_type;
+ bool same_verdict;
+ uint32_t i;
+
+ merge_type = merge_stmt_type(ctx, from, to);
+
+ switch (merge_type) {
+ case MERGE_BY_VERDICT:
+ same_verdict = stmt_verdict_cmp(ctx, from, to);
+ if (merge->num_stmts > 1) {
+ if (same_verdict)
+ merge_concat_stmts(ctx, from, to, merge);
+ else
+ merge_concat_stmts_vmap(ctx, from, to, merge);
+ } else {
+ if (same_verdict)
+ merge_stmts(ctx, from, to, merge);
+ else
+ merge_stmts_vmap(ctx, from, to, merge);
+ }
+ break;
+ case MERGE_BY_NAT_MAP:
+ if (merge->num_stmts > 1)
+ merge_concat_nat(ctx, from, to, merge);
+ else
+ merge_nat(ctx, from, to, merge);
+ break;
+ case MERGE_BY_NAT:
+ if (merge->num_stmts > 1)
+ merge_concat_stmts(ctx, from, to, merge);
+ else
+ merge_stmts(ctx, from, to, merge);
+ break;
+ default:
+ assert(0);
+ }
+
+ if (ctx->rule[from]->comment) {
+ xfree(ctx->rule[from]->comment);
+ ctx->rule[from]->comment = NULL;
+ }
+
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+
+ fprintf(octx->error_fp, "Merging:\n");
+ rule_optimize_print(octx, ctx->rule[from]);
+
+ for (i = from + 1; i <= to; i++) {
+ rule_optimize_print(octx, ctx->rule[i]);
+ list_del(&ctx->rule[i]->list);
+ rule_free(ctx->rule[i]);
+ }
+
+ fprintf(octx->error_fp, "into:\n\t");
+ rule_print(ctx->rule[from], octx);
+ fprintf(octx->error_fp, "\n");
+
+ octx->flags &= ~NFT_CTX_OUTPUT_STATELESS;
+}
+
+static bool stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ if (!stmt_a && !stmt_b)
+ return true;
+ else if (!stmt_a)
+ return false;
+ else if (!stmt_b)
+ return false;
+
+ return __stmt_type_eq(stmt_a, stmt_b, true);
+}
+
+static bool stmt_is_mergeable(const struct stmt *stmt)
+{
+ if (!stmt)
+ return false;
+
+ switch (stmt->ops->type) {
+ case STMT_VERDICT:
+ if (stmt->expr->etype == EXPR_MAP)
+ return true;
+ break;
+ case STMT_EXPRESSION:
+ case STMT_NAT:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool rules_eq(const struct optimize_ctx *ctx, int i, int j)
+{
+ uint32_t k, mergeable = 0;
+
+ for (k = 0; k < ctx->num_stmts; k++) {
+ if (stmt_is_mergeable(ctx->stmt_matrix[i][k]))
+ mergeable++;
+
+ if (!stmt_type_eq(ctx->stmt_matrix[i][k], ctx->stmt_matrix[j][k]))
+ return false;
+ }
+
+ if (mergeable == 0)
+ return false;
+
+ return true;
+}
+
+static int chain_optimize(struct nft_ctx *nft, struct list_head *rules)
+{
+ struct optimize_ctx *ctx;
+ uint32_t num_merges = 0;
+ struct merge *merge;
+ uint32_t i, j, m, k;
+ struct rule *rule;
+ int ret;
+
+ ctx = xzalloc(sizeof(*ctx));
+
+ /* Step 1: collect statements in rules */
+ list_for_each_entry(rule, rules, list) {
+ ret = rule_collect_stmts(ctx, rule);
+ if (ret < 0)
+ goto err;
+
+ ctx->num_rules++;
+ }
+
+ ctx->rule = xzalloc(sizeof(*ctx->rule) * ctx->num_rules);
+ ctx->stmt_matrix = xzalloc(sizeof(*ctx->stmt_matrix) * ctx->num_rules);
+ for (i = 0; i < ctx->num_rules; i++)
+ ctx->stmt_matrix[i] = xzalloc_array(MAX_STMTS,
+ sizeof(**ctx->stmt_matrix));
+
+ merge = xzalloc(sizeof(*merge) * ctx->num_rules);
+
+ /* Step 2: Build matrix of statements */
+ i = 0;
+ list_for_each_entry(rule, rules, list)
+ rule_build_stmt_matrix_stmts(ctx, rule, &i);
+
+ /* Step 3: Look for common selectors for possible rule mergers */
+ for (i = 0; i < ctx->num_rules; i++) {
+ for (j = i + 1; j < ctx->num_rules; j++) {
+ if (!rules_eq(ctx, i, j)) {
+ if (merge[num_merges].num_rules > 0)
+ num_merges++;
+
+ i = j - 1;
+ break;
+ }
+ if (merge[num_merges].num_rules > 0) {
+ merge[num_merges].num_rules++;
+ } else {
+ merge[num_merges].rule_from = i;
+ merge[num_merges].num_rules = 2;
+ }
+ }
+ if (j == ctx->num_rules && merge[num_merges].num_rules > 0) {
+ num_merges++;
+ break;
+ }
+ }
+
+ /* Step 4: Infer how to merge the candidate rules */
+ for (k = 0; k < num_merges; k++) {
+ i = merge[k].rule_from;
+
+ for (m = 0; m < ctx->num_stmts; m++) {
+ if (!ctx->stmt_matrix[i][m])
+ continue;
+ switch (ctx->stmt_matrix[i][m]->ops->type) {
+ case STMT_EXPRESSION:
+ merge[k].stmt[merge[k].num_stmts++] = m;
+ break;
+ case STMT_VERDICT:
+ if (ctx->stmt_matrix[i][m]->expr->etype == EXPR_MAP)
+ merge[k].stmt[merge[k].num_stmts++] = m;
+ break;
+ default:
+ break;
+ }
+ }
+
+ j = merge[k].num_rules - 1;
+ merge_rules(ctx, i, i + j, &merge[k], &nft->output);
+ }
+ ret = 0;
+ for (i = 0; i < ctx->num_rules; i++)
+ xfree(ctx->stmt_matrix[i]);
+
+ xfree(ctx->stmt_matrix);
+ xfree(merge);
+err:
+ for (i = 0; i < ctx->num_stmts; i++)
+ stmt_free(ctx->stmt[i]);
+
+ xfree(ctx->rule);
+ xfree(ctx);
+
+ return ret;
+}
+
+static int cmd_optimize(struct nft_ctx *nft, struct cmd *cmd)
+{
+ struct table *table;
+ struct chain *chain;
+ int ret = 0;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ table = cmd->table;
+ if (!table)
+ break;
+
+ list_for_each_entry(chain, &table->chains, list) {
+ if (chain->flags & CHAIN_F_HW_OFFLOAD)
+ continue;
+
+ chain_optimize(nft, &chain->rules);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int nft_optimize(struct nft_ctx *nft, struct list_head *cmds)
+{
+ struct cmd *cmd;
+ int ret = 0;
+
+ list_for_each_entry(cmd, cmds, list) {
+ switch (cmd->op) {
+ case CMD_ADD:
+ ret = cmd_optimize(nft, cmd);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
diff --git a/src/osf.c b/src/osf.c
new file mode 100644
index 0000000..a8f80b2
--- /dev/null
+++ b/src/osf.c
@@ -0,0 +1,84 @@
+/*
+ * 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 <osf.h>
+#include <json.h>
+
+static const char *osf_ttl_int_to_str(const uint8_t ttl)
+{
+ if (ttl == 1)
+ return "ttl loose ";
+ else if (ttl == 2)
+ return "ttl skip ";
+
+ return "";
+}
+
+static void osf_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *ttl_str = osf_ttl_int_to_str(expr->osf.ttl);
+
+ if (expr->osf.flags & NFT_OSF_F_VERSION)
+ nft_print(octx, "osf %sversion", ttl_str);
+ else
+ nft_print(octx, "osf %sname", ttl_str);
+}
+
+static void osf_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->osf.ttl = expr->osf.ttl;
+ new->osf.flags = expr->osf.flags;
+}
+
+static bool osf_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return (e1->osf.ttl == e2->osf.ttl) &&
+ (e1->osf.flags == e2->osf.flags);
+}
+
+static int osf_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ return 0;
+}
+
+static struct expr *osf_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ return osf_expr_alloc(&internal_location, 0, 0);
+}
+
+const struct expr_ops osf_expr_ops = {
+ .type = EXPR_OSF,
+ .name = "osf",
+ .print = osf_expr_print,
+ .clone = osf_expr_clone,
+ .cmp = osf_expr_cmp,
+ .json = osf_expr_json,
+ .parse_udata = osf_expr_parse_udata,
+ .build_udata = osf_expr_build_udata,
+};
+
+struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl,
+ const uint32_t flags)
+{
+ unsigned int len = NFT_OSF_MAXGENRELEN * BITS_PER_BYTE;
+ const struct datatype *type = &string_type;
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_OSF, type,
+ BYTEORDER_HOST_ENDIAN, len);
+ expr->osf.ttl = ttl;
+ expr->osf.flags = flags;
+
+ return expr;
+}
diff --git a/src/owner.c b/src/owner.c
new file mode 100644
index 0000000..65eaad3
--- /dev/null
+++ b/src/owner.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2021 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <inttypes.h>
+#include <dirent.h>
+
+#include <netlink.h>
+#include <owner.h>
+
+static char *pid2name(pid_t pid)
+{
+ char procname[256], *prog;
+ FILE *fp;
+ int ret;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%lu/stat", (unsigned long)pid);
+ if (ret < 0 || ret > (int)sizeof(procname))
+ return NULL;
+
+ fp = fopen(procname, "r");
+ if (!fp)
+ return NULL;
+
+ ret = fscanf(fp, "%*u (%m[^)]", &prog);
+
+ fclose(fp);
+
+ if (ret == 1)
+ return prog;
+
+ return NULL;
+}
+
+static char *portid2name(pid_t pid, uint32_t portid, unsigned long inode)
+{
+ const struct dirent *ent;
+ char procname[256];
+ DIR *dir;
+ int ret;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%lu/fd/", (unsigned long)pid);
+ if (ret < 0 || ret >= (int)sizeof(procname))
+ return NULL;
+
+ dir = opendir(procname);
+ if (!dir)
+ return NULL;
+
+ for (;;) {
+ unsigned long ino;
+ char tmp[128];
+ ssize_t rl;
+
+ ent = readdir(dir);
+ if (!ent)
+ break;
+
+ if (ent->d_type != DT_LNK)
+ continue;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%d/fd/%s",
+ pid, ent->d_name);
+ if (ret < 0 || ret >= (int)sizeof(procname))
+ continue;
+
+ rl = readlink(procname, tmp, sizeof(tmp));
+ if (rl <= 0 || rl >= (ssize_t)sizeof(tmp))
+ continue;
+
+ tmp[rl] = 0;
+
+ ret = sscanf(tmp, "socket:[%lu]", &ino);
+ if (ret == 1 && ino == inode) {
+ closedir(dir);
+ return pid2name(pid);
+ }
+ }
+
+ closedir(dir);
+ return NULL;
+}
+
+static char *name_by_portid(uint32_t portid, unsigned long inode)
+{
+ const struct dirent *ent;
+ char *prog;
+ DIR *dir;
+
+ /* Many netlink users use their process ID to allocate the first port id. */
+ prog = portid2name(portid, portid, inode);
+ if (prog)
+ return prog;
+
+ /* no luck, search harder. */
+ dir = opendir("/proc");
+ if (!dir)
+ return NULL;
+
+ for (;;) {
+ unsigned long pid;
+ char *end;
+
+ ent = readdir(dir);
+ if (!ent)
+ break;
+
+ if (ent->d_type != DT_DIR)
+ continue;
+
+ pid = strtoul(ent->d_name, &end, 10);
+ if (pid <= 1 || *end)
+ continue;
+
+ if (pid == portid) /* already tried */
+ continue;
+
+ prog = portid2name(pid, portid, inode);
+ if (prog)
+ break;
+ }
+
+ closedir(dir);
+ return prog;
+}
+
+char *get_progname(uint32_t portid)
+{
+ FILE *fp = fopen("/proc/net/netlink", "r");
+ uint32_t portid_check;
+ unsigned long inode;
+ int ret, prot;
+
+ if (!fp)
+ return NULL;
+
+ for (;;) {
+ char line[256];
+
+ if (!fgets(line, sizeof(line), fp))
+ break;
+
+ ret = sscanf(line, "%*x %d %u %*x %*d %*d %*x %*d %*u %lu\n",
+ &prot, &portid_check, &inode);
+
+ if (ret == EOF)
+ break;
+
+ if (ret == 3 && portid_check == portid && prot == NETLINK_NETFILTER) {
+ static uint32_t last_portid;
+ static uint32_t last_inode;
+ static char *last_program;
+ char *prog;
+
+ fclose(fp);
+
+ if (last_portid == portid && last_inode == inode)
+ return last_program;
+
+ prog = name_by_portid(portid, inode);
+
+ free(last_program);
+ last_program = prog;
+ last_portid = portid;
+ last_inode = inode;
+ return prog;
+ }
+ }
+
+ fclose(fp);
+ return NULL;
+}
diff --git a/src/parser_bison.c b/src/parser_bison.c
new file mode 100644
index 0000000..379f322
--- /dev/null
+++ b/src/parser_bison.c
@@ -0,0 +1,17491 @@
+/* A Bison parser, made by GNU Bison 3.7.5. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output, and Bison version. */
+#define YYBISON 30705
+
+/* Bison version string. */
+#define YYBISON_VERSION "3.7.5"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+/* Substitute the variable and function names. */
+#define yyparse nft_parse
+#define yylex nft_lex
+#define yyerror nft_error
+#define yydebug nft_debug
+#define yynerrs nft_nerrs
+
+/* First part of user prologue. */
+#line 11 "parser_bison.y"
+
+#include <nft.h>
+
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <syslog.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/if_ether.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/nfnetlink_osf.h>
+#include <linux/netfilter/nf_synproxy.h>
+#include <linux/xfrm.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <libnftnl/common.h>
+#include <libnftnl/set.h>
+#include <libnftnl/udata.h>
+
+#include <rule.h>
+#include <statement.h>
+#include <expression.h>
+#include <headers.h>
+#include <utils.h>
+#include <parser.h>
+#include <erec.h>
+#include <sctp_chunk.h>
+
+#include "parser_bison.h"
+
+void parser_init(struct nft_ctx *nft, struct parser_state *state,
+ struct list_head *msgs, struct list_head *cmds,
+ struct scope *top_scope)
+{
+ memset(state, 0, sizeof(*state));
+ state->msgs = msgs;
+ state->cmds = cmds;
+ state->scopes[0] = scope_init(top_scope, NULL);
+ init_list_head(&state->indesc_list);
+}
+
+static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner,
+ struct parser_state *state, const char *s)
+{
+ erec_queue(error(loc, "%s", s), state->msgs);
+}
+
+static struct scope *current_scope(const struct parser_state *state)
+{
+ return state->scopes[state->scope];
+}
+
+static int open_scope(struct parser_state *state, struct scope *scope)
+{
+ 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)
+{
+ if (state->scope_err || state->scope == 0) {
+ state->scope_err = false;
+ return;
+ }
+
+ state->scope--;
+}
+
+static void location_init(void *scanner, struct parser_state *state,
+ struct location *loc)
+{
+ memset(loc, 0, sizeof(*loc));
+ loc->indesc = state->indesc;
+}
+
+static void location_update(struct location *loc, struct location *rhs, int n)
+{
+ if (n) {
+ loc->indesc = rhs[n].indesc;
+ loc->token_offset = rhs[1].token_offset;
+ loc->line_offset = rhs[1].line_offset;
+ loc->first_line = rhs[1].first_line;
+ loc->first_column = rhs[1].first_column;
+ loc->last_line = rhs[n].last_line;
+ loc->last_column = rhs[n].last_column;
+ } else {
+ loc->indesc = rhs[0].indesc;
+ loc->token_offset = rhs[0].token_offset;
+ loc->line_offset = rhs[0].line_offset;
+ loc->first_line = loc->last_line = rhs[0].last_line;
+ loc->first_column = loc->last_column = rhs[0].last_column;
+ }
+}
+
+static struct expr *handle_concat_expr(const struct location *loc,
+ struct expr *expr,
+ struct expr *expr_l, struct expr *expr_r,
+ struct location loc_rhs[3])
+{
+ if (expr->etype != EXPR_CONCAT) {
+ expr = concat_expr_alloc(loc);
+ compound_expr_add(expr, expr_l);
+ } else {
+ location_update(&expr_r->location, loc_rhs, 2);
+
+ expr = expr_l;
+ expr->location = *loc;
+ }
+
+ compound_expr_add(expr, expr_r);
+ return expr;
+}
+
+static bool already_set(const void *attr, const struct location *loc,
+ struct parser_state *state)
+{
+ if (!attr)
+ return false;
+
+ erec_queue(error(loc, "You can only specify this once. This statement is duplicated."),
+ state->msgs);
+ return true;
+}
+
+static struct expr *ifname_expr_alloc(const struct location *location,
+ struct list_head *queue,
+ const char *name)
+{
+ unsigned int length = strlen(name);
+ struct expr *expr;
+
+ if (length == 0) {
+ xfree(name);
+ erec_queue(error(location, "empty interface name"), queue);
+ return NULL;
+ }
+
+ if (length > 16) {
+ xfree(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);
+
+ xfree(name);
+
+ return expr;
+}
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N)
+
+#define symbol_value(loc, str) \
+ symbol_expr_alloc(loc, SYMBOL_VALUE, current_scope(state), str)
+
+/* Declare those here to avoid compiler warnings */
+void nft_set_debug(int, void *);
+int nft_lex(void *, void *, void *);
+
+#line 250 "parser_bison.c"
+
+# ifndef YY_CAST
+# ifdef __cplusplus
+# define YY_CAST(Type, Val) static_cast<Type> (Val)
+# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+# else
+# define YY_CAST(Type, Val) ((Type) (Val))
+# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+# endif
+# endif
+# ifndef YY_NULLPTR
+# if defined __cplusplus
+# if 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# else
+# define YY_NULLPTR ((void*)0)
+# endif
+# endif
+
+/* Use api.header.include to #include this header
+ instead of duplicating it here. */
+#ifndef YY_NFT_PARSER_BISON_H_INCLUDED
+# define YY_NFT_PARSER_BISON_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int nft_debug;
+#endif
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ TOKEN_EOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ JUNK = 258, /* "junk" */
+ NEWLINE = 259, /* "newline" */
+ COLON = 260, /* "colon" */
+ SEMICOLON = 261, /* "semicolon" */
+ COMMA = 262, /* "comma" */
+ DOT = 263, /* "." */
+ EQ = 264, /* "==" */
+ NEQ = 265, /* "!=" */
+ LT = 266, /* "<" */
+ GT = 267, /* ">" */
+ GTE = 268, /* ">=" */
+ LTE = 269, /* "<=" */
+ LSHIFT = 270, /* "<<" */
+ RSHIFT = 271, /* ">>" */
+ AMPERSAND = 272, /* "&" */
+ CARET = 273, /* "^" */
+ NOT = 274, /* "!" */
+ SLASH = 275, /* "/" */
+ ASTERISK = 276, /* "*" */
+ DASH = 277, /* "-" */
+ AT = 278, /* "@" */
+ VMAP = 279, /* "vmap" */
+ PLUS = 280, /* "+" */
+ INCLUDE = 281, /* "include" */
+ DEFINE = 282, /* "define" */
+ REDEFINE = 283, /* "redefine" */
+ UNDEFINE = 284, /* "undefine" */
+ FIB = 285, /* "fib" */
+ SOCKET = 286, /* "socket" */
+ TRANSPARENT = 287, /* "transparent" */
+ WILDCARD = 288, /* "wildcard" */
+ CGROUPV2 = 289, /* "cgroupv2" */
+ TPROXY = 290, /* "tproxy" */
+ OSF = 291, /* "osf" */
+ SYNPROXY = 292, /* "synproxy" */
+ MSS = 293, /* "mss" */
+ WSCALE = 294, /* "wscale" */
+ TYPEOF = 295, /* "typeof" */
+ HOOK = 296, /* "hook" */
+ HOOKS = 297, /* "hooks" */
+ DEVICE = 298, /* "device" */
+ DEVICES = 299, /* "devices" */
+ TABLE = 300, /* "table" */
+ TABLES = 301, /* "tables" */
+ CHAIN = 302, /* "chain" */
+ CHAINS = 303, /* "chains" */
+ RULE = 304, /* "rule" */
+ RULES = 305, /* "rules" */
+ SETS = 306, /* "sets" */
+ SET = 307, /* "set" */
+ ELEMENT = 308, /* "element" */
+ MAP = 309, /* "map" */
+ MAPS = 310, /* "maps" */
+ FLOWTABLE = 311, /* "flowtable" */
+ HANDLE = 312, /* "handle" */
+ RULESET = 313, /* "ruleset" */
+ TRACE = 314, /* "trace" */
+ INET = 315, /* "inet" */
+ NETDEV = 316, /* "netdev" */
+ ADD = 317, /* "add" */
+ UPDATE = 318, /* "update" */
+ REPLACE = 319, /* "replace" */
+ CREATE = 320, /* "create" */
+ INSERT = 321, /* "insert" */
+ DELETE = 322, /* "delete" */
+ GET = 323, /* "get" */
+ LIST = 324, /* "list" */
+ RESET = 325, /* "reset" */
+ FLUSH = 326, /* "flush" */
+ RENAME = 327, /* "rename" */
+ DESCRIBE = 328, /* "describe" */
+ IMPORT = 329, /* "import" */
+ EXPORT = 330, /* "export" */
+ DESTROY = 331, /* "destroy" */
+ MONITOR = 332, /* "monitor" */
+ ALL = 333, /* "all" */
+ ACCEPT = 334, /* "accept" */
+ DROP = 335, /* "drop" */
+ CONTINUE = 336, /* "continue" */
+ JUMP = 337, /* "jump" */
+ GOTO = 338, /* "goto" */
+ RETURN = 339, /* "return" */
+ TO = 340, /* "to" */
+ CONSTANT = 341, /* "constant" */
+ INTERVAL = 342, /* "interval" */
+ DYNAMIC = 343, /* "dynamic" */
+ AUTOMERGE = 344, /* "auto-merge" */
+ TIMEOUT = 345, /* "timeout" */
+ GC_INTERVAL = 346, /* "gc-interval" */
+ ELEMENTS = 347, /* "elements" */
+ EXPIRES = 348, /* "expires" */
+ POLICY = 349, /* "policy" */
+ MEMORY = 350, /* "memory" */
+ PERFORMANCE = 351, /* "performance" */
+ SIZE = 352, /* "size" */
+ FLOW = 353, /* "flow" */
+ OFFLOAD = 354, /* "offload" */
+ METER = 355, /* "meter" */
+ METERS = 356, /* "meters" */
+ FLOWTABLES = 357, /* "flowtables" */
+ NUM = 358, /* "number" */
+ STRING = 359, /* "string" */
+ QUOTED_STRING = 360, /* "quoted string" */
+ ASTERISK_STRING = 361, /* "string with a trailing asterisk" */
+ LL_HDR = 362, /* "ll" */
+ NETWORK_HDR = 363, /* "nh" */
+ TRANSPORT_HDR = 364, /* "th" */
+ BRIDGE = 365, /* "bridge" */
+ ETHER = 366, /* "ether" */
+ SADDR = 367, /* "saddr" */
+ DADDR = 368, /* "daddr" */
+ TYPE = 369, /* "type" */
+ VLAN = 370, /* "vlan" */
+ ID = 371, /* "id" */
+ CFI = 372, /* "cfi" */
+ DEI = 373, /* "dei" */
+ PCP = 374, /* "pcp" */
+ ARP = 375, /* "arp" */
+ HTYPE = 376, /* "htype" */
+ PTYPE = 377, /* "ptype" */
+ HLEN = 378, /* "hlen" */
+ PLEN = 379, /* "plen" */
+ OPERATION = 380, /* "operation" */
+ IP = 381, /* "ip" */
+ HDRVERSION = 382, /* "version" */
+ HDRLENGTH = 383, /* "hdrlength" */
+ DSCP = 384, /* "dscp" */
+ ECN = 385, /* "ecn" */
+ LENGTH = 386, /* "length" */
+ FRAG_OFF = 387, /* "frag-off" */
+ TTL = 388, /* "ttl" */
+ PROTOCOL = 389, /* "protocol" */
+ CHECKSUM = 390, /* "checksum" */
+ PTR = 391, /* "ptr" */
+ VALUE = 392, /* "value" */
+ LSRR = 393, /* "lsrr" */
+ RR = 394, /* "rr" */
+ SSRR = 395, /* "ssrr" */
+ RA = 396, /* "ra" */
+ ICMP = 397, /* "icmp" */
+ CODE = 398, /* "code" */
+ SEQUENCE = 399, /* "seq" */
+ GATEWAY = 400, /* "gateway" */
+ MTU = 401, /* "mtu" */
+ IGMP = 402, /* "igmp" */
+ MRT = 403, /* "mrt" */
+ OPTIONS = 404, /* "options" */
+ IP6 = 405, /* "ip6" */
+ PRIORITY = 406, /* "priority" */
+ FLOWLABEL = 407, /* "flowlabel" */
+ NEXTHDR = 408, /* "nexthdr" */
+ HOPLIMIT = 409, /* "hoplimit" */
+ ICMP6 = 410, /* "icmpv6" */
+ PPTR = 411, /* "param-problem" */
+ MAXDELAY = 412, /* "max-delay" */
+ TADDR = 413, /* "taddr" */
+ AH = 414, /* "ah" */
+ RESERVED = 415, /* "reserved" */
+ SPI = 416, /* "spi" */
+ ESP = 417, /* "esp" */
+ COMP = 418, /* "comp" */
+ FLAGS = 419, /* "flags" */
+ CPI = 420, /* "cpi" */
+ PORT = 421, /* "port" */
+ UDP = 422, /* "udp" */
+ SPORT = 423, /* "sport" */
+ DPORT = 424, /* "dport" */
+ UDPLITE = 425, /* "udplite" */
+ CSUMCOV = 426, /* "csumcov" */
+ TCP = 427, /* "tcp" */
+ ACKSEQ = 428, /* "ackseq" */
+ DOFF = 429, /* "doff" */
+ WINDOW = 430, /* "window" */
+ URGPTR = 431, /* "urgptr" */
+ OPTION = 432, /* "option" */
+ ECHO = 433, /* "echo" */
+ EOL = 434, /* "eol" */
+ MPTCP = 435, /* "mptcp" */
+ NOP = 436, /* "nop" */
+ SACK = 437, /* "sack" */
+ SACK0 = 438, /* "sack0" */
+ SACK1 = 439, /* "sack1" */
+ SACK2 = 440, /* "sack2" */
+ SACK3 = 441, /* "sack3" */
+ SACK_PERM = 442, /* "sack-permitted" */
+ FASTOPEN = 443, /* "fastopen" */
+ MD5SIG = 444, /* "md5sig" */
+ TIMESTAMP = 445, /* "timestamp" */
+ COUNT = 446, /* "count" */
+ LEFT = 447, /* "left" */
+ RIGHT = 448, /* "right" */
+ TSVAL = 449, /* "tsval" */
+ TSECR = 450, /* "tsecr" */
+ SUBTYPE = 451, /* "subtype" */
+ DCCP = 452, /* "dccp" */
+ VXLAN = 453, /* "vxlan" */
+ VNI = 454, /* "vni" */
+ GRE = 455, /* "gre" */
+ GRETAP = 456, /* "gretap" */
+ GENEVE = 457, /* "geneve" */
+ SCTP = 458, /* "sctp" */
+ CHUNK = 459, /* "chunk" */
+ DATA = 460, /* "data" */
+ INIT = 461, /* "init" */
+ INIT_ACK = 462, /* "init-ack" */
+ HEARTBEAT = 463, /* "heartbeat" */
+ HEARTBEAT_ACK = 464, /* "heartbeat-ack" */
+ ABORT = 465, /* "abort" */
+ SHUTDOWN = 466, /* "shutdown" */
+ SHUTDOWN_ACK = 467, /* "shutdown-ack" */
+ ERROR = 468, /* "error" */
+ COOKIE_ECHO = 469, /* "cookie-echo" */
+ COOKIE_ACK = 470, /* "cookie-ack" */
+ ECNE = 471, /* "ecne" */
+ CWR = 472, /* "cwr" */
+ SHUTDOWN_COMPLETE = 473, /* "shutdown-complete" */
+ ASCONF_ACK = 474, /* "asconf-ack" */
+ FORWARD_TSN = 475, /* "forward-tsn" */
+ ASCONF = 476, /* "asconf" */
+ TSN = 477, /* "tsn" */
+ STREAM = 478, /* "stream" */
+ SSN = 479, /* "ssn" */
+ PPID = 480, /* "ppid" */
+ INIT_TAG = 481, /* "init-tag" */
+ A_RWND = 482, /* "a-rwnd" */
+ NUM_OSTREAMS = 483, /* "num-outbound-streams" */
+ NUM_ISTREAMS = 484, /* "num-inbound-streams" */
+ INIT_TSN = 485, /* "initial-tsn" */
+ CUM_TSN_ACK = 486, /* "cum-tsn-ack" */
+ NUM_GACK_BLOCKS = 487, /* "num-gap-ack-blocks" */
+ NUM_DUP_TSNS = 488, /* "num-dup-tsns" */
+ LOWEST_TSN = 489, /* "lowest-tsn" */
+ SEQNO = 490, /* "seqno" */
+ NEW_CUM_TSN = 491, /* "new-cum-tsn" */
+ VTAG = 492, /* "vtag" */
+ RT = 493, /* "rt" */
+ RT0 = 494, /* "rt0" */
+ RT2 = 495, /* "rt2" */
+ RT4 = 496, /* "srh" */
+ SEG_LEFT = 497, /* "seg-left" */
+ ADDR = 498, /* "addr" */
+ LAST_ENT = 499, /* "last-entry" */
+ TAG = 500, /* "tag" */
+ SID = 501, /* "sid" */
+ HBH = 502, /* "hbh" */
+ FRAG = 503, /* "frag" */
+ RESERVED2 = 504, /* "reserved2" */
+ MORE_FRAGMENTS = 505, /* "more-fragments" */
+ DST = 506, /* "dst" */
+ MH = 507, /* "mh" */
+ META = 508, /* "meta" */
+ MARK = 509, /* "mark" */
+ IIF = 510, /* "iif" */
+ IIFNAME = 511, /* "iifname" */
+ IIFTYPE = 512, /* "iiftype" */
+ OIF = 513, /* "oif" */
+ OIFNAME = 514, /* "oifname" */
+ OIFTYPE = 515, /* "oiftype" */
+ SKUID = 516, /* "skuid" */
+ SKGID = 517, /* "skgid" */
+ NFTRACE = 518, /* "nftrace" */
+ RTCLASSID = 519, /* "rtclassid" */
+ IBRIPORT = 520, /* "ibriport" */
+ OBRIPORT = 521, /* "obriport" */
+ IBRIDGENAME = 522, /* "ibrname" */
+ OBRIDGENAME = 523, /* "obrname" */
+ PKTTYPE = 524, /* "pkttype" */
+ CPU = 525, /* "cpu" */
+ IIFGROUP = 526, /* "iifgroup" */
+ OIFGROUP = 527, /* "oifgroup" */
+ CGROUP = 528, /* "cgroup" */
+ TIME = 529, /* "time" */
+ CLASSID = 530, /* "classid" */
+ NEXTHOP = 531, /* "nexthop" */
+ CT = 532, /* "ct" */
+ L3PROTOCOL = 533, /* "l3proto" */
+ PROTO_SRC = 534, /* "proto-src" */
+ PROTO_DST = 535, /* "proto-dst" */
+ ZONE = 536, /* "zone" */
+ DIRECTION = 537, /* "direction" */
+ EVENT = 538, /* "event" */
+ EXPECTATION = 539, /* "expectation" */
+ EXPIRATION = 540, /* "expiration" */
+ HELPER = 541, /* "helper" */
+ LABEL = 542, /* "label" */
+ STATE = 543, /* "state" */
+ STATUS = 544, /* "status" */
+ ORIGINAL = 545, /* "original" */
+ REPLY = 546, /* "reply" */
+ COUNTER = 547, /* "counter" */
+ NAME = 548, /* "name" */
+ PACKETS = 549, /* "packets" */
+ BYTES = 550, /* "bytes" */
+ AVGPKT = 551, /* "avgpkt" */
+ LAST = 552, /* "last" */
+ NEVER = 553, /* "never" */
+ COUNTERS = 554, /* "counters" */
+ QUOTAS = 555, /* "quotas" */
+ LIMITS = 556, /* "limits" */
+ SYNPROXYS = 557, /* "synproxys" */
+ HELPERS = 558, /* "helpers" */
+ LOG = 559, /* "log" */
+ PREFIX = 560, /* "prefix" */
+ GROUP = 561, /* "group" */
+ SNAPLEN = 562, /* "snaplen" */
+ QUEUE_THRESHOLD = 563, /* "queue-threshold" */
+ LEVEL = 564, /* "level" */
+ LIMIT = 565, /* "limit" */
+ RATE = 566, /* "rate" */
+ BURST = 567, /* "burst" */
+ OVER = 568, /* "over" */
+ UNTIL = 569, /* "until" */
+ QUOTA = 570, /* "quota" */
+ USED = 571, /* "used" */
+ SECMARK = 572, /* "secmark" */
+ SECMARKS = 573, /* "secmarks" */
+ SECOND = 574, /* "second" */
+ MINUTE = 575, /* "minute" */
+ HOUR = 576, /* "hour" */
+ DAY = 577, /* "day" */
+ WEEK = 578, /* "week" */
+ _REJECT = 579, /* "reject" */
+ WITH = 580, /* "with" */
+ ICMPX = 581, /* "icmpx" */
+ SNAT = 582, /* "snat" */
+ DNAT = 583, /* "dnat" */
+ MASQUERADE = 584, /* "masquerade" */
+ REDIRECT = 585, /* "redirect" */
+ RANDOM = 586, /* "random" */
+ FULLY_RANDOM = 587, /* "fully-random" */
+ PERSISTENT = 588, /* "persistent" */
+ QUEUE = 589, /* "queue" */
+ QUEUENUM = 590, /* "num" */
+ BYPASS = 591, /* "bypass" */
+ FANOUT = 592, /* "fanout" */
+ DUP = 593, /* "dup" */
+ FWD = 594, /* "fwd" */
+ NUMGEN = 595, /* "numgen" */
+ INC = 596, /* "inc" */
+ MOD = 597, /* "mod" */
+ OFFSET = 598, /* "offset" */
+ JHASH = 599, /* "jhash" */
+ SYMHASH = 600, /* "symhash" */
+ SEED = 601, /* "seed" */
+ POSITION = 602, /* "position" */
+ INDEX = 603, /* "index" */
+ COMMENT = 604, /* "comment" */
+ XML = 605, /* "xml" */
+ JSON = 606, /* "json" */
+ VM = 607, /* "vm" */
+ NOTRACK = 608, /* "notrack" */
+ EXISTS = 609, /* "exists" */
+ MISSING = 610, /* "missing" */
+ EXTHDR = 611, /* "exthdr" */
+ IPSEC = 612, /* "ipsec" */
+ REQID = 613, /* "reqid" */
+ SPNUM = 614, /* "spnum" */
+ IN = 615, /* "in" */
+ OUT = 616, /* "out" */
+ XT = 617 /* "xt" */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+/* Token kinds. */
+#define YYEMPTY -2
+#define TOKEN_EOF 0
+#define YYerror 256
+#define YYUNDEF 257
+#define JUNK 258
+#define NEWLINE 259
+#define COLON 260
+#define SEMICOLON 261
+#define COMMA 262
+#define DOT 263
+#define EQ 264
+#define NEQ 265
+#define LT 266
+#define GT 267
+#define GTE 268
+#define LTE 269
+#define LSHIFT 270
+#define RSHIFT 271
+#define AMPERSAND 272
+#define CARET 273
+#define NOT 274
+#define SLASH 275
+#define ASTERISK 276
+#define DASH 277
+#define AT 278
+#define VMAP 279
+#define PLUS 280
+#define INCLUDE 281
+#define DEFINE 282
+#define REDEFINE 283
+#define UNDEFINE 284
+#define FIB 285
+#define SOCKET 286
+#define TRANSPARENT 287
+#define WILDCARD 288
+#define CGROUPV2 289
+#define TPROXY 290
+#define OSF 291
+#define SYNPROXY 292
+#define MSS 293
+#define WSCALE 294
+#define TYPEOF 295
+#define HOOK 296
+#define HOOKS 297
+#define DEVICE 298
+#define DEVICES 299
+#define TABLE 300
+#define TABLES 301
+#define CHAIN 302
+#define CHAINS 303
+#define RULE 304
+#define RULES 305
+#define SETS 306
+#define SET 307
+#define ELEMENT 308
+#define MAP 309
+#define MAPS 310
+#define FLOWTABLE 311
+#define HANDLE 312
+#define RULESET 313
+#define TRACE 314
+#define INET 315
+#define NETDEV 316
+#define ADD 317
+#define UPDATE 318
+#define REPLACE 319
+#define CREATE 320
+#define INSERT 321
+#define DELETE 322
+#define GET 323
+#define LIST 324
+#define RESET 325
+#define FLUSH 326
+#define RENAME 327
+#define DESCRIBE 328
+#define IMPORT 329
+#define EXPORT 330
+#define DESTROY 331
+#define MONITOR 332
+#define ALL 333
+#define ACCEPT 334
+#define DROP 335
+#define CONTINUE 336
+#define JUMP 337
+#define GOTO 338
+#define RETURN 339
+#define TO 340
+#define CONSTANT 341
+#define INTERVAL 342
+#define DYNAMIC 343
+#define AUTOMERGE 344
+#define TIMEOUT 345
+#define GC_INTERVAL 346
+#define ELEMENTS 347
+#define EXPIRES 348
+#define POLICY 349
+#define MEMORY 350
+#define PERFORMANCE 351
+#define SIZE 352
+#define FLOW 353
+#define OFFLOAD 354
+#define METER 355
+#define METERS 356
+#define FLOWTABLES 357
+#define NUM 358
+#define STRING 359
+#define QUOTED_STRING 360
+#define ASTERISK_STRING 361
+#define LL_HDR 362
+#define NETWORK_HDR 363
+#define TRANSPORT_HDR 364
+#define BRIDGE 365
+#define ETHER 366
+#define SADDR 367
+#define DADDR 368
+#define TYPE 369
+#define VLAN 370
+#define ID 371
+#define CFI 372
+#define DEI 373
+#define PCP 374
+#define ARP 375
+#define HTYPE 376
+#define PTYPE 377
+#define HLEN 378
+#define PLEN 379
+#define OPERATION 380
+#define IP 381
+#define HDRVERSION 382
+#define HDRLENGTH 383
+#define DSCP 384
+#define ECN 385
+#define LENGTH 386
+#define FRAG_OFF 387
+#define TTL 388
+#define PROTOCOL 389
+#define CHECKSUM 390
+#define PTR 391
+#define VALUE 392
+#define LSRR 393
+#define RR 394
+#define SSRR 395
+#define RA 396
+#define ICMP 397
+#define CODE 398
+#define SEQUENCE 399
+#define GATEWAY 400
+#define MTU 401
+#define IGMP 402
+#define MRT 403
+#define OPTIONS 404
+#define IP6 405
+#define PRIORITY 406
+#define FLOWLABEL 407
+#define NEXTHDR 408
+#define HOPLIMIT 409
+#define ICMP6 410
+#define PPTR 411
+#define MAXDELAY 412
+#define TADDR 413
+#define AH 414
+#define RESERVED 415
+#define SPI 416
+#define ESP 417
+#define COMP 418
+#define FLAGS 419
+#define CPI 420
+#define PORT 421
+#define UDP 422
+#define SPORT 423
+#define DPORT 424
+#define UDPLITE 425
+#define CSUMCOV 426
+#define TCP 427
+#define ACKSEQ 428
+#define DOFF 429
+#define WINDOW 430
+#define URGPTR 431
+#define OPTION 432
+#define ECHO 433
+#define EOL 434
+#define MPTCP 435
+#define NOP 436
+#define SACK 437
+#define SACK0 438
+#define SACK1 439
+#define SACK2 440
+#define SACK3 441
+#define SACK_PERM 442
+#define FASTOPEN 443
+#define MD5SIG 444
+#define TIMESTAMP 445
+#define COUNT 446
+#define LEFT 447
+#define RIGHT 448
+#define TSVAL 449
+#define TSECR 450
+#define SUBTYPE 451
+#define DCCP 452
+#define VXLAN 453
+#define VNI 454
+#define GRE 455
+#define GRETAP 456
+#define GENEVE 457
+#define SCTP 458
+#define CHUNK 459
+#define DATA 460
+#define INIT 461
+#define INIT_ACK 462
+#define HEARTBEAT 463
+#define HEARTBEAT_ACK 464
+#define ABORT 465
+#define SHUTDOWN 466
+#define SHUTDOWN_ACK 467
+#define ERROR 468
+#define COOKIE_ECHO 469
+#define COOKIE_ACK 470
+#define ECNE 471
+#define CWR 472
+#define SHUTDOWN_COMPLETE 473
+#define ASCONF_ACK 474
+#define FORWARD_TSN 475
+#define ASCONF 476
+#define TSN 477
+#define STREAM 478
+#define SSN 479
+#define PPID 480
+#define INIT_TAG 481
+#define A_RWND 482
+#define NUM_OSTREAMS 483
+#define NUM_ISTREAMS 484
+#define INIT_TSN 485
+#define CUM_TSN_ACK 486
+#define NUM_GACK_BLOCKS 487
+#define NUM_DUP_TSNS 488
+#define LOWEST_TSN 489
+#define SEQNO 490
+#define NEW_CUM_TSN 491
+#define VTAG 492
+#define RT 493
+#define RT0 494
+#define RT2 495
+#define RT4 496
+#define SEG_LEFT 497
+#define ADDR 498
+#define LAST_ENT 499
+#define TAG 500
+#define SID 501
+#define HBH 502
+#define FRAG 503
+#define RESERVED2 504
+#define MORE_FRAGMENTS 505
+#define DST 506
+#define MH 507
+#define META 508
+#define MARK 509
+#define IIF 510
+#define IIFNAME 511
+#define IIFTYPE 512
+#define OIF 513
+#define OIFNAME 514
+#define OIFTYPE 515
+#define SKUID 516
+#define SKGID 517
+#define NFTRACE 518
+#define RTCLASSID 519
+#define IBRIPORT 520
+#define OBRIPORT 521
+#define IBRIDGENAME 522
+#define OBRIDGENAME 523
+#define PKTTYPE 524
+#define CPU 525
+#define IIFGROUP 526
+#define OIFGROUP 527
+#define CGROUP 528
+#define TIME 529
+#define CLASSID 530
+#define NEXTHOP 531
+#define CT 532
+#define L3PROTOCOL 533
+#define PROTO_SRC 534
+#define PROTO_DST 535
+#define ZONE 536
+#define DIRECTION 537
+#define EVENT 538
+#define EXPECTATION 539
+#define EXPIRATION 540
+#define HELPER 541
+#define LABEL 542
+#define STATE 543
+#define STATUS 544
+#define ORIGINAL 545
+#define REPLY 546
+#define COUNTER 547
+#define NAME 548
+#define PACKETS 549
+#define BYTES 550
+#define AVGPKT 551
+#define LAST 552
+#define NEVER 553
+#define COUNTERS 554
+#define QUOTAS 555
+#define LIMITS 556
+#define SYNPROXYS 557
+#define HELPERS 558
+#define LOG 559
+#define PREFIX 560
+#define GROUP 561
+#define SNAPLEN 562
+#define QUEUE_THRESHOLD 563
+#define LEVEL 564
+#define LIMIT 565
+#define RATE 566
+#define BURST 567
+#define OVER 568
+#define UNTIL 569
+#define QUOTA 570
+#define USED 571
+#define SECMARK 572
+#define SECMARKS 573
+#define SECOND 574
+#define MINUTE 575
+#define HOUR 576
+#define DAY 577
+#define WEEK 578
+#define _REJECT 579
+#define WITH 580
+#define ICMPX 581
+#define SNAT 582
+#define DNAT 583
+#define MASQUERADE 584
+#define REDIRECT 585
+#define RANDOM 586
+#define FULLY_RANDOM 587
+#define PERSISTENT 588
+#define QUEUE 589
+#define QUEUENUM 590
+#define BYPASS 591
+#define FANOUT 592
+#define DUP 593
+#define FWD 594
+#define NUMGEN 595
+#define INC 596
+#define MOD 597
+#define OFFSET 598
+#define JHASH 599
+#define SYMHASH 600
+#define SEED 601
+#define POSITION 602
+#define INDEX 603
+#define COMMENT 604
+#define XML 605
+#define JSON 606
+#define VM 607
+#define NOTRACK 608
+#define EXISTS 609
+#define MISSING 610
+#define EXTHDR 611
+#define IPSEC 612
+#define REQID 613
+#define SPNUM 614
+#define IN 615
+#define OUT 616
+#define XT 617
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+union YYSTYPE
+{
+#line 205 "parser_bison.y"
+
+ uint64_t val;
+ uint32_t val32;
+ uint8_t val8;
+ const char * string;
+
+ struct list_head *list;
+ struct cmd *cmd;
+ struct handle handle;
+ struct table *table;
+ struct chain *chain;
+ struct rule *rule;
+ struct stmt *stmt;
+ struct expr *expr;
+ struct set *set;
+ struct obj *obj;
+ struct flowtable *flowtable;
+ struct ct *ct;
+ const struct datatype *datatype;
+ struct handle_spec handle_spec;
+ struct position_spec position_spec;
+ struct prio_spec prio_spec;
+ struct limit_rate limit_rate;
+ struct tcp_kind_field {
+ uint16_t kind; /* must allow > 255 for SACK1, 2.. hack */
+ uint8_t field;
+ } tcp_kind_field;
+
+#line 1056 "parser_bison.c"
+
+};
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+/* Location type. */
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+int nft_parse (struct nft_ctx *nft, void *scanner, struct parser_state *state);
+
+#endif /* !YY_NFT_PARSER_BISON_H_INCLUDED */
+/* Symbol kind. */
+enum yysymbol_kind_t
+{
+ YYSYMBOL_YYEMPTY = -2,
+ YYSYMBOL_YYEOF = 0, /* "end of file" */
+ YYSYMBOL_YYerror = 1, /* error */
+ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */
+ YYSYMBOL_JUNK = 3, /* "junk" */
+ YYSYMBOL_NEWLINE = 4, /* "newline" */
+ YYSYMBOL_COLON = 5, /* "colon" */
+ YYSYMBOL_SEMICOLON = 6, /* "semicolon" */
+ YYSYMBOL_COMMA = 7, /* "comma" */
+ YYSYMBOL_DOT = 8, /* "." */
+ YYSYMBOL_EQ = 9, /* "==" */
+ YYSYMBOL_NEQ = 10, /* "!=" */
+ YYSYMBOL_LT = 11, /* "<" */
+ YYSYMBOL_GT = 12, /* ">" */
+ YYSYMBOL_GTE = 13, /* ">=" */
+ YYSYMBOL_LTE = 14, /* "<=" */
+ YYSYMBOL_LSHIFT = 15, /* "<<" */
+ YYSYMBOL_RSHIFT = 16, /* ">>" */
+ YYSYMBOL_AMPERSAND = 17, /* "&" */
+ YYSYMBOL_CARET = 18, /* "^" */
+ YYSYMBOL_NOT = 19, /* "!" */
+ YYSYMBOL_SLASH = 20, /* "/" */
+ YYSYMBOL_ASTERISK = 21, /* "*" */
+ YYSYMBOL_DASH = 22, /* "-" */
+ YYSYMBOL_AT = 23, /* "@" */
+ YYSYMBOL_VMAP = 24, /* "vmap" */
+ YYSYMBOL_PLUS = 25, /* "+" */
+ YYSYMBOL_INCLUDE = 26, /* "include" */
+ YYSYMBOL_DEFINE = 27, /* "define" */
+ YYSYMBOL_REDEFINE = 28, /* "redefine" */
+ YYSYMBOL_UNDEFINE = 29, /* "undefine" */
+ YYSYMBOL_FIB = 30, /* "fib" */
+ YYSYMBOL_SOCKET = 31, /* "socket" */
+ YYSYMBOL_TRANSPARENT = 32, /* "transparent" */
+ YYSYMBOL_WILDCARD = 33, /* "wildcard" */
+ YYSYMBOL_CGROUPV2 = 34, /* "cgroupv2" */
+ YYSYMBOL_TPROXY = 35, /* "tproxy" */
+ YYSYMBOL_OSF = 36, /* "osf" */
+ YYSYMBOL_SYNPROXY = 37, /* "synproxy" */
+ YYSYMBOL_MSS = 38, /* "mss" */
+ YYSYMBOL_WSCALE = 39, /* "wscale" */
+ YYSYMBOL_TYPEOF = 40, /* "typeof" */
+ YYSYMBOL_HOOK = 41, /* "hook" */
+ YYSYMBOL_HOOKS = 42, /* "hooks" */
+ YYSYMBOL_DEVICE = 43, /* "device" */
+ YYSYMBOL_DEVICES = 44, /* "devices" */
+ YYSYMBOL_TABLE = 45, /* "table" */
+ YYSYMBOL_TABLES = 46, /* "tables" */
+ YYSYMBOL_CHAIN = 47, /* "chain" */
+ YYSYMBOL_CHAINS = 48, /* "chains" */
+ YYSYMBOL_RULE = 49, /* "rule" */
+ YYSYMBOL_RULES = 50, /* "rules" */
+ YYSYMBOL_SETS = 51, /* "sets" */
+ YYSYMBOL_SET = 52, /* "set" */
+ YYSYMBOL_ELEMENT = 53, /* "element" */
+ YYSYMBOL_MAP = 54, /* "map" */
+ YYSYMBOL_MAPS = 55, /* "maps" */
+ YYSYMBOL_FLOWTABLE = 56, /* "flowtable" */
+ YYSYMBOL_HANDLE = 57, /* "handle" */
+ YYSYMBOL_RULESET = 58, /* "ruleset" */
+ YYSYMBOL_TRACE = 59, /* "trace" */
+ YYSYMBOL_INET = 60, /* "inet" */
+ YYSYMBOL_NETDEV = 61, /* "netdev" */
+ YYSYMBOL_ADD = 62, /* "add" */
+ YYSYMBOL_UPDATE = 63, /* "update" */
+ YYSYMBOL_REPLACE = 64, /* "replace" */
+ YYSYMBOL_CREATE = 65, /* "create" */
+ YYSYMBOL_INSERT = 66, /* "insert" */
+ YYSYMBOL_DELETE = 67, /* "delete" */
+ YYSYMBOL_GET = 68, /* "get" */
+ YYSYMBOL_LIST = 69, /* "list" */
+ YYSYMBOL_RESET = 70, /* "reset" */
+ YYSYMBOL_FLUSH = 71, /* "flush" */
+ YYSYMBOL_RENAME = 72, /* "rename" */
+ YYSYMBOL_DESCRIBE = 73, /* "describe" */
+ YYSYMBOL_IMPORT = 74, /* "import" */
+ YYSYMBOL_EXPORT = 75, /* "export" */
+ YYSYMBOL_DESTROY = 76, /* "destroy" */
+ YYSYMBOL_MONITOR = 77, /* "monitor" */
+ YYSYMBOL_ALL = 78, /* "all" */
+ YYSYMBOL_ACCEPT = 79, /* "accept" */
+ YYSYMBOL_DROP = 80, /* "drop" */
+ YYSYMBOL_CONTINUE = 81, /* "continue" */
+ YYSYMBOL_JUMP = 82, /* "jump" */
+ YYSYMBOL_GOTO = 83, /* "goto" */
+ YYSYMBOL_RETURN = 84, /* "return" */
+ YYSYMBOL_TO = 85, /* "to" */
+ YYSYMBOL_CONSTANT = 86, /* "constant" */
+ YYSYMBOL_INTERVAL = 87, /* "interval" */
+ YYSYMBOL_DYNAMIC = 88, /* "dynamic" */
+ YYSYMBOL_AUTOMERGE = 89, /* "auto-merge" */
+ YYSYMBOL_TIMEOUT = 90, /* "timeout" */
+ YYSYMBOL_GC_INTERVAL = 91, /* "gc-interval" */
+ YYSYMBOL_ELEMENTS = 92, /* "elements" */
+ YYSYMBOL_EXPIRES = 93, /* "expires" */
+ YYSYMBOL_POLICY = 94, /* "policy" */
+ YYSYMBOL_MEMORY = 95, /* "memory" */
+ YYSYMBOL_PERFORMANCE = 96, /* "performance" */
+ YYSYMBOL_SIZE = 97, /* "size" */
+ YYSYMBOL_FLOW = 98, /* "flow" */
+ YYSYMBOL_OFFLOAD = 99, /* "offload" */
+ YYSYMBOL_METER = 100, /* "meter" */
+ YYSYMBOL_METERS = 101, /* "meters" */
+ YYSYMBOL_FLOWTABLES = 102, /* "flowtables" */
+ YYSYMBOL_NUM = 103, /* "number" */
+ YYSYMBOL_STRING = 104, /* "string" */
+ YYSYMBOL_QUOTED_STRING = 105, /* "quoted string" */
+ YYSYMBOL_ASTERISK_STRING = 106, /* "string with a trailing asterisk" */
+ YYSYMBOL_LL_HDR = 107, /* "ll" */
+ YYSYMBOL_NETWORK_HDR = 108, /* "nh" */
+ YYSYMBOL_TRANSPORT_HDR = 109, /* "th" */
+ YYSYMBOL_BRIDGE = 110, /* "bridge" */
+ YYSYMBOL_ETHER = 111, /* "ether" */
+ YYSYMBOL_SADDR = 112, /* "saddr" */
+ YYSYMBOL_DADDR = 113, /* "daddr" */
+ YYSYMBOL_TYPE = 114, /* "type" */
+ YYSYMBOL_VLAN = 115, /* "vlan" */
+ YYSYMBOL_ID = 116, /* "id" */
+ YYSYMBOL_CFI = 117, /* "cfi" */
+ YYSYMBOL_DEI = 118, /* "dei" */
+ YYSYMBOL_PCP = 119, /* "pcp" */
+ YYSYMBOL_ARP = 120, /* "arp" */
+ YYSYMBOL_HTYPE = 121, /* "htype" */
+ YYSYMBOL_PTYPE = 122, /* "ptype" */
+ YYSYMBOL_HLEN = 123, /* "hlen" */
+ YYSYMBOL_PLEN = 124, /* "plen" */
+ YYSYMBOL_OPERATION = 125, /* "operation" */
+ YYSYMBOL_IP = 126, /* "ip" */
+ YYSYMBOL_HDRVERSION = 127, /* "version" */
+ YYSYMBOL_HDRLENGTH = 128, /* "hdrlength" */
+ YYSYMBOL_DSCP = 129, /* "dscp" */
+ YYSYMBOL_ECN = 130, /* "ecn" */
+ YYSYMBOL_LENGTH = 131, /* "length" */
+ YYSYMBOL_FRAG_OFF = 132, /* "frag-off" */
+ YYSYMBOL_TTL = 133, /* "ttl" */
+ YYSYMBOL_PROTOCOL = 134, /* "protocol" */
+ YYSYMBOL_CHECKSUM = 135, /* "checksum" */
+ YYSYMBOL_PTR = 136, /* "ptr" */
+ YYSYMBOL_VALUE = 137, /* "value" */
+ YYSYMBOL_LSRR = 138, /* "lsrr" */
+ YYSYMBOL_RR = 139, /* "rr" */
+ YYSYMBOL_SSRR = 140, /* "ssrr" */
+ YYSYMBOL_RA = 141, /* "ra" */
+ YYSYMBOL_ICMP = 142, /* "icmp" */
+ YYSYMBOL_CODE = 143, /* "code" */
+ YYSYMBOL_SEQUENCE = 144, /* "seq" */
+ YYSYMBOL_GATEWAY = 145, /* "gateway" */
+ YYSYMBOL_MTU = 146, /* "mtu" */
+ YYSYMBOL_IGMP = 147, /* "igmp" */
+ YYSYMBOL_MRT = 148, /* "mrt" */
+ YYSYMBOL_OPTIONS = 149, /* "options" */
+ YYSYMBOL_IP6 = 150, /* "ip6" */
+ YYSYMBOL_PRIORITY = 151, /* "priority" */
+ YYSYMBOL_FLOWLABEL = 152, /* "flowlabel" */
+ YYSYMBOL_NEXTHDR = 153, /* "nexthdr" */
+ YYSYMBOL_HOPLIMIT = 154, /* "hoplimit" */
+ YYSYMBOL_ICMP6 = 155, /* "icmpv6" */
+ YYSYMBOL_PPTR = 156, /* "param-problem" */
+ YYSYMBOL_MAXDELAY = 157, /* "max-delay" */
+ YYSYMBOL_TADDR = 158, /* "taddr" */
+ YYSYMBOL_AH = 159, /* "ah" */
+ YYSYMBOL_RESERVED = 160, /* "reserved" */
+ YYSYMBOL_SPI = 161, /* "spi" */
+ YYSYMBOL_ESP = 162, /* "esp" */
+ YYSYMBOL_COMP = 163, /* "comp" */
+ YYSYMBOL_FLAGS = 164, /* "flags" */
+ YYSYMBOL_CPI = 165, /* "cpi" */
+ YYSYMBOL_PORT = 166, /* "port" */
+ YYSYMBOL_UDP = 167, /* "udp" */
+ YYSYMBOL_SPORT = 168, /* "sport" */
+ YYSYMBOL_DPORT = 169, /* "dport" */
+ YYSYMBOL_UDPLITE = 170, /* "udplite" */
+ YYSYMBOL_CSUMCOV = 171, /* "csumcov" */
+ YYSYMBOL_TCP = 172, /* "tcp" */
+ YYSYMBOL_ACKSEQ = 173, /* "ackseq" */
+ YYSYMBOL_DOFF = 174, /* "doff" */
+ YYSYMBOL_WINDOW = 175, /* "window" */
+ YYSYMBOL_URGPTR = 176, /* "urgptr" */
+ YYSYMBOL_OPTION = 177, /* "option" */
+ YYSYMBOL_ECHO = 178, /* "echo" */
+ YYSYMBOL_EOL = 179, /* "eol" */
+ YYSYMBOL_MPTCP = 180, /* "mptcp" */
+ YYSYMBOL_NOP = 181, /* "nop" */
+ YYSYMBOL_SACK = 182, /* "sack" */
+ YYSYMBOL_SACK0 = 183, /* "sack0" */
+ YYSYMBOL_SACK1 = 184, /* "sack1" */
+ YYSYMBOL_SACK2 = 185, /* "sack2" */
+ YYSYMBOL_SACK3 = 186, /* "sack3" */
+ YYSYMBOL_SACK_PERM = 187, /* "sack-permitted" */
+ YYSYMBOL_FASTOPEN = 188, /* "fastopen" */
+ YYSYMBOL_MD5SIG = 189, /* "md5sig" */
+ YYSYMBOL_TIMESTAMP = 190, /* "timestamp" */
+ YYSYMBOL_COUNT = 191, /* "count" */
+ YYSYMBOL_LEFT = 192, /* "left" */
+ YYSYMBOL_RIGHT = 193, /* "right" */
+ YYSYMBOL_TSVAL = 194, /* "tsval" */
+ YYSYMBOL_TSECR = 195, /* "tsecr" */
+ YYSYMBOL_SUBTYPE = 196, /* "subtype" */
+ YYSYMBOL_DCCP = 197, /* "dccp" */
+ YYSYMBOL_VXLAN = 198, /* "vxlan" */
+ YYSYMBOL_VNI = 199, /* "vni" */
+ YYSYMBOL_GRE = 200, /* "gre" */
+ YYSYMBOL_GRETAP = 201, /* "gretap" */
+ YYSYMBOL_GENEVE = 202, /* "geneve" */
+ YYSYMBOL_SCTP = 203, /* "sctp" */
+ YYSYMBOL_CHUNK = 204, /* "chunk" */
+ YYSYMBOL_DATA = 205, /* "data" */
+ YYSYMBOL_INIT = 206, /* "init" */
+ YYSYMBOL_INIT_ACK = 207, /* "init-ack" */
+ YYSYMBOL_HEARTBEAT = 208, /* "heartbeat" */
+ YYSYMBOL_HEARTBEAT_ACK = 209, /* "heartbeat-ack" */
+ YYSYMBOL_ABORT = 210, /* "abort" */
+ YYSYMBOL_SHUTDOWN = 211, /* "shutdown" */
+ YYSYMBOL_SHUTDOWN_ACK = 212, /* "shutdown-ack" */
+ YYSYMBOL_ERROR = 213, /* "error" */
+ YYSYMBOL_COOKIE_ECHO = 214, /* "cookie-echo" */
+ YYSYMBOL_COOKIE_ACK = 215, /* "cookie-ack" */
+ YYSYMBOL_ECNE = 216, /* "ecne" */
+ YYSYMBOL_CWR = 217, /* "cwr" */
+ YYSYMBOL_SHUTDOWN_COMPLETE = 218, /* "shutdown-complete" */
+ YYSYMBOL_ASCONF_ACK = 219, /* "asconf-ack" */
+ YYSYMBOL_FORWARD_TSN = 220, /* "forward-tsn" */
+ YYSYMBOL_ASCONF = 221, /* "asconf" */
+ YYSYMBOL_TSN = 222, /* "tsn" */
+ YYSYMBOL_STREAM = 223, /* "stream" */
+ YYSYMBOL_SSN = 224, /* "ssn" */
+ YYSYMBOL_PPID = 225, /* "ppid" */
+ YYSYMBOL_INIT_TAG = 226, /* "init-tag" */
+ YYSYMBOL_A_RWND = 227, /* "a-rwnd" */
+ YYSYMBOL_NUM_OSTREAMS = 228, /* "num-outbound-streams" */
+ YYSYMBOL_NUM_ISTREAMS = 229, /* "num-inbound-streams" */
+ YYSYMBOL_INIT_TSN = 230, /* "initial-tsn" */
+ YYSYMBOL_CUM_TSN_ACK = 231, /* "cum-tsn-ack" */
+ YYSYMBOL_NUM_GACK_BLOCKS = 232, /* "num-gap-ack-blocks" */
+ YYSYMBOL_NUM_DUP_TSNS = 233, /* "num-dup-tsns" */
+ YYSYMBOL_LOWEST_TSN = 234, /* "lowest-tsn" */
+ YYSYMBOL_SEQNO = 235, /* "seqno" */
+ YYSYMBOL_NEW_CUM_TSN = 236, /* "new-cum-tsn" */
+ YYSYMBOL_VTAG = 237, /* "vtag" */
+ YYSYMBOL_RT = 238, /* "rt" */
+ YYSYMBOL_RT0 = 239, /* "rt0" */
+ YYSYMBOL_RT2 = 240, /* "rt2" */
+ YYSYMBOL_RT4 = 241, /* "srh" */
+ YYSYMBOL_SEG_LEFT = 242, /* "seg-left" */
+ YYSYMBOL_ADDR = 243, /* "addr" */
+ YYSYMBOL_LAST_ENT = 244, /* "last-entry" */
+ YYSYMBOL_TAG = 245, /* "tag" */
+ YYSYMBOL_SID = 246, /* "sid" */
+ YYSYMBOL_HBH = 247, /* "hbh" */
+ YYSYMBOL_FRAG = 248, /* "frag" */
+ YYSYMBOL_RESERVED2 = 249, /* "reserved2" */
+ YYSYMBOL_MORE_FRAGMENTS = 250, /* "more-fragments" */
+ YYSYMBOL_DST = 251, /* "dst" */
+ YYSYMBOL_MH = 252, /* "mh" */
+ YYSYMBOL_META = 253, /* "meta" */
+ YYSYMBOL_MARK = 254, /* "mark" */
+ YYSYMBOL_IIF = 255, /* "iif" */
+ YYSYMBOL_IIFNAME = 256, /* "iifname" */
+ YYSYMBOL_IIFTYPE = 257, /* "iiftype" */
+ YYSYMBOL_OIF = 258, /* "oif" */
+ YYSYMBOL_OIFNAME = 259, /* "oifname" */
+ YYSYMBOL_OIFTYPE = 260, /* "oiftype" */
+ YYSYMBOL_SKUID = 261, /* "skuid" */
+ YYSYMBOL_SKGID = 262, /* "skgid" */
+ YYSYMBOL_NFTRACE = 263, /* "nftrace" */
+ YYSYMBOL_RTCLASSID = 264, /* "rtclassid" */
+ YYSYMBOL_IBRIPORT = 265, /* "ibriport" */
+ YYSYMBOL_OBRIPORT = 266, /* "obriport" */
+ YYSYMBOL_IBRIDGENAME = 267, /* "ibrname" */
+ YYSYMBOL_OBRIDGENAME = 268, /* "obrname" */
+ YYSYMBOL_PKTTYPE = 269, /* "pkttype" */
+ YYSYMBOL_CPU = 270, /* "cpu" */
+ YYSYMBOL_IIFGROUP = 271, /* "iifgroup" */
+ YYSYMBOL_OIFGROUP = 272, /* "oifgroup" */
+ YYSYMBOL_CGROUP = 273, /* "cgroup" */
+ YYSYMBOL_TIME = 274, /* "time" */
+ YYSYMBOL_CLASSID = 275, /* "classid" */
+ YYSYMBOL_NEXTHOP = 276, /* "nexthop" */
+ YYSYMBOL_CT = 277, /* "ct" */
+ YYSYMBOL_L3PROTOCOL = 278, /* "l3proto" */
+ YYSYMBOL_PROTO_SRC = 279, /* "proto-src" */
+ YYSYMBOL_PROTO_DST = 280, /* "proto-dst" */
+ YYSYMBOL_ZONE = 281, /* "zone" */
+ YYSYMBOL_DIRECTION = 282, /* "direction" */
+ YYSYMBOL_EVENT = 283, /* "event" */
+ YYSYMBOL_EXPECTATION = 284, /* "expectation" */
+ YYSYMBOL_EXPIRATION = 285, /* "expiration" */
+ YYSYMBOL_HELPER = 286, /* "helper" */
+ YYSYMBOL_LABEL = 287, /* "label" */
+ YYSYMBOL_STATE = 288, /* "state" */
+ YYSYMBOL_STATUS = 289, /* "status" */
+ YYSYMBOL_ORIGINAL = 290, /* "original" */
+ YYSYMBOL_REPLY = 291, /* "reply" */
+ YYSYMBOL_COUNTER = 292, /* "counter" */
+ YYSYMBOL_NAME = 293, /* "name" */
+ YYSYMBOL_PACKETS = 294, /* "packets" */
+ YYSYMBOL_BYTES = 295, /* "bytes" */
+ YYSYMBOL_AVGPKT = 296, /* "avgpkt" */
+ YYSYMBOL_LAST = 297, /* "last" */
+ YYSYMBOL_NEVER = 298, /* "never" */
+ YYSYMBOL_COUNTERS = 299, /* "counters" */
+ YYSYMBOL_QUOTAS = 300, /* "quotas" */
+ YYSYMBOL_LIMITS = 301, /* "limits" */
+ YYSYMBOL_SYNPROXYS = 302, /* "synproxys" */
+ YYSYMBOL_HELPERS = 303, /* "helpers" */
+ YYSYMBOL_LOG = 304, /* "log" */
+ YYSYMBOL_PREFIX = 305, /* "prefix" */
+ YYSYMBOL_GROUP = 306, /* "group" */
+ YYSYMBOL_SNAPLEN = 307, /* "snaplen" */
+ YYSYMBOL_QUEUE_THRESHOLD = 308, /* "queue-threshold" */
+ YYSYMBOL_LEVEL = 309, /* "level" */
+ YYSYMBOL_LIMIT = 310, /* "limit" */
+ YYSYMBOL_RATE = 311, /* "rate" */
+ YYSYMBOL_BURST = 312, /* "burst" */
+ YYSYMBOL_OVER = 313, /* "over" */
+ YYSYMBOL_UNTIL = 314, /* "until" */
+ YYSYMBOL_QUOTA = 315, /* "quota" */
+ YYSYMBOL_USED = 316, /* "used" */
+ YYSYMBOL_SECMARK = 317, /* "secmark" */
+ YYSYMBOL_SECMARKS = 318, /* "secmarks" */
+ YYSYMBOL_SECOND = 319, /* "second" */
+ YYSYMBOL_MINUTE = 320, /* "minute" */
+ YYSYMBOL_HOUR = 321, /* "hour" */
+ YYSYMBOL_DAY = 322, /* "day" */
+ YYSYMBOL_WEEK = 323, /* "week" */
+ YYSYMBOL__REJECT = 324, /* "reject" */
+ YYSYMBOL_WITH = 325, /* "with" */
+ YYSYMBOL_ICMPX = 326, /* "icmpx" */
+ YYSYMBOL_SNAT = 327, /* "snat" */
+ YYSYMBOL_DNAT = 328, /* "dnat" */
+ YYSYMBOL_MASQUERADE = 329, /* "masquerade" */
+ YYSYMBOL_REDIRECT = 330, /* "redirect" */
+ YYSYMBOL_RANDOM = 331, /* "random" */
+ YYSYMBOL_FULLY_RANDOM = 332, /* "fully-random" */
+ YYSYMBOL_PERSISTENT = 333, /* "persistent" */
+ YYSYMBOL_QUEUE = 334, /* "queue" */
+ YYSYMBOL_QUEUENUM = 335, /* "num" */
+ YYSYMBOL_BYPASS = 336, /* "bypass" */
+ YYSYMBOL_FANOUT = 337, /* "fanout" */
+ YYSYMBOL_DUP = 338, /* "dup" */
+ YYSYMBOL_FWD = 339, /* "fwd" */
+ YYSYMBOL_NUMGEN = 340, /* "numgen" */
+ YYSYMBOL_INC = 341, /* "inc" */
+ YYSYMBOL_MOD = 342, /* "mod" */
+ YYSYMBOL_OFFSET = 343, /* "offset" */
+ YYSYMBOL_JHASH = 344, /* "jhash" */
+ YYSYMBOL_SYMHASH = 345, /* "symhash" */
+ YYSYMBOL_SEED = 346, /* "seed" */
+ YYSYMBOL_POSITION = 347, /* "position" */
+ YYSYMBOL_INDEX = 348, /* "index" */
+ YYSYMBOL_COMMENT = 349, /* "comment" */
+ YYSYMBOL_XML = 350, /* "xml" */
+ YYSYMBOL_JSON = 351, /* "json" */
+ YYSYMBOL_VM = 352, /* "vm" */
+ YYSYMBOL_NOTRACK = 353, /* "notrack" */
+ YYSYMBOL_EXISTS = 354, /* "exists" */
+ YYSYMBOL_MISSING = 355, /* "missing" */
+ YYSYMBOL_EXTHDR = 356, /* "exthdr" */
+ YYSYMBOL_IPSEC = 357, /* "ipsec" */
+ YYSYMBOL_REQID = 358, /* "reqid" */
+ YYSYMBOL_SPNUM = 359, /* "spnum" */
+ YYSYMBOL_IN = 360, /* "in" */
+ YYSYMBOL_OUT = 361, /* "out" */
+ YYSYMBOL_XT = 362, /* "xt" */
+ YYSYMBOL_363_ = 363, /* '=' */
+ YYSYMBOL_364_ = 364, /* '{' */
+ YYSYMBOL_365_ = 365, /* '}' */
+ YYSYMBOL_366_ = 366, /* '(' */
+ YYSYMBOL_367_ = 367, /* ')' */
+ YYSYMBOL_368_ = 368, /* '|' */
+ YYSYMBOL_369_ = 369, /* '$' */
+ YYSYMBOL_370_ = 370, /* '[' */
+ YYSYMBOL_371_ = 371, /* ']' */
+ YYSYMBOL_YYACCEPT = 372, /* $accept */
+ YYSYMBOL_input = 373, /* input */
+ YYSYMBOL_stmt_separator = 374, /* stmt_separator */
+ YYSYMBOL_opt_newline = 375, /* opt_newline */
+ YYSYMBOL_close_scope_ah = 376, /* close_scope_ah */
+ YYSYMBOL_close_scope_arp = 377, /* close_scope_arp */
+ YYSYMBOL_close_scope_at = 378, /* close_scope_at */
+ YYSYMBOL_close_scope_comp = 379, /* close_scope_comp */
+ YYSYMBOL_close_scope_ct = 380, /* close_scope_ct */
+ YYSYMBOL_close_scope_counter = 381, /* close_scope_counter */
+ YYSYMBOL_close_scope_last = 382, /* close_scope_last */
+ YYSYMBOL_close_scope_dccp = 383, /* close_scope_dccp */
+ YYSYMBOL_close_scope_destroy = 384, /* close_scope_destroy */
+ YYSYMBOL_close_scope_dst = 385, /* close_scope_dst */
+ YYSYMBOL_close_scope_dup = 386, /* close_scope_dup */
+ YYSYMBOL_close_scope_esp = 387, /* close_scope_esp */
+ YYSYMBOL_close_scope_eth = 388, /* close_scope_eth */
+ YYSYMBOL_close_scope_export = 389, /* close_scope_export */
+ YYSYMBOL_close_scope_fib = 390, /* close_scope_fib */
+ YYSYMBOL_close_scope_frag = 391, /* close_scope_frag */
+ YYSYMBOL_close_scope_fwd = 392, /* close_scope_fwd */
+ YYSYMBOL_close_scope_gre = 393, /* close_scope_gre */
+ YYSYMBOL_close_scope_hash = 394, /* close_scope_hash */
+ YYSYMBOL_close_scope_hbh = 395, /* close_scope_hbh */
+ YYSYMBOL_close_scope_ip = 396, /* close_scope_ip */
+ YYSYMBOL_close_scope_ip6 = 397, /* close_scope_ip6 */
+ YYSYMBOL_close_scope_vlan = 398, /* close_scope_vlan */
+ YYSYMBOL_close_scope_icmp = 399, /* close_scope_icmp */
+ YYSYMBOL_close_scope_igmp = 400, /* close_scope_igmp */
+ YYSYMBOL_close_scope_import = 401, /* close_scope_import */
+ YYSYMBOL_close_scope_ipsec = 402, /* close_scope_ipsec */
+ YYSYMBOL_close_scope_list = 403, /* close_scope_list */
+ YYSYMBOL_close_scope_limit = 404, /* close_scope_limit */
+ YYSYMBOL_close_scope_meta = 405, /* close_scope_meta */
+ YYSYMBOL_close_scope_mh = 406, /* close_scope_mh */
+ YYSYMBOL_close_scope_monitor = 407, /* close_scope_monitor */
+ YYSYMBOL_close_scope_nat = 408, /* close_scope_nat */
+ YYSYMBOL_close_scope_numgen = 409, /* close_scope_numgen */
+ YYSYMBOL_close_scope_osf = 410, /* close_scope_osf */
+ YYSYMBOL_close_scope_policy = 411, /* close_scope_policy */
+ YYSYMBOL_close_scope_quota = 412, /* close_scope_quota */
+ YYSYMBOL_close_scope_queue = 413, /* close_scope_queue */
+ YYSYMBOL_close_scope_reject = 414, /* close_scope_reject */
+ YYSYMBOL_close_scope_reset = 415, /* close_scope_reset */
+ YYSYMBOL_close_scope_rt = 416, /* close_scope_rt */
+ YYSYMBOL_close_scope_sctp = 417, /* close_scope_sctp */
+ YYSYMBOL_close_scope_sctp_chunk = 418, /* close_scope_sctp_chunk */
+ YYSYMBOL_close_scope_secmark = 419, /* close_scope_secmark */
+ YYSYMBOL_close_scope_socket = 420, /* close_scope_socket */
+ YYSYMBOL_close_scope_tcp = 421, /* close_scope_tcp */
+ YYSYMBOL_close_scope_tproxy = 422, /* close_scope_tproxy */
+ YYSYMBOL_close_scope_type = 423, /* close_scope_type */
+ YYSYMBOL_close_scope_th = 424, /* close_scope_th */
+ YYSYMBOL_close_scope_udp = 425, /* close_scope_udp */
+ YYSYMBOL_close_scope_udplite = 426, /* close_scope_udplite */
+ YYSYMBOL_close_scope_log = 427, /* close_scope_log */
+ YYSYMBOL_close_scope_synproxy = 428, /* close_scope_synproxy */
+ YYSYMBOL_close_scope_xt = 429, /* close_scope_xt */
+ YYSYMBOL_common_block = 430, /* common_block */
+ YYSYMBOL_line = 431, /* line */
+ YYSYMBOL_base_cmd = 432, /* base_cmd */
+ YYSYMBOL_add_cmd = 433, /* add_cmd */
+ YYSYMBOL_replace_cmd = 434, /* replace_cmd */
+ YYSYMBOL_create_cmd = 435, /* create_cmd */
+ YYSYMBOL_insert_cmd = 436, /* insert_cmd */
+ YYSYMBOL_table_or_id_spec = 437, /* table_or_id_spec */
+ YYSYMBOL_chain_or_id_spec = 438, /* chain_or_id_spec */
+ YYSYMBOL_set_or_id_spec = 439, /* set_or_id_spec */
+ YYSYMBOL_obj_or_id_spec = 440, /* obj_or_id_spec */
+ YYSYMBOL_delete_cmd = 441, /* delete_cmd */
+ YYSYMBOL_destroy_cmd = 442, /* destroy_cmd */
+ YYSYMBOL_get_cmd = 443, /* get_cmd */
+ YYSYMBOL_list_cmd = 444, /* list_cmd */
+ YYSYMBOL_basehook_device_name = 445, /* basehook_device_name */
+ YYSYMBOL_basehook_spec = 446, /* basehook_spec */
+ YYSYMBOL_reset_cmd = 447, /* reset_cmd */
+ YYSYMBOL_flush_cmd = 448, /* flush_cmd */
+ YYSYMBOL_rename_cmd = 449, /* rename_cmd */
+ YYSYMBOL_import_cmd = 450, /* import_cmd */
+ YYSYMBOL_export_cmd = 451, /* export_cmd */
+ YYSYMBOL_monitor_cmd = 452, /* monitor_cmd */
+ YYSYMBOL_monitor_event = 453, /* monitor_event */
+ YYSYMBOL_monitor_object = 454, /* monitor_object */
+ YYSYMBOL_monitor_format = 455, /* monitor_format */
+ YYSYMBOL_markup_format = 456, /* markup_format */
+ YYSYMBOL_describe_cmd = 457, /* describe_cmd */
+ YYSYMBOL_table_block_alloc = 458, /* table_block_alloc */
+ YYSYMBOL_table_options = 459, /* table_options */
+ YYSYMBOL_table_block = 460, /* table_block */
+ YYSYMBOL_chain_block_alloc = 461, /* chain_block_alloc */
+ YYSYMBOL_chain_block = 462, /* chain_block */
+ YYSYMBOL_subchain_block = 463, /* subchain_block */
+ YYSYMBOL_typeof_data_expr = 464, /* typeof_data_expr */
+ YYSYMBOL_typeof_expr = 465, /* typeof_expr */
+ YYSYMBOL_set_block_alloc = 466, /* set_block_alloc */
+ YYSYMBOL_set_block = 467, /* set_block */
+ YYSYMBOL_set_block_expr = 468, /* set_block_expr */
+ YYSYMBOL_set_flag_list = 469, /* set_flag_list */
+ YYSYMBOL_set_flag = 470, /* set_flag */
+ YYSYMBOL_map_block_alloc = 471, /* map_block_alloc */
+ YYSYMBOL_map_block_obj_type = 472, /* map_block_obj_type */
+ YYSYMBOL_map_block_data_interval = 473, /* map_block_data_interval */
+ YYSYMBOL_map_block = 474, /* map_block */
+ YYSYMBOL_set_mechanism = 475, /* set_mechanism */
+ YYSYMBOL_set_policy_spec = 476, /* set_policy_spec */
+ YYSYMBOL_flowtable_block_alloc = 477, /* flowtable_block_alloc */
+ YYSYMBOL_flowtable_block = 478, /* flowtable_block */
+ YYSYMBOL_flowtable_expr = 479, /* flowtable_expr */
+ YYSYMBOL_flowtable_list_expr = 480, /* flowtable_list_expr */
+ YYSYMBOL_flowtable_expr_member = 481, /* flowtable_expr_member */
+ YYSYMBOL_data_type_atom_expr = 482, /* data_type_atom_expr */
+ YYSYMBOL_data_type_expr = 483, /* data_type_expr */
+ YYSYMBOL_obj_block_alloc = 484, /* obj_block_alloc */
+ YYSYMBOL_counter_block = 485, /* counter_block */
+ YYSYMBOL_quota_block = 486, /* quota_block */
+ YYSYMBOL_ct_helper_block = 487, /* ct_helper_block */
+ YYSYMBOL_ct_timeout_block = 488, /* ct_timeout_block */
+ YYSYMBOL_ct_expect_block = 489, /* ct_expect_block */
+ YYSYMBOL_limit_block = 490, /* limit_block */
+ YYSYMBOL_secmark_block = 491, /* secmark_block */
+ YYSYMBOL_synproxy_block = 492, /* synproxy_block */
+ YYSYMBOL_type_identifier = 493, /* type_identifier */
+ YYSYMBOL_hook_spec = 494, /* hook_spec */
+ YYSYMBOL_prio_spec = 495, /* prio_spec */
+ YYSYMBOL_extended_prio_name = 496, /* extended_prio_name */
+ YYSYMBOL_extended_prio_spec = 497, /* extended_prio_spec */
+ YYSYMBOL_int_num = 498, /* int_num */
+ YYSYMBOL_dev_spec = 499, /* dev_spec */
+ YYSYMBOL_flags_spec = 500, /* flags_spec */
+ YYSYMBOL_policy_spec = 501, /* policy_spec */
+ YYSYMBOL_policy_expr = 502, /* policy_expr */
+ YYSYMBOL_chain_policy = 503, /* chain_policy */
+ YYSYMBOL_identifier = 504, /* identifier */
+ YYSYMBOL_string = 505, /* string */
+ YYSYMBOL_time_spec = 506, /* time_spec */
+ YYSYMBOL_time_spec_or_num_s = 507, /* time_spec_or_num_s */
+ YYSYMBOL_family_spec = 508, /* family_spec */
+ YYSYMBOL_family_spec_explicit = 509, /* family_spec_explicit */
+ YYSYMBOL_table_spec = 510, /* table_spec */
+ YYSYMBOL_tableid_spec = 511, /* tableid_spec */
+ YYSYMBOL_chain_spec = 512, /* chain_spec */
+ YYSYMBOL_chainid_spec = 513, /* chainid_spec */
+ YYSYMBOL_chain_identifier = 514, /* chain_identifier */
+ YYSYMBOL_set_spec = 515, /* set_spec */
+ YYSYMBOL_setid_spec = 516, /* setid_spec */
+ YYSYMBOL_set_identifier = 517, /* set_identifier */
+ YYSYMBOL_flowtable_spec = 518, /* flowtable_spec */
+ YYSYMBOL_flowtableid_spec = 519, /* flowtableid_spec */
+ YYSYMBOL_flowtable_identifier = 520, /* flowtable_identifier */
+ YYSYMBOL_obj_spec = 521, /* obj_spec */
+ YYSYMBOL_objid_spec = 522, /* objid_spec */
+ YYSYMBOL_obj_identifier = 523, /* obj_identifier */
+ YYSYMBOL_handle_spec = 524, /* handle_spec */
+ YYSYMBOL_position_spec = 525, /* position_spec */
+ YYSYMBOL_index_spec = 526, /* index_spec */
+ YYSYMBOL_rule_position = 527, /* rule_position */
+ YYSYMBOL_ruleid_spec = 528, /* ruleid_spec */
+ YYSYMBOL_comment_spec = 529, /* comment_spec */
+ YYSYMBOL_ruleset_spec = 530, /* ruleset_spec */
+ YYSYMBOL_rule = 531, /* rule */
+ YYSYMBOL_rule_alloc = 532, /* rule_alloc */
+ YYSYMBOL_stmt_list = 533, /* stmt_list */
+ YYSYMBOL_stateful_stmt_list = 534, /* stateful_stmt_list */
+ YYSYMBOL_stateful_stmt = 535, /* stateful_stmt */
+ YYSYMBOL_stmt = 536, /* stmt */
+ YYSYMBOL_xt_stmt = 537, /* xt_stmt */
+ YYSYMBOL_chain_stmt_type = 538, /* chain_stmt_type */
+ YYSYMBOL_chain_stmt = 539, /* chain_stmt */
+ YYSYMBOL_verdict_stmt = 540, /* verdict_stmt */
+ YYSYMBOL_verdict_map_stmt = 541, /* verdict_map_stmt */
+ YYSYMBOL_verdict_map_expr = 542, /* verdict_map_expr */
+ YYSYMBOL_verdict_map_list_expr = 543, /* verdict_map_list_expr */
+ YYSYMBOL_verdict_map_list_member_expr = 544, /* verdict_map_list_member_expr */
+ YYSYMBOL_connlimit_stmt = 545, /* connlimit_stmt */
+ YYSYMBOL_counter_stmt = 546, /* counter_stmt */
+ YYSYMBOL_counter_stmt_alloc = 547, /* counter_stmt_alloc */
+ YYSYMBOL_counter_args = 548, /* counter_args */
+ YYSYMBOL_counter_arg = 549, /* counter_arg */
+ YYSYMBOL_last_stmt = 550, /* last_stmt */
+ YYSYMBOL_log_stmt = 551, /* log_stmt */
+ YYSYMBOL_log_stmt_alloc = 552, /* log_stmt_alloc */
+ YYSYMBOL_log_args = 553, /* log_args */
+ YYSYMBOL_log_arg = 554, /* log_arg */
+ YYSYMBOL_level_type = 555, /* level_type */
+ YYSYMBOL_log_flags = 556, /* log_flags */
+ YYSYMBOL_log_flags_tcp = 557, /* log_flags_tcp */
+ YYSYMBOL_log_flag_tcp = 558, /* log_flag_tcp */
+ YYSYMBOL_limit_stmt = 559, /* limit_stmt */
+ YYSYMBOL_quota_mode = 560, /* quota_mode */
+ YYSYMBOL_quota_unit = 561, /* quota_unit */
+ YYSYMBOL_quota_used = 562, /* quota_used */
+ YYSYMBOL_quota_stmt = 563, /* quota_stmt */
+ YYSYMBOL_limit_mode = 564, /* limit_mode */
+ YYSYMBOL_limit_burst_pkts = 565, /* limit_burst_pkts */
+ YYSYMBOL_limit_rate_pkts = 566, /* limit_rate_pkts */
+ YYSYMBOL_limit_burst_bytes = 567, /* limit_burst_bytes */
+ YYSYMBOL_limit_rate_bytes = 568, /* limit_rate_bytes */
+ YYSYMBOL_limit_bytes = 569, /* limit_bytes */
+ YYSYMBOL_time_unit = 570, /* time_unit */
+ YYSYMBOL_reject_stmt = 571, /* reject_stmt */
+ YYSYMBOL_reject_stmt_alloc = 572, /* reject_stmt_alloc */
+ YYSYMBOL_reject_with_expr = 573, /* reject_with_expr */
+ YYSYMBOL_reject_opts = 574, /* reject_opts */
+ YYSYMBOL_nat_stmt = 575, /* nat_stmt */
+ YYSYMBOL_nat_stmt_alloc = 576, /* nat_stmt_alloc */
+ YYSYMBOL_tproxy_stmt = 577, /* tproxy_stmt */
+ YYSYMBOL_synproxy_stmt = 578, /* synproxy_stmt */
+ YYSYMBOL_synproxy_stmt_alloc = 579, /* synproxy_stmt_alloc */
+ YYSYMBOL_synproxy_args = 580, /* synproxy_args */
+ YYSYMBOL_synproxy_arg = 581, /* synproxy_arg */
+ YYSYMBOL_synproxy_config = 582, /* synproxy_config */
+ YYSYMBOL_synproxy_obj = 583, /* synproxy_obj */
+ YYSYMBOL_synproxy_ts = 584, /* synproxy_ts */
+ YYSYMBOL_synproxy_sack = 585, /* synproxy_sack */
+ YYSYMBOL_primary_stmt_expr = 586, /* primary_stmt_expr */
+ YYSYMBOL_shift_stmt_expr = 587, /* shift_stmt_expr */
+ YYSYMBOL_and_stmt_expr = 588, /* and_stmt_expr */
+ YYSYMBOL_exclusive_or_stmt_expr = 589, /* exclusive_or_stmt_expr */
+ YYSYMBOL_inclusive_or_stmt_expr = 590, /* inclusive_or_stmt_expr */
+ YYSYMBOL_basic_stmt_expr = 591, /* basic_stmt_expr */
+ YYSYMBOL_concat_stmt_expr = 592, /* concat_stmt_expr */
+ YYSYMBOL_map_stmt_expr_set = 593, /* map_stmt_expr_set */
+ YYSYMBOL_map_stmt_expr = 594, /* map_stmt_expr */
+ YYSYMBOL_prefix_stmt_expr = 595, /* prefix_stmt_expr */
+ YYSYMBOL_range_stmt_expr = 596, /* range_stmt_expr */
+ YYSYMBOL_multiton_stmt_expr = 597, /* multiton_stmt_expr */
+ YYSYMBOL_stmt_expr = 598, /* stmt_expr */
+ YYSYMBOL_nat_stmt_args = 599, /* nat_stmt_args */
+ YYSYMBOL_masq_stmt = 600, /* masq_stmt */
+ YYSYMBOL_masq_stmt_alloc = 601, /* masq_stmt_alloc */
+ YYSYMBOL_masq_stmt_args = 602, /* masq_stmt_args */
+ YYSYMBOL_redir_stmt = 603, /* redir_stmt */
+ YYSYMBOL_redir_stmt_alloc = 604, /* redir_stmt_alloc */
+ YYSYMBOL_redir_stmt_arg = 605, /* redir_stmt_arg */
+ YYSYMBOL_dup_stmt = 606, /* dup_stmt */
+ YYSYMBOL_fwd_stmt = 607, /* fwd_stmt */
+ YYSYMBOL_nf_nat_flags = 608, /* nf_nat_flags */
+ YYSYMBOL_nf_nat_flag = 609, /* nf_nat_flag */
+ YYSYMBOL_queue_stmt = 610, /* queue_stmt */
+ YYSYMBOL_queue_stmt_compat = 611, /* queue_stmt_compat */
+ YYSYMBOL_queue_stmt_alloc = 612, /* queue_stmt_alloc */
+ YYSYMBOL_queue_stmt_args = 613, /* queue_stmt_args */
+ YYSYMBOL_queue_stmt_arg = 614, /* queue_stmt_arg */
+ YYSYMBOL_queue_expr = 615, /* queue_expr */
+ YYSYMBOL_queue_stmt_expr_simple = 616, /* queue_stmt_expr_simple */
+ YYSYMBOL_queue_stmt_expr = 617, /* queue_stmt_expr */
+ YYSYMBOL_queue_stmt_flags = 618, /* queue_stmt_flags */
+ YYSYMBOL_queue_stmt_flag = 619, /* queue_stmt_flag */
+ YYSYMBOL_set_elem_expr_stmt = 620, /* set_elem_expr_stmt */
+ YYSYMBOL_set_elem_expr_stmt_alloc = 621, /* set_elem_expr_stmt_alloc */
+ YYSYMBOL_set_stmt = 622, /* set_stmt */
+ YYSYMBOL_set_stmt_op = 623, /* set_stmt_op */
+ YYSYMBOL_map_stmt = 624, /* map_stmt */
+ YYSYMBOL_meter_stmt = 625, /* meter_stmt */
+ YYSYMBOL_flow_stmt_legacy_alloc = 626, /* flow_stmt_legacy_alloc */
+ YYSYMBOL_flow_stmt_opts = 627, /* flow_stmt_opts */
+ YYSYMBOL_flow_stmt_opt = 628, /* flow_stmt_opt */
+ YYSYMBOL_meter_stmt_alloc = 629, /* meter_stmt_alloc */
+ YYSYMBOL_match_stmt = 630, /* match_stmt */
+ YYSYMBOL_variable_expr = 631, /* variable_expr */
+ YYSYMBOL_symbol_expr = 632, /* symbol_expr */
+ YYSYMBOL_set_ref_expr = 633, /* set_ref_expr */
+ YYSYMBOL_set_ref_symbol_expr = 634, /* set_ref_symbol_expr */
+ YYSYMBOL_integer_expr = 635, /* integer_expr */
+ YYSYMBOL_primary_expr = 636, /* primary_expr */
+ YYSYMBOL_fib_expr = 637, /* fib_expr */
+ YYSYMBOL_fib_result = 638, /* fib_result */
+ YYSYMBOL_fib_flag = 639, /* fib_flag */
+ YYSYMBOL_fib_tuple = 640, /* fib_tuple */
+ YYSYMBOL_osf_expr = 641, /* osf_expr */
+ YYSYMBOL_osf_ttl = 642, /* osf_ttl */
+ YYSYMBOL_shift_expr = 643, /* shift_expr */
+ YYSYMBOL_and_expr = 644, /* and_expr */
+ YYSYMBOL_exclusive_or_expr = 645, /* exclusive_or_expr */
+ YYSYMBOL_inclusive_or_expr = 646, /* inclusive_or_expr */
+ YYSYMBOL_basic_expr = 647, /* basic_expr */
+ YYSYMBOL_concat_expr = 648, /* concat_expr */
+ YYSYMBOL_prefix_rhs_expr = 649, /* prefix_rhs_expr */
+ YYSYMBOL_range_rhs_expr = 650, /* range_rhs_expr */
+ YYSYMBOL_multiton_rhs_expr = 651, /* multiton_rhs_expr */
+ YYSYMBOL_map_expr = 652, /* map_expr */
+ YYSYMBOL_expr = 653, /* expr */
+ YYSYMBOL_set_expr = 654, /* set_expr */
+ YYSYMBOL_set_list_expr = 655, /* set_list_expr */
+ YYSYMBOL_set_list_member_expr = 656, /* set_list_member_expr */
+ YYSYMBOL_meter_key_expr = 657, /* meter_key_expr */
+ YYSYMBOL_meter_key_expr_alloc = 658, /* meter_key_expr_alloc */
+ YYSYMBOL_set_elem_expr = 659, /* set_elem_expr */
+ YYSYMBOL_set_elem_key_expr = 660, /* set_elem_key_expr */
+ YYSYMBOL_set_elem_expr_alloc = 661, /* set_elem_expr_alloc */
+ YYSYMBOL_set_elem_options = 662, /* set_elem_options */
+ YYSYMBOL_set_elem_option = 663, /* set_elem_option */
+ YYSYMBOL_set_elem_expr_options = 664, /* set_elem_expr_options */
+ YYSYMBOL_set_elem_stmt_list = 665, /* set_elem_stmt_list */
+ YYSYMBOL_set_elem_stmt = 666, /* set_elem_stmt */
+ YYSYMBOL_set_elem_expr_option = 667, /* set_elem_expr_option */
+ YYSYMBOL_set_lhs_expr = 668, /* set_lhs_expr */
+ YYSYMBOL_set_rhs_expr = 669, /* set_rhs_expr */
+ YYSYMBOL_initializer_expr = 670, /* initializer_expr */
+ YYSYMBOL_counter_config = 671, /* counter_config */
+ YYSYMBOL_counter_obj = 672, /* counter_obj */
+ YYSYMBOL_quota_config = 673, /* quota_config */
+ YYSYMBOL_quota_obj = 674, /* quota_obj */
+ YYSYMBOL_secmark_config = 675, /* secmark_config */
+ YYSYMBOL_secmark_obj = 676, /* secmark_obj */
+ YYSYMBOL_ct_obj_type = 677, /* ct_obj_type */
+ YYSYMBOL_ct_cmd_type = 678, /* ct_cmd_type */
+ YYSYMBOL_ct_l4protoname = 679, /* ct_l4protoname */
+ YYSYMBOL_ct_helper_config = 680, /* ct_helper_config */
+ YYSYMBOL_timeout_states = 681, /* timeout_states */
+ YYSYMBOL_timeout_state = 682, /* timeout_state */
+ YYSYMBOL_ct_timeout_config = 683, /* ct_timeout_config */
+ YYSYMBOL_ct_expect_config = 684, /* ct_expect_config */
+ YYSYMBOL_ct_obj_alloc = 685, /* ct_obj_alloc */
+ YYSYMBOL_limit_config = 686, /* limit_config */
+ YYSYMBOL_limit_obj = 687, /* limit_obj */
+ YYSYMBOL_relational_expr = 688, /* relational_expr */
+ YYSYMBOL_list_rhs_expr = 689, /* list_rhs_expr */
+ YYSYMBOL_rhs_expr = 690, /* rhs_expr */
+ YYSYMBOL_shift_rhs_expr = 691, /* shift_rhs_expr */
+ YYSYMBOL_and_rhs_expr = 692, /* and_rhs_expr */
+ YYSYMBOL_exclusive_or_rhs_expr = 693, /* exclusive_or_rhs_expr */
+ YYSYMBOL_inclusive_or_rhs_expr = 694, /* inclusive_or_rhs_expr */
+ YYSYMBOL_basic_rhs_expr = 695, /* basic_rhs_expr */
+ YYSYMBOL_concat_rhs_expr = 696, /* concat_rhs_expr */
+ YYSYMBOL_boolean_keys = 697, /* boolean_keys */
+ YYSYMBOL_boolean_expr = 698, /* boolean_expr */
+ YYSYMBOL_keyword_expr = 699, /* keyword_expr */
+ YYSYMBOL_primary_rhs_expr = 700, /* primary_rhs_expr */
+ YYSYMBOL_relational_op = 701, /* relational_op */
+ YYSYMBOL_verdict_expr = 702, /* verdict_expr */
+ YYSYMBOL_chain_expr = 703, /* chain_expr */
+ YYSYMBOL_meta_expr = 704, /* meta_expr */
+ YYSYMBOL_meta_key = 705, /* meta_key */
+ YYSYMBOL_meta_key_qualified = 706, /* meta_key_qualified */
+ YYSYMBOL_meta_key_unqualified = 707, /* meta_key_unqualified */
+ YYSYMBOL_meta_stmt = 708, /* meta_stmt */
+ YYSYMBOL_socket_expr = 709, /* socket_expr */
+ YYSYMBOL_socket_key = 710, /* socket_key */
+ YYSYMBOL_offset_opt = 711, /* offset_opt */
+ YYSYMBOL_numgen_type = 712, /* numgen_type */
+ YYSYMBOL_numgen_expr = 713, /* numgen_expr */
+ YYSYMBOL_xfrm_spnum = 714, /* xfrm_spnum */
+ YYSYMBOL_xfrm_dir = 715, /* xfrm_dir */
+ YYSYMBOL_xfrm_state_key = 716, /* xfrm_state_key */
+ YYSYMBOL_xfrm_state_proto_key = 717, /* xfrm_state_proto_key */
+ YYSYMBOL_xfrm_expr = 718, /* xfrm_expr */
+ YYSYMBOL_hash_expr = 719, /* hash_expr */
+ YYSYMBOL_nf_key_proto = 720, /* nf_key_proto */
+ YYSYMBOL_rt_expr = 721, /* rt_expr */
+ YYSYMBOL_rt_key = 722, /* rt_key */
+ YYSYMBOL_ct_expr = 723, /* ct_expr */
+ YYSYMBOL_ct_dir = 724, /* ct_dir */
+ YYSYMBOL_ct_key = 725, /* ct_key */
+ YYSYMBOL_ct_key_dir = 726, /* ct_key_dir */
+ YYSYMBOL_ct_key_proto_field = 727, /* ct_key_proto_field */
+ YYSYMBOL_ct_key_dir_optional = 728, /* ct_key_dir_optional */
+ YYSYMBOL_symbol_stmt_expr = 729, /* symbol_stmt_expr */
+ YYSYMBOL_list_stmt_expr = 730, /* list_stmt_expr */
+ YYSYMBOL_ct_stmt = 731, /* ct_stmt */
+ YYSYMBOL_payload_stmt = 732, /* payload_stmt */
+ YYSYMBOL_payload_expr = 733, /* payload_expr */
+ YYSYMBOL_payload_raw_expr = 734, /* payload_raw_expr */
+ YYSYMBOL_payload_base_spec = 735, /* payload_base_spec */
+ YYSYMBOL_eth_hdr_expr = 736, /* eth_hdr_expr */
+ YYSYMBOL_eth_hdr_field = 737, /* eth_hdr_field */
+ YYSYMBOL_vlan_hdr_expr = 738, /* vlan_hdr_expr */
+ YYSYMBOL_vlan_hdr_field = 739, /* vlan_hdr_field */
+ YYSYMBOL_arp_hdr_expr = 740, /* arp_hdr_expr */
+ YYSYMBOL_arp_hdr_field = 741, /* arp_hdr_field */
+ YYSYMBOL_ip_hdr_expr = 742, /* ip_hdr_expr */
+ YYSYMBOL_ip_hdr_field = 743, /* ip_hdr_field */
+ YYSYMBOL_ip_option_type = 744, /* ip_option_type */
+ YYSYMBOL_ip_option_field = 745, /* ip_option_field */
+ YYSYMBOL_icmp_hdr_expr = 746, /* icmp_hdr_expr */
+ YYSYMBOL_icmp_hdr_field = 747, /* icmp_hdr_field */
+ YYSYMBOL_igmp_hdr_expr = 748, /* igmp_hdr_expr */
+ YYSYMBOL_igmp_hdr_field = 749, /* igmp_hdr_field */
+ YYSYMBOL_ip6_hdr_expr = 750, /* ip6_hdr_expr */
+ YYSYMBOL_ip6_hdr_field = 751, /* ip6_hdr_field */
+ YYSYMBOL_icmp6_hdr_expr = 752, /* icmp6_hdr_expr */
+ YYSYMBOL_icmp6_hdr_field = 753, /* icmp6_hdr_field */
+ YYSYMBOL_auth_hdr_expr = 754, /* auth_hdr_expr */
+ YYSYMBOL_auth_hdr_field = 755, /* auth_hdr_field */
+ YYSYMBOL_esp_hdr_expr = 756, /* esp_hdr_expr */
+ YYSYMBOL_esp_hdr_field = 757, /* esp_hdr_field */
+ YYSYMBOL_comp_hdr_expr = 758, /* comp_hdr_expr */
+ YYSYMBOL_comp_hdr_field = 759, /* comp_hdr_field */
+ YYSYMBOL_udp_hdr_expr = 760, /* udp_hdr_expr */
+ YYSYMBOL_udp_hdr_field = 761, /* udp_hdr_field */
+ YYSYMBOL_udplite_hdr_expr = 762, /* udplite_hdr_expr */
+ YYSYMBOL_udplite_hdr_field = 763, /* udplite_hdr_field */
+ YYSYMBOL_tcp_hdr_expr = 764, /* tcp_hdr_expr */
+ YYSYMBOL_inner_inet_expr = 765, /* inner_inet_expr */
+ YYSYMBOL_inner_eth_expr = 766, /* inner_eth_expr */
+ YYSYMBOL_inner_expr = 767, /* inner_expr */
+ YYSYMBOL_vxlan_hdr_expr = 768, /* vxlan_hdr_expr */
+ YYSYMBOL_vxlan_hdr_field = 769, /* vxlan_hdr_field */
+ YYSYMBOL_geneve_hdr_expr = 770, /* geneve_hdr_expr */
+ YYSYMBOL_geneve_hdr_field = 771, /* geneve_hdr_field */
+ YYSYMBOL_gre_hdr_expr = 772, /* gre_hdr_expr */
+ YYSYMBOL_gre_hdr_field = 773, /* gre_hdr_field */
+ YYSYMBOL_gretap_hdr_expr = 774, /* gretap_hdr_expr */
+ YYSYMBOL_optstrip_stmt = 775, /* optstrip_stmt */
+ YYSYMBOL_tcp_hdr_field = 776, /* tcp_hdr_field */
+ YYSYMBOL_tcp_hdr_option_kind_and_field = 777, /* tcp_hdr_option_kind_and_field */
+ YYSYMBOL_tcp_hdr_option_sack = 778, /* tcp_hdr_option_sack */
+ YYSYMBOL_tcp_hdr_option_type = 779, /* tcp_hdr_option_type */
+ YYSYMBOL_tcpopt_field_sack = 780, /* tcpopt_field_sack */
+ YYSYMBOL_tcpopt_field_window = 781, /* tcpopt_field_window */
+ YYSYMBOL_tcpopt_field_tsopt = 782, /* tcpopt_field_tsopt */
+ YYSYMBOL_tcpopt_field_maxseg = 783, /* tcpopt_field_maxseg */
+ YYSYMBOL_tcpopt_field_mptcp = 784, /* tcpopt_field_mptcp */
+ YYSYMBOL_dccp_hdr_expr = 785, /* dccp_hdr_expr */
+ YYSYMBOL_dccp_hdr_field = 786, /* dccp_hdr_field */
+ YYSYMBOL_sctp_chunk_type = 787, /* sctp_chunk_type */
+ YYSYMBOL_sctp_chunk_common_field = 788, /* sctp_chunk_common_field */
+ YYSYMBOL_sctp_chunk_data_field = 789, /* sctp_chunk_data_field */
+ YYSYMBOL_sctp_chunk_init_field = 790, /* sctp_chunk_init_field */
+ YYSYMBOL_sctp_chunk_sack_field = 791, /* sctp_chunk_sack_field */
+ YYSYMBOL_sctp_chunk_alloc = 792, /* sctp_chunk_alloc */
+ YYSYMBOL_sctp_hdr_expr = 793, /* sctp_hdr_expr */
+ YYSYMBOL_sctp_hdr_field = 794, /* sctp_hdr_field */
+ YYSYMBOL_th_hdr_expr = 795, /* th_hdr_expr */
+ YYSYMBOL_th_hdr_field = 796, /* th_hdr_field */
+ YYSYMBOL_exthdr_expr = 797, /* exthdr_expr */
+ YYSYMBOL_hbh_hdr_expr = 798, /* hbh_hdr_expr */
+ YYSYMBOL_hbh_hdr_field = 799, /* hbh_hdr_field */
+ YYSYMBOL_rt_hdr_expr = 800, /* rt_hdr_expr */
+ YYSYMBOL_rt_hdr_field = 801, /* rt_hdr_field */
+ YYSYMBOL_rt0_hdr_expr = 802, /* rt0_hdr_expr */
+ YYSYMBOL_rt0_hdr_field = 803, /* rt0_hdr_field */
+ YYSYMBOL_rt2_hdr_expr = 804, /* rt2_hdr_expr */
+ YYSYMBOL_rt2_hdr_field = 805, /* rt2_hdr_field */
+ YYSYMBOL_rt4_hdr_expr = 806, /* rt4_hdr_expr */
+ YYSYMBOL_rt4_hdr_field = 807, /* rt4_hdr_field */
+ YYSYMBOL_frag_hdr_expr = 808, /* frag_hdr_expr */
+ YYSYMBOL_frag_hdr_field = 809, /* frag_hdr_field */
+ YYSYMBOL_dst_hdr_expr = 810, /* dst_hdr_expr */
+ YYSYMBOL_dst_hdr_field = 811, /* dst_hdr_field */
+ YYSYMBOL_mh_hdr_expr = 812, /* mh_hdr_expr */
+ YYSYMBOL_mh_hdr_field = 813, /* mh_hdr_field */
+ YYSYMBOL_exthdr_exists_expr = 814, /* exthdr_exists_expr */
+ YYSYMBOL_exthdr_key = 815 /* exthdr_key */
+};
+typedef enum yysymbol_kind_t yysymbol_kind_t;
+
+
+
+
+#ifdef short
+# undef short
+#endif
+
+/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure
+ <limits.h> and (if available) <stdint.h> are included
+ so that the code can choose integer types of a good width. */
+
+#ifndef __PTRDIFF_MAX__
+# include <limits.h> /* INFRINGES ON USER NAME SPACE */
+# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stdint.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_STDINT_H
+# endif
+#endif
+
+/* Narrow types that promote to a signed type and that can represent a
+ signed or unsigned integer of at least N bits. In tables they can
+ save space and decrease cache pressure. Promoting to a signed type
+ helps avoid bugs in integer arithmetic. */
+
+#ifdef __INT_LEAST8_MAX__
+typedef __INT_LEAST8_TYPE__ yytype_int8;
+#elif defined YY_STDINT_H
+typedef int_least8_t yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef __INT_LEAST16_MAX__
+typedef __INT_LEAST16_TYPE__ yytype_int16;
+#elif defined YY_STDINT_H
+typedef int_least16_t yytype_int16;
+#else
+typedef short yytype_int16;
+#endif
+
+/* Work around bug in HP-UX 11.23, which defines these macros
+ incorrectly for preprocessor constants. This workaround can likely
+ be removed in 2023, as HPE has promised support for HP-UX 11.23
+ (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of
+ <https://h20195.www2.hpe.com/V2/getpdf.aspx/4AA4-7673ENW.pdf>. */
+#ifdef __hpux
+# undef UINT_LEAST8_MAX
+# undef UINT_LEAST16_MAX
+# define UINT_LEAST8_MAX 255
+# define UINT_LEAST16_MAX 65535
+#endif
+
+#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST8_TYPE__ yytype_uint8;
+#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST8_MAX <= INT_MAX)
+typedef uint_least8_t yytype_uint8;
+#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX
+typedef unsigned char yytype_uint8;
+#else
+typedef short yytype_uint8;
+#endif
+
+#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__
+typedef __UINT_LEAST16_TYPE__ yytype_uint16;
+#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \
+ && UINT_LEAST16_MAX <= INT_MAX)
+typedef uint_least16_t yytype_uint16;
+#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX
+typedef unsigned short yytype_uint16;
+#else
+typedef int yytype_uint16;
+#endif
+
+#ifndef YYPTRDIFF_T
+# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__
+# define YYPTRDIFF_T __PTRDIFF_TYPE__
+# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__
+# elif defined PTRDIFF_MAX
+# ifndef ptrdiff_t
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# endif
+# define YYPTRDIFF_T ptrdiff_t
+# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX
+# else
+# define YYPTRDIFF_T long
+# define YYPTRDIFF_MAXIMUM LONG_MAX
+# endif
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM \
+ YY_CAST (YYPTRDIFF_T, \
+ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \
+ ? YYPTRDIFF_MAXIMUM \
+ : YY_CAST (YYSIZE_T, -1)))
+
+#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X))
+
+
+/* Stored state numbers (used for stacks). */
+typedef yytype_int16 yy_state_t;
+
+/* State numbers in computations. */
+typedef int yy_state_fast_t;
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+# define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+# define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YY_USE(E) ((void) (E))
+#else
+# define YY_USE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END \
+ _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+
+#define YY_ASSERT(E) ((void) (0 && (E)))
+
+#if 1
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* 1 */
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \
+ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yy_state_t yyss_alloc;
+ YYSTYPE yyvs_alloc;
+ YYLTYPE yyls_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE) \
+ + YYSIZEOF (YYLTYPE)) \
+ + 2 * YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYPTRDIFF_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / YYSIZEOF (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYPTRDIFF_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 8857
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 372
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 444
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 1368
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 2353
+
+/* YYMAXUTOK -- Last valid token kind. */
+#define YYMAXUTOK 617
+
+
+/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, with out-of-bounds checking. */
+#define YYTRANSLATE(YYX) \
+ (0 <= (YYX) && (YYX) <= YYMAXUTOK \
+ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \
+ : YYSYMBOL_YYUNDEF)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex. */
+static const yytype_int16 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 369, 2, 2, 2,
+ 366, 367, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 363, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 370, 2, 371, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 364, 368, 365, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
+ 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
+ 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+ 225, 226, 227, 228, 229, 230, 231, 232, 233, 234,
+ 235, 236, 237, 238, 239, 240, 241, 242, 243, 244,
+ 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
+ 255, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_int16 yyrline[] =
+{
+ 0, 978, 978, 979, 988, 989, 992, 993, 996, 997,
+ 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007,
+ 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017,
+ 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027,
+ 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037,
+ 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1048,
+ 1049, 1050, 1052, 1060, 1075, 1082, 1094, 1102, 1103, 1104,
+ 1105, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133,
+ 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1143, 1147, 1154,
+ 1158, 1166, 1170, 1174, 1181, 1188, 1192, 1199, 1208, 1212,
+ 1216, 1220, 1224, 1228, 1232, 1236, 1240, 1244, 1248, 1252,
+ 1256, 1262, 1268, 1272, 1279, 1283, 1291, 1298, 1305, 1309,
+ 1316, 1325, 1329, 1333, 1337, 1341, 1345, 1349, 1353, 1359,
+ 1365, 1366, 1369, 1370, 1373, 1374, 1377, 1378, 1381, 1385,
+ 1389, 1396, 1400, 1404, 1408, 1412, 1416, 1420, 1427, 1431,
+ 1435, 1441, 1445, 1449, 1455, 1459, 1463, 1467, 1471, 1475,
+ 1479, 1483, 1487, 1494, 1498, 1502, 1508, 1512, 1516, 1523,
+ 1529, 1533, 1537, 1541, 1545, 1549, 1553, 1557, 1561, 1565,
+ 1569, 1573, 1577, 1581, 1585, 1589, 1593, 1597, 1601, 1605,
+ 1609, 1613, 1617, 1621, 1625, 1629, 1633, 1637, 1641, 1645,
+ 1649, 1653, 1657, 1661, 1667, 1673, 1677, 1687, 1691, 1695,
+ 1700, 1704, 1708, 1712, 1717, 1721, 1725, 1729, 1734, 1738,
+ 1743, 1747, 1751, 1755, 1761, 1765, 1769, 1773, 1777, 1781,
+ 1785, 1791, 1798, 1804, 1812, 1818, 1826, 1835, 1836, 1839,
+ 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1849, 1850, 1853,
+ 1854, 1855, 1858, 1867, 1877, 1892, 1902, 1903, 1904, 1905,
+ 1906, 1917, 1927, 1938, 1948, 1959, 1970, 1979, 1988, 1997,
+ 2008, 2019, 2033, 2043, 2044, 2045, 2046, 2047, 2048, 2049,
+ 2054, 2063, 2073, 2074, 2075, 2082, 2103, 2114, 2125, 2138,
+ 2143, 2144, 2145, 2146, 2151, 2157, 2162, 2167, 2172, 2178,
+ 2183, 2188, 2189, 2200, 2201, 2204, 2208, 2211, 2212, 2213,
+ 2214, 2218, 2223, 2224, 2225, 2226, 2227, 2230, 2231, 2234,
+ 2235, 2236, 2237, 2242, 2247, 2258, 2269, 2281, 2290, 2295,
+ 2301, 2306, 2315, 2318, 2322, 2328, 2329, 2333, 2338, 2339,
+ 2340, 2341, 2355, 2359, 2363, 2369, 2374, 2381, 2386, 2391,
+ 2394, 2403, 2412, 2419, 2432, 2439, 2440, 2452, 2457, 2458,
+ 2459, 2460, 2464, 2474, 2475, 2476, 2477, 2481, 2491, 2492,
+ 2493, 2494, 2498, 2509, 2513, 2514, 2515, 2519, 2529, 2530,
+ 2531, 2532, 2536, 2546, 2547, 2548, 2549, 2553, 2563, 2564,
+ 2565, 2566, 2570, 2580, 2581, 2582, 2583, 2587, 2597, 2598,
+ 2599, 2600, 2601, 2604, 2635, 2642, 2646, 2649, 2659, 2666,
+ 2677, 2690, 2705, 2706, 2709, 2720, 2726, 2730, 2733, 2739,
+ 2752, 2757, 2766, 2767, 2770, 2771, 2774, 2775, 2776, 2779,
+ 2795, 2796, 2799, 2800, 2803, 2804, 2805, 2806, 2807, 2808,
+ 2811, 2820, 2829, 2837, 2845, 2853, 2861, 2869, 2877, 2885,
+ 2893, 2901, 2909, 2917, 2925, 2933, 2941, 2949, 2953, 2958,
+ 2966, 2973, 2980, 2994, 2998, 3005, 3009, 3015, 3027, 3033,
+ 3040, 3046, 3053, 3054, 3055, 3056, 3057, 3060, 3061, 3062,
+ 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, 3071, 3072,
+ 3073, 3074, 3075, 3076, 3077, 3078, 3079, 3080, 3081, 3084,
+ 3095, 3096, 3099, 3108, 3112, 3118, 3124, 3129, 3132, 3137,
+ 3142, 3145, 3151, 3156, 3164, 3165, 3167, 3171, 3179, 3183,
+ 3186, 3190, 3196, 3200, 3204, 3212, 3213, 3216, 3222, 3226,
+ 3229, 3354, 3359, 3364, 3369, 3374, 3380, 3410, 3414, 3418,
+ 3422, 3426, 3432, 3436, 3439, 3443, 3449, 3463, 3472, 3480,
+ 3481, 3482, 3485, 3486, 3489, 3490, 3505, 3521, 3529, 3530,
+ 3531, 3534, 3535, 3538, 3545, 3546, 3549, 3563, 3570, 3571,
+ 3586, 3587, 3588, 3589, 3590, 3593, 3596, 3602, 3608, 3612,
+ 3616, 3623, 3630, 3637, 3644, 3650, 3656, 3662, 3665, 3666,
+ 3669, 3675, 3681, 3687, 3694, 3701, 3709, 3710, 3713, 3717,
+ 3725, 3729, 3732, 3737, 3742, 3746, 3752, 3768, 3787, 3793,
+ 3794, 3800, 3801, 3807, 3808, 3809, 3810, 3811, 3812, 3813,
+ 3814, 3815, 3816, 3817, 3818, 3819, 3822, 3823, 3827, 3833,
+ 3834, 3840, 3841, 3847, 3848, 3854, 3857, 3858, 3869, 3870,
+ 3873, 3877, 3880, 3886, 3892, 3893, 3896, 3897, 3898, 3901,
+ 3905, 3909, 3914, 3919, 3924, 3930, 3934, 3938, 3942, 3948,
+ 3953, 3957, 3965, 3974, 3975, 3978, 3981, 3985, 3990, 3996,
+ 3997, 4000, 4003, 4007, 4011, 4015, 4020, 4027, 4032, 4040,
+ 4045, 4054, 4055, 4061, 4062, 4063, 4066, 4067, 4071, 4075,
+ 4081, 4082, 4085, 4091, 4095, 4098, 4103, 4109, 4110, 4113,
+ 4114, 4115, 4121, 4122, 4123, 4124, 4127, 4128, 4134, 4135,
+ 4138, 4139, 4142, 4148, 4155, 4162, 4173, 4174, 4175, 4178,
+ 4186, 4198, 4205, 4208, 4214, 4218, 4221, 4227, 4236, 4247,
+ 4253, 4279, 4280, 4289, 4290, 4293, 4302, 4313, 4314, 4315,
+ 4316, 4317, 4318, 4319, 4320, 4321, 4322, 4323, 4324, 4325,
+ 4326, 4327, 4330, 4353, 4354, 4355, 4358, 4359, 4360, 4361,
+ 4362, 4365, 4369, 4372, 4376, 4383, 4386, 4402, 4403, 4407,
+ 4413, 4414, 4420, 4421, 4427, 4428, 4434, 4437, 4438, 4449,
+ 4455, 4461, 4462, 4465, 4471, 4472, 4473, 4476, 4483, 4488,
+ 4493, 4496, 4500, 4504, 4510, 4511, 4518, 4524, 4525, 4528,
+ 4529, 4532, 4538, 4544, 4548, 4551, 4555, 4559, 4569, 4573,
+ 4576, 4582, 4589, 4593, 4599, 4613, 4627, 4632, 4638, 4654,
+ 4658, 4666, 4670, 4674, 4684, 4687, 4688, 4691, 4692, 4693,
+ 4694, 4705, 4716, 4722, 4743, 4749, 4766, 4772, 4773, 4774,
+ 4777, 4778, 4779, 4782, 4783, 4786, 4802, 4808, 4814, 4821,
+ 4834, 4842, 4850, 4856, 4860, 4864, 4868, 4872, 4879, 4884,
+ 4895, 4909, 4915, 4919, 4923, 4927, 4931, 4935, 4939, 4943,
+ 4949, 4955, 4963, 4964, 4965, 4968, 4969, 4973, 4979, 4980,
+ 4986, 4987, 4993, 4994, 5000, 5003, 5004, 5005, 5014, 5025,
+ 5026, 5029, 5037, 5038, 5039, 5040, 5041, 5042, 5043, 5044,
+ 5045, 5046, 5047, 5048, 5049, 5050, 5053, 5054, 5055, 5056,
+ 5057, 5064, 5071, 5078, 5085, 5092, 5099, 5106, 5113, 5120,
+ 5127, 5134, 5141, 5148, 5151, 5152, 5153, 5154, 5155, 5156,
+ 5157, 5160, 5164, 5168, 5172, 5176, 5180, 5186, 5187, 5197,
+ 5201, 5205, 5221, 5222, 5225, 5226, 5227, 5228, 5229, 5232,
+ 5233, 5234, 5235, 5236, 5237, 5238, 5239, 5240, 5241, 5242,
+ 5243, 5244, 5245, 5246, 5247, 5248, 5249, 5250, 5251, 5252,
+ 5253, 5254, 5255, 5258, 5278, 5282, 5296, 5300, 5304, 5310,
+ 5314, 5320, 5321, 5322, 5325, 5326, 5329, 5330, 5333, 5339,
+ 5340, 5343, 5344, 5347, 5348, 5351, 5352, 5355, 5363, 5390,
+ 5395, 5400, 5406, 5407, 5410, 5414, 5434, 5435, 5436, 5437,
+ 5440, 5444, 5448, 5454, 5455, 5458, 5459, 5460, 5461, 5462,
+ 5463, 5464, 5465, 5466, 5467, 5468, 5469, 5470, 5471, 5472,
+ 5473, 5474, 5477, 5478, 5479, 5480, 5481, 5482, 5483, 5486,
+ 5487, 5488, 5489, 5492, 5493, 5494, 5495, 5498, 5499, 5502,
+ 5508, 5516, 5529, 5536, 5542, 5548, 5557, 5558, 5559, 5560,
+ 5561, 5562, 5563, 5564, 5565, 5566, 5567, 5568, 5569, 5570,
+ 5571, 5572, 5573, 5574, 5575, 5576, 5577, 5578, 5581, 5590,
+ 5591, 5592, 5593, 5606, 5612, 5613, 5614, 5617, 5623, 5624,
+ 5625, 5626, 5627, 5630, 5636, 5637, 5638, 5639, 5640, 5641,
+ 5642, 5643, 5644, 5647, 5651, 5659, 5666, 5667, 5668, 5669,
+ 5670, 5671, 5672, 5673, 5674, 5675, 5676, 5677, 5680, 5681,
+ 5682, 5683, 5686, 5687, 5688, 5689, 5690, 5693, 5699, 5700,
+ 5701, 5702, 5703, 5704, 5705, 5708, 5714, 5715, 5716, 5717,
+ 5720, 5726, 5727, 5728, 5729, 5730, 5731, 5732, 5733, 5734,
+ 5736, 5742, 5743, 5744, 5745, 5746, 5747, 5748, 5749, 5750,
+ 5751, 5754, 5760, 5761, 5762, 5763, 5764, 5767, 5773, 5774,
+ 5777, 5783, 5784, 5785, 5788, 5794, 5795, 5796, 5797, 5800,
+ 5806, 5807, 5808, 5809, 5812, 5816, 5821, 5825, 5832, 5833,
+ 5834, 5835, 5836, 5837, 5838, 5839, 5840, 5841, 5842, 5843,
+ 5844, 5845, 5848, 5849, 5850, 5853, 5854, 5857, 5865, 5873,
+ 5874, 5877, 5885, 5893, 5894, 5897, 5901, 5908, 5909, 5910,
+ 5913, 5920, 5927, 5928, 5929, 5930, 5931, 5932, 5933, 5934,
+ 5935, 5936, 5939, 5944, 5949, 5954, 5959, 5964, 5971, 5972,
+ 5973, 5974, 5975, 5978, 5979, 5980, 5981, 5982, 5983, 5984,
+ 5985, 5986, 5987, 5988, 5989, 5998, 5999, 6002, 6005, 6006,
+ 6009, 6012, 6015, 6019, 6030, 6031, 6032, 6035, 6036, 6037,
+ 6038, 6039, 6040, 6041, 6042, 6043, 6044, 6045, 6046, 6047,
+ 6048, 6049, 6050, 6051, 6052, 6055, 6056, 6057, 6060, 6061,
+ 6062, 6063, 6066, 6067, 6068, 6069, 6070, 6073, 6074, 6075,
+ 6076, 6079, 6084, 6088, 6092, 6096, 6100, 6104, 6109, 6114,
+ 6119, 6124, 6129, 6136, 6140, 6146, 6147, 6148, 6149, 6152,
+ 6160, 6161, 6164, 6165, 6166, 6167, 6168, 6169, 6170, 6171,
+ 6174, 6180, 6181, 6184, 6190, 6191, 6192, 6193, 6196, 6202,
+ 6208, 6214, 6217, 6223, 6224, 6225, 6226, 6232, 6238, 6239,
+ 6240, 6241, 6242, 6243, 6246, 6252, 6253, 6256, 6262, 6263,
+ 6264, 6265, 6266, 6269, 6283, 6284, 6285, 6286, 6287
+};
+#endif
+
+/** Accessing symbol of state STATE. */
+#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State])
+
+#if 1
+/* The user-facing name of the symbol whose (internal) number is
+ YYSYMBOL. No bounds checking. */
+static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED;
+
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "\"end of file\"", "error", "\"invalid token\"", "\"junk\"",
+ "\"newline\"", "\"colon\"", "\"semicolon\"", "\"comma\"", "\".\"",
+ "\"==\"", "\"!=\"", "\"<\"", "\">\"", "\">=\"", "\"<=\"", "\"<<\"",
+ "\">>\"", "\"&\"", "\"^\"", "\"!\"", "\"/\"", "\"*\"", "\"-\"", "\"@\"",
+ "\"vmap\"", "\"+\"", "\"include\"", "\"define\"", "\"redefine\"",
+ "\"undefine\"", "\"fib\"", "\"socket\"", "\"transparent\"",
+ "\"wildcard\"", "\"cgroupv2\"", "\"tproxy\"", "\"osf\"", "\"synproxy\"",
+ "\"mss\"", "\"wscale\"", "\"typeof\"", "\"hook\"", "\"hooks\"",
+ "\"device\"", "\"devices\"", "\"table\"", "\"tables\"", "\"chain\"",
+ "\"chains\"", "\"rule\"", "\"rules\"", "\"sets\"", "\"set\"",
+ "\"element\"", "\"map\"", "\"maps\"", "\"flowtable\"", "\"handle\"",
+ "\"ruleset\"", "\"trace\"", "\"inet\"", "\"netdev\"", "\"add\"",
+ "\"update\"", "\"replace\"", "\"create\"", "\"insert\"", "\"delete\"",
+ "\"get\"", "\"list\"", "\"reset\"", "\"flush\"", "\"rename\"",
+ "\"describe\"", "\"import\"", "\"export\"", "\"destroy\"", "\"monitor\"",
+ "\"all\"", "\"accept\"", "\"drop\"", "\"continue\"", "\"jump\"",
+ "\"goto\"", "\"return\"", "\"to\"", "\"constant\"", "\"interval\"",
+ "\"dynamic\"", "\"auto-merge\"", "\"timeout\"", "\"gc-interval\"",
+ "\"elements\"", "\"expires\"", "\"policy\"", "\"memory\"",
+ "\"performance\"", "\"size\"", "\"flow\"", "\"offload\"", "\"meter\"",
+ "\"meters\"", "\"flowtables\"", "\"number\"", "\"string\"",
+ "\"quoted string\"", "\"string with a trailing asterisk\"", "\"ll\"",
+ "\"nh\"", "\"th\"", "\"bridge\"", "\"ether\"", "\"saddr\"", "\"daddr\"",
+ "\"type\"", "\"vlan\"", "\"id\"", "\"cfi\"", "\"dei\"", "\"pcp\"",
+ "\"arp\"", "\"htype\"", "\"ptype\"", "\"hlen\"", "\"plen\"",
+ "\"operation\"", "\"ip\"", "\"version\"", "\"hdrlength\"", "\"dscp\"",
+ "\"ecn\"", "\"length\"", "\"frag-off\"", "\"ttl\"", "\"protocol\"",
+ "\"checksum\"", "\"ptr\"", "\"value\"", "\"lsrr\"", "\"rr\"", "\"ssrr\"",
+ "\"ra\"", "\"icmp\"", "\"code\"", "\"seq\"", "\"gateway\"", "\"mtu\"",
+ "\"igmp\"", "\"mrt\"", "\"options\"", "\"ip6\"", "\"priority\"",
+ "\"flowlabel\"", "\"nexthdr\"", "\"hoplimit\"", "\"icmpv6\"",
+ "\"param-problem\"", "\"max-delay\"", "\"taddr\"", "\"ah\"",
+ "\"reserved\"", "\"spi\"", "\"esp\"", "\"comp\"", "\"flags\"", "\"cpi\"",
+ "\"port\"", "\"udp\"", "\"sport\"", "\"dport\"", "\"udplite\"",
+ "\"csumcov\"", "\"tcp\"", "\"ackseq\"", "\"doff\"", "\"window\"",
+ "\"urgptr\"", "\"option\"", "\"echo\"", "\"eol\"", "\"mptcp\"",
+ "\"nop\"", "\"sack\"", "\"sack0\"", "\"sack1\"", "\"sack2\"",
+ "\"sack3\"", "\"sack-permitted\"", "\"fastopen\"", "\"md5sig\"",
+ "\"timestamp\"", "\"count\"", "\"left\"", "\"right\"", "\"tsval\"",
+ "\"tsecr\"", "\"subtype\"", "\"dccp\"", "\"vxlan\"", "\"vni\"",
+ "\"gre\"", "\"gretap\"", "\"geneve\"", "\"sctp\"", "\"chunk\"",
+ "\"data\"", "\"init\"", "\"init-ack\"", "\"heartbeat\"",
+ "\"heartbeat-ack\"", "\"abort\"", "\"shutdown\"", "\"shutdown-ack\"",
+ "\"error\"", "\"cookie-echo\"", "\"cookie-ack\"", "\"ecne\"", "\"cwr\"",
+ "\"shutdown-complete\"", "\"asconf-ack\"", "\"forward-tsn\"",
+ "\"asconf\"", "\"tsn\"", "\"stream\"", "\"ssn\"", "\"ppid\"",
+ "\"init-tag\"", "\"a-rwnd\"", "\"num-outbound-streams\"",
+ "\"num-inbound-streams\"", "\"initial-tsn\"", "\"cum-tsn-ack\"",
+ "\"num-gap-ack-blocks\"", "\"num-dup-tsns\"", "\"lowest-tsn\"",
+ "\"seqno\"", "\"new-cum-tsn\"", "\"vtag\"", "\"rt\"", "\"rt0\"",
+ "\"rt2\"", "\"srh\"", "\"seg-left\"", "\"addr\"", "\"last-entry\"",
+ "\"tag\"", "\"sid\"", "\"hbh\"", "\"frag\"", "\"reserved2\"",
+ "\"more-fragments\"", "\"dst\"", "\"mh\"", "\"meta\"", "\"mark\"",
+ "\"iif\"", "\"iifname\"", "\"iiftype\"", "\"oif\"", "\"oifname\"",
+ "\"oiftype\"", "\"skuid\"", "\"skgid\"", "\"nftrace\"", "\"rtclassid\"",
+ "\"ibriport\"", "\"obriport\"", "\"ibrname\"", "\"obrname\"",
+ "\"pkttype\"", "\"cpu\"", "\"iifgroup\"", "\"oifgroup\"", "\"cgroup\"",
+ "\"time\"", "\"classid\"", "\"nexthop\"", "\"ct\"", "\"l3proto\"",
+ "\"proto-src\"", "\"proto-dst\"", "\"zone\"", "\"direction\"",
+ "\"event\"", "\"expectation\"", "\"expiration\"", "\"helper\"",
+ "\"label\"", "\"state\"", "\"status\"", "\"original\"", "\"reply\"",
+ "\"counter\"", "\"name\"", "\"packets\"", "\"bytes\"", "\"avgpkt\"",
+ "\"last\"", "\"never\"", "\"counters\"", "\"quotas\"", "\"limits\"",
+ "\"synproxys\"", "\"helpers\"", "\"log\"", "\"prefix\"", "\"group\"",
+ "\"snaplen\"", "\"queue-threshold\"", "\"level\"", "\"limit\"",
+ "\"rate\"", "\"burst\"", "\"over\"", "\"until\"", "\"quota\"",
+ "\"used\"", "\"secmark\"", "\"secmarks\"", "\"second\"", "\"minute\"",
+ "\"hour\"", "\"day\"", "\"week\"", "\"reject\"", "\"with\"", "\"icmpx\"",
+ "\"snat\"", "\"dnat\"", "\"masquerade\"", "\"redirect\"", "\"random\"",
+ "\"fully-random\"", "\"persistent\"", "\"queue\"", "\"num\"",
+ "\"bypass\"", "\"fanout\"", "\"dup\"", "\"fwd\"", "\"numgen\"",
+ "\"inc\"", "\"mod\"", "\"offset\"", "\"jhash\"", "\"symhash\"",
+ "\"seed\"", "\"position\"", "\"index\"", "\"comment\"", "\"xml\"",
+ "\"json\"", "\"vm\"", "\"notrack\"", "\"exists\"", "\"missing\"",
+ "\"exthdr\"", "\"ipsec\"", "\"reqid\"", "\"spnum\"", "\"in\"", "\"out\"",
+ "\"xt\"", "'='", "'{'", "'}'", "'('", "')'", "'|'", "'$'", "'['", "']'",
+ "$accept", "input", "stmt_separator", "opt_newline", "close_scope_ah",
+ "close_scope_arp", "close_scope_at", "close_scope_comp",
+ "close_scope_ct", "close_scope_counter", "close_scope_last",
+ "close_scope_dccp", "close_scope_destroy", "close_scope_dst",
+ "close_scope_dup", "close_scope_esp", "close_scope_eth",
+ "close_scope_export", "close_scope_fib", "close_scope_frag",
+ "close_scope_fwd", "close_scope_gre", "close_scope_hash",
+ "close_scope_hbh", "close_scope_ip", "close_scope_ip6",
+ "close_scope_vlan", "close_scope_icmp", "close_scope_igmp",
+ "close_scope_import", "close_scope_ipsec", "close_scope_list",
+ "close_scope_limit", "close_scope_meta", "close_scope_mh",
+ "close_scope_monitor", "close_scope_nat", "close_scope_numgen",
+ "close_scope_osf", "close_scope_policy", "close_scope_quota",
+ "close_scope_queue", "close_scope_reject", "close_scope_reset",
+ "close_scope_rt", "close_scope_sctp", "close_scope_sctp_chunk",
+ "close_scope_secmark", "close_scope_socket", "close_scope_tcp",
+ "close_scope_tproxy", "close_scope_type", "close_scope_th",
+ "close_scope_udp", "close_scope_udplite", "close_scope_log",
+ "close_scope_synproxy", "close_scope_xt", "common_block", "line",
+ "base_cmd", "add_cmd", "replace_cmd", "create_cmd", "insert_cmd",
+ "table_or_id_spec", "chain_or_id_spec", "set_or_id_spec",
+ "obj_or_id_spec", "delete_cmd", "destroy_cmd", "get_cmd", "list_cmd",
+ "basehook_device_name", "basehook_spec", "reset_cmd", "flush_cmd",
+ "rename_cmd", "import_cmd", "export_cmd", "monitor_cmd", "monitor_event",
+ "monitor_object", "monitor_format", "markup_format", "describe_cmd",
+ "table_block_alloc", "table_options", "table_block", "chain_block_alloc",
+ "chain_block", "subchain_block", "typeof_data_expr", "typeof_expr",
+ "set_block_alloc", "set_block", "set_block_expr", "set_flag_list",
+ "set_flag", "map_block_alloc", "map_block_obj_type",
+ "map_block_data_interval", "map_block", "set_mechanism",
+ "set_policy_spec", "flowtable_block_alloc", "flowtable_block",
+ "flowtable_expr", "flowtable_list_expr", "flowtable_expr_member",
+ "data_type_atom_expr", "data_type_expr", "obj_block_alloc",
+ "counter_block", "quota_block", "ct_helper_block", "ct_timeout_block",
+ "ct_expect_block", "limit_block", "secmark_block", "synproxy_block",
+ "type_identifier", "hook_spec", "prio_spec", "extended_prio_name",
+ "extended_prio_spec", "int_num", "dev_spec", "flags_spec", "policy_spec",
+ "policy_expr", "chain_policy", "identifier", "string", "time_spec",
+ "time_spec_or_num_s", "family_spec", "family_spec_explicit",
+ "table_spec", "tableid_spec", "chain_spec", "chainid_spec",
+ "chain_identifier", "set_spec", "setid_spec", "set_identifier",
+ "flowtable_spec", "flowtableid_spec", "flowtable_identifier", "obj_spec",
+ "objid_spec", "obj_identifier", "handle_spec", "position_spec",
+ "index_spec", "rule_position", "ruleid_spec", "comment_spec",
+ "ruleset_spec", "rule", "rule_alloc", "stmt_list", "stateful_stmt_list",
+ "stateful_stmt", "stmt", "xt_stmt", "chain_stmt_type", "chain_stmt",
+ "verdict_stmt", "verdict_map_stmt", "verdict_map_expr",
+ "verdict_map_list_expr", "verdict_map_list_member_expr",
+ "connlimit_stmt", "counter_stmt", "counter_stmt_alloc", "counter_args",
+ "counter_arg", "last_stmt", "log_stmt", "log_stmt_alloc", "log_args",
+ "log_arg", "level_type", "log_flags", "log_flags_tcp", "log_flag_tcp",
+ "limit_stmt", "quota_mode", "quota_unit", "quota_used", "quota_stmt",
+ "limit_mode", "limit_burst_pkts", "limit_rate_pkts", "limit_burst_bytes",
+ "limit_rate_bytes", "limit_bytes", "time_unit", "reject_stmt",
+ "reject_stmt_alloc", "reject_with_expr", "reject_opts", "nat_stmt",
+ "nat_stmt_alloc", "tproxy_stmt", "synproxy_stmt", "synproxy_stmt_alloc",
+ "synproxy_args", "synproxy_arg", "synproxy_config", "synproxy_obj",
+ "synproxy_ts", "synproxy_sack", "primary_stmt_expr", "shift_stmt_expr",
+ "and_stmt_expr", "exclusive_or_stmt_expr", "inclusive_or_stmt_expr",
+ "basic_stmt_expr", "concat_stmt_expr", "map_stmt_expr_set",
+ "map_stmt_expr", "prefix_stmt_expr", "range_stmt_expr",
+ "multiton_stmt_expr", "stmt_expr", "nat_stmt_args", "masq_stmt",
+ "masq_stmt_alloc", "masq_stmt_args", "redir_stmt", "redir_stmt_alloc",
+ "redir_stmt_arg", "dup_stmt", "fwd_stmt", "nf_nat_flags", "nf_nat_flag",
+ "queue_stmt", "queue_stmt_compat", "queue_stmt_alloc", "queue_stmt_args",
+ "queue_stmt_arg", "queue_expr", "queue_stmt_expr_simple",
+ "queue_stmt_expr", "queue_stmt_flags", "queue_stmt_flag",
+ "set_elem_expr_stmt", "set_elem_expr_stmt_alloc", "set_stmt",
+ "set_stmt_op", "map_stmt", "meter_stmt", "flow_stmt_legacy_alloc",
+ "flow_stmt_opts", "flow_stmt_opt", "meter_stmt_alloc", "match_stmt",
+ "variable_expr", "symbol_expr", "set_ref_expr", "set_ref_symbol_expr",
+ "integer_expr", "primary_expr", "fib_expr", "fib_result", "fib_flag",
+ "fib_tuple", "osf_expr", "osf_ttl", "shift_expr", "and_expr",
+ "exclusive_or_expr", "inclusive_or_expr", "basic_expr", "concat_expr",
+ "prefix_rhs_expr", "range_rhs_expr", "multiton_rhs_expr", "map_expr",
+ "expr", "set_expr", "set_list_expr", "set_list_member_expr",
+ "meter_key_expr", "meter_key_expr_alloc", "set_elem_expr",
+ "set_elem_key_expr", "set_elem_expr_alloc", "set_elem_options",
+ "set_elem_option", "set_elem_expr_options", "set_elem_stmt_list",
+ "set_elem_stmt", "set_elem_expr_option", "set_lhs_expr", "set_rhs_expr",
+ "initializer_expr", "counter_config", "counter_obj", "quota_config",
+ "quota_obj", "secmark_config", "secmark_obj", "ct_obj_type",
+ "ct_cmd_type", "ct_l4protoname", "ct_helper_config", "timeout_states",
+ "timeout_state", "ct_timeout_config", "ct_expect_config", "ct_obj_alloc",
+ "limit_config", "limit_obj", "relational_expr", "list_rhs_expr",
+ "rhs_expr", "shift_rhs_expr", "and_rhs_expr", "exclusive_or_rhs_expr",
+ "inclusive_or_rhs_expr", "basic_rhs_expr", "concat_rhs_expr",
+ "boolean_keys", "boolean_expr", "keyword_expr", "primary_rhs_expr",
+ "relational_op", "verdict_expr", "chain_expr", "meta_expr", "meta_key",
+ "meta_key_qualified", "meta_key_unqualified", "meta_stmt", "socket_expr",
+ "socket_key", "offset_opt", "numgen_type", "numgen_expr", "xfrm_spnum",
+ "xfrm_dir", "xfrm_state_key", "xfrm_state_proto_key", "xfrm_expr",
+ "hash_expr", "nf_key_proto", "rt_expr", "rt_key", "ct_expr", "ct_dir",
+ "ct_key", "ct_key_dir", "ct_key_proto_field", "ct_key_dir_optional",
+ "symbol_stmt_expr", "list_stmt_expr", "ct_stmt", "payload_stmt",
+ "payload_expr", "payload_raw_expr", "payload_base_spec", "eth_hdr_expr",
+ "eth_hdr_field", "vlan_hdr_expr", "vlan_hdr_field", "arp_hdr_expr",
+ "arp_hdr_field", "ip_hdr_expr", "ip_hdr_field", "ip_option_type",
+ "ip_option_field", "icmp_hdr_expr", "icmp_hdr_field", "igmp_hdr_expr",
+ "igmp_hdr_field", "ip6_hdr_expr", "ip6_hdr_field", "icmp6_hdr_expr",
+ "icmp6_hdr_field", "auth_hdr_expr", "auth_hdr_field", "esp_hdr_expr",
+ "esp_hdr_field", "comp_hdr_expr", "comp_hdr_field", "udp_hdr_expr",
+ "udp_hdr_field", "udplite_hdr_expr", "udplite_hdr_field", "tcp_hdr_expr",
+ "inner_inet_expr", "inner_eth_expr", "inner_expr", "vxlan_hdr_expr",
+ "vxlan_hdr_field", "geneve_hdr_expr", "geneve_hdr_field", "gre_hdr_expr",
+ "gre_hdr_field", "gretap_hdr_expr", "optstrip_stmt", "tcp_hdr_field",
+ "tcp_hdr_option_kind_and_field", "tcp_hdr_option_sack",
+ "tcp_hdr_option_type", "tcpopt_field_sack", "tcpopt_field_window",
+ "tcpopt_field_tsopt", "tcpopt_field_maxseg", "tcpopt_field_mptcp",
+ "dccp_hdr_expr", "dccp_hdr_field", "sctp_chunk_type",
+ "sctp_chunk_common_field", "sctp_chunk_data_field",
+ "sctp_chunk_init_field", "sctp_chunk_sack_field", "sctp_chunk_alloc",
+ "sctp_hdr_expr", "sctp_hdr_field", "th_hdr_expr", "th_hdr_field",
+ "exthdr_expr", "hbh_hdr_expr", "hbh_hdr_field", "rt_hdr_expr",
+ "rt_hdr_field", "rt0_hdr_expr", "rt0_hdr_field", "rt2_hdr_expr",
+ "rt2_hdr_field", "rt4_hdr_expr", "rt4_hdr_field", "frag_hdr_expr",
+ "frag_hdr_field", "dst_hdr_expr", "dst_hdr_field", "mh_hdr_expr",
+ "mh_hdr_field", "exthdr_exists_expr", "exthdr_key", YY_NULLPTR
+};
+
+static const char *
+yysymbol_name (yysymbol_kind_t yysymbol)
+{
+ return yytname[yysymbol];
+}
+#endif
+
+#ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_int16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
+ 395, 396, 397, 398, 399, 400, 401, 402, 403, 404,
+ 405, 406, 407, 408, 409, 410, 411, 412, 413, 414,
+ 415, 416, 417, 418, 419, 420, 421, 422, 423, 424,
+ 425, 426, 427, 428, 429, 430, 431, 432, 433, 434,
+ 435, 436, 437, 438, 439, 440, 441, 442, 443, 444,
+ 445, 446, 447, 448, 449, 450, 451, 452, 453, 454,
+ 455, 456, 457, 458, 459, 460, 461, 462, 463, 464,
+ 465, 466, 467, 468, 469, 470, 471, 472, 473, 474,
+ 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
+ 485, 486, 487, 488, 489, 490, 491, 492, 493, 494,
+ 495, 496, 497, 498, 499, 500, 501, 502, 503, 504,
+ 505, 506, 507, 508, 509, 510, 511, 512, 513, 514,
+ 515, 516, 517, 518, 519, 520, 521, 522, 523, 524,
+ 525, 526, 527, 528, 529, 530, 531, 532, 533, 534,
+ 535, 536, 537, 538, 539, 540, 541, 542, 543, 544,
+ 545, 546, 547, 548, 549, 550, 551, 552, 553, 554,
+ 555, 556, 557, 558, 559, 560, 561, 562, 563, 564,
+ 565, 566, 567, 568, 569, 570, 571, 572, 573, 574,
+ 575, 576, 577, 578, 579, 580, 581, 582, 583, 584,
+ 585, 586, 587, 588, 589, 590, 591, 592, 593, 594,
+ 595, 596, 597, 598, 599, 600, 601, 602, 603, 604,
+ 605, 606, 607, 608, 609, 610, 611, 612, 613, 614,
+ 615, 616, 617, 61, 123, 125, 40, 41, 124, 36,
+ 91, 93
+};
+#endif
+
+#define YYPACT_NINF (-1837)
+
+#define yypact_value_is_default(Yyn) \
+ ((Yyn) == YYPACT_NINF)
+
+#define YYTABLE_NINF (-1049)
+
+#define yytable_value_is_error(Yyn) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int16 yypact[] =
+{
+ -1837, 8167, -1837, 370, -1837, -1837, 120, 257, 257, 257,
+ 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, -1837, -1837,
+ 2577, 296, 2378, 319, 1563, 227, 2797, 881, 1594, 348,
+ 7783, 199, 208, 2365, 325, -1837, -1837, -1837, -1837, 577,
+ 1315, 1315, 1315, 1315, -1837, -1837, -1837, 1024, -1837, 257,
+ -1837, 257, 134, 6943, -1837, 370, -1837, -1837, 275, 281,
+ 370, 257, -1837, 122, 250, 6943, 257, -1837, 323, -1837,
+ 257, -1837, -1837, 1315, -1837, 1315, 1315, 1315, 1315, 1315,
+ 1315, 1315, 578, 1315, 1315, 1315, 1315, -1837, 1315, -1837,
+ 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 612, 1315,
+ 1315, 1315, 1315, -1837, 1315, -1837, 1315, 1315, 1315, 1315,
+ 1315, 1315, 1372, 1315, 1315, 1315, 1315, 1315, 532, 1315,
+ 1315, 1315, 113, 1315, 2325, 2443, 2452, 2534, 1315, 1315,
+ 1315, 2661, -1837, 1315, 728, 1315, 1315, 1315, 1315, 1228,
+ 1237, 1315, -1837, 1315, 1315, 1315, 1315, 1315, 493, 1315,
+ -1837, 1315, -1837, 1559, 632, 785, 528, -1837, -1837, -1837,
+ -1837, 788, 1034, 1590, 2270, 2686, 1131, 657, 2079, 2810,
+ 1668, 123, 924, 939, 1151, 3220, 913, 3634, 773, -1837,
+ 5759, 818, 977, 432, 438, 800, 235, 1149, 295, 1722,
+ 5013, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 5435, -1837, -1837, 5, 7419, 357, 1272, 606,
+ 7783, 257, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 1088, -1837, -1837, 367, -1837, -1837, 1088, -1837, -1837,
+ 1315, 1315, 1315, 1315, 1315, 1315, 1315, 1315, 612, 1315,
+ 1315, 1315, 1315, -1837, -1837, -1837, 1611, -1837, -1837, -1837,
+ 1315, 1315, 1315, -44, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 636, 665, 679, -1837, -1837, -1837, 821, 466, 1005,
+ -1837, -1837, -1837, 655, -1837, -1837, -1837, 127, 127, -1837,
+ 355, 257, 8446, 3291, 547, 550, -1837, 96, 749, -1837,
+ -1837, -1837, -1837, -1837, 174, 770, 897, -1837, 768, 893,
+ -1837, 570, 6943, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 757, -1837, -1837, 919, -1837, -1837, -1837, 596,
+ -1837, 5327, -1837, -1837, 853, -1837, 241, -1837, 424, -1837,
+ -1837, -1837, -1837, 1391, -1837, 146, -1837, -1837, 858, -1837,
+ -1837, -1837, 1095, 911, 923, 582, -1837, 752, -1837, 6457,
+ -1837, -1837, -1837, 936, -1837, -1837, -1837, 940, -1837, -1837,
+ 6797, 6797, -1837, -1837, 156, 677, 707, -1837, -1837, 711,
+ -1837, -1837, -1837, 716, -1837, 721, 963, 6943, -1837, 122,
+ 250, -1837, 323, -1837, -1837, 1315, 1315, 1315, 682, -1837,
+ -1837, -1837, 6943, -1837, 274, -1837, -1837, -1837, 383, -1837,
+ -1837, -1837, 440, 250, -1837, -1837, -1837, 500, -1837, -1837,
+ 323, -1837, 506, 733, -1837, -1837, -1837, -1837, 1315, -1837,
+ -1837, -1837, -1837, 323, -1837, -1837, -1837, 1063, -1837, -1837,
+ -1837, -1837, 1315, -1837, -1837, -1837, -1837, -1837, -1837, 1315,
+ 1315, -1837, -1837, -1837, 1086, 1090, -1837, 1315, 1093, -1837,
+ 1315, -1837, 1315, -1837, 1315, -1837, 1315, -1837, -1837, -1837,
+ -1837, 1315, -1837, -1837, -1837, 1315, 1315, 328, 257, -1837,
+ -1837, -1837, 323, -1837, -1837, 1315, -1837, -1837, 1315, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1315, -1837,
+ 257, -1837, -1837, -1837, -1837, 1145, -1837, -1837, -1837, -1837,
+ -1837, 1171, 656, -1837, -1837, 875, -1837, -1837, 1087, 49,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 673, 698, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 1312, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 2809, -1837, -1837, -1837, -1837, 1092, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, 3029, -1837, 5968, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, 3975, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 554, -1837,
+ -1837, 840, -1837, -1837, -1837, -1837, -1837, -1837, 850, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 2175, -1837, -1837, -1837, -1837, 908, 262, 912, 1157,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 921,
+ 929, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, 323, -1837, 733, -1837, 1315, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 1088, -1837, -1837, -1837, -1837, 39, 13, 690,
+ 111, -1837, -1837, -1837, 5536, 1216, 7210, 7783, 1126, -1837,
+ -1837, -1837, -1837, 1283, 1285, 82, 1259, 1263, 1269, 126,
+ 1271, 2175, 1276, 7210, 114, 7210, 842, 7210, -1837, -1837,
+ 1227, 7783, 866, 7210, 7210, 1248, 1644, -1837, 6475, 163,
+ -1837, 1644, -1837, -1837, -1837, 972, -1837, 1242, 1249, 757,
+ -1837, -1837, -1837, 884, 1644, 1253, 1267, 1303, 1644, 919,
+ -1837, -1837, 130, -1837, -1837, 7210, -1837, -1837, 5745, 1277,
+ 1034, 1590, 2270, 2686, -1837, 2079, 664, -1837, -1837, -1837,
+ -1837, 1281, -1837, -1837, -1837, -1837, 7210, -1837, 1255, 1392,
+ 1398, 1062, 441, 327, -1837, -1837, -1837, -1837, 1429, 1484,
+ 1438, -1837, -1837, -1837, -1837, 1449, -1837, -1837, -1837, -1837,
+ 622, -1837, -1837, 1456, 1460, -1837, -1837, -1837, 1370, 1381,
+ -1837, -1837, 853, -1837, -1837, 1474, -1837, -1837, -1837, -1837,
+ 1480, -1837, -1837, 5954, -1837, 1480, -1837, -1837, -1837, 102,
+ -1837, -1837, 1391, -1837, 1486, -1837, 257, -1837, 1125, -1837,
+ 257, 157, -1837, 8299, 8299, 8299, 8299, 8299, 7783, 121,
+ 7988, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, 8299, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, 703, -1837, 1357, 1489, 1495, 1147,
+ 902, 1513, -1837, -1837, -1837, 7988, 7210, 7210, 1452, 159,
+ 370, 1525, -1837, 1168, 370, 1464, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, 1503, 1195, 1206, 1209, -1837,
+ 1225, 1239, -1837, -1837, -1837, -1837, 1298, 1290, 1099, 1644,
+ -1837, -1837, 1508, 1510, 1515, 1256, 1530, -1837, 1532, 1278,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1536, -1837, -1837,
+ -1837, -1837, -1837, 1315, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 1541, 632, -1837, -1837, -1837, -1837, 1546,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1176, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 1548, -1837, 1459, -1837, -1837, 1462, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1306, -1837,
+ 1311, 1524, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1163,
+ 1689, 1777, 1777, -1837, -1837, -1837, 1425, -1837, -1837, -1837,
+ -1837, 1430, 1439, -1837, 1440, 1436, 1443, 572, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1588, -1837, -1837,
+ 1593, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 1396, -1837, 1405, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 1595, 1608, 1350, -1837, -1837, -1837, -1837,
+ -1837, 1612, 272, -1837, -1837, -1837, 1353, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, 1355, 1356, 1367, 1632, -1837, -1837,
+ 842, -1837, -1837, -1837, 1635, -1837, -1837, -1837, -1837, 7210,
+ 2686, 2079, 1735, 6163, -1837, 146, 260, 1734, 3115, 1644,
+ 1644, 1653, 7783, 7210, 7210, 7210, -1837, 1662, 7210, 1715,
+ 7210, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1665, -1837,
+ 154, 1749, -1837, -1837, 247, 297, 262, -1837, 410, 476,
+ 183, 1730, -1837, 7210, -1837, -1837, 893, 1542, 1134, 277,
+ -1837, 829, 1513, 893, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 1628, 591, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 1073, 1164, -1837, 1265, -1837, -1837, -1837,
+ 7210, 1774, 7210, -1837, -1837, -1837, 667, 726, -1837, 7210,
+ -1837, -1837, 1417, -1837, -1837, 7210, 7210, 7210, 7210, 7210,
+ 1686, 7210, 7210, 177, 7210, 1480, 7210, 1707, 1787, 1713,
+ 2495, 2495, -1837, -1837, -1837, 7210, 1484, 7210, 1484, -1837,
+ 1778, 1784, -1837, 866, -1837, 7783, -1837, 7783, -1837, -1837,
+ -1837, 1357, 1489, 1495, -1837, 893, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 1441, 8299, 8299, 8299, 8299, 8299, 8299,
+ 8299, 8299, 8488, 8299, 8299, 795, -1837, 1178, -1837, -1837,
+ -1837, -1837, -1837, 1708, -1837, 304, 409, -1837, 2905, 3652,
+ 3251, 4477, 841, -1837, -1837, -1837, -1837, -1837, -1837, 1446,
+ 1468, 1471, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1806, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, 3115, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1453,
+ 1470, -1837, -1837, -1837, -1837, -1837, -1837, 1350, 668, 1742,
+ -1837, -1837, -1837, -1837, -1837, 1437, -1837, -1837, -1837, -1837,
+ -1837, 1554, 1203, -1837, 1665, 1673, -1837, 539, 154, -1837,
+ 990, -1837, -1837, 7210, 7210, 1841, -1837, 1747, 1747, -1837,
+ 260, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ 1500, 1734, 6943, 260, -1837, -1837, -1837, -1837, -1837, -1837,
+ 7210, -1837, -1837, 253, 1555, 1560, 1856, -1837, -1837, -1837,
+ 1567, 102, -1837, 7783, 102, 7210, 1836, -1837, 8218, -1837,
+ 1696, 1597, 1573, 1581, 1099, 1134, -1837, 1747, 1747, -1837,
+ 277, -1837, 6475, -1837, 5051, -1837, -1837, -1837, -1837, 1888,
+ -1837, -1837, 1461, -1837, -1837, 1461, -1837, 1826, 1461, -1837,
+ -1837, 7210, -1837, -1837, -1837, -1837, -1837, 1255, 1392, 1398,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1897, 7210, 1737,
+ 7210, -1837, -1837, -1837, -1837, 1484, -1837, 1484, 1480, -1837,
+ -1837, 237, 6943, 6579, 166, -1837, -1837, -1837, 1525, 1900,
+ -1837, -1837, 1357, 1489, 1495, -1837, 231, 1525, -1837, -1837,
+ 829, 8299, 8488, -1837, 1805, 1878, -1837, -1837, -1837, -1837,
+ -1837, 257, 257, 257, 257, 257, 1815, 658, 257, 257,
+ 257, 257, -1837, -1837, -1837, 370, -1837, 1562, 108, -1837,
+ 1821, -1837, -1837, -1837, 370, 370, 370, 370, 370, 7783,
+ -1837, 1747, 1747, 1566, 1482, 1820, 983, 1766, 1741, -1837,
+ -1837, -1837, 370, 370, 531, -1837, 7783, 1747, 1747, 1570,
+ 983, 1766, -1837, -1837, -1837, 370, 370, 531, 1830, 1577,
+ 1837, -1837, -1837, -1837, -1837, -1837, 5203, 4006, 3513, 4831,
+ 1207, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 4360, 1501,
+ -1837, -1837, 1838, -1837, -1837, -1837, 1937, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, 1843, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, 2014, -1837, 737, 472, 1072, 1844,
+ -1837, -1837, -1837, -1837, -1837, 1555, 1560, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1567, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, 7210, -1837, -1837, -1837, -1837,
+ -1837, -1837, 7783, 1585, 260, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 1731, 1934, -1837, 1857, -1837, 1858, -1837, 1731,
+ 1861, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 7210, 127,
+ 127, 893, 1513, -1837, 251, 1866, -1837, 185, 842, 1867,
+ -1837, -1837, -1837, -1837, -1837, -1837, 370, -1837, 591, -1837,
+ -1837, -1837, -1837, -1837, -1837, 7210, -1837, 1874, -1837, 1480,
+ 1480, 7783, -1837, 436, 1606, 1967, 893, -1837, 1525, 1525,
+ 1785, 1871, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, 257, 257, 257, -1837, -1837, -1837, -1837,
+ -1837, 416, -1837, -1837, -1837, -1837, -1837, 1873, -1837, -1837,
+ -1837, -1837, -1837, -1837, 1279, -1837, 370, 370, 323, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ 1380, -1837, -1837, -1837, -1837, -1837, 1336, -1837, -1837, -1837,
+ -1837, -1837, 1027, 370, 370, 323, 1110, 1336, -1837, -1837,
+ -1837, 1831, 416, 370, -1837, -1837, -1837, -1837, -1837, -1837,
+ 1603, 1032, 1754, -1837, -1837, -1837, 1880, -1837, 1350, -1837,
+ -1837, -1837, 1618, 812, 1315, -1837, -1837, -1837, -1837, -1837,
+ 1747, 1883, 812, 1884, 1315, -1837, -1837, -1837, -1837, -1837,
+ 1889, 1315, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, 6943, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, 1694, -1837, 288, -1837, -1837,
+ -1837, 154, -1837, -1837, -1837, -1837, -1837, -1837, 1886, 1702,
+ -1837, -1837, 1665, 154, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 7210, 1633, 7783, -1837, -1837, 2106, 6579, -1837, -1837,
+ 1813, 370, 1649, 1650, 1652, 1655, 1657, -1837, -1837, -1837,
+ 1659, 1660, 1661, 1667, 139, 370, -1837, -1837, 1988, 7783,
+ -1837, -1837, -1837, -1837, -1837, 983, -1837, 1766, -1837, 7607,
+ -1837, -1837, -1837, 603, -1837, 301, 370, 370, -1837, -1837,
+ -1837, -1837, -1837, 2027, -1837, 1671, -1837, -1837, 370, 370,
+ -1837, 370, 370, 370, 370, 370, -1837, 1902, 370, -1837,
+ 1674, -1837, -1837, -1837, -1837, -1837, 1942, -1837, -1837, 1555,
+ 1560, 1567, -1837, -1837, -1837, -1837, 1681, 893, -1837, -1837,
+ 1785, -1837, -1837, -1837, -1837, -1837, 1684, 1693, 1697, -1837,
+ -1837, -1837, -1837, -1837, -1837, 168, -1837, -1837, -1837, 1956,
+ -1837, -1837, -1837, -1837, 7783, 370, 2054, 2058, -1837, -1837,
+ -1837, -1837, -1837, -1837, 370, 983, 1964, -1837, -1837, -1837,
+ 1103, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1966,
+ -1837, 1968, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 812, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 1813, 1376, 4714, 4123, 6351, 2117, -1837, -1837, -1837,
+ 1442, 2345, 1557, 1188, 135, -1837, 1551, 1279, -1837, 7783,
+ -1837, -1837, -1837, -1837, -1837, -1837, 1380, -1837, 1971, 1972,
+ -1837, 2065, 171, -1837, 370, -1837, -1837, -1837, -1837, -1837,
+ 370, 370, 370, 370, 370, 1833, 1115, 2111, 370, 370,
+ 370, 370, -1837, -1837, 224, 1720, 1831, -1837, 2063, -1837,
+ -1837, -1837, -1837, 1478, 1968, 370, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 416, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, 370, 370, 370, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_int16 yydefact[] =
+{
+ 2, 0, 1, 0, 4, 5, 0, 0, 0, 0,
+ 432, 432, 432, 432, 432, 432, 432, 432, 436, 439,
+ 432, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 237, 438, 9, 28, 29, 0,
+ 432, 432, 432, 432, 68, 67, 3, 0, 71, 0,
+ 433, 0, 457, 0, 66, 0, 424, 425, 0, 0,
+ 0, 0, 608, 87, 89, 0, 0, 289, 0, 311,
+ 0, 337, 72, 432, 73, 432, 432, 432, 432, 432,
+ 432, 432, 0, 432, 432, 432, 432, 74, 432, 75,
+ 432, 432, 432, 432, 432, 432, 432, 432, 0, 432,
+ 432, 432, 432, 76, 432, 77, 432, 463, 432, 463,
+ 432, 463, 463, 432, 432, 463, 432, 463, 0, 432,
+ 463, 463, 0, 432, 463, 463, 463, 463, 432, 432,
+ 432, 463, 35, 432, 463, 432, 432, 432, 432, 463,
+ 463, 432, 47, 432, 432, 432, 432, 463, 0, 432,
+ 80, 432, 81, 0, 0, 0, 765, 736, 426, 427,
+ 428, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 25, 25,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 949, 950, 951, 952, 953, 954, 955, 956, 957,
+ 958, 959, 960, 961, 962, 963, 964, 965, 966, 967,
+ 968, 970, 0, 972, 971, 0, 0, 0, 0, 34,
+ 0, 0, 85, 732, 731, 737, 738, 252, 748, 749,
+ 742, 940, 743, 746, 750, 747, 744, 745, 739, 1056,
+ 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066,
+ 1067, 1068, 1069, 53, 1074, 1075, 1076, 1077, 1071, 1072,
+ 1073, 740, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329,
+ 741, 0, 249, 250, 0, 33, 233, 0, 21, 235,
+ 432, 432, 432, 432, 432, 432, 432, 432, 0, 432,
+ 432, 432, 432, 16, 238, 39, 239, 437, 434, 435,
+ 432, 432, 432, 13, 861, 834, 836, 70, 69, 440,
+ 442, 0, 0, 0, 459, 458, 460, 0, 598, 0,
+ 716, 717, 718, 0, 931, 932, 933, 500, 501, 936,
+ 723, 0, 0, 0, 516, 522, 527, 0, 551, 576,
+ 588, 589, 665, 671, 692, 0, 0, 976, 0, 7,
+ 92, 465, 467, 481, 468, 61, 272, 496, 477, 504,
+ 475, 13, 514, 14, 59, 525, 473, 474, 46, 579,
+ 40, 0, 54, 60, 596, 40, 664, 40, 670, 18,
+ 24, 487, 45, 690, 493, 0, 494, 479, 0, 722,
+ 478, 767, 770, 772, 774, 776, 777, 784, 786, 0,
+ 785, 729, 503, 940, 482, 488, 480, 739, 497, 62,
+ 0, 0, 65, 451, 0, 0, 0, 91, 445, 0,
+ 95, 304, 303, 0, 448, 0, 0, 0, 608, 112,
+ 114, 289, 0, 311, 337, 432, 432, 432, 13, 861,
+ 834, 836, 0, 60, 0, 136, 137, 138, 0, 130,
+ 131, 139, 0, 132, 133, 141, 142, 0, 134, 135,
+ 0, 143, 0, 145, 146, 838, 839, 837, 432, 13,
+ 36, 44, 51, 0, 60, 203, 464, 205, 170, 171,
+ 172, 173, 432, 174, 176, 200, 199, 198, 192, 432,
+ 463, 196, 195, 197, 838, 839, 840, 432, 0, 13,
+ 432, 177, 432, 180, 432, 183, 432, 189, 36, 44,
+ 51, 432, 186, 78, 220, 432, 432, 464, 216, 218,
+ 215, 222, 0, 223, 13, 432, 208, 207, 432, 213,
+ 211, 44, 79, 224, 225, 226, 227, 230, 432, 229,
+ 0, 1082, 1079, 1080, 56, 0, 756, 757, 758, 759,
+ 760, 762, 0, 981, 983, 0, 982, 52, 0, 0,
+ 1320, 1321, 56, 1084, 1085, 55, 20, 55, 1088, 1089,
+ 1090, 1091, 30, 0, 0, 1094, 1095, 1096, 1097, 1098,
+ 9, 1116, 1117, 1111, 1106, 1107, 1108, 1109, 1110, 1112,
+ 1113, 1114, 1115, 0, 28, 55, 1131, 1130, 1129, 1132,
+ 1133, 1134, 31, 55, 1137, 1138, 1139, 32, 1148, 1149,
+ 1141, 1142, 1143, 1145, 1144, 1146, 1147, 29, 1160, 55,
+ 1156, 1153, 1152, 1157, 1155, 1154, 1158, 1159, 31, 1163,
+ 1166, 1162, 1164, 1165, 8, 1169, 1168, 19, 1171, 1172,
+ 1173, 11, 1177, 1178, 1175, 1176, 57, 1183, 1180, 1181,
+ 1182, 58, 1230, 1224, 1227, 1228, 1222, 1223, 1225, 1226,
+ 1229, 1231, 0, 1184, 55, 1264, 1265, 0, 15, 1210,
+ 1209, 1202, 1203, 1204, 1188, 1189, 1190, 1191, 1192, 1193,
+ 1194, 1195, 1196, 1197, 53, 1206, 1205, 1208, 1207, 1199,
+ 1200, 1201, 1217, 1219, 1218, 0, 25, 0, 1214, 1213,
+ 1212, 1211, 1318, 1315, 1316, 0, 1317, 49, 55, 28,
+ 1335, 1008, 29, 1334, 1337, 1006, 1007, 34, 0, 48,
+ 48, 0, 48, 1341, 48, 1344, 1343, 1345, 0, 48,
+ 1332, 1331, 27, 1353, 1350, 1348, 1349, 1351, 1352, 23,
+ 1356, 1355, 17, 55, 1359, 1362, 1358, 1361, 38, 37,
+ 944, 945, 946, 51, 947, 34, 37, 942, 943, 1023,
+ 1024, 1030, 1016, 1017, 1015, 1025, 1026, 1046, 1019, 1028,
+ 1021, 1022, 1027, 1018, 1020, 1013, 1014, 1044, 1043, 1045,
+ 51, 0, 12, 1031, 987, 986, 0, 784, 0, 0,
+ 48, 27, 23, 17, 38, 1363, 991, 992, 969, 990,
+ 0, 730, 1070, 232, 251, 82, 234, 83, 60, 154,
+ 155, 132, 156, 157, 0, 158, 160, 161, 432, 13,
+ 36, 44, 51, 86, 84, 240, 241, 243, 242, 245,
+ 246, 244, 247, 858, 858, 858, 97, 0, 0, 551,
+ 0, 454, 455, 456, 0, 0, 0, 0, 0, 938,
+ 937, 934, 935, 0, 0, 0, 37, 37, 0, 0,
+ 0, 0, 12, 0, 0, 0, 560, 0, 549, 550,
+ 0, 0, 0, 0, 0, 0, 0, 6, 0, 0,
+ 788, 0, 466, 469, 498, 0, 472, 0, 0, 515,
+ 518, 476, 483, 0, 0, 0, 0, 0, 0, 526,
+ 528, 484, 0, 575, 485, 0, 47, 16, 0, 0,
+ 20, 30, 9, 28, 899, 29, 0, 904, 902, 903,
+ 14, 0, 40, 40, 889, 890, 0, 626, 629, 631,
+ 633, 635, 636, 641, 646, 644, 645, 647, 649, 587,
+ 613, 614, 624, 891, 615, 622, 616, 623, 619, 620,
+ 0, 617, 618, 0, 648, 621, 486, 495, 0, 0,
+ 605, 604, 597, 600, 489, 0, 683, 684, 685, 663,
+ 668, 681, 490, 0, 669, 674, 491, 492, 686, 0,
+ 708, 709, 691, 693, 696, 706, 0, 734, 0, 733,
+ 0, 0, 724, 0, 0, 0, 0, 0, 0, 0,
+ 0, 924, 925, 926, 927, 928, 929, 930, 20, 30,
+ 9, 28, 31, 916, 29, 31, 8, 19, 11, 57,
+ 58, 53, 15, 25, 49, 40, 0, 906, 874, 907,
+ 781, 782, 886, 873, 863, 862, 878, 880, 882, 884,
+ 885, 872, 908, 909, 875, 0, 0, 0, 0, 7,
+ 0, 828, 827, 885, 0, 0, 393, 60, 256, 273,
+ 290, 319, 338, 461, 111, 0, 0, 0, 0, 118,
+ 0, 0, 858, 858, 858, 120, 0, 0, 551, 0,
+ 129, 153, 0, 0, 0, 0, 0, 144, 0, 0,
+ 858, 148, 151, 149, 152, 169, 191, 0, 206, 175,
+ 194, 193, 12, 432, 179, 178, 181, 184, 190, 185,
+ 182, 188, 187, 217, 219, 221, 210, 209, 212, 214,
+ 228, 231, 1081, 0, 0, 55, 753, 754, 22, 0,
+ 979, 766, 42, 42, 1319, 1086, 1083, 1092, 1087, 20,
+ 28, 20, 28, 1093, 1118, 1119, 1120, 1121, 28, 1103,
+ 1128, 1127, 1136, 1135, 1140, 1151, 1150, 1161, 1167, 1170,
+ 1174, 1179, 10, 1248, 1254, 1252, 1243, 1244, 1247, 1249,
+ 1238, 1239, 1240, 1241, 1242, 1250, 1245, 1246, 1251, 1186,
+ 1253, 1185, 1266, 15, 1262, 1198, 1216, 1215, 1220, 1270,
+ 1267, 1268, 1269, 1271, 1272, 1273, 1274, 1275, 1276, 1277,
+ 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1301, 50, 1313,
+ 1336, 1002, 1003, 1009, 48, 1004, 1333, 0, 1338, 1340,
+ 0, 1342, 1330, 1347, 1354, 1360, 1357, 941, 948, 939,
+ 1029, 1032, 1033, 0, 1035, 0, 1034, 1036, 1037, 12,
+ 12, 1038, 1010, 0, 0, 984, 1365, 1364, 1366, 1367,
+ 1368, 0, 0, 751, 168, 159, 0, 858, 163, 166,
+ 164, 167, 236, 248, 0, 0, 0, 0, 358, 13,
+ 560, 383, 36, 363, 0, 44, 388, 835, 51, 0,
+ 28, 29, 590, 0, 599, 0, 710, 712, 0, 0,
+ 0, 0, 0, 0, 0, 0, 12, 0, 0, 1038,
+ 0, 517, 429, 523, 524, 36, 558, 559, 0, 44,
+ 0, 0, 705, 45, 700, 699, 0, 704, 702, 703,
+ 0, 677, 679, 0, 499, 800, 7, 7, 802, 797,
+ 799, 885, 824, 7, 787, 462, 282, 520, 521, 519,
+ 541, 20, 0, 0, 539, 535, 530, 531, 532, 533,
+ 536, 534, 529, 0, 0, 53, 0, 655, 900, 901,
+ 0, 650, 0, 892, 895, 896, 893, 894, 905, 0,
+ 898, 897, 0, 613, 622, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 657, 0, 0, 0, 0,
+ 0, 0, 602, 603, 601, 0, 0, 0, 672, 695,
+ 700, 699, 694, 0, 10, 0, 726, 0, 725, 768,
+ 769, 771, 773, 775, 778, 7, 505, 507, 783, 893,
+ 915, 894, 917, 914, 913, 919, 911, 912, 910, 920,
+ 918, 921, 922, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 869, 868, 885, 974, 1055,
+ 830, 829, 63, 0, 64, 0, 0, 109, 0, 0,
+ 0, 0, 0, 60, 256, 273, 290, 319, 338, 0,
+ 0, 0, 13, 36, 44, 51, 452, 441, 443, 273,
+ 446, 449, 338, 12, 204, 201, 12, 0, 761, 755,
+ 752, 52, 763, 764, 1099, 1101, 1100, 1102, 55, 1123,
+ 1125, 1124, 1126, 1105, 28, 0, 1260, 1232, 1257, 1234,
+ 1261, 1237, 1258, 1259, 1235, 1255, 1256, 1233, 1236, 1263,
+ 1298, 1297, 1299, 1300, 1306, 1288, 1289, 1290, 1291, 1303,
+ 1292, 1293, 1294, 1295, 1296, 1304, 1305, 1307, 1308, 1309,
+ 1310, 1311, 1312, 55, 1287, 1286, 1302, 49, 1005, 0,
+ 0, 28, 28, 29, 29, 1011, 1012, 984, 984, 0,
+ 26, 989, 993, 994, 34, 0, 338, 12, 373, 378,
+ 368, 0, 0, 98, 0, 0, 105, 0, 0, 100,
+ 0, 107, 592, 0, 0, 591, 713, 0, 0, 807,
+ 711, 803, 1248, 1252, 1247, 1251, 1253, 53, 10, 10,
+ 0, 796, 0, 794, 37, 37, 12, 512, 12, 12,
+ 0, 12, 548, 0, 561, 564, 0, 557, 553, 552,
+ 554, 0, 687, 0, 0, 0, 0, 791, 0, 792,
+ 0, 13, 0, 0, 551, 801, 810, 0, 0, 823,
+ 798, 808, 790, 789, 0, 540, 28, 544, 545, 53,
+ 543, 577, 0, 581, 578, 0, 583, 0, 0, 585,
+ 656, 0, 660, 662, 625, 627, 628, 630, 632, 634,
+ 642, 643, 637, 640, 639, 638, 652, 651, 0, 0,
+ 0, 1047, 1048, 1049, 1050, 666, 682, 673, 675, 707,
+ 735, 0, 0, 0, 0, 508, 923, 871, 865, 0,
+ 876, 877, 879, 881, 883, 870, 779, 864, 780, 887,
+ 888, 0, 0, 779, 0, 0, 60, 395, 394, 397,
+ 396, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 88, 258, 257, 0, 255, 0, 0, 55,
+ 0, 90, 275, 274, 0, 0, 0, 0, 0, 0,
+ 300, 0, 0, 0, 0, 0, 0, 0, 0, 93,
+ 292, 291, 0, 0, 0, 470, 0, 0, 0, 0,
+ 0, 0, 94, 321, 320, 0, 0, 0, 0, 0,
+ 0, 13, 96, 340, 339, 128, 0, 0, 0, 0,
+ 0, 373, 378, 368, 121, 126, 122, 127, 0, 0,
+ 150, 202, 0, 980, 1122, 1104, 0, 1285, 1314, 1339,
+ 1346, 1039, 1040, 1041, 1042, 41, 0, 26, 985, 1001,
+ 997, 996, 995, 34, 0, 165, 0, 0, 0, 0,
+ 13, 360, 359, 362, 361, 561, 564, 36, 385, 384,
+ 387, 386, 44, 365, 364, 367, 366, 554, 51, 390,
+ 389, 392, 391, 593, 595, 0, 805, 806, 804, 1221,
+ 978, 977, 0, 0, 795, 975, 973, 1052, 513, 1053,
+ 12, 1051, 0, 566, 568, 0, 36, 0, 36, 0,
+ 0, 44, 701, 697, 698, 45, 45, 678, 0, 0,
+ 0, 7, 825, 826, 0, 0, 812, 0, 560, 0,
+ 811, 821, 822, 809, 502, 283, 0, 538, 0, 537,
+ 55, 55, 47, 55, 653, 0, 659, 0, 661, 667,
+ 676, 0, 714, 0, 0, 0, 7, 506, 867, 866,
+ 609, 0, 110, 453, 357, 444, 272, 447, 289, 311,
+ 450, 337, 254, 0, 0, 0, 357, 357, 357, 357,
+ 259, 0, 422, 423, 43, 421, 420, 0, 418, 276,
+ 278, 277, 281, 279, 0, 287, 0, 0, 0, 336,
+ 335, 43, 334, 398, 400, 401, 399, 354, 402, 355,
+ 0, 353, 307, 308, 310, 309, 0, 306, 301, 302,
+ 298, 471, 0, 0, 0, 0, 0, 0, 332, 331,
+ 329, 0, 0, 0, 343, 113, 115, 116, 117, 119,
+ 0, 0, 0, 140, 147, 10, 0, 988, 984, 1000,
+ 998, 162, 0, 0, 0, 12, 375, 374, 377, 376,
+ 0, 0, 0, 0, 0, 12, 380, 379, 382, 381,
+ 0, 0, 12, 370, 369, 372, 371, 831, 99, 859,
+ 860, 106, 101, 833, 108, 594, 0, 727, 1054, 570,
+ 571, 572, 573, 574, 563, 0, 546, 0, 565, 547,
+ 567, 0, 556, 688, 689, 680, 793, 12, 0, 0,
+ 14, 14, 0, 0, 284, 542, 31, 31, 586, 584,
+ 654, 0, 0, 0, 715, 721, 0, 510, 509, 610,
+ 611, 0, 0, 0, 0, 0, 0, 357, 357, 357,
+ 0, 0, 0, 0, 0, 0, 346, 419, 0, 0,
+ 294, 296, 297, 299, 333, 0, 55, 0, 295, 0,
+ 322, 323, 330, 318, 328, 0, 0, 0, 344, 12,
+ 12, 12, 1078, 0, 26, 0, 57, 53, 0, 0,
+ 103, 0, 0, 0, 0, 0, 104, 0, 0, 102,
+ 0, 562, 569, 555, 816, 12, 0, 819, 820, 561,
+ 564, 554, 580, 582, 658, 719, 0, 7, 612, 606,
+ 609, 393, 273, 290, 319, 338, 0, 0, 0, 358,
+ 383, 363, 388, 351, 350, 0, 347, 352, 280, 0,
+ 288, 356, 293, 305, 0, 0, 0, 285, 60, 317,
+ 13, 36, 44, 51, 0, 0, 0, 412, 406, 405,
+ 409, 404, 407, 408, 341, 342, 124, 125, 123, 0,
+ 999, 0, 844, 843, 850, 852, 855, 856, 853, 854,
+ 857, 0, 846, 728, 817, 13, 36, 36, 44, 720,
+ 511, 611, 0, 0, 0, 0, 0, 373, 378, 368,
+ 0, 0, 0, 0, 7, 345, 417, 0, 325, 0,
+ 316, 312, 314, 313, 315, 55, 0, 413, 0, 0,
+ 1187, 0, 0, 847, 0, 813, 814, 815, 818, 607,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 349, 348, 0, 0, 0, 326, 286, 327,
+ 55, 411, 410, 0, 0, 0, 55, 60, 260, 261,
+ 262, 263, 12, 12, 12, 13, 36, 44, 51, 414,
+ 415, 0, 403, 324, 430, 431, 849, 848, 43, 845,
+ 271, 0, 0, 0, 264, 269, 265, 270, 416, 851,
+ 267, 268, 266
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -1837, -1837, -1, -1275, 1070, 54, -1321, 1067, 1068, -352,
+ -898, -718, 1182, 1297, -1837, 1074, -519, -1837, -1837, 1301,
+ -1837, -140, -1625, 1304, -8, -14, 1526, -601, -1837, -1837,
+ -687, -1837, -493, -724, 1305, -1837, -305, -1837, 964, -1828,
+ -489, -1233, -1837, -875, -492, -919, -1837, -497, 610, -659,
+ -1837, -546, 1544, -982, 1089, -1837, -399, -1837, 16, -1837,
+ -1837, 2084, -1837, -1837, -1837, 1832, 1834, 595, 1069, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, 11, -1837, 1691, -1837, 660, -330,
+ -1384, -1837, -1837, -1624, -424, -1406, -420, 354, 1, -423,
+ -1837, -1837, -1417, -1416, -1837, -429, -1413, -1836, -1837, -138,
+ 2, -1639, -685, -59, -60, -1671, -1667, -1664, -57, -58,
+ -40, -1837, -1837, -164, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 175, -773, -1477, -1837, 340, -33, 3359, -1837,
+ 309, -1837, -1837, 780, -1837, 425, 792, 1868, -1837, 211,
+ -1837, -722, 1733, -1837, -1837, 268, 700, 758, 834, -42,
+ -1837, -1837, -1420, -1398, -346, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, 230, -1837, -1837, -1837, -1837, 1273, -1837, -1837,
+ -1837, -1837, 1261, -1837, -1837, -1837, 255, -1837, -320, -1428,
+ -1649, -1837, -1193, -1690, -1475, -1681, -1470, 287, 286, -1837,
+ -1837, -1047, -1837, -1837, -1837, -1837, -1837, -1837, -1837, 1204,
+ -353, 1740, -9, -79, 25, 797, 798, 796, -1837, -806,
+ -1837, -1837, -1837, -1837, -1837, -1837, 1744, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -350, 783, -1837, -1837,
+ -1837, -1837, 1198, 560, -913, 573, 1321, 799, -1340, -1837,
+ -1837, 1864, -1837, -1837, -1837, -1837, 1208, -1837, -1837, -67,
+ 246, -851, -349, 1084, -27, -1837, -1837, -1837, 1071, 3,
+ -1837, -1837, -1837, -1837, -1837, -182, -208, -1837, -1837, 759,
+ -823, 1985, -52, -1837, 872, -1277, -1837, -1555, -1837, -1837,
+ 609, -1395, -1837, -1837, 585, 583, -1837, -1837, 1811, -604,
+ 1786, -552, 1789, -540, 1793, 170, -1837, -1753, -1837, -1837,
+ -88, -1837, -1837, -622, -516, 1788, -1837, -385, -328, -854,
+ -844, -840, -1837, -284, -859, -1837, 1322, 1538, -759, -1837,
+ -1509, -324, 128, 1898, -1837, 32, -1837, 155, -1837, -1422,
+ -1837, 307, -1837, -1837, -1837, -1837, -1837, 571, -282, 947,
+ 1517, 1039, 1903, 1905, -1837, -1837, -478, 207, -1837, -1837,
+ -1837, 1109, -1837, -1837, -68, -1837, -48, -1837, -43, -1837,
+ -64, -1837, -1837, -1837, -31, -1837, -26, -1837, -21, -1837,
+ -13, -1837, -12, -1837, -6, -1837, 0, -1837, 9, -1837,
+ 19, -1837, 24, 1545, -1837, -84, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, 1579, -1061, -1837, -1837,
+ -1837, -1837, -1837, 29, -1837, -1837, -1837, -1837, 1051, -1837,
+ -1837, 30, -1837, 34, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837, -1837,
+ -1837, -1837, -1837, -1837
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ 0, 1, 1783, 878, 1157, 1365, 1505, 1159, 1242, 836,
+ 891, 1184, 823, 1224, 976, 1158, 1363, 807, 1490, 1223,
+ 977, 695, 1819, 1222, 1419, 1421, 1364, 1151, 1153, 805,
+ 798, 513, 1092, 1227, 1226, 824, 904, 2017, 1492, 2117,
+ 1093, 978, 901, 532, 1215, 1209, 1547, 1094, 1130, 802,
+ 956, 1135, 1122, 1160, 1161, 892, 957, 884, 1784, 46,
+ 47, 48, 74, 87, 89, 447, 451, 456, 443, 103,
+ 293, 105, 132, 1098, 475, 142, 150, 152, 275, 278,
+ 295, 296, 832, 1262, 276, 222, 415, 1735, 1458, 416,
+ 1459, 1644, 2205, 1964, 419, 1460, 420, 1986, 1987, 423,
+ 2214, 2215, 1461, 1762, 1971, 425, 1462, 2115, 2195, 2196,
+ 1979, 1980, 2102, 1572, 1577, 1828, 1826, 1827, 1575, 1580,
+ 1456, 1981, 1744, 2136, 2220, 2221, 2222, 2306, 1745, 1746,
+ 1954, 1955, 1933, 223, 1304, 2336, 49, 50, 61, 450,
+ 52, 454, 1936, 458, 459, 1938, 71, 464, 1941, 445,
+ 446, 1934, 314, 315, 316, 53, 427, 1589, 477, 1748,
+ 351, 352, 1764, 353, 354, 355, 356, 357, 358, 359,
+ 1416, 1694, 1695, 360, 361, 362, 889, 890, 363, 364,
+ 365, 899, 900, 1351, 1345, 1649, 1650, 366, 1274, 1620,
+ 1881, 367, 1308, 1876, 1614, 1878, 1615, 1616, 2064, 368,
+ 369, 1653, 903, 370, 371, 372, 373, 374, 962, 963,
+ 1720, 414, 2100, 2179, 927, 928, 929, 930, 931, 932,
+ 933, 1673, 934, 935, 936, 937, 938, 939, 375, 376,
+ 969, 377, 378, 974, 379, 380, 970, 971, 381, 382,
+ 383, 982, 983, 1311, 1312, 1313, 984, 985, 1285, 1286,
+ 384, 385, 386, 387, 388, 991, 992, 389, 390, 224,
+ 940, 988, 1028, 941, 391, 228, 1128, 551, 552, 942,
+ 559, 392, 393, 394, 395, 396, 397, 1030, 1031, 1032,
+ 398, 399, 400, 879, 880, 1602, 1603, 1327, 1328, 1329,
+ 1590, 1591, 1640, 1635, 1636, 1641, 1330, 1891, 1050, 1834,
+ 837, 1846, 839, 1852, 840, 468, 498, 2148, 2046, 2282,
+ 2283, 2029, 2039, 1264, 1841, 838, 401, 1051, 1052, 1036,
+ 1037, 1038, 1039, 1331, 1041, 943, 944, 945, 1044, 1045,
+ 402, 851, 946, 756, 757, 231, 404, 947, 557, 1560,
+ 786, 948, 1252, 799, 1564, 1823, 234, 949, 718, 951,
+ 719, 952, 781, 782, 1239, 1240, 783, 953, 954, 405,
+ 406, 955, 239, 545, 240, 566, 241, 572, 242, 580,
+ 243, 594, 1148, 1504, 244, 602, 245, 607, 246, 617,
+ 247, 628, 248, 634, 249, 637, 250, 641, 251, 646,
+ 252, 651, 253, 685, 686, 687, 254, 688, 255, 701,
+ 256, 696, 257, 408, 663, 1179, 1596, 1181, 1517, 1509,
+ 1514, 1507, 1511, 258, 668, 1207, 1546, 1529, 1535, 1524,
+ 1208, 259, 707, 260, 562, 261, 262, 732, 263, 720,
+ 264, 722, 265, 724, 266, 729, 267, 739, 268, 742,
+ 269, 748, 270, 795
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int16 yytable[] =
+{
+ 44, 421, 54, 227, 852, 1071, 883, 1068, 787, 886,
+ 1070, 350, 1069, 1111, 1034, 1109, 422, 45, 870, 1332,
+ 1110, 1137, 1368, 417, 299, 1185, 885, 1156, 975, 298,
+ 1213, 1358, 1229, 229, 1089, 845, 989, 1426, 800, 697,
+ 1087, 1777, 1119, 279, 1081, 1775, 308, 1136, 1317, 1150,
+ 1789, 1627, 1629, 1095, 409, 1790, 229, 1152, 1642, 412,
+ 1788, 1057, 1765, 1765, 875, 1691, 1399, 1277, 229, 1799,
+ 964, 1035, 972, 1155, 476, 1096, 476, 1574, 476, 476,
+ 1622, 1787, 476, 1690, 476, 403, 1075, 476, 476, 950,
+ 297, 476, 476, 476, 476, 1798, 700, 403, 476, 1835,
+ 1067, 517, 1115, 1324, 1836, 1431, 517, 517, 1335, 671,
+ 1856, 1857, 671, 674, 476, 1040, 674, 1091, 1182, 1893,
+ 1372, 1346, 2012, 1085, 2010, 1350, 1053, 1053, 2011, 672,
+ 1692, 1996, 672, 1229, 673, 1815, 1817, 673, 1925, 877,
+ 1693, 1411, 1992, 2124, 986, 2049, 675, 1104, 1417, 675,
+ 1847, 676, 1412, 1824, 676, 2050, 677, 1413, 230, 677,
+ 1901, 1902, 1210, 877, 678, 679, 2137, 678, 679, 986,
+ 1333, 680, 1116, 1926, 680, 2264, 1132, 681, 2314, 1291,
+ 681, 230, 58, 59, 60, 232, 682, 1952, 1953, 682,
+ 1403, 311, 2019, 230, 1055, 1858, 683, 1225, 2053, 683,
+ 986, 684, 990, 494, 684, 157, 689, 690, 232, 689,
+ 690, 691, 1265, 1266, 691, 158, 159, 160, 1302, 229,
+ 232, 62, 758, 229, 309, 55, 310, 1597, 1216, 1296,
+ 1218, 56, 1219, 1269, 1409, 1410, 413, 1221, -736, 2193,
+ 2194, 418, 1921, 2193, 2194, 424, -736, -736, -736, -736,
+ -832, 303, 304, 305, 306, -731, 1228, 271, 1618, 871,
+ 850, 850, -731, -731, -731, -731, 277, 635, 1623, -697,
+ 998, 1923, 1353, 1872, 1966, 1967, 225, 1860, 1861, 2153,
+ 104, 65, 803, 1230, 636, 1354, 428, 1275, 806, 1302,
+ 1993, 1994, 497, 1765, 438, 439, 440, 441, 1246, 225,
+ 1278, -731, 1355, 1241, 1429, -738, 1277, 1656, 4, 1659,
+ 5, 225, -738, -738, -738, -738, 1000, 474, 987, -698,
+ -832, 64, 1272, 2216, 1270, 1261, 965, 1259, 158, 159,
+ 160, 1082, 1260, 1267, 499, 1382, 784, 233, 872, 508,
+ 509, 510, 1133, 1714, 230, 73, 785, 1033, 230, 524,
+ 1587, -738, 531, 1588, 2077, 229, 442, 1873, 1033, 1033,
+ 233, 56, 1428, 730, 758, 421, 1991, 1637, 88, 1777,
+ 1638, 232, 233, 1775, 4, 232, 5, 1271, 56, 1991,
+ 422, 1383, 426, 1299, 403, 1064, 430, 1256, 731, 865,
+ 1765, 1765, 2162, 421, 1255, 151, 801, 495, 709, 467,
+ 1080, 453, 426, 1268, 2217, 2218, 421, 866, 422, 1254,
+ 3, 1420, 1303, 4, 1422, 5, 496, 853, -746, 480,
+ 2081, 422, 712, 740, 57, -746, -746, -746, -746, 294,
+ 229, 448, -433, 1562, 1586, 6, 7, 8, 9, 1297,
+ 1083, 2093, 426, 519, 1806, 229, 1292, 1055, 741, 1619,
+ 1469, 1470, 1471, 534, 854, 421, 1356, 476, 818, 403,
+ 540, 1380, 225, 1381, -746, 1519, 225, 1258, 1483, 1858,
+ 422, 221, 1472, 3, 403, 1276, 4, 221, 5, 2246,
+ 230, 312, 313, 2080, -747, 1415, -253, 56, 2284, 2247,
+ 221, -747, -747, -747, -747, 2348, 221, 1084, 6, 7,
+ 8, 9, 849, 849, 221, 2206, 855, 232, 221, 973,
+ 2349, 833, 834, 835, 1758, 221, 1598, 1599, 1624, 2230,
+ 1056, 1407, 2248, 233, 1451, 1991, 1474, 233, 1334, 334,
+ -747, 1927, 1674, 2265, 335, 4, 2315, 5, 538, 1475,
+ 3, 349, 1925, 4, 56, 5, 221, 337, 1874, 272,
+ 273, 274, 338, 2151, 57, 230, 1187, 1086, 272, 273,
+ 274, 1473, 2030, 1088, 2078, 6, 7, 8, 9, 2031,
+ 230, 57, 966, 967, 968, 1671, 2276, 489, 490, 1489,
+ 2267, 2092, 232, 1874, 1702, 2056, 1149, 2177, 2297, 1385,
+ 2295, 811, 426, 221, 2296, 1703, 2144, 232, 225, -736,
+ 1704, 235, 1922, 1154, 56, 1910, 2032, 2169, 1911, 881,
+ 56, 1913, 2170, 1188, -272, -731, 2076, 1370, 1371, 413,
+ 1494, 448, 1496, 309, 235, -433, 881, 310, 1808, 671,
+ 1563, 674, 418, 674, 1143, 1567, 235, 424, 410, 1287,
+ 2208, 2033, -551, 2163, 411, 1027, 1072, 1073, 1074, 672,
+ 989, 2097, 2073, 2074, 673, 2171, 1027, 1027, 1457, 233,
+ 1445, 558, 2219, 1316, 675, -738, 675, 300, 435, 676,
+ 221, 676, 1418, 225, 677, 721, 677, 1700, 1701, 1090,
+ 57, 723, 678, 679, 678, 679, 1543, 349, 225, 680,
+ 2209, 680, 221, 310, 2142, 681, 1657, 681, 1212, 789,
+ 711, 1211, 465, 1544, 682, 2082, 682, 1386, 1102, 1387,
+ 1434, 1886, 1463, 1758, 683, 1121, 683, 1446, 804, 684,
+ 1432, 684, 1548, 1435, 689, 690, 689, 690, 334, 691,
+ 521, 691, 523, 335, 233, 1647, 1545, 57, 3, 841,
+ 1648, 4, 1433, 5, 546, 547, 337, 421, 1943, 233,
+ 2034, 338, -1002, 2176, -1002, 966, 967, 968, 881, 846,
+ 998, 1447, 422, 6, 7, 8, 9, 2255, 842, 1892,
+ 1125, 603, 2256, 515, 1716, 516, 999, 2254, -746, 1576,
+ 2114, 1581, 843, 1332, 1139, 221, 1579, 235, 18, 19,
+ 709, 235, 604, 455, 67, 68, 69, 57, 2253, 1140,
+ 1317, 2094, 1434, 57, 1314, 605, 1000, 1277, 1758, 1141,
+ 711, -1003, 1612, -1003, 712, 1711, 1414, 553, 554, 555,
+ 1617, 881, 1645, 334, 1142, 1114, 1326, 848, 335, 715,
+ 716, 2022, -432, 514, 1332, 1777, 2335, 2035, 35, 1775,
+ 863, 337, 3, 1263, -747, 4, 338, 5, 36, 1453,
+ 229, 1443, 868, 869, 37, 873, 1765, 1765, 431, 432,
+ 433, 301, 436, 302, 437, 1388, 864, 6, 7, 8,
+ 9, 2023, 876, 434, 229, 460, 461, 1820, 38, 813,
+ 1865, 1866, 1778, 1430, 473, 1779, 548, 549, 881, 463,
+ 550, 958, 959, 484, 485, 2210, 466, 877, 467, 491,
+ 692, 1367, 2250, 990, 1842, 1366, 844, 693, 487, 1441,
+ -1002, 717, 1400, 2211, 1126, 1127, 522, 1573, 2212, 881,
+ 2213, 902, 1442, 235, 1443, 535, 536, 1389, 995, 539,
+ 133, 134, 987, 135, 136, 137, 989, 694, 1859, 715,
+ 716, 996, 1944, 479, 1945, 481, 483, 709, 1033, 486,
+ 997, 488, 1804, 702, 492, 493, 560, 561, 501, 503,
+ 505, 507, 1340, 606, 725, 512, 796, 797, 520, -1003,
+ 1565, 712, -1002, 527, 530, 230, -832, 236, 1797, 2146,
+ 1795, 537, 874, 812, 2147, 1796, 703, 704, 1046, 2302,
+ 1909, 3, 1047, 1033, 4, 1341, 5, 1807, 235, 230,
+ 236, 229, 232, 868, 869, 1780, 1946, 1947, 1948, 1949,
+ 1342, 1559, 236, 235, 1816, 2024, 6, 7, 8, 9,
+ 311, 717, 705, 709, 307, -432, 232, 664, 4, 1257,
+ 5, -1003, 2129, 3, 989, 2119, 4, 2088, 5, 556,
+ 960, 1058, 867, 961, 726, 727, 728, 712, 1688, 1452,
+ 1698, 887, 888, 1454, 1273, 706, 1343, 1707, 6, 7,
+ 8, 9, 868, 869, 1785, 814, 815, 320, 321, 237,
+ 642, 1059, 322, 3, 643, 1060, 4, 638, 5, 816,
+ 1061, 665, 666, 893, 1601, 1062, 881, 1973, 639, 640,
+ 667, 708, 237, 225, 158, 159, 160, -337, 6, 7,
+ 8, 9, 2025, 709, 237, 710, 1097, 644, 645, 882,
+ 993, 994, 1974, 1975, 226, 2133, 3, 225, 2125, 4,
+ 1794, 5, 2030, 711, 1027, 2278, 230, 712, 2279, 2031,
+ 713, -841, 1495, 1781, 1497, -842, 2020, 226, 1103, 238,
+ 1503, 6, 7, 8, 9, 1344, 563, 564, 565, 226,
+ 1697, 1699, 1123, 232, 233, 1306, 1307, 1705, 1699, 1708,
+ 1710, 1404, 407, 236, 2232, 1406, 2032, 236, 469, 470,
+ 471, 472, 1373, 138, 407, 1441, 157, 1651, 1318, 1124,
+ 139, 140, 2167, 2168, 1129, 1441, 2040, 1652, 1453, 3,
+ 1443, 1131, 4, 1957, 5, 1183, 141, 1287, 1712, 1601,
+ 1443, 2033, 980, 981, 3, 2030, 1782, 4, 3, 5,
+ 1217, 4, 2031, 5, 6, 7, 8, 9, 987, 714,
+ 1220, 2107, 2108, 2109, 894, 895, 896, 897, 898, 6,
+ 7, 8, 9, 6, 7, 8, 9, 1976, 1332, 1027,
+ 1027, 1027, 1027, 1027, 225, 595, 1027, 596, 1778, 2032,
+ 1243, 1779, 715, 716, 1244, 237, 1863, 1977, 1978, 237,
+ 1245, 2110, 2111, 2112, 2113, 733, 597, 157, 1651, 1100,
+ 1375, 1376, 1027, 525, 598, 599, 600, 601, 1655, 1896,
+ 1251, 734, 528, 4, 2033, 5, 647, 2119, 18, 19,
+ 1498, 1027, 158, 159, 160, 229, 1253, 18, 19, 236,
+ 226, 1283, 735, 1288, 226, 233, 1289, 1499, 1290, 736,
+ 2034, 1293, 1500, 1501, 1899, 1294, 987, 1932, 1120, 648,
+ 649, 1295, 650, 1298, 1101, 238, 1928, 1929, 1300, 238,
+ 1310, 1675, -432, 1323, 717, 1919, 1336, 1920, 35, 881,
+ 4, -432, 5, 2127, 2051, 1337, 1924, 35, 36, 808,
+ 2041, 2054, 1338, 2052, 37, 1848, 1347, 36, 819, 820,
+ 821, 822, 1362, 37, 2086, 2087, 1369, 2089, 157, 1651,
+ 1348, 1780, 1436, 1437, 236, 18, 19, 3, 38, 1658,
+ 4, 881, 5, 2066, 4, 2069, 5, 38, 2125, 236,
+ 1520, 237, 2072, 2034, 1521, 1522, 1523, 2140, 737, 738,
+ 1665, 1666, 6, 7, 8, 9, 1349, 1672, 229, 1377,
+ 229, 1630, 868, 869, 1055, 1316, 1378, 482, 235, 1502,
+ 230, 881, 2186, 2187, 2188, 35, 1631, 1699, 1699, 2004,
+ 1379, 1632, 18, 19, 1384, 36, 226, 2042, 272, 273,
+ 274, 37, 1319, 3, 1633, -1047, 4, 232, 5, 1634,
+ 1144, 1145, 1146, 1147, 1715, 1717, -1048, 1733, 1742, 1760,
+ 1773, 407, 229, 1390, 881, 38, 237, 1391, 6, 7,
+ 8, 9, 1718, 1392, 1734, 1743, 1761, 1774, 2048, 1395,
+ 2323, 237, 35, 1029, 1393, 2172, 2173, 1396, 2233, 1405,
+ 1277, 403, 36, 1403, 1029, 1029, 1805, 1267, 37, 1781,
+ 1512, 1513, 3, 1515, 1516, 4, 1438, 5, 1551, 1552,
+ 790, 226, 2106, 1439, 2104, 1440, 2105, 1553, 1554, 791,
+ 792, 1444, 38, 793, 794, -432, 226, 6, 7, 8,
+ 9, 2329, 1434, 230, -432, 230, 407, 881, 225, 1813,
+ 1814, 1055, 1778, 1811, 1812, 1779, 877, 1628, 2123, 1821,
+ 1822, 407, 881, 2301, 1883, 1450, 1314, 1400, 3, 1464,
+ 232, 4, 232, 5, 157, 1651, 852, 1455, 1830, 235,
+ 1465, 1831, 2009, 1466, 1838, 2132, 1843, 1969, 1970, 1849,
+ 2202, 2334, 1302, 6, 7, 8, 9, 230, 1832, 1467,
+ 1326, 1839, 1267, 1844, 2304, 2305, 1850, 1683, 1684, 233,
+ 90, 1270, 1906, 1468, 3, 229, 2103, 4, 91, 5,
+ 92, 1476, 93, 1477, 232, 94, 95, 96, 1478, 97,
+ 1479, 1373, 1373, 1373, 1373, 1373, 229, 1373, 1373, 6,
+ 7, 8, 9, 1480, 403, 1481, 1681, 1681, 1907, 143,
+ 1484, 144, 1482, 1905, 1487, 1506, 145, 229, 146, 1491,
+ 1508, 225, 147, 225, 1601, 1518, 1537, 825, 1510, 826,
+ -551, 827, 828, 541, 1538, 1780, 542, 543, 544, 829,
+ 830, 1956, 1541, 1539, 3, 1540, 403, 4, 1542, 5,
+ 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 1027,
+ 1027, 1549, 148, 1559, 149, 229, 1550, 2022, 1557, 6,
+ 7, 8, 9, 831, 567, 225, 568, 569, 570, 571,
+ 2160, 1558, 233, 1287, 233, 1561, 2274, 1566, 2272, 1568,
+ 1569, 1042, 1965, 2273, 403, 881, 979, 980, 981, 2309,
+ 230, 1570, 1042, 1042, 1950, 1571, 1267, 2023, 1578, 1965,
+ 1583, 2290, 998, 1959, 1960, 1961, 1962, 1963, 158, 159,
+ 160, 230, 229, 2286, 2287, 3, 1600, 232, 4, 2288,
+ 5, 1988, 1989, 1990, 2333, 1608, 233, 1610, 1613, 229,
+ 2339, 1621, 230, 1625, 1998, 1999, 2000, 1646, 232, 1661,
+ 6, 7, 8, 9, 1664, 1733, 1742, 1760, 1773, 1670,
+ 229, 881, 1678, 1781, 236, 1679, 629, 1742, 1680, 232,
+ -697, 229, 1734, 1743, 1761, 1774, -698, 2298, 1696, 2270,
+ 1791, 1713, 630, 1802, 1743, 966, 967, 968, 236, 403,
+ 230, 631, 850, 850, 1809, 2026, 2036, 2043, 632, 633,
+ 403, 2347, 1792, 2345, 3, 1793, 743, 4, 2346, 5,
+ 98, 1810, 2027, 2037, 2044, 1818, 1855, 232, 225, 1829,
+ 744, 1302, 1982, 1983, 1984, 99, 1985, 745, 2271, 6,
+ 7, 8, 9, 235, 1862, 229, 2014, 1875, 2040, 225,
+ 868, 869, 1877, 100, 1027, 746, 1879, 230, 101, 1888,
+ 102, 2024, 747, 1880, 2116, 1287, 237, 1894, 1027, 1897,
+ 225, 1895, 1898, 2285, 230, 1908, 1912, 1935, 1937, 1937,
+ 1940, 421, 1915, 1917, 232, 2084, 881, 1441, 1930, 233,
+ 237, 1525, 1526, 1527, 1528, 230, 422, 1931, 2340, 1942,
+ 1958, 232, 2300, 1972, 229, 1951, 230, 2022, 421, 1968,
+ 1318, 226, 859, 1995, 2001, 2116, 2003, 1043, 225, 1027,
+ 2002, 2015, 232, 422, 2016, 236, 2018, 2047, 1043, 1043,
+ 2057, 233, 881, 232, -569, 1315, 238, 1027, 1027, 2091,
+ 2065, 2067, 1029, 2120, 2071, 2121, 2122, 2023, 2139, 2079,
+ 2083, 2095, 2096, 2344, 2101, 2099, 235, 2118, 235, 2126,
+ 238, 2145, 2135, 2143, 1270, 2128, 2152, 2154, 2161, 2165,
+ 230, 2149, 2130, 2131, 2157, 225, 2134, 2166, 2175, 233,
+ 2178, 2155, 2138, 1530, 1531, 1532, 1533, 1534, 2158, 2026,
+ 2036, 2043, 225, 2181, 2182, 3, 2183, 232, 4, 2184,
+ 5, 2185, 881, 2189, 2190, 2191, 2027, 2037, 2044, 2199,
+ 235, 2192, 2041, 225, 2229, 2231, 2241, 237, 1837, 2243,
+ 6, 7, 8, 9, 225, 2245, 2249, 2197, 2257, 230,
+ 2059, 2060, 2061, 2062, 2063, 1778, 233, 2258, 1779, 229,
+ 2266, 2259, 2269, 1401, 849, 849, -287, 2277, 2223, 2280,
+ 2313, -288, 2281, 233, 2311, 2312, 232, 1029, 1029, 1029,
+ 1029, 1029, 226, 2331, 1029, 1425, 1423, 1639, 403, 1359,
+ 1249, 1424, 2200, 1248, 233, 1247, 229, 1493, 1138, 1250,
+ 2180, 1803, 2207, 881, 72, 233, 1134, 238, 225, 1427,
+ 1029, 2024, 3, 809, 2198, 4, 810, 5, 3, 2141,
+ 1066, 4, 229, 5, 1786, 1997, 2303, 2201, 2203, 1029,
+ 2260, 2262, 229, 2261, 2263, 2224, 2225, 6, 7, 8,
+ 9, 2252, 2332, 6, 7, 8, 9, 2234, 2235, 1939,
+ 2236, 2237, 2238, 2239, 2240, 817, 2098, 2242, 1778, 1063,
+ 1352, 1779, 1339, 2085, 2068, 2070, 1394, 225, 1065, 233,
+ 1485, 2251, 2289, 235, 1667, 1669, 1668, 1965, 1780, 1686,
+ 1402, 1882, 881, 847, 230, 324, 325, 326, 1889, 1890,
+ 329, 608, 609, 1320, 1319, 1488, 1885, 2197, 2322, 1408,
+ 1042, 788, 1689, 1709, 2268, 1643, 610, 229, 611, 612,
+ 613, 232, 1864, 2275, 1719, 235, 1736, 1747, 1763, 1776,
+ 1900, 230, 1054, 1903, 1076, 2040, 2337, 1077, 233, 1078,
+ 857, 614, 615, 616, 1079, 1214, 861, 2330, 862, 236,
+ 1186, 1180, 2308, 1536, 0, 0, 0, 230, 232, 0,
+ 0, 1717, 1742, 1760, 1773, 0, 229, 230, 0, 1831,
+ 1838, 1843, 1849, 235, 2116, 0, 2307, 0, 1718, 1743,
+ 1761, 1774, 229, 0, 232, 2310, 1832, 1839, 1844, 1850,
+ 0, 1780, 0, 2316, 232, 403, 0, 1231, 1232, 2317,
+ 2318, 2319, 2320, 2321, 2026, 2036, 2043, 2325, 2326, 2327,
+ 2328, 1233, 225, 0, 0, 0, 1781, 1555, 1556, 1234,
+ 0, 2027, 2037, 2044, 2338, 1042, 1042, 1042, 1042, 1042,
+ 235, 0, 1042, 0, 0, 1235, 0, 0, 0, 0,
+ 1833, 237, 230, 1840, 0, 1845, 0, 235, 1851, 225,
+ 2350, 2351, 2352, 1027, 0, 0, 3, 0, 1042, 4,
+ 0, 5, 236, 0, 236, 0, 0, 0, 235, 232,
+ 0, 0, 0, 233, 1607, 225, 0, 1042, 0, 235,
+ 500, 6, 7, 8, 9, 225, 226, 0, 0, 2021,
+ 0, 230, 573, 574, 0, 18, 19, 0, 0, 2041,
+ 0, 575, 576, 577, 578, 579, 0, 230, 1639, 0,
+ 233, 238, 280, 0, 0, 0, 236, 0, 232, 1781,
+ 281, 0, 282, 0, 283, 75, 1043, 284, 285, 286,
+ 0, 287, 0, 76, 232, 77, 233, 0, 0, 0,
+ 78, 79, 80, 235, 81, 35, 233, 1654, 1654, 0,
+ 1654, 0, 0, 0, 237, 36, 237, 0, 0, 0,
+ 225, 37, 0, 1236, 1237, 1238, 767, 0, 0, 0,
+ 881, 0, 0, 0, 1374, 0, 0, 0, 0, 777,
+ 778, 779, 0, 0, 0, 38, 2324, 0, 0, 0,
+ 0, 0, 2294, 0, 0, 0, 0, 0, 502, 226,
+ 0, 226, 235, 0, 0, 0, 0, 504, 237, 225,
+ 0, 0, 0, 18, 19, 0, 0, 0, 0, 0,
+ 0, 233, 18, 19, 238, 225, 238, 0, 1029, 1029,
+ 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 0,
+ 0, 1043, 1043, 1043, 1043, 1043, 0, 0, 1043, 0,
+ 0, 0, 0, 226, 1736, 1747, 1763, 1776, 0, 236,
+ 0, 1800, 0, 35, 1801, 0, 1747, 0, 0, 0,
+ 233, 0, 35, 36, 1043, 906, 0, 0, 407, 37,
+ 236, 907, 36, 0, 0, 0, 233, 0, 37, 506,
+ 0, 0, 0, 1043, 2028, 2038, 2045, 0, 1282, 0,
+ 1284, 236, 0, 38, 18, 19, 0, 0, 0, 158,
+ 159, 160, 38, 0, 0, 0, 1008, 1301, 0, 1305,
+ 1009, 1309, 0, 0, 10, 1010, 0, 1321, 1322, 0,
+ 0, 1011, 11, 0, 12, 914, 13, 235, 0, 14,
+ 15, 16, 0, 17, 0, 1825, 0, 18, 19, 236,
+ 0, 237, 288, 0, 35, 1014, 0, 0, 0, 1357,
+ 0, 0, 1361, 0, 36, 82, 1270, 289, 0, 0,
+ 37, 0, 237, 0, 235, 0, 0, 0, 0, 0,
+ 83, 0, 0, 0, 1867, 290, 1868, 1869, 0, 1871,
+ 291, 0, 292, 237, 38, 0, 226, 35, 84, 0,
+ 235, 0, 0, 85, 881, 86, 236, 36, 0, 0,
+ 235, 0, 0, 37, 0, 1884, 511, 1315, 1401, 0,
+ 2299, 407, 1029, 236, 0, 0, 0, 1398, 0, 0,
+ 0, 18, 19, 0, 0, 0, 1029, 38, 226, 0,
+ 0, 237, 238, 0, 236, 0, 1654, 0, 0, 1654,
+ 0, 0, 1654, 0, 0, 236, 0, 0, 0, 0,
+ 0, 0, 0, 407, 0, 0, 1042, 1042, 1042, 1042,
+ 1042, 1042, 1042, 1042, 1042, 1042, 1042, 0, 2028, 2038,
+ 2045, 35, 0, 0, 0, 235, 226, 1029, 0, 0,
+ 0, 36, 917, 0, 0, 918, 919, 37, 237, 0,
+ 1448, 1449, 920, 0, 0, 1029, 1029, 0, 581, 582,
+ 0, 407, 583, 0, 0, 237, 0, 0, 0, 236,
+ 0, 38, 0, 584, 585, 586, 587, 588, 589, 590,
+ 591, 592, 922, 923, 235, 0, 237, 0, 0, 0,
+ 0, 0, 1162, 226, 106, 0, 0, 237, 0, 107,
+ 235, 0, 108, 109, 110, 111, 0, 1163, 112, 113,
+ 226, 114, 115, 116, 39, 117, 0, 0, 238, 0,
+ 0, 0, 0, 593, 221, 0, 0, 0, 236, 40,
+ 0, 226, 0, 0, 0, 238, 0, 0, 0, 0,
+ 0, 0, 226, 0, 0, 0, 0, 41, 0, 0,
+ 0, 0, 42, 0, 43, 118, 407, 119, 120, 121,
+ 0, 237, 0, 0, 0, 0, 3, 407, 0, 4,
+ 0, 5, 1164, 1374, 1374, 1374, 1374, 1374, 0, 1374,
+ 1374, 0, 0, 618, 619, 0, 620, 0, 1682, 1682,
+ 0, 6, 7, 8, 9, 0, 0, 0, 2058, 0,
+ 0, 0, 1721, 0, 0, 621, 226, 0, 0, 0,
+ 1042, 0, 1722, 622, 623, 0, 624, 1723, 0, 1724,
+ 237, 1725, 0, 0, 1042, 0, 625, 626, 627, 0,
+ 0, 238, 1043, 1043, 1043, 1043, 1043, 1043, 1043, 1043,
+ 1043, 1043, 1043, 0, 1165, 0, 0, 1166, 1167, 1168,
+ 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178,
+ 0, 0, 0, 236, 0, 226, 0, 0, 0, 0,
+ 1719, 1747, 1763, 1776, 0, 1042, 0, 0, 1833, 1840,
+ 1845, 1851, 0, 1582, 0, 0, 0, 1585, 0, 0,
+ 238, 0, 0, 1042, 1042, 0, 0, 1604, 1605, 1606,
+ 236, 0, 1609, 0, 1611, 0, 0, 0, 0, 0,
+ 0, 0, 0, 2028, 2038, 2045, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 236, 1626, 0, 1726,
+ 0, 0, 0, 0, 122, 0, 236, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 123,
+ 0, 0, 0, 2150, 0, 237, 124, 125, 126, 127,
+ 0, 0, 0, 2156, 1660, 0, 1662, 128, 0, 0,
+ 2159, 0, 129, 1663, 130, 131, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1676, 0,
+ 1677, 0, 237, 0, 0, 0, 0, 0, 161, 1685,
+ 226, 1687, 0, 0, 0, 2164, 0, 0, 0, 0,
+ 0, 236, 0, 1592, 0, 165, 0, 0, 237, 0,
+ 0, 0, 0, 0, 0, 407, 1043, 0, 237, 0,
+ 0, 166, 0, 0, 0, 0, 167, 226, 0, 168,
+ 1043, 1029, 1727, 0, 169, 0, 0, 0, 170, 0,
+ 0, 171, 172, 0, 0, 0, 173, 1728, 0, 174,
+ 236, 175, 238, 226, 0, 0, 0, 2226, 2227, 2228,
+ 0, 0, 0, 226, 0, 1729, 236, 0, 1164, 0,
+ 1730, 0, 1731, 0, 0, 0, 176, 0, 238, 0,
+ 0, 1043, 181, 2244, 0, 0, 0, 0, 238, 0,
+ 0, 0, 0, 237, 0, 0, 0, 0, 0, 1043,
+ 1043, 0, 3, 0, 881, 4, 0, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1732, 0, 0, 0, 0, 0, 0, 6, 7, 8,
+ 9, 0, 0, 0, 0, 0, 0, 0, 226, 0,
+ 1593, 1749, 237, 1166, 1167, 1594, 1169, 1170, 1171, 1172,
+ 1173, 1174, 1175, 1176, 1177, 1595, 0, 0, 237, 0,
+ 0, 0, 0, 238, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1853, 1854, 0,
+ 0, 0, 0, 0, 0, 0, 0, 226, 0, 0,
+ 1750, 1751, 1752, 1753, 0, 1754, 0, 0, 1755, 0,
+ 0, 0, 0, 226, 1870, 652, 0, 0, 0, 0,
+ 51, 0, 407, 0, 653, 1756, 0, 0, 0, 1887,
+ 63, 51, 51, 66, 66, 66, 70, 0, 238, 51,
+ 654, 858, 0, 0, 655, 0, 0, 0, 656, 657,
+ 2341, 2342, 2343, 658, 659, 660, 661, 662, 0, 0,
+ 0, 0, 0, 759, 760, 1914, 0, 761, 0, 0,
+ 0, 0, 0, 0, 0, 1757, 0, 0, 0, 1042,
+ 0, 0, 1916, 0, 1918, 762, 0, 0, 0, 0,
+ 0, 0, 51, 0, 0, 429, 51, 66, 66, 66,
+ 70, 0, 0, 0, 0, 0, 0, 51, 0, 444,
+ 449, 452, 51, 457, 66, 66, 462, 0, 444, 444,
+ 444, 444, 0, 66, 0, 0, 0, 478, 0, 51,
+ 0, 0, 66, 66, 0, 70, 0, 0, 66, 0,
+ 0, 0, 859, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 51, 518, 457, 66, 457, 0, 526, 529,
+ 0, 0, 533, 51, 66, 66, 0, 0, 66, 0,
+ 51, 0, 0, 0, 3, 0, 0, 4, 0, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1758, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,
+ 7, 8, 9, 334, 0, 763, 0, 0, 335, 0,
+ 0, 0, 0, 1749, 0, 0, 0, 0, 0, 0,
+ 0, 337, 0, 0, 0, 0, 338, 0, 0, 764,
+ 765, 766, 767, 768, 769, 860, 770, 771, 772, 773,
+ 774, 775, 776, 0, 0, 777, 778, 779, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2055,
+ 881, 0, 1750, 1751, 1752, 1753, 0, 1754, 780, 0,
+ 1755, 0, 0, 0, 0, 0, 1759, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1756, 0, 0,
+ 0, 0, 2075, 0, 0, 1043, 0, 0, 0, 444,
+ 449, 452, 51, 457, 66, 66, 462, 0, 444, 444,
+ 444, 444, 0, 3, 0, 0, 4, 0, 5, 2090,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 153, 0, 1757, 6, 7,
+ 8, 9, 154, 155, 0, 0, 0, 317, 156, 318,
+ 0, 0, 0, 0, 0, 0, 1737, 0, 0, 0,
+ 0, 0, 0, 0, 319, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 320, 321, 0, 0, 0, 322,
+ 0, 0, 323, 0, 0, 0, 0, 0, 0, 0,
+ 0, 324, 325, 326, 327, 328, 329, 0, 0, 0,
+ 0, 0, 0, 161, 0, 162, 1738, 0, 0, 163,
+ 330, 0, 331, 0, 164, 157, 158, 159, 160, 0,
+ 165, 161, 0, 162, 0, 0, 1739, 163, 0, 0,
+ 0, 0, 164, 0, 0, 0, 166, 0, 165, 0,
+ 0, 167, 0, 0, 168, 0, 0, 0, 0, 169,
+ 1758, 0, 0, 170, 166, 0, 171, 172, 669, 167,
+ 0, 173, 168, 0, 174, 334, 175, 169, 0, 0,
+ 335, 170, 0, 0, 171, 172, 1740, 0, 0, 173,
+ 0, 0, 174, 337, 175, 0, 0, 0, 338, 0,
+ 0, 176, 0, 670, 0, 2174, 0, 181, 0, 0,
+ 0, 1099, 0, 0, 0, 0, 0, 0, 66, 176,
+ 177, 0, 178, 179, 180, 181, 0, 0, 0, 1105,
+ 0, 1106, 881, 1107, 0, 1108, 0, 0, 0, 0,
+ 1112, 0, 0, 0, 1113, 51, 0, 0, 2007, 0,
+ 0, 0, 0, 0, 1117, 0, 0, 1118, 0, 0,
+ 182, 183, 184, 185, 0, 0, 0, 66, 0, 186,
+ 187, 0, 0, 188, 189, 332, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 210, 211, 0, 0, 333,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 334, 0, 0, 0, 0, 335,
+ 0, 0, 0, 0, 0, 0, 336, 0, 0, 0,
+ 0, 0, 337, 0, 0, 0, 0, 338, 0, 0,
+ 0, 0, 0, 213, 214, 0, 339, 0, 0, 340,
+ 341, 342, 343, 0, 0, 0, 344, 0, 0, 0,
+ 345, 346, 215, 0, 0, 0, 216, 217, 0, 0,
+ 0, 881, 0, 0, 0, 347, 0, 3, 218, 219,
+ 4, 0, 5, 0, 348, 0, 349, 1741, 220, 0,
+ 0, 221, 0, 0, 0, 0, 0, 0, 0, 153,
+ 0, 0, 6, 7, 8, 9, 154, 155, 0, 0,
+ 0, 317, 156, 318, 0, 0, 0, 0, 0, 0,
+ 1737, 0, 0, 0, 0, 0, 0, 0, 319, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 320, 321,
+ 0, 0, 0, 322, 0, 0, 323, 0, 0, 0,
+ 0, 0, 0, 0, 0, 324, 325, 326, 327, 328,
+ 329, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1738, 0, 0, 0, 330, 0, 331, 0, 0, 157,
+ 158, 159, 160, 0, 0, 161, 0, 162, 0, 0,
+ 1739, 163, 0, 0, 3, 0, 164, 4, 0, 5,
+ 0, 0, 165, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 166, 6,
+ 7, 8, 9, 167, 0, 0, 168, 1189, 0, 0,
+ 0, 169, 0, 1749, 0, 170, 0, 0, 171, 172,
+ 1740, 0, 0, 173, 0, 0, 174, 0, 175, 0,
+ 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199,
+ 1200, 1201, 1202, 1203, 1204, 1205, 1206, 0, 0, 0,
+ 0, 0, 0, 176, 177, 0, 178, 179, 180, 181,
+ 0, 0, 1750, 1751, 1752, 1753, 0, 1754, 0, 0,
+ 1755, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1756, 0, 0,
+ 0, 0, 0, 0, 182, 183, 184, 185, 0, 0,
+ 0, 0, 0, 186, 187, 0, 0, 188, 189, 332,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
+ 211, 0, 0, 333, 0, 0, 0, 1757, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 334, 0,
+ 0, 0, 0, 335, 0, 0, 0, 0, 0, 0,
+ 336, 0, 0, 0, 0, 0, 337, 0, 0, 0,
+ 0, 338, 0, 0, 0, 0, 0, 213, 214, 0,
+ 339, 0, 0, 340, 341, 342, 343, 0, 0, 0,
+ 344, 0, 0, 0, 345, 346, 215, 0, 0, 0,
+ 216, 217, 0, 0, 0, 881, 0, 0, 0, 347,
+ 0, 3, 218, 219, 4, 0, 5, 0, 348, 0,
+ 349, 2006, 220, 0, 0, 221, 0, 0, 0, 0,
+ 0, 0, 0, 153, 0, 0, 6, 7, 8, 9,
+ 154, 155, 0, 0, 0, 317, 156, 318, 0, 0,
+ 1758, 0, 0, 0, 1737, 0, 0, 0, 0, 0,
+ 0, 0, 319, 0, 0, 334, 0, 0, 0, 0,
+ 335, 0, 320, 321, 0, 0, 0, 322, 0, 0,
+ 323, 0, 0, 337, 0, 0, 0, 0, 338, 324,
+ 325, 326, 327, 328, 329, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1738, 0, 0, 0, 330, 0,
+ 331, 0, 1486, 157, 158, 159, 160, 0, 0, 161,
+ 0, 162, 881, 0, 1739, 163, 0, 0, 3, 0,
+ 164, 4, 0, 5, 0, 0, 165, 0, 2292, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 166, 6, 7, 8, 9, 167, 0, 0,
+ 168, 0, 0, 0, 0, 169, 0, 1766, 0, 170,
+ 0, 0, 171, 172, 1740, 0, 0, 173, 0, 0,
+ 174, 0, 175, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 176, 177, 0,
+ 178, 179, 180, 181, 0, 0, 0, 1767, 1768, 1769,
+ 0, 1754, 0, 0, 1755, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1770, 0, 0, 0, 0, 0, 0, 182, 183,
+ 184, 185, 0, 0, 0, 0, 0, 186, 187, 0,
+ 0, 188, 189, 332, 191, 192, 193, 194, 195, 196,
+ 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
+ 207, 208, 209, 210, 211, 0, 0, 333, 0, 0,
+ 0, 1771, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 334, 0, 0, 0, 0, 335, 0, 0,
+ 0, 0, 0, 0, 336, 0, 0, 0, 0, 0,
+ 337, 0, 0, 0, 0, 338, 0, 0, 0, 0,
+ 0, 213, 214, 0, 339, 0, 0, 340, 341, 342,
+ 343, 0, 0, 0, 344, 0, 0, 0, 345, 346,
+ 215, 0, 0, 0, 216, 217, 0, 0, 0, 881,
+ 0, 0, 0, 347, 0, 3, 218, 219, 4, 0,
+ 5, 0, 348, 0, 349, 2013, 220, 0, 0, 221,
+ 0, 0, 0, 0, 0, 0, 0, 153, 0, 0,
+ 6, 7, 8, 9, 154, 155, 0, 0, 0, 317,
+ 156, 318, 0, 0, 1758, 0, 0, 0, 1737, 0,
+ 0, 0, 0, 0, 0, 0, 319, 0, 0, 334,
+ 0, 0, 0, 0, 335, 0, 320, 321, 0, 0,
+ 0, 322, 0, 0, 323, 0, 0, 337, 0, 0,
+ 0, 0, 338, 324, 325, 326, 327, 328, 329, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1738, 0,
+ 0, 0, 330, 0, 331, 0, 0, 157, 158, 159,
+ 160, 0, 0, 161, 0, 162, 881, 0, 1739, 163,
+ 0, 0, 3, 0, 164, 4, 0, 5, 0, 0,
+ 165, 0, 1772, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 166, 6, 7, 8,
+ 9, 167, 0, 0, 168, 0, 0, 0, 0, 169,
+ 0, 1766, 0, 170, 0, 0, 171, 172, 1740, 0,
+ 0, 173, 0, 0, 174, 0, 175, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 176, 177, 0, 178, 179, 180, 181, 0, 0,
+ 0, 1767, 1768, 1769, 0, 1754, 0, 0, 1755, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1770, 0, 0, 0, 0,
+ 0, 0, 182, 183, 184, 185, 0, 0, 0, 0,
+ 0, 186, 187, 0, 0, 188, 189, 332, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+ 203, 204, 205, 206, 207, 208, 209, 210, 211, 0,
+ 0, 333, 0, 0, 0, 1771, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 334, 0, 0, 0,
+ 0, 335, 0, 0, 0, 0, 0, 0, 336, 0,
+ 0, 0, 0, 0, 337, 0, 0, 0, 0, 338,
+ 0, 0, 0, 0, 0, 213, 214, 0, 339, 0,
+ 0, 340, 341, 342, 343, 0, 0, 0, 344, 0,
+ 0, 0, 345, 346, 215, 4, 0, 5, 216, 217,
+ 0, 0, 0, 881, 0, 0, 0, 347, 0, 0,
+ 218, 219, 0, 0, 153, 0, 348, 0, 349, 2291,
+ 220, 154, 155, 221, 0, 0, 317, 156, 318, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 319, 0, 0, 0, 0, 1758, 0,
+ 0, 0, 0, 320, 321, 0, 0, 749, 322, 0,
+ 0, 323, 0, 334, 0, 0, 0, 0, 335, 0,
+ 324, 325, 326, 327, 328, 329, 0, 0, 0, 0,
+ 0, 337, 0, 0, 750, 0, 338, 751, 0, 330,
+ 0, 331, 0, 0, 157, 158, 159, 160, 0, 0,
+ 161, 0, 162, 0, 752, 0, 163, 0, 0, 0,
+ 0, 164, 0, 0, 0, 0, 0, 165, 0, 0,
+ 881, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 166, 0, 0, 2008, 0, 167, 0,
+ 0, 168, 0, 0, 3, 0, 169, 4, 0, 5,
+ 170, 0, 0, 171, 172, 0, 0, 0, 173, 0,
+ 0, 174, 0, 175, 0, 0, 0, 0, 0, 6,
+ 7, 8, 9, 0, 0, 0, 0, 0, 0, 0,
+ 1721, 0, 0, 0, 0, 0, 0, 0, 176, 177,
+ 1722, 178, 179, 180, 181, 1723, 0, 1724, 0, 1725,
+ 0, 0, 0, 0, 0, 0, 0, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211, 0, 182,
+ 183, 184, 185, 0, 0, 0, 0, 0, 186, 187,
+ 0, 0, 188, 189, 332, 191, 192, 193, 194, 195,
+ 196, 197, 198, 199, 200, 201, 202, 203, 204, 205,
+ 206, 207, 208, 209, 210, 211, 0, 0, 333, 0,
+ 753, 0, 905, 0, 213, 214, 0, 0, 0, 0,
+ 0, 0, 0, 334, 754, 0, 0, 0, 335, 0,
+ 153, 0, 0, 0, 0, 336, 0, 0, 155, 0,
+ 0, 337, 0, 156, 0, 0, 338, 1726, 0, 0,
+ 755, 0, 213, 214, 0, 339, 0, 0, 340, 341,
+ 342, 343, 0, 0, 0, 344, 0, 0, 0, 345,
+ 346, 215, 0, 0, 0, 216, 217, 906, 0, 0,
+ 0, 0, 0, 907, 347, 0, 0, 218, 219, 0,
+ 0, 0, 908, 348, 909, 349, 1904, 220, 0, 0,
+ 221, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 157, 158, 159, 160, 0, 0, 161, 0, 910, 0,
+ 0, 0, 911, 0, 0, 0, 0, 912, 0, 0,
+ 0, 0, 0, 913, 0, 0, 0, 914, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 166,
+ 0, 0, 0, 0, 167, 0, 0, 915, 0, 0,
+ 1727, 0, 169, 0, 0, 0, 170, 0, 0, 171,
+ 172, 0, 0, 0, 173, 1728, 0, 174, 0, 175,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1729, 0, 0, 0, 0, 1730, 0,
+ 1731, 0, 0, 0, 176, 177, 0, 178, 179, 180,
+ 181, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1279, 0, 0, 0, 0, 0, 759, 760, 0,
+ 0, 761, 881, 0, 0, 0, 0, 0, 0, 153,
+ 0, 0, 0, 0, 0, 916, 0, 155, 2005, 762,
+ 0, 0, 156, 0, 0, 0, 0, 0, 0, 0,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 0, 0, 212, 0, 906, 0, 0, 0,
+ 0, 0, 907, 0, 917, 0, 0, 918, 919, 0,
+ 0, 0, 0, 0, 920, 0, 0, 0, 0, 0,
+ 0, 0, 921, 0, 0, 0, 0, 0, 0, 157,
+ 158, 159, 160, 0, 0, 161, 0, 910, 213, 214,
+ 0, 911, 0, 0, 922, 923, 912, 0, 0, 0,
+ 0, 0, 1280, 0, 0, 0, 914, 215, 0, 0,
+ 0, 216, 217, 0, 0, 0, 0, 0, 166, 0,
+ 0, 924, 925, 167, 755, 0, 1281, 0, 0, 763,
+ 0, 169, 0, 926, 0, 170, 221, 0, 171, 172,
+ 0, 0, 0, 173, 0, 0, 174, 0, 175, 0,
+ 0, 0, 0, 764, 765, 766, 767, 768, 769, 0,
+ 770, 771, 772, 773, 774, 775, 776, 0, 0, 777,
+ 778, 779, 0, 176, 177, 0, 178, 179, 180, 181,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1360, 0, 780, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 153, 0,
+ 0, 0, 0, 0, 916, 0, 155, 0, 0, 0,
+ 0, 156, 0, 0, 0, 0, 0, 0, 0, 190,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
+ 211, 0, 0, 212, 0, 906, 0, 0, 0, 0,
+ 0, 907, 0, 917, 0, 0, 918, 919, 0, 0,
+ 0, 0, 0, 920, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 157, 158,
+ 159, 160, 0, 0, 161, 0, 910, 213, 214, 0,
+ 911, 0, 0, 922, 923, 912, 0, 0, 161, 0,
+ 162, 1280, 0, 698, 163, 914, 215, 0, 0, 164,
+ 216, 217, 0, 0, 0, 165, 0, 166, 0, 0,
+ 924, 925, 167, 755, 0, 1281, 0, 0, 0, 0,
+ 169, 166, 926, 0, 170, 221, 167, 171, 172, 168,
+ 0, 0, 173, 0, 169, 174, 0, 175, 170, 0,
+ 0, 171, 172, 0, 0, 0, 173, 0, 0, 174,
+ 0, 175, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 176, 177, 0, 178, 179, 180, 181, 0,
+ 0, 0, 0, 0, 0, 0, 176, 0, 699, 1397,
+ 0, 0, 181, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 153, 0, 0,
+ 0, 0, 0, 916, 0, 155, 0, 0, 0, 0,
+ 156, 0, 0, 0, 0, 0, 0, 0, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201,
+ 202, 203, 204, 205, 206, 207, 208, 209, 210, 211,
+ 0, 0, 212, 0, 906, 0, 0, 0, 0, 0,
+ 907, 0, 917, 0, 0, 918, 919, 0, 0, 0,
+ 0, 0, 920, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 157, 158, 159,
+ 160, 0, 0, 161, 0, 910, 213, 214, 0, 911,
+ 0, 0, 922, 923, 912, 0, 0, 161, 0, 162,
+ 1280, 0, 0, 163, 914, 215, 0, 0, 164, 216,
+ 217, 0, 0, 0, 165, 0, 166, 0, 0, 924,
+ 925, 167, 755, 0, 1281, 0, 0, 0, 0, 169,
+ 166, 926, 0, 170, 221, 167, 171, 172, 168, 0,
+ 0, 173, 0, 169, 174, 0, 175, 170, 0, 0,
+ 171, 172, 0, 0, 0, 173, 0, 0, 174, 0,
+ 175, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 176, 177, 0, 178, 179, 180, 181, 0, 0,
+ 0, 0, 0, 0, 0, 176, 0, 0, 1584, 0,
+ 0, 181, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 153, 0, 0, 0,
+ 0, 0, 916, 0, 155, 0, 0, 0, 0, 156,
+ 0, 0, 0, 0, 0, 0, 0, 190, 191, 192,
+ 193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
+ 203, 204, 205, 206, 207, 208, 209, 210, 211, 0,
+ 0, 212, 0, 906, 0, 0, 0, 0, 0, 907,
+ 0, 917, 0, 0, 918, 919, 0, 0, 0, 0,
+ 0, 920, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 157, 158, 159, 160,
+ 0, 0, 161, 0, 910, 213, 214, 0, 911, 0,
+ 0, 922, 923, 912, 0, 0, 0, 0, 0, 1280,
+ 0, 0, 0, 914, 215, 0, 0, 0, 216, 217,
+ 0, 0, 0, 0, 0, 166, 0, 0, 924, 925,
+ 167, 755, 0, 1281, 0, 0, 0, 0, 169, 0,
+ 926, 0, 170, 221, 0, 171, 172, 0, 0, 0,
+ 173, 0, 0, 174, 0, 175, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 0, 0, 4, 0, 5, 0, 0,
+ 176, 177, 0, 178, 179, 180, 181, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 6, 7, 8,
+ 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1766, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 916, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 190, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211, 0, 0,
+ 212, 1767, 1768, 1769, 0, 1754, 0, 0, 1755, 0,
+ 917, 0, 0, 918, 919, 0, 0, 0, 0, 0,
+ 920, 0, 0, 0, 0, 1770, 1001, 1002, 1003, 1004,
+ 1005, 1006, 0, 0, 0, 0, 1007, 0, 0, 0,
+ 986, 0, 0, 0, 213, 214, 0, 0, 0, 0,
+ 922, 923, 0, 0, 0, 0, 1325, 0, 0, 0,
+ 0, 0, 0, 215, 0, 0, 0, 216, 217, 0,
+ 0, 0, 0, 0, 0, 1771, 0, 924, 925, 0,
+ 755, 0, 0, 0, 0, 0, 0, 906, 0, 926,
+ 0, 0, 221, 907, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 906, 0, 0, 0, 0,
+ 0, 907, 0, 0, 0, 0, 0, 0, 0, 0,
+ 157, 158, 159, 160, 0, 0, 0, 0, 1008, 0,
+ 0, 0, 1009, 0, 0, 0, 0, 1010, 157, 158,
+ 159, 160, 0, 1011, 0, 0, 1008, 914, 0, 0,
+ 1009, 0, 0, 0, 0, 1010, 0, 0, 0, 1012,
+ 1325, 1011, 0, 0, 1013, 914, 0, 1014, 0, 0,
+ 0, 0, 1015, 0, 0, 0, 1016, 1012, 0, 1017,
+ 1018, 0, 1013, 0, 1019, 1014, 0, 1020, 1758, 1021,
+ 1015, 0, 0, 0, 1016, 0, 0, 1017, 1018, 0,
+ 0, 0, 1019, 334, 0, 1020, 0, 1021, 335, 906,
+ 0, 0, 0, 0, 1022, 907, 0, 1023, 0, 0,
+ 1024, 337, 0, 0, 0, 0, 338, 0, 0, 0,
+ 0, 0, 1022, 0, 0, 1023, 0, 0, 1024, 0,
+ 0, 0, 157, 158, 159, 160, 0, 0, 0, 0,
+ 1008, 0, 0, 0, 1009, 0, 0, 0, 0, 1010,
+ 881, 0, 0, 0, 0, 1011, 0, 0, 0, 914,
+ 0, 0, 0, 0, 0, 0, 2293, 0, 0, 0,
+ 0, 1012, 0, 0, 0, 0, 1013, 0, 0, 1014,
+ 0, 0, 0, 0, 1015, 0, 0, 0, 1016, 0,
+ 0, 1017, 1018, 0, 917, 0, 1019, 918, 919, 1020,
+ 0, 1021, 0, 0, 920, 0, 0, 0, 0, 0,
+ 0, 0, 917, 0, 0, 918, 919, 0, 0, 0,
+ 0, 0, 920, 0, 0, 0, 1022, 0, 0, 1023,
+ 0, 0, 1024, 0, 922, 923, 0, 1025, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 922, 923, 0, 1025, 0, 0, 0, 0,
+ 0, 924, 925, 0, 0, 0, 0, 0, 0, 1048,
+ 986, 349, 0, 1026, 0, 0, 221, 0, 0, 924,
+ 925, 0, 0, 0, 0, 0, 0, 0, 0, 349,
+ 0, 1026, 0, 0, 221, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 917, 906, 0, 918,
+ 919, 0, 0, 907, 0, 0, 920, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 157, 158, 159, 160, 0, 0, 922, 923, 1008, 1025,
+ 0, 0, 1009, 0, 0, 0, 0, 1010, 0, 0,
+ 0, 0, 0, 1011, 0, 0, 0, 914, 0, 0,
+ 0, 0, 0, 924, 925, 0, 0, 0, 0, 1012,
+ 0, 0, 0, 0, 1013, 1026, 0, 1014, 221, 0,
+ 0, 0, 1015, 0, 0, 0, 1016, 0, 0, 1017,
+ 1018, 0, 0, 0, 1019, 0, 153, 1020, 0, 1021,
+ 0, 0, 0, 154, 155, 0, 0, 0, 317, 156,
+ 318, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1022, 319, 0, 1023, 0, 0,
+ 1024, 0, 0, 0, 0, 320, 321, 0, 0, 0,
+ 322, 0, 0, 323, 0, 0, 0, 0, 0, 0,
+ 0, 0, 324, 325, 326, 327, 328, 329, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 330, 0, 331, 0, 0, 157, 158, 159, 160,
+ 0, 0, 161, 0, 162, 0, 0, 0, 163, 0,
+ 0, 0, 0, 164, 0, 0, 0, 0, 0, 165,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 917, 166, 0, 918, 919, 0,
+ 167, 0, 0, 168, 920, 0, 0, 0, 169, 0,
+ 0, 0, 170, 0, 0, 171, 172, 0, 0, 0,
+ 173, 0, 0, 174, 0, 175, 0, 0, 0, 0,
+ 0, 0, 0, 0, 922, 923, 0, 1025, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 176, 177, 0, 178, 179, 180, 181, 0, 0, 0,
+ 0, 924, 925, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1049, 0, 1026, 0, 0, 221, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 182, 183, 184, 185, 0, 0, 0, 0, 0,
+ 186, 187, 0, 0, 188, 189, 332, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211, 0, 0,
+ 333, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 153, 0, 334, 0, 0, 0, 0,
+ 335, 155, 0, 0, 0, 0, 156, 336, 0, 0,
+ 0, 0, 0, 337, 0, 0, 0, 0, 338, 0,
+ 0, 0, 0, 0, 213, 214, 0, 339, 0, 0,
+ 340, 341, 342, 343, 0, 0, 0, 344, 0, 0,
+ 906, 345, 346, 215, 0, 0, 907, 216, 217, 0,
+ 0, 0, 0, 0, 0, 0, 347, 0, 0, 218,
+ 219, 0, 0, 0, 0, 348, 0, 349, 0, 220,
+ 0, 0, 221, 157, 158, 159, 160, 0, 0, 161,
+ 0, 910, 0, 0, 0, 911, 0, 0, 0, 0,
+ 912, 0, 0, 0, 0, 0, 1280, 0, 0, 0,
+ 914, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 166, 0, 0, 0, 0, 167, 0, 0,
+ 1281, 0, 0, 0, 0, 169, 0, 0, 0, 170,
+ 0, 0, 171, 172, 0, 0, 0, 173, 0, 0,
+ 174, 0, 175, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 176, 177, 0,
+ 178, 179, 180, 181, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 153, 0, 0, 0, 0, 0, 916, 154,
+ 155, 0, 0, 0, 0, 156, 0, 0, 0, 0,
+ 0, 0, 0, 190, 191, 192, 193, 194, 195, 196,
+ 197, 198, 199, 200, 201, 202, 203, 204, 205, 206,
+ 207, 208, 209, 210, 211, 0, 0, 212, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 917, 0, 0,
+ 918, 919, 0, 0, 0, 0, 0, 920, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 157, 158, 159, 160, 0, 0, 161, 0,
+ 162, 213, 214, 0, 163, 0, 0, 922, 923, 164,
+ 0, 0, 0, 0, 0, 165, 0, 0, 0, 0,
+ 215, 0, 0, 0, 216, 217, 0, 0, 0, 0,
+ 0, 166, 0, 0, 924, 925, 167, 755, 0, 168,
+ 0, 0, 0, 0, 169, 0, 926, 0, 170, 221,
+ 0, 171, 172, 0, 0, 0, 173, 0, 0, 174,
+ 0, 175, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 176, 177, 0, 178,
+ 179, 180, 181, 0, 0, 0, 0, 0, 0, 0,
+ 153, 0, 0, 0, 0, 0, 0, 154, 155, 0,
+ 0, 0, 0, 156, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 182, 183, 184,
+ 185, 0, 0, 0, 0, 0, 186, 187, 0, 0,
+ 188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
+ 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 2204, 0, 212, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 157, 158, 159, 160, 0, 0, 161, 0, 162, 0,
+ 0, 0, 163, 0, 0, 0, 0, 164, 0, 0,
+ 0, 0, 0, 165, 0, 0, 0, 0, 0, 0,
+ 213, 214, 0, 0, 0, 0, 0, 0, 0, 166,
+ 0, 0, 0, 0, 167, 0, 0, 168, 0, 215,
+ 0, 0, 169, 216, 217, 0, 170, 0, 0, 171,
+ 172, 0, 0, 0, 173, 218, 219, 174, 0, 175,
+ 0, 0, 0, 349, 0, 220, 0, 0, 221, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 176, 177, 153, 178, 179, 180,
+ 181, 0, 0, 154, 155, 0, 0, 0, 0, 156,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 182, 183, 184, 185, 0,
+ 0, 0, 0, 0, 186, 187, 0, 0, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 0, 0, 212, 0, 157, 158, 159, 160,
+ 0, 0, 161, 0, 162, 0, 0, 0, 163, 0,
+ 0, 0, 0, 164, 0, 0, 0, 0, 0, 165,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 166, 0, 0, 213, 214,
+ 167, 0, 0, 168, 0, 0, 0, 0, 169, 0,
+ 0, 0, 170, 0, 0, 171, 172, 215, 0, 0,
+ 173, 216, 217, 174, 0, 175, 0, 0, 0, 0,
+ 0, 0, 0, 218, 219, 0, 0, 0, 0, 0,
+ 0, 0, 0, 220, 0, 0, 221, 0, 0, 0,
+ 176, 177, 0, 178, 179, 180, 181, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 986, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 182, 183, 184, 185, 0, 0, 0, 0, 0,
+ 186, 187, 0, 0, 188, 189, 190, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211, 906, 0,
+ 212, 0, 0, 0, 907, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 157, 158, 159, 160, 0, 0, 0, 0, 1008,
+ 0, 0, 0, 1009, 213, 214, 0, 0, 1010, 0,
+ 0, 0, 0, 0, 1011, 0, 0, 0, 914, 0,
+ 0, 0, 0, 215, 0, 0, 0, 216, 217, 0,
+ 1012, 0, 0, 0, 0, 1013, 0, 0, 1014, 218,
+ 219, 0, 0, 1015, 0, 0, 0, 1016, 0, 220,
+ 1017, 1018, 221, 0, 0, 1019, 0, 0, 1020, 0,
+ 1021, 0, 0, 0, 0, 0, 0, 2, 3, 0,
+ 0, 4, 0, 5, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1022, 0, 0, 1023, 0,
+ 0, 1024, 0, 6, 7, 8, 9, 0, 0, 0,
+ 0, 0, 0, 0, 10, 0, 0, 0, 0, 0,
+ 0, 0, 11, 0, 12, 0, 13, 0, 0, 14,
+ 15, 16, 0, 17, 0, 0, 0, 18, 19, 20,
+ 0, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -432, 0, 0, 0, 917, 0, 35, 918, 919,
+ 0, 0, 0, 0, 0, 920, 0, 36, 906, 0,
+ 0, 0, 0, 37, 907, 0, 0, 324, 325, 326,
+ 1889, 1890, 329, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 922, 923, 38, 1025, 0,
+ 0, 157, 158, 159, 160, 0, 0, 0, 0, 1008,
+ 0, 0, 0, 1009, 0, 0, 0, 0, 1010, 0,
+ 0, 0, 924, 925, 1011, 0, 0, 0, 914, 0,
+ 0, 0, 349, 0, 1026, 0, 0, 221, 0, 0,
+ 1012, 0, 0, 0, 0, 1013, 0, 0, 1014, 906,
+ 0, 0, 0, 1015, 0, 907, 0, 1016, 0, 0,
+ 1017, 1018, 0, 0, 0, 1019, 0, 0, 1020, 0,
+ 1021, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 157, 158, 159, 160, 0, 0, 0, 0,
+ 1008, 0, 0, 0, 1009, 1022, 0, 0, 1023, 1010,
+ 0, 1024, 0, 0, 0, 1011, 0, 0, 0, 914,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1012, 0, 0, 39, 0, 1013, 0, 0, 1014,
+ 0, 0, 0, 0, 1015, 0, 0, 0, 1016, 40,
+ 0, 1017, 1018, 0, -432, 0, 1019, 0, 0, 1020,
+ 0, 1021, 0, 0, 0, 0, 0, 41, 0, 0,
+ 0, 0, 42, 0, 43, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1022, 0, 0, 1023,
+ 0, 0, 1024, 0, 0, 917, 0, 0, 918, 919,
+ 0, 0, 0, 0, 0, 920, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 922, 923, 0, 1025, 0,
+ 856, 0, 0, 0, 0, 0, 0, 0, 906, 0,
+ 0, 0, 0, 0, 907, 0, 0, 0, 0, 0,
+ 0, 0, 924, 925, 0, 0, 0, 750, 0, 0,
+ 751, 0, 0, 0, 1026, 0, 917, 221, 0, 918,
+ 919, 1706, 158, 159, 160, 0, 920, 752, 0, 1008,
+ 0, 0, 0, 1009, 0, 0, 0, 0, 1010, 0,
+ 0, 0, 0, 0, 1011, 0, 0, 0, 914, 0,
+ 0, 0, 0, 0, 0, 0, 922, 923, 0, 1025,
+ 1012, 0, 0, 0, 0, 1013, 0, 0, 1014, 0,
+ 0, 0, 0, 1015, 0, 0, 0, 1016, 0, 0,
+ 1017, 1018, 0, 924, 925, 1019, 0, 0, 1020, 0,
+ 1021, 0, 0, 0, 0, 1026, 0, 0, 221, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1022, 0, 0, 1023, 0,
+ 0, 1024, 0, 0, 0, 0, 0, 0, 0, 0,
+ 191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
+ 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,
+ 211, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 753, 0, 0, 0, 213, 214, 0,
+ 0, 0, 0, 0, 0, 917, 0, 754, 918, 919,
+ 0, 0, 0, 0, 0, 920, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 755, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 922, 923, 0, 1025, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 924, 925, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1026, 0, 0, 221
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 1, 68, 3, 30, 328, 434, 352, 431, 216, 361,
+ 433, 53, 432, 510, 399, 508, 68, 1, 338, 878,
+ 509, 567, 920, 65, 38, 684, 356, 628, 378, 37,
+ 717, 906, 756, 30, 463, 317, 385, 1019, 220, 179,
+ 460, 1461, 531, 32, 443, 1461, 47, 566, 871, 595,
+ 1467, 1326, 1327, 473, 55, 1468, 53, 603, 1333, 60,
+ 1466, 414, 1460, 1461, 346, 1405, 979, 840, 65, 1482,
+ 375, 399, 377, 619, 107, 474, 109, 1270, 111, 112,
+ 1313, 1465, 115, 1404, 117, 53, 438, 120, 121, 371,
+ 36, 124, 125, 126, 127, 1479, 180, 65, 131, 1574,
+ 430, 134, 522, 876, 1574, 1024, 139, 140, 881, 177,
+ 1587, 1588, 180, 177, 147, 399, 180, 469, 664, 1628,
+ 926, 894, 1793, 453, 1791, 898, 410, 411, 1792, 177,
+ 1407, 1770, 180, 857, 177, 1557, 1558, 180, 1693, 4,
+ 1415, 995, 1766, 1971, 23, 1835, 177, 499, 999, 180,
+ 1578, 177, 996, 1566, 180, 1836, 177, 997, 30, 180,
+ 1637, 1638, 708, 4, 177, 177, 2002, 180, 180, 23,
+ 7, 177, 524, 7, 180, 7, 127, 177, 7, 97,
+ 180, 53, 7, 8, 9, 30, 177, 79, 80, 180,
+ 7, 57, 1817, 65, 38, 1590, 177, 743, 1847, 180,
+ 23, 177, 45, 90, 180, 103, 177, 177, 53, 180,
+ 180, 177, 834, 835, 180, 104, 105, 106, 104, 216,
+ 65, 10, 190, 220, 49, 105, 51, 1288, 720, 103,
+ 722, 104, 724, 837, 993, 994, 61, 729, 7, 104,
+ 105, 66, 5, 104, 105, 70, 15, 16, 17, 18,
+ 294, 40, 41, 42, 43, 8, 753, 58, 104, 85,
+ 327, 328, 15, 16, 17, 18, 58, 144, 85, 22,
+ 8, 1691, 142, 20, 1751, 1752, 30, 1598, 1599, 2032,
+ 53, 13, 271, 780, 161, 155, 75, 839, 277, 104,
+ 1767, 1768, 122, 1691, 83, 84, 85, 86, 790, 53,
+ 840, 54, 172, 781, 1022, 8, 1079, 1354, 4, 1356,
+ 6, 65, 15, 16, 17, 18, 54, 106, 385, 22,
+ 364, 12, 838, 22, 311, 822, 85, 820, 104, 105,
+ 106, 57, 821, 294, 123, 8, 331, 30, 164, 128,
+ 129, 130, 293, 39, 216, 49, 341, 399, 220, 138,
+ 90, 54, 141, 93, 103, 352, 88, 104, 410, 411,
+ 53, 104, 1021, 128, 332, 432, 1764, 90, 49, 1789,
+ 93, 216, 65, 1789, 4, 220, 6, 364, 104, 1777,
+ 432, 54, 73, 861, 352, 427, 77, 816, 153, 293,
+ 1788, 1789, 104, 460, 814, 47, 221, 284, 126, 286,
+ 442, 92, 93, 364, 103, 104, 473, 311, 460, 808,
+ 1, 1012, 298, 4, 1015, 6, 303, 62, 8, 110,
+ 1897, 473, 150, 128, 297, 15, 16, 17, 18, 104,
+ 427, 91, 104, 161, 1285, 26, 27, 28, 29, 313,
+ 57, 5, 133, 134, 1505, 442, 364, 38, 153, 295,
+ 1072, 1073, 1074, 144, 99, 522, 326, 490, 288, 427,
+ 151, 20, 216, 22, 54, 1183, 220, 819, 1090, 1864,
+ 522, 369, 1076, 1, 442, 364, 4, 369, 6, 2169,
+ 352, 347, 348, 298, 8, 364, 364, 104, 2241, 2170,
+ 369, 15, 16, 17, 18, 2331, 369, 57, 26, 27,
+ 28, 29, 327, 328, 369, 2129, 331, 352, 369, 85,
+ 2338, 300, 301, 302, 277, 369, 1289, 1290, 335, 2144,
+ 364, 364, 2171, 216, 365, 1923, 1078, 220, 365, 292,
+ 54, 365, 1383, 365, 297, 4, 365, 6, 45, 1079,
+ 1, 364, 2097, 4, 104, 6, 369, 310, 295, 350,
+ 351, 352, 315, 2030, 297, 427, 696, 57, 350, 351,
+ 352, 1077, 90, 57, 313, 26, 27, 28, 29, 97,
+ 442, 297, 331, 332, 333, 1381, 2215, 45, 46, 1125,
+ 2204, 1921, 427, 295, 1438, 1862, 594, 2096, 2259, 939,
+ 2257, 282, 283, 369, 2258, 1439, 2018, 442, 352, 368,
+ 1440, 30, 365, 617, 104, 1652, 134, 2082, 1655, 349,
+ 104, 1658, 2082, 697, 364, 368, 1891, 922, 923, 444,
+ 1139, 281, 1141, 448, 53, 297, 349, 452, 1547, 697,
+ 358, 695, 457, 697, 580, 1257, 65, 462, 363, 847,
+ 37, 169, 103, 2071, 363, 399, 435, 436, 437, 697,
+ 999, 1926, 1885, 1886, 697, 2083, 410, 411, 1057, 352,
+ 1045, 133, 361, 871, 695, 368, 697, 90, 90, 695,
+ 369, 697, 1000, 427, 695, 243, 697, 1436, 1437, 468,
+ 297, 243, 695, 695, 697, 697, 114, 364, 442, 695,
+ 87, 697, 369, 518, 2015, 695, 1355, 697, 712, 342,
+ 146, 709, 90, 131, 695, 1898, 697, 85, 497, 87,
+ 7, 1624, 1065, 277, 695, 540, 697, 1045, 351, 695,
+ 1025, 697, 1214, 20, 695, 695, 697, 697, 292, 695,
+ 135, 697, 137, 297, 427, 144, 164, 297, 1, 103,
+ 149, 4, 1026, 6, 112, 113, 310, 814, 90, 442,
+ 278, 315, 85, 2093, 87, 331, 332, 333, 349, 293,
+ 8, 1045, 814, 26, 27, 28, 29, 2184, 103, 1628,
+ 114, 114, 2185, 45, 365, 47, 24, 2183, 368, 1272,
+ 364, 1278, 103, 1642, 111, 369, 1275, 216, 60, 61,
+ 126, 220, 135, 93, 14, 15, 16, 297, 2182, 126,
+ 1623, 365, 7, 297, 871, 148, 54, 1580, 277, 111,
+ 146, 85, 1305, 87, 150, 20, 998, 32, 33, 34,
+ 1309, 349, 1341, 292, 126, 516, 878, 172, 297, 275,
+ 276, 94, 104, 133, 1693, 2255, 2313, 365, 110, 2255,
+ 293, 310, 1, 832, 368, 4, 315, 6, 120, 20,
+ 847, 22, 313, 314, 126, 85, 2254, 2255, 78, 79,
+ 80, 284, 284, 286, 286, 243, 316, 26, 27, 28,
+ 29, 134, 104, 81, 871, 95, 96, 1564, 150, 284,
+ 1604, 1605, 41, 1023, 104, 44, 254, 255, 349, 97,
+ 258, 38, 39, 113, 114, 292, 284, 4, 286, 119,
+ 127, 915, 2177, 45, 365, 913, 85, 134, 116, 7,
+ 243, 357, 979, 310, 258, 259, 136, 1269, 315, 349,
+ 317, 325, 20, 352, 22, 145, 146, 305, 17, 149,
+ 49, 50, 999, 52, 53, 54, 1285, 164, 1597, 275,
+ 276, 18, 284, 109, 286, 111, 112, 126, 1000, 115,
+ 368, 117, 1498, 135, 120, 121, 168, 169, 124, 125,
+ 126, 127, 78, 306, 164, 131, 360, 361, 134, 243,
+ 1252, 150, 305, 139, 140, 847, 294, 30, 1475, 167,
+ 1473, 147, 85, 283, 172, 1474, 168, 169, 52, 2264,
+ 1649, 1, 52, 1045, 4, 111, 6, 1543, 427, 871,
+ 53, 998, 847, 313, 314, 164, 1728, 1729, 1730, 1731,
+ 126, 343, 65, 442, 346, 278, 26, 27, 28, 29,
+ 57, 357, 204, 126, 0, 297, 871, 114, 4, 818,
+ 6, 305, 5, 1, 1383, 8, 4, 1912, 6, 254,
+ 187, 364, 293, 190, 244, 245, 246, 150, 1398, 1050,
+ 1435, 294, 295, 1054, 364, 237, 172, 1442, 26, 27,
+ 28, 29, 313, 314, 1463, 285, 286, 62, 63, 30,
+ 131, 364, 67, 1, 135, 364, 4, 153, 6, 287,
+ 364, 168, 169, 164, 1292, 364, 349, 104, 164, 165,
+ 177, 114, 53, 847, 104, 105, 106, 364, 26, 27,
+ 28, 29, 365, 126, 65, 128, 43, 168, 169, 351,
+ 15, 16, 129, 130, 30, 5, 1, 871, 8, 4,
+ 1472, 6, 90, 146, 878, 22, 998, 150, 25, 97,
+ 153, 45, 1140, 292, 1142, 45, 1823, 53, 45, 30,
+ 1148, 26, 27, 28, 29, 261, 112, 113, 114, 65,
+ 1434, 1435, 7, 998, 847, 313, 314, 1441, 1442, 1443,
+ 1444, 986, 53, 216, 2146, 990, 134, 220, 99, 100,
+ 101, 102, 926, 292, 65, 7, 103, 104, 871, 8,
+ 299, 300, 2080, 2081, 309, 7, 114, 114, 20, 1,
+ 22, 104, 4, 1739, 6, 103, 315, 1405, 20, 1407,
+ 22, 169, 336, 337, 1, 90, 365, 4, 1, 6,
+ 370, 4, 97, 6, 26, 27, 28, 29, 1285, 242,
+ 370, 1943, 1944, 1945, 305, 306, 307, 308, 309, 26,
+ 27, 28, 29, 26, 27, 28, 29, 254, 2097, 993,
+ 994, 995, 996, 997, 998, 114, 1000, 116, 41, 134,
+ 342, 44, 275, 276, 342, 216, 1602, 274, 275, 220,
+ 103, 1946, 1947, 1948, 1949, 116, 135, 103, 104, 489,
+ 15, 16, 1026, 45, 143, 144, 145, 146, 114, 1631,
+ 359, 132, 45, 4, 169, 6, 135, 8, 60, 61,
+ 114, 1045, 104, 105, 106, 1292, 367, 60, 61, 352,
+ 216, 85, 153, 177, 220, 998, 23, 131, 23, 160,
+ 278, 52, 136, 137, 1634, 52, 1383, 1716, 538, 168,
+ 169, 52, 171, 52, 490, 216, 1711, 1712, 52, 220,
+ 103, 1383, 104, 85, 357, 1685, 364, 1687, 110, 349,
+ 4, 104, 6, 7, 1837, 103, 1692, 110, 120, 280,
+ 278, 1848, 103, 1842, 126, 365, 103, 120, 289, 290,
+ 291, 292, 85, 126, 1910, 1911, 85, 1913, 103, 104,
+ 103, 164, 15, 16, 427, 60, 61, 1, 150, 114,
+ 4, 349, 6, 1876, 4, 1878, 6, 150, 8, 442,
+ 227, 352, 1881, 278, 231, 232, 233, 365, 249, 250,
+ 1375, 1376, 26, 27, 28, 29, 103, 1382, 1405, 17,
+ 1407, 277, 313, 314, 38, 1623, 18, 45, 847, 243,
+ 1292, 349, 2107, 2108, 2109, 110, 292, 1711, 1712, 1781,
+ 368, 297, 60, 61, 5, 120, 352, 365, 350, 351,
+ 352, 126, 871, 1, 310, 7, 4, 1292, 6, 315,
+ 138, 139, 140, 141, 1455, 1456, 7, 1458, 1459, 1460,
+ 1461, 352, 1459, 7, 349, 150, 427, 7, 26, 27,
+ 28, 29, 1456, 103, 1458, 1459, 1460, 1461, 1830, 5,
+ 365, 442, 110, 399, 103, 2086, 2087, 7, 2147, 364,
+ 2263, 1459, 120, 7, 410, 411, 1504, 294, 126, 292,
+ 194, 195, 1, 192, 193, 4, 17, 6, 112, 113,
+ 238, 427, 1941, 18, 1938, 368, 1939, 112, 113, 247,
+ 248, 8, 150, 251, 252, 297, 442, 26, 27, 28,
+ 29, 2304, 7, 1405, 297, 1407, 427, 349, 1292, 1553,
+ 1554, 38, 41, 1551, 1552, 44, 4, 5, 1968, 112,
+ 113, 442, 349, 365, 1621, 103, 1623, 1624, 1, 364,
+ 1405, 4, 1407, 6, 103, 104, 1890, 103, 365, 998,
+ 364, 1572, 365, 364, 1575, 1995, 1577, 95, 96, 1580,
+ 2126, 103, 104, 26, 27, 28, 29, 1459, 1572, 364,
+ 1642, 1575, 294, 1577, 43, 44, 1580, 1390, 1391, 1292,
+ 37, 311, 1644, 364, 1, 1602, 1936, 4, 45, 6,
+ 47, 103, 49, 103, 1459, 52, 53, 54, 103, 56,
+ 364, 1375, 1376, 1377, 1378, 1379, 1623, 1381, 1382, 26,
+ 27, 28, 29, 103, 1602, 103, 1390, 1391, 1646, 45,
+ 104, 47, 364, 1644, 103, 97, 52, 1644, 54, 103,
+ 191, 1405, 58, 1407, 1862, 131, 231, 46, 196, 48,
+ 103, 50, 51, 104, 234, 164, 107, 108, 109, 58,
+ 59, 1738, 236, 234, 1, 235, 1644, 4, 235, 6,
+ 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443,
+ 1444, 103, 98, 343, 100, 1692, 103, 94, 103, 26,
+ 27, 28, 29, 92, 114, 1459, 116, 117, 118, 119,
+ 2056, 103, 1405, 1921, 1407, 103, 2213, 364, 2211, 364,
+ 364, 399, 1749, 2212, 1692, 349, 335, 336, 337, 2275,
+ 1602, 364, 410, 411, 1735, 103, 294, 134, 103, 1766,
+ 5, 365, 8, 1744, 1745, 1746, 1747, 1748, 104, 105,
+ 106, 1623, 1749, 2246, 2247, 1, 103, 1602, 4, 2248,
+ 6, 1762, 1763, 1764, 2310, 103, 1459, 52, 103, 1766,
+ 2316, 22, 1644, 43, 1775, 1776, 1777, 149, 1623, 5,
+ 26, 27, 28, 29, 367, 1786, 1787, 1788, 1789, 103,
+ 1787, 349, 85, 292, 847, 8, 128, 1798, 85, 1644,
+ 22, 1798, 1786, 1787, 1788, 1789, 22, 365, 367, 2208,
+ 364, 103, 144, 7, 1798, 331, 332, 333, 871, 1787,
+ 1692, 153, 1889, 1890, 371, 1826, 1827, 1828, 160, 161,
+ 1798, 2328, 364, 2326, 1, 364, 114, 4, 2327, 6,
+ 277, 371, 1826, 1827, 1828, 103, 5, 1692, 1602, 295,
+ 128, 104, 86, 87, 88, 292, 90, 135, 2210, 26,
+ 27, 28, 29, 1292, 364, 1862, 365, 312, 114, 1623,
+ 313, 314, 312, 310, 1628, 153, 20, 1749, 315, 43,
+ 317, 278, 160, 316, 1951, 2093, 847, 191, 1642, 316,
+ 1644, 294, 311, 2245, 1766, 7, 70, 1722, 1723, 1724,
+ 1725, 1968, 5, 166, 1749, 1906, 349, 7, 103, 1602,
+ 871, 222, 223, 224, 225, 1787, 1968, 39, 2317, 104,
+ 99, 1766, 365, 103, 1921, 363, 1798, 94, 1995, 363,
+ 1623, 847, 191, 363, 104, 2002, 99, 399, 1692, 1693,
+ 363, 103, 1787, 1995, 7, 998, 103, 103, 410, 411,
+ 365, 1644, 349, 1798, 20, 871, 847, 1711, 1712, 85,
+ 103, 103, 878, 1964, 103, 1966, 1967, 134, 365, 103,
+ 103, 365, 5, 2325, 103, 190, 1405, 104, 1407, 1980,
+ 871, 363, 151, 103, 311, 1986, 103, 103, 294, 103,
+ 1862, 2024, 1993, 1994, 105, 1749, 1997, 295, 365, 1692,
+ 187, 2034, 2003, 226, 227, 228, 229, 230, 2041, 2010,
+ 2011, 2012, 1766, 364, 364, 1, 364, 1862, 4, 364,
+ 6, 364, 349, 364, 364, 364, 2010, 2011, 2012, 41,
+ 1459, 364, 278, 1787, 7, 364, 134, 998, 365, 365,
+ 26, 27, 28, 29, 1798, 103, 365, 2114, 364, 1921,
+ 319, 320, 321, 322, 323, 41, 1749, 364, 44, 2056,
+ 104, 364, 8, 979, 1889, 1890, 8, 103, 2135, 103,
+ 5, 8, 104, 1766, 103, 103, 1921, 993, 994, 995,
+ 996, 997, 998, 363, 1000, 1018, 1016, 1329, 2056, 907,
+ 793, 1017, 2119, 792, 1787, 791, 2093, 1133, 572, 794,
+ 2101, 1491, 2129, 349, 20, 1798, 562, 998, 1862, 1020,
+ 1026, 278, 1, 281, 2115, 4, 282, 6, 1, 365,
+ 429, 4, 2119, 6, 1464, 1771, 2264, 2125, 2127, 1045,
+ 2189, 2191, 2129, 2190, 2192, 2136, 2137, 26, 27, 28,
+ 29, 2181, 2306, 26, 27, 28, 29, 2148, 2149, 1724,
+ 2151, 2152, 2153, 2154, 2155, 287, 1926, 2158, 41, 426,
+ 899, 44, 889, 1908, 1877, 1879, 962, 1921, 428, 1862,
+ 1102, 2180, 2251, 1602, 1377, 1379, 1378, 2204, 164, 1396,
+ 982, 1621, 349, 319, 2056, 79, 80, 81, 82, 83,
+ 84, 112, 113, 872, 1623, 1124, 1623, 2264, 365, 991,
+ 878, 216, 1403, 1444, 2205, 1333, 127, 2204, 129, 130,
+ 131, 2056, 1603, 2214, 1456, 1644, 1458, 1459, 1460, 1461,
+ 1635, 2093, 411, 1640, 438, 114, 2314, 439, 1921, 440,
+ 332, 152, 153, 154, 441, 718, 333, 2304, 333, 1292,
+ 695, 662, 2269, 1192, -1, -1, -1, 2119, 2093, -1,
+ -1, 2252, 2253, 2254, 2255, -1, 2253, 2129, -1, 2260,
+ 2261, 2262, 2263, 1692, 2331, -1, 2267, -1, 2252, 2253,
+ 2254, 2255, 2269, -1, 2119, 2276, 2260, 2261, 2262, 2263,
+ -1, 164, -1, 2284, 2129, 2253, -1, 112, 113, 2290,
+ 2291, 2292, 2293, 2294, 2295, 2296, 2297, 2298, 2299, 2300,
+ 2301, 126, 2056, -1, -1, -1, 292, 1239, 1240, 134,
+ -1, 2295, 2296, 2297, 2315, 993, 994, 995, 996, 997,
+ 1749, -1, 1000, -1, -1, 150, -1, -1, -1, -1,
+ 1572, 1292, 2204, 1575, -1, 1577, -1, 1766, 1580, 2093,
+ 2341, 2342, 2343, 2097, -1, -1, 1, -1, 1026, 4,
+ -1, 6, 1405, -1, 1407, -1, -1, -1, 1787, 2204,
+ -1, -1, -1, 2056, 1296, 2119, -1, 1045, -1, 1798,
+ 45, 26, 27, 28, 29, 2129, 1292, -1, -1, 365,
+ -1, 2253, 112, 113, -1, 60, 61, -1, -1, 278,
+ -1, 121, 122, 123, 124, 125, -1, 2269, 1640, -1,
+ 2093, 1292, 37, -1, -1, -1, 1459, -1, 2253, 292,
+ 45, -1, 47, -1, 49, 37, 878, 52, 53, 54,
+ -1, 56, -1, 45, 2269, 47, 2119, -1, -1, -1,
+ 52, 53, 54, 1862, 56, 110, 2129, 1353, 1354, -1,
+ 1356, -1, -1, -1, 1405, 120, 1407, -1, -1, -1,
+ 2204, 126, -1, 278, 279, 280, 281, -1, -1, -1,
+ 349, -1, -1, -1, 926, -1, -1, -1, -1, 294,
+ 295, 296, -1, -1, -1, 150, 365, -1, -1, -1,
+ -1, -1, 365, -1, -1, -1, -1, -1, 45, 1405,
+ -1, 1407, 1921, -1, -1, -1, -1, 45, 1459, 2253,
+ -1, -1, -1, 60, 61, -1, -1, -1, -1, -1,
+ -1, 2204, 60, 61, 1405, 2269, 1407, -1, 1434, 1435,
+ 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, 1444, -1,
+ -1, 993, 994, 995, 996, 997, -1, -1, 1000, -1,
+ -1, -1, -1, 1459, 1786, 1787, 1788, 1789, -1, 1602,
+ -1, 1483, -1, 110, 1486, -1, 1798, -1, -1, -1,
+ 2253, -1, 110, 120, 1026, 70, -1, -1, 1459, 126,
+ 1623, 76, 120, -1, -1, -1, 2269, -1, 126, 45,
+ -1, -1, -1, 1045, 1826, 1827, 1828, -1, 844, -1,
+ 846, 1644, -1, 150, 60, 61, -1, -1, -1, 104,
+ 105, 106, 150, -1, -1, -1, 111, 863, -1, 865,
+ 115, 867, -1, -1, 37, 120, -1, 873, 874, -1,
+ -1, 126, 45, -1, 47, 130, 49, 2056, -1, 52,
+ 53, 54, -1, 56, -1, 1567, -1, 60, 61, 1692,
+ -1, 1602, 277, -1, 110, 150, -1, -1, -1, 905,
+ -1, -1, 908, -1, 120, 277, 311, 292, -1, -1,
+ 126, -1, 1623, -1, 2093, -1, -1, -1, -1, -1,
+ 292, -1, -1, -1, 1606, 310, 1608, 1609, -1, 1611,
+ 315, -1, 317, 1644, 150, -1, 1602, 110, 310, -1,
+ 2119, -1, -1, 315, 349, 317, 1749, 120, -1, -1,
+ 2129, -1, -1, 126, -1, 1621, 45, 1623, 1624, -1,
+ 365, 1602, 1628, 1766, -1, -1, -1, 973, -1, -1,
+ -1, 60, 61, -1, -1, -1, 1642, 150, 1644, -1,
+ -1, 1692, 1623, -1, 1787, -1, 1652, -1, -1, 1655,
+ -1, -1, 1658, -1, -1, 1798, -1, -1, -1, -1,
+ -1, -1, -1, 1644, -1, -1, 1434, 1435, 1436, 1437,
+ 1438, 1439, 1440, 1441, 1442, 1443, 1444, -1, 2010, 2011,
+ 2012, 110, -1, -1, -1, 2204, 1692, 1693, -1, -1,
+ -1, 120, 287, -1, -1, 290, 291, 126, 1749, -1,
+ 1046, 1047, 297, -1, -1, 1711, 1712, -1, 112, 113,
+ -1, 1692, 116, -1, -1, 1766, -1, -1, -1, 1862,
+ -1, 150, -1, 127, 128, 129, 130, 131, 132, 133,
+ 134, 135, 327, 328, 2253, -1, 1787, -1, -1, -1,
+ -1, -1, 23, 1749, 37, -1, -1, 1798, -1, 42,
+ 2269, -1, 45, 46, 47, 48, -1, 38, 51, 52,
+ 1766, 54, 55, 56, 277, 58, -1, -1, 1749, -1,
+ -1, -1, -1, 177, 369, -1, -1, -1, 1921, 292,
+ -1, 1787, -1, -1, -1, 1766, -1, -1, -1, -1,
+ -1, -1, 1798, -1, -1, -1, -1, 310, -1, -1,
+ -1, -1, 315, -1, 317, 98, 1787, 100, 101, 102,
+ -1, 1862, -1, -1, -1, -1, 1, 1798, -1, 4,
+ -1, 6, 103, 1375, 1376, 1377, 1378, 1379, -1, 1381,
+ 1382, -1, -1, 113, 114, -1, 116, -1, 1390, 1391,
+ -1, 26, 27, 28, 29, -1, -1, -1, 1870, -1,
+ -1, -1, 37, -1, -1, 135, 1862, -1, -1, -1,
+ 1628, -1, 47, 143, 144, -1, 146, 52, -1, 54,
+ 1921, 56, -1, -1, 1642, -1, 156, 157, 158, -1,
+ -1, 1862, 1434, 1435, 1436, 1437, 1438, 1439, 1440, 1441,
+ 1442, 1443, 1444, -1, 175, -1, -1, 178, 179, 180,
+ 181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
+ -1, -1, -1, 2056, -1, 1921, -1, -1, -1, -1,
+ 2252, 2253, 2254, 2255, -1, 1693, -1, -1, 2260, 2261,
+ 2262, 2263, -1, 1279, -1, -1, -1, 1283, -1, -1,
+ 1921, -1, -1, 1711, 1712, -1, -1, 1293, 1294, 1295,
+ 2093, -1, 1298, -1, 1300, -1, -1, -1, -1, -1,
+ -1, -1, -1, 2295, 2296, 2297, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 2119, 1323, -1, 164,
+ -1, -1, -1, -1, 277, -1, 2129, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 292,
+ -1, -1, -1, 2025, -1, 2056, 299, 300, 301, 302,
+ -1, -1, -1, 2035, 1360, -1, 1362, 310, -1, -1,
+ 2042, -1, 315, 1369, 317, 318, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 1384, -1,
+ 1386, -1, 2093, -1, -1, -1, -1, -1, 109, 1395,
+ 2056, 1397, -1, -1, -1, 2077, -1, -1, -1, -1,
+ -1, 2204, -1, 38, -1, 126, -1, -1, 2119, -1,
+ -1, -1, -1, -1, -1, 2056, 1628, -1, 2129, -1,
+ -1, 142, -1, -1, -1, -1, 147, 2093, -1, 150,
+ 1642, 2097, 277, -1, 155, -1, -1, -1, 159, -1,
+ -1, 162, 163, -1, -1, -1, 167, 292, -1, 170,
+ 2253, 172, 2093, 2119, -1, -1, -1, 2139, 2140, 2141,
+ -1, -1, -1, 2129, -1, 310, 2269, -1, 103, -1,
+ 315, -1, 317, -1, -1, -1, 197, -1, 2119, -1,
+ -1, 1693, 203, 2165, -1, -1, -1, -1, 2129, -1,
+ -1, -1, -1, 2204, -1, -1, -1, -1, -1, 1711,
+ 1712, -1, 1, -1, 349, 4, -1, 6, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 365, -1, -1, -1, -1, -1, -1, 26, 27, 28,
+ 29, -1, -1, -1, -1, -1, -1, -1, 2204, -1,
+ 175, 40, 2253, 178, 179, 180, 181, 182, 183, 184,
+ 185, 186, 187, 188, 189, 190, -1, -1, 2269, -1,
+ -1, -1, -1, 2204, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 1583, 1584, -1,
+ -1, -1, -1, -1, -1, -1, -1, 2253, -1, -1,
+ 89, 90, 91, 92, -1, 94, -1, -1, 97, -1,
+ -1, -1, -1, 2269, 1610, 135, -1, -1, -1, -1,
+ 1, -1, 2253, -1, 144, 114, -1, -1, -1, 1625,
+ 11, 12, 13, 14, 15, 16, 17, -1, 2269, 20,
+ 160, 90, -1, -1, 164, -1, -1, -1, 168, 169,
+ 2322, 2323, 2324, 173, 174, 175, 176, 177, -1, -1,
+ -1, -1, -1, 112, 113, 1661, -1, 116, -1, -1,
+ -1, -1, -1, -1, -1, 164, -1, -1, -1, 2097,
+ -1, -1, 1678, -1, 1680, 134, -1, -1, -1, -1,
+ -1, -1, 73, -1, -1, 76, 77, 78, 79, 80,
+ 81, -1, -1, -1, -1, -1, -1, 88, -1, 90,
+ 91, 92, 93, 94, 95, 96, 97, -1, 99, 100,
+ 101, 102, -1, 104, -1, -1, -1, 108, -1, 110,
+ -1, -1, 113, 114, -1, 116, -1, -1, 119, -1,
+ -1, -1, 191, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 133, 134, 135, 136, 137, -1, 139, 140,
+ -1, -1, 143, 144, 145, 146, -1, -1, 149, -1,
+ 151, -1, -1, -1, 1, -1, -1, 4, -1, 6,
+ -1, -1, -1, -1, -1, -1, -1, -1, 277, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 26,
+ 27, 28, 29, 292, -1, 254, -1, -1, 297, -1,
+ -1, -1, -1, 40, -1, -1, -1, -1, -1, -1,
+ -1, 310, -1, -1, -1, -1, 315, -1, -1, 278,
+ 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, -1, -1, 294, 295, 296, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 1855,
+ 349, -1, 89, 90, 91, 92, -1, 94, 317, -1,
+ 97, -1, -1, -1, -1, -1, 365, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 114, -1, -1,
+ -1, -1, 1888, -1, -1, 2097, -1, -1, -1, 280,
+ 281, 282, 283, 284, 285, 286, 287, -1, 289, 290,
+ 291, 292, -1, 1, -1, -1, 4, -1, 6, 1915,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 23, -1, 164, 26, 27,
+ 28, 29, 30, 31, -1, -1, -1, 35, 36, 37,
+ -1, -1, -1, -1, -1, -1, 44, -1, -1, -1,
+ -1, -1, -1, -1, 52, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 62, 63, -1, -1, -1, 67,
+ -1, -1, 70, -1, -1, -1, -1, -1, -1, -1,
+ -1, 79, 80, 81, 82, 83, 84, -1, -1, -1,
+ -1, -1, -1, 109, -1, 111, 94, -1, -1, 115,
+ 98, -1, 100, -1, 120, 103, 104, 105, 106, -1,
+ 126, 109, -1, 111, -1, -1, 114, 115, -1, -1,
+ -1, -1, 120, -1, -1, -1, 142, -1, 126, -1,
+ -1, 147, -1, -1, 150, -1, -1, -1, -1, 155,
+ 277, -1, -1, 159, 142, -1, 162, 163, 164, 147,
+ -1, 167, 150, -1, 170, 292, 172, 155, -1, -1,
+ 297, 159, -1, -1, 162, 163, 164, -1, -1, 167,
+ -1, -1, 170, 310, 172, -1, -1, -1, 315, -1,
+ -1, 197, -1, 199, -1, 2091, -1, 203, -1, -1,
+ -1, 482, -1, -1, -1, -1, -1, -1, 489, 197,
+ 198, -1, 200, 201, 202, 203, -1, -1, -1, 500,
+ -1, 502, 349, 504, -1, 506, -1, -1, -1, -1,
+ 511, -1, -1, -1, 515, 516, -1, -1, 365, -1,
+ -1, -1, -1, -1, 525, -1, -1, 528, -1, -1,
+ 238, 239, 240, 241, -1, -1, -1, 538, -1, 247,
+ 248, -1, -1, 251, 252, 253, 254, 255, 256, 257,
+ 258, 259, 260, 261, 262, 263, 264, 265, 266, 267,
+ 268, 269, 270, 271, 272, 273, 274, -1, -1, 277,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 292, -1, -1, -1, -1, 297,
+ -1, -1, -1, -1, -1, -1, 304, -1, -1, -1,
+ -1, -1, 310, -1, -1, -1, -1, 315, -1, -1,
+ -1, -1, -1, 321, 322, -1, 324, -1, -1, 327,
+ 328, 329, 330, -1, -1, -1, 334, -1, -1, -1,
+ 338, 339, 340, -1, -1, -1, 344, 345, -1, -1,
+ -1, 349, -1, -1, -1, 353, -1, 1, 356, 357,
+ 4, -1, 6, -1, 362, -1, 364, 365, 366, -1,
+ -1, 369, -1, -1, -1, -1, -1, -1, -1, 23,
+ -1, -1, 26, 27, 28, 29, 30, 31, -1, -1,
+ -1, 35, 36, 37, -1, -1, -1, -1, -1, -1,
+ 44, -1, -1, -1, -1, -1, -1, -1, 52, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 62, 63,
+ -1, -1, -1, 67, -1, -1, 70, -1, -1, -1,
+ -1, -1, -1, -1, -1, 79, 80, 81, 82, 83,
+ 84, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 94, -1, -1, -1, 98, -1, 100, -1, -1, 103,
+ 104, 105, 106, -1, -1, 109, -1, 111, -1, -1,
+ 114, 115, -1, -1, 1, -1, 120, 4, -1, 6,
+ -1, -1, 126, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 142, 26,
+ 27, 28, 29, 147, -1, -1, 150, 182, -1, -1,
+ -1, 155, -1, 40, -1, 159, -1, -1, 162, 163,
+ 164, -1, -1, 167, -1, -1, 170, -1, 172, -1,
+ 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, -1, -1, -1,
+ -1, -1, -1, 197, 198, -1, 200, 201, 202, 203,
+ -1, -1, 89, 90, 91, 92, -1, 94, -1, -1,
+ 97, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 114, -1, -1,
+ -1, -1, -1, -1, 238, 239, 240, 241, -1, -1,
+ -1, -1, -1, 247, 248, -1, -1, 251, 252, 253,
+ 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
+ 274, -1, -1, 277, -1, -1, -1, 164, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 292, -1,
+ -1, -1, -1, 297, -1, -1, -1, -1, -1, -1,
+ 304, -1, -1, -1, -1, -1, 310, -1, -1, -1,
+ -1, 315, -1, -1, -1, -1, -1, 321, 322, -1,
+ 324, -1, -1, 327, 328, 329, 330, -1, -1, -1,
+ 334, -1, -1, -1, 338, 339, 340, -1, -1, -1,
+ 344, 345, -1, -1, -1, 349, -1, -1, -1, 353,
+ -1, 1, 356, 357, 4, -1, 6, -1, 362, -1,
+ 364, 365, 366, -1, -1, 369, -1, -1, -1, -1,
+ -1, -1, -1, 23, -1, -1, 26, 27, 28, 29,
+ 30, 31, -1, -1, -1, 35, 36, 37, -1, -1,
+ 277, -1, -1, -1, 44, -1, -1, -1, -1, -1,
+ -1, -1, 52, -1, -1, 292, -1, -1, -1, -1,
+ 297, -1, 62, 63, -1, -1, -1, 67, -1, -1,
+ 70, -1, -1, 310, -1, -1, -1, -1, 315, 79,
+ 80, 81, 82, 83, 84, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 94, -1, -1, -1, 98, -1,
+ 100, -1, 1103, 103, 104, 105, 106, -1, -1, 109,
+ -1, 111, 349, -1, 114, 115, -1, -1, 1, -1,
+ 120, 4, -1, 6, -1, -1, 126, -1, 365, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 142, 26, 27, 28, 29, 147, -1, -1,
+ 150, -1, -1, -1, -1, 155, -1, 40, -1, 159,
+ -1, -1, 162, 163, 164, -1, -1, 167, -1, -1,
+ 170, -1, 172, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 197, 198, -1,
+ 200, 201, 202, 203, -1, -1, -1, 90, 91, 92,
+ -1, 94, -1, -1, 97, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 114, -1, -1, -1, -1, -1, -1, 238, 239,
+ 240, 241, -1, -1, -1, -1, -1, 247, 248, -1,
+ -1, 251, 252, 253, 254, 255, 256, 257, 258, 259,
+ 260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, -1, -1, 277, -1, -1,
+ -1, 164, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 292, -1, -1, -1, -1, 297, -1, -1,
+ -1, -1, -1, -1, 304, -1, -1, -1, -1, -1,
+ 310, -1, -1, -1, -1, 315, -1, -1, -1, -1,
+ -1, 321, 322, -1, 324, -1, -1, 327, 328, 329,
+ 330, -1, -1, -1, 334, -1, -1, -1, 338, 339,
+ 340, -1, -1, -1, 344, 345, -1, -1, -1, 349,
+ -1, -1, -1, 353, -1, 1, 356, 357, 4, -1,
+ 6, -1, 362, -1, 364, 365, 366, -1, -1, 369,
+ -1, -1, -1, -1, -1, -1, -1, 23, -1, -1,
+ 26, 27, 28, 29, 30, 31, -1, -1, -1, 35,
+ 36, 37, -1, -1, 277, -1, -1, -1, 44, -1,
+ -1, -1, -1, -1, -1, -1, 52, -1, -1, 292,
+ -1, -1, -1, -1, 297, -1, 62, 63, -1, -1,
+ -1, 67, -1, -1, 70, -1, -1, 310, -1, -1,
+ -1, -1, 315, 79, 80, 81, 82, 83, 84, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 94, -1,
+ -1, -1, 98, -1, 100, -1, -1, 103, 104, 105,
+ 106, -1, -1, 109, -1, 111, 349, -1, 114, 115,
+ -1, -1, 1, -1, 120, 4, -1, 6, -1, -1,
+ 126, -1, 365, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 142, 26, 27, 28,
+ 29, 147, -1, -1, 150, -1, -1, -1, -1, 155,
+ -1, 40, -1, 159, -1, -1, 162, 163, 164, -1,
+ -1, 167, -1, -1, 170, -1, 172, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 197, 198, -1, 200, 201, 202, 203, -1, -1,
+ -1, 90, 91, 92, -1, 94, -1, -1, 97, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 114, -1, -1, -1, -1,
+ -1, -1, 238, 239, 240, 241, -1, -1, -1, -1,
+ -1, 247, 248, -1, -1, 251, 252, 253, 254, 255,
+ 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, -1,
+ -1, 277, -1, -1, -1, 164, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 292, -1, -1, -1,
+ -1, 297, -1, -1, -1, -1, -1, -1, 304, -1,
+ -1, -1, -1, -1, 310, -1, -1, -1, -1, 315,
+ -1, -1, -1, -1, -1, 321, 322, -1, 324, -1,
+ -1, 327, 328, 329, 330, -1, -1, -1, 334, -1,
+ -1, -1, 338, 339, 340, 4, -1, 6, 344, 345,
+ -1, -1, -1, 349, -1, -1, -1, 353, -1, -1,
+ 356, 357, -1, -1, 23, -1, 362, -1, 364, 365,
+ 366, 30, 31, 369, -1, -1, 35, 36, 37, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 52, -1, -1, -1, -1, 277, -1,
+ -1, -1, -1, 62, 63, -1, -1, 104, 67, -1,
+ -1, 70, -1, 292, -1, -1, -1, -1, 297, -1,
+ 79, 80, 81, 82, 83, 84, -1, -1, -1, -1,
+ -1, 310, -1, -1, 131, -1, 315, 134, -1, 98,
+ -1, 100, -1, -1, 103, 104, 105, 106, -1, -1,
+ 109, -1, 111, -1, 151, -1, 115, -1, -1, -1,
+ -1, 120, -1, -1, -1, -1, -1, 126, -1, -1,
+ 349, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 142, -1, -1, 365, -1, 147, -1,
+ -1, 150, -1, -1, 1, -1, 155, 4, -1, 6,
+ 159, -1, -1, 162, 163, -1, -1, -1, 167, -1,
+ -1, 170, -1, 172, -1, -1, -1, -1, -1, 26,
+ 27, 28, 29, -1, -1, -1, -1, -1, -1, -1,
+ 37, -1, -1, -1, -1, -1, -1, -1, 197, 198,
+ 47, 200, 201, 202, 203, 52, -1, 54, -1, 56,
+ -1, -1, -1, -1, -1, -1, -1, 254, 255, 256,
+ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 273, 274, -1, 238,
+ 239, 240, 241, -1, -1, -1, -1, -1, 247, 248,
+ -1, -1, 251, 252, 253, 254, 255, 256, 257, 258,
+ 259, 260, 261, 262, 263, 264, 265, 266, 267, 268,
+ 269, 270, 271, 272, 273, 274, -1, -1, 277, -1,
+ 317, -1, 5, -1, 321, 322, -1, -1, -1, -1,
+ -1, -1, -1, 292, 331, -1, -1, -1, 297, -1,
+ 23, -1, -1, -1, -1, 304, -1, -1, 31, -1,
+ -1, 310, -1, 36, -1, -1, 315, 164, -1, -1,
+ 357, -1, 321, 322, -1, 324, -1, -1, 327, 328,
+ 329, 330, -1, -1, -1, 334, -1, -1, -1, 338,
+ 339, 340, -1, -1, -1, 344, 345, 70, -1, -1,
+ -1, -1, -1, 76, 353, -1, -1, 356, 357, -1,
+ -1, -1, 85, 362, 87, 364, 365, 366, -1, -1,
+ 369, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 103, 104, 105, 106, -1, -1, 109, -1, 111, -1,
+ -1, -1, 115, -1, -1, -1, -1, 120, -1, -1,
+ -1, -1, -1, 126, -1, -1, -1, 130, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 142,
+ -1, -1, -1, -1, 147, -1, -1, 150, -1, -1,
+ 277, -1, 155, -1, -1, -1, 159, -1, -1, 162,
+ 163, -1, -1, -1, 167, 292, -1, 170, -1, 172,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 310, -1, -1, -1, -1, 315, -1,
+ 317, -1, -1, -1, 197, 198, -1, 200, 201, 202,
+ 203, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 5, -1, -1, -1, -1, -1, 112, 113, -1,
+ -1, 116, 349, -1, -1, -1, -1, -1, -1, 23,
+ -1, -1, -1, -1, -1, 238, -1, 31, 365, 134,
+ -1, -1, 36, -1, -1, -1, -1, -1, -1, -1,
+ 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, -1, -1, 277, -1, 70, -1, -1, -1,
+ -1, -1, 76, -1, 287, -1, -1, 290, 291, -1,
+ -1, -1, -1, -1, 297, -1, -1, -1, -1, -1,
+ -1, -1, 305, -1, -1, -1, -1, -1, -1, 103,
+ 104, 105, 106, -1, -1, 109, -1, 111, 321, 322,
+ -1, 115, -1, -1, 327, 328, 120, -1, -1, -1,
+ -1, -1, 126, -1, -1, -1, 130, 340, -1, -1,
+ -1, 344, 345, -1, -1, -1, -1, -1, 142, -1,
+ -1, 354, 355, 147, 357, -1, 150, -1, -1, 254,
+ -1, 155, -1, 366, -1, 159, 369, -1, 162, 163,
+ -1, -1, -1, 167, -1, -1, 170, -1, 172, -1,
+ -1, -1, -1, 278, 279, 280, 281, 282, 283, -1,
+ 285, 286, 287, 288, 289, 290, 291, -1, -1, 294,
+ 295, 296, -1, 197, 198, -1, 200, 201, 202, 203,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 5, -1, 317, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 23, -1,
+ -1, -1, -1, -1, 238, -1, 31, -1, -1, -1,
+ -1, 36, -1, -1, -1, -1, -1, -1, -1, 253,
+ 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
+ 274, -1, -1, 277, -1, 70, -1, -1, -1, -1,
+ -1, 76, -1, 287, -1, -1, 290, 291, -1, -1,
+ -1, -1, -1, 297, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 103, 104,
+ 105, 106, -1, -1, 109, -1, 111, 321, 322, -1,
+ 115, -1, -1, 327, 328, 120, -1, -1, 109, -1,
+ 111, 126, -1, 114, 115, 130, 340, -1, -1, 120,
+ 344, 345, -1, -1, -1, 126, -1, 142, -1, -1,
+ 354, 355, 147, 357, -1, 150, -1, -1, -1, -1,
+ 155, 142, 366, -1, 159, 369, 147, 162, 163, 150,
+ -1, -1, 167, -1, 155, 170, -1, 172, 159, -1,
+ -1, 162, 163, -1, -1, -1, 167, -1, -1, 170,
+ -1, 172, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 197, 198, -1, 200, 201, 202, 203, -1,
+ -1, -1, -1, -1, -1, -1, 197, -1, 199, 5,
+ -1, -1, 203, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 23, -1, -1,
+ -1, -1, -1, 238, -1, 31, -1, -1, -1, -1,
+ 36, -1, -1, -1, -1, -1, -1, -1, 253, 254,
+ 255, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ -1, -1, 277, -1, 70, -1, -1, -1, -1, -1,
+ 76, -1, 287, -1, -1, 290, 291, -1, -1, -1,
+ -1, -1, 297, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 103, 104, 105,
+ 106, -1, -1, 109, -1, 111, 321, 322, -1, 115,
+ -1, -1, 327, 328, 120, -1, -1, 109, -1, 111,
+ 126, -1, -1, 115, 130, 340, -1, -1, 120, 344,
+ 345, -1, -1, -1, 126, -1, 142, -1, -1, 354,
+ 355, 147, 357, -1, 150, -1, -1, -1, -1, 155,
+ 142, 366, -1, 159, 369, 147, 162, 163, 150, -1,
+ -1, 167, -1, 155, 170, -1, 172, 159, -1, -1,
+ 162, 163, -1, -1, -1, 167, -1, -1, 170, -1,
+ 172, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 197, 198, -1, 200, 201, 202, 203, -1, -1,
+ -1, -1, -1, -1, -1, 197, -1, -1, 5, -1,
+ -1, 203, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 23, -1, -1, -1,
+ -1, -1, 238, -1, 31, -1, -1, -1, -1, 36,
+ -1, -1, -1, -1, -1, -1, -1, 253, 254, 255,
+ 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, -1,
+ -1, 277, -1, 70, -1, -1, -1, -1, -1, 76,
+ -1, 287, -1, -1, 290, 291, -1, -1, -1, -1,
+ -1, 297, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 103, 104, 105, 106,
+ -1, -1, 109, -1, 111, 321, 322, -1, 115, -1,
+ -1, 327, 328, 120, -1, -1, -1, -1, -1, 126,
+ -1, -1, -1, 130, 340, -1, -1, -1, 344, 345,
+ -1, -1, -1, -1, -1, 142, -1, -1, 354, 355,
+ 147, 357, -1, 150, -1, -1, -1, -1, 155, -1,
+ 366, -1, 159, 369, -1, 162, 163, -1, -1, -1,
+ 167, -1, -1, 170, -1, 172, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 1, -1, -1, 4, -1, 6, -1, -1,
+ 197, 198, -1, 200, 201, 202, 203, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 26, 27, 28,
+ 29, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 40, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 238, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 253, 254, 255, 256,
+ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 273, 274, -1, -1,
+ 277, 90, 91, 92, -1, 94, -1, -1, 97, -1,
+ 287, -1, -1, 290, 291, -1, -1, -1, -1, -1,
+ 297, -1, -1, -1, -1, 114, 9, 10, 11, 12,
+ 13, 14, -1, -1, -1, -1, 19, -1, -1, -1,
+ 23, -1, -1, -1, 321, 322, -1, -1, -1, -1,
+ 327, 328, -1, -1, -1, -1, 21, -1, -1, -1,
+ -1, -1, -1, 340, -1, -1, -1, 344, 345, -1,
+ -1, -1, -1, -1, -1, 164, -1, 354, 355, -1,
+ 357, -1, -1, -1, -1, -1, -1, 70, -1, 366,
+ -1, -1, 369, 76, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 70, -1, -1, -1, -1,
+ -1, 76, -1, -1, -1, -1, -1, -1, -1, -1,
+ 103, 104, 105, 106, -1, -1, -1, -1, 111, -1,
+ -1, -1, 115, -1, -1, -1, -1, 120, 103, 104,
+ 105, 106, -1, 126, -1, -1, 111, 130, -1, -1,
+ 115, -1, -1, -1, -1, 120, -1, -1, -1, 142,
+ 21, 126, -1, -1, 147, 130, -1, 150, -1, -1,
+ -1, -1, 155, -1, -1, -1, 159, 142, -1, 162,
+ 163, -1, 147, -1, 167, 150, -1, 170, 277, 172,
+ 155, -1, -1, -1, 159, -1, -1, 162, 163, -1,
+ -1, -1, 167, 292, -1, 170, -1, 172, 297, 70,
+ -1, -1, -1, -1, 197, 76, -1, 200, -1, -1,
+ 203, 310, -1, -1, -1, -1, 315, -1, -1, -1,
+ -1, -1, 197, -1, -1, 200, -1, -1, 203, -1,
+ -1, -1, 103, 104, 105, 106, -1, -1, -1, -1,
+ 111, -1, -1, -1, 115, -1, -1, -1, -1, 120,
+ 349, -1, -1, -1, -1, 126, -1, -1, -1, 130,
+ -1, -1, -1, -1, -1, -1, 365, -1, -1, -1,
+ -1, 142, -1, -1, -1, -1, 147, -1, -1, 150,
+ -1, -1, -1, -1, 155, -1, -1, -1, 159, -1,
+ -1, 162, 163, -1, 287, -1, 167, 290, 291, 170,
+ -1, 172, -1, -1, 297, -1, -1, -1, -1, -1,
+ -1, -1, 287, -1, -1, 290, 291, -1, -1, -1,
+ -1, -1, 297, -1, -1, -1, 197, -1, -1, 200,
+ -1, -1, 203, -1, 327, 328, -1, 330, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 327, 328, -1, 330, -1, -1, -1, -1,
+ -1, 354, 355, -1, -1, -1, -1, -1, -1, 22,
+ 23, 364, -1, 366, -1, -1, 369, -1, -1, 354,
+ 355, -1, -1, -1, -1, -1, -1, -1, -1, 364,
+ -1, 366, -1, -1, 369, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 287, 70, -1, 290,
+ 291, -1, -1, 76, -1, -1, 297, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 103, 104, 105, 106, -1, -1, 327, 328, 111, 330,
+ -1, -1, 115, -1, -1, -1, -1, 120, -1, -1,
+ -1, -1, -1, 126, -1, -1, -1, 130, -1, -1,
+ -1, -1, -1, 354, 355, -1, -1, -1, -1, 142,
+ -1, -1, -1, -1, 147, 366, -1, 150, 369, -1,
+ -1, -1, 155, -1, -1, -1, 159, -1, -1, 162,
+ 163, -1, -1, -1, 167, -1, 23, 170, -1, 172,
+ -1, -1, -1, 30, 31, -1, -1, -1, 35, 36,
+ 37, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 197, 52, -1, 200, -1, -1,
+ 203, -1, -1, -1, -1, 62, 63, -1, -1, -1,
+ 67, -1, -1, 70, -1, -1, -1, -1, -1, -1,
+ -1, -1, 79, 80, 81, 82, 83, 84, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 98, -1, 100, -1, -1, 103, 104, 105, 106,
+ -1, -1, 109, -1, 111, -1, -1, -1, 115, -1,
+ -1, -1, -1, 120, -1, -1, -1, -1, -1, 126,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 287, 142, -1, 290, 291, -1,
+ 147, -1, -1, 150, 297, -1, -1, -1, 155, -1,
+ -1, -1, 159, -1, -1, 162, 163, -1, -1, -1,
+ 167, -1, -1, 170, -1, 172, -1, -1, -1, -1,
+ -1, -1, -1, -1, 327, 328, -1, 330, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 197, 198, -1, 200, 201, 202, 203, -1, -1, -1,
+ -1, 354, 355, -1, -1, -1, -1, -1, -1, -1,
+ -1, 364, -1, 366, -1, -1, 369, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 238, 239, 240, 241, -1, -1, -1, -1, -1,
+ 247, 248, -1, -1, 251, 252, 253, 254, 255, 256,
+ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 273, 274, -1, -1,
+ 277, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 23, -1, 292, -1, -1, -1, -1,
+ 297, 31, -1, -1, -1, -1, 36, 304, -1, -1,
+ -1, -1, -1, 310, -1, -1, -1, -1, 315, -1,
+ -1, -1, -1, -1, 321, 322, -1, 324, -1, -1,
+ 327, 328, 329, 330, -1, -1, -1, 334, -1, -1,
+ 70, 338, 339, 340, -1, -1, 76, 344, 345, -1,
+ -1, -1, -1, -1, -1, -1, 353, -1, -1, 356,
+ 357, -1, -1, -1, -1, 362, -1, 364, -1, 366,
+ -1, -1, 369, 103, 104, 105, 106, -1, -1, 109,
+ -1, 111, -1, -1, -1, 115, -1, -1, -1, -1,
+ 120, -1, -1, -1, -1, -1, 126, -1, -1, -1,
+ 130, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 142, -1, -1, -1, -1, 147, -1, -1,
+ 150, -1, -1, -1, -1, 155, -1, -1, -1, 159,
+ -1, -1, 162, 163, -1, -1, -1, 167, -1, -1,
+ 170, -1, 172, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 197, 198, -1,
+ 200, 201, 202, 203, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 23, -1, -1, -1, -1, -1, 238, 30,
+ 31, -1, -1, -1, -1, 36, -1, -1, -1, -1,
+ -1, -1, -1, 253, 254, 255, 256, 257, 258, 259,
+ 260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, -1, -1, 277, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 287, -1, -1,
+ 290, 291, -1, -1, -1, -1, -1, 297, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 103, 104, 105, 106, -1, -1, 109, -1,
+ 111, 321, 322, -1, 115, -1, -1, 327, 328, 120,
+ -1, -1, -1, -1, -1, 126, -1, -1, -1, -1,
+ 340, -1, -1, -1, 344, 345, -1, -1, -1, -1,
+ -1, 142, -1, -1, 354, 355, 147, 357, -1, 150,
+ -1, -1, -1, -1, 155, -1, 366, -1, 159, 369,
+ -1, 162, 163, -1, -1, -1, 167, -1, -1, 170,
+ -1, 172, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 197, 198, -1, 200,
+ 201, 202, 203, -1, -1, -1, -1, -1, -1, -1,
+ 23, -1, -1, -1, -1, -1, -1, 30, 31, -1,
+ -1, -1, -1, 36, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 238, 239, 240,
+ 241, -1, -1, -1, -1, -1, 247, 248, -1, -1,
+ 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 267, 268, 269, 270,
+ 271, 272, 273, 274, 87, -1, 277, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 103, 104, 105, 106, -1, -1, 109, -1, 111, -1,
+ -1, -1, 115, -1, -1, -1, -1, 120, -1, -1,
+ -1, -1, -1, 126, -1, -1, -1, -1, -1, -1,
+ 321, 322, -1, -1, -1, -1, -1, -1, -1, 142,
+ -1, -1, -1, -1, 147, -1, -1, 150, -1, 340,
+ -1, -1, 155, 344, 345, -1, 159, -1, -1, 162,
+ 163, -1, -1, -1, 167, 356, 357, 170, -1, 172,
+ -1, -1, -1, 364, -1, 366, -1, -1, 369, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 197, 198, 23, 200, 201, 202,
+ 203, -1, -1, 30, 31, -1, -1, -1, -1, 36,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 238, 239, 240, 241, -1,
+ -1, -1, -1, -1, 247, 248, -1, -1, 251, 252,
+ 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, -1, -1, 277, -1, 103, 104, 105, 106,
+ -1, -1, 109, -1, 111, -1, -1, -1, 115, -1,
+ -1, -1, -1, 120, -1, -1, -1, -1, -1, 126,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 142, -1, -1, 321, 322,
+ 147, -1, -1, 150, -1, -1, -1, -1, 155, -1,
+ -1, -1, 159, -1, -1, 162, 163, 340, -1, -1,
+ 167, 344, 345, 170, -1, 172, -1, -1, -1, -1,
+ -1, -1, -1, 356, 357, -1, -1, -1, -1, -1,
+ -1, -1, -1, 366, -1, -1, 369, -1, -1, -1,
+ 197, 198, -1, 200, 201, 202, 203, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 23, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 238, 239, 240, 241, -1, -1, -1, -1, -1,
+ 247, 248, -1, -1, 251, 252, 253, 254, 255, 256,
+ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 273, 274, 70, -1,
+ 277, -1, -1, -1, 76, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 103, 104, 105, 106, -1, -1, -1, -1, 111,
+ -1, -1, -1, 115, 321, 322, -1, -1, 120, -1,
+ -1, -1, -1, -1, 126, -1, -1, -1, 130, -1,
+ -1, -1, -1, 340, -1, -1, -1, 344, 345, -1,
+ 142, -1, -1, -1, -1, 147, -1, -1, 150, 356,
+ 357, -1, -1, 155, -1, -1, -1, 159, -1, 366,
+ 162, 163, 369, -1, -1, 167, -1, -1, 170, -1,
+ 172, -1, -1, -1, -1, -1, -1, 0, 1, -1,
+ -1, 4, -1, 6, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 197, -1, -1, 200, -1,
+ -1, 203, -1, 26, 27, 28, 29, -1, -1, -1,
+ -1, -1, -1, -1, 37, -1, -1, -1, -1, -1,
+ -1, -1, 45, -1, 47, -1, 49, -1, -1, 52,
+ 53, 54, -1, 56, -1, -1, -1, 60, 61, 62,
+ -1, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 104, -1, -1, -1, 287, -1, 110, 290, 291,
+ -1, -1, -1, -1, -1, 297, -1, 120, 70, -1,
+ -1, -1, -1, 126, 76, -1, -1, 79, 80, 81,
+ 82, 83, 84, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 327, 328, 150, 330, -1,
+ -1, 103, 104, 105, 106, -1, -1, -1, -1, 111,
+ -1, -1, -1, 115, -1, -1, -1, -1, 120, -1,
+ -1, -1, 354, 355, 126, -1, -1, -1, 130, -1,
+ -1, -1, 364, -1, 366, -1, -1, 369, -1, -1,
+ 142, -1, -1, -1, -1, 147, -1, -1, 150, 70,
+ -1, -1, -1, 155, -1, 76, -1, 159, -1, -1,
+ 162, 163, -1, -1, -1, 167, -1, -1, 170, -1,
+ 172, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 103, 104, 105, 106, -1, -1, -1, -1,
+ 111, -1, -1, -1, 115, 197, -1, -1, 200, 120,
+ -1, 203, -1, -1, -1, 126, -1, -1, -1, 130,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 142, -1, -1, 277, -1, 147, -1, -1, 150,
+ -1, -1, -1, -1, 155, -1, -1, -1, 159, 292,
+ -1, 162, 163, -1, 297, -1, 167, -1, -1, 170,
+ -1, 172, -1, -1, -1, -1, -1, 310, -1, -1,
+ -1, -1, 315, -1, 317, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 197, -1, -1, 200,
+ -1, -1, 203, -1, -1, 287, -1, -1, 290, 291,
+ -1, -1, -1, -1, -1, 297, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 327, 328, -1, 330, -1,
+ 104, -1, -1, -1, -1, -1, -1, -1, 70, -1,
+ -1, -1, -1, -1, 76, -1, -1, -1, -1, -1,
+ -1, -1, 354, 355, -1, -1, -1, 131, -1, -1,
+ 134, -1, -1, -1, 366, -1, 287, 369, -1, 290,
+ 291, 103, 104, 105, 106, -1, 297, 151, -1, 111,
+ -1, -1, -1, 115, -1, -1, -1, -1, 120, -1,
+ -1, -1, -1, -1, 126, -1, -1, -1, 130, -1,
+ -1, -1, -1, -1, -1, -1, 327, 328, -1, 330,
+ 142, -1, -1, -1, -1, 147, -1, -1, 150, -1,
+ -1, -1, -1, 155, -1, -1, -1, 159, -1, -1,
+ 162, 163, -1, 354, 355, 167, -1, -1, 170, -1,
+ 172, -1, -1, -1, -1, 366, -1, -1, 369, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 197, -1, -1, 200, -1,
+ -1, 203, -1, -1, -1, -1, -1, -1, -1, -1,
+ 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
+ 274, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 317, -1, -1, -1, 321, 322, -1,
+ -1, -1, -1, -1, -1, 287, -1, 331, 290, 291,
+ -1, -1, -1, -1, -1, 297, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 357, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 327, 328, -1, 330, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 354, 355, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 366, -1, -1, 369
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_int16 yystos[] =
+{
+ 0, 373, 0, 1, 4, 6, 26, 27, 28, 29,
+ 37, 45, 47, 49, 52, 53, 54, 56, 60, 61,
+ 62, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 110, 120, 126, 150, 277,
+ 292, 310, 315, 317, 374, 430, 431, 432, 433, 508,
+ 509, 510, 512, 527, 374, 105, 104, 297, 504, 504,
+ 504, 510, 521, 510, 512, 527, 510, 515, 515, 515,
+ 510, 518, 433, 49, 434, 37, 45, 47, 52, 53,
+ 54, 56, 277, 292, 310, 315, 317, 435, 49, 436,
+ 37, 45, 47, 49, 52, 53, 54, 56, 277, 292,
+ 310, 315, 317, 441, 53, 443, 37, 42, 45, 46,
+ 47, 48, 51, 52, 54, 55, 56, 58, 98, 100,
+ 101, 102, 277, 292, 299, 300, 301, 302, 310, 315,
+ 317, 318, 444, 49, 50, 52, 53, 54, 292, 299,
+ 300, 315, 447, 45, 47, 52, 54, 58, 98, 100,
+ 448, 47, 449, 23, 30, 31, 36, 103, 104, 105,
+ 106, 109, 111, 115, 120, 126, 142, 147, 150, 155,
+ 159, 162, 163, 167, 170, 172, 197, 198, 200, 201,
+ 202, 203, 238, 239, 240, 241, 247, 248, 251, 252,
+ 253, 254, 255, 256, 257, 258, 259, 260, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, 277, 321, 322, 340, 344, 345, 356, 357,
+ 366, 369, 457, 505, 631, 632, 635, 636, 637, 641,
+ 704, 707, 709, 713, 718, 719, 721, 723, 733, 734,
+ 736, 738, 740, 742, 746, 748, 750, 752, 754, 756,
+ 758, 760, 762, 764, 768, 770, 772, 774, 785, 793,
+ 795, 797, 798, 800, 802, 804, 806, 808, 810, 812,
+ 814, 58, 350, 351, 352, 450, 456, 58, 451, 456,
+ 37, 45, 47, 49, 52, 53, 54, 56, 277, 292,
+ 310, 315, 317, 442, 104, 452, 453, 377, 396, 397,
+ 90, 284, 286, 521, 521, 521, 521, 0, 374, 504,
+ 504, 57, 347, 348, 524, 525, 526, 35, 37, 52,
+ 62, 63, 67, 70, 79, 80, 81, 82, 83, 84,
+ 98, 100, 253, 277, 292, 297, 304, 310, 315, 324,
+ 327, 328, 329, 330, 334, 338, 339, 353, 362, 364,
+ 531, 532, 533, 535, 536, 537, 538, 539, 540, 541,
+ 545, 546, 547, 550, 551, 552, 559, 563, 571, 572,
+ 575, 576, 577, 578, 579, 600, 601, 603, 604, 606,
+ 607, 610, 611, 612, 622, 623, 624, 625, 626, 629,
+ 630, 636, 643, 644, 645, 646, 647, 648, 652, 653,
+ 654, 688, 702, 707, 708, 731, 732, 733, 775, 374,
+ 363, 363, 374, 504, 583, 458, 461, 531, 504, 466,
+ 468, 631, 654, 471, 504, 477, 512, 528, 521, 510,
+ 512, 515, 515, 515, 518, 90, 284, 286, 521, 521,
+ 521, 521, 527, 440, 510, 521, 522, 437, 508, 510,
+ 511, 438, 510, 512, 513, 528, 439, 510, 515, 516,
+ 515, 515, 510, 518, 519, 90, 284, 286, 677, 440,
+ 440, 440, 440, 515, 521, 446, 509, 530, 510, 530,
+ 512, 530, 45, 530, 515, 515, 530, 518, 530, 45,
+ 46, 515, 530, 530, 90, 284, 303, 677, 678, 521,
+ 45, 530, 45, 530, 45, 530, 45, 530, 521, 521,
+ 521, 45, 530, 403, 528, 45, 47, 509, 510, 512,
+ 530, 439, 515, 439, 521, 45, 510, 530, 45, 510,
+ 530, 521, 415, 510, 512, 515, 515, 530, 45, 515,
+ 512, 104, 107, 108, 109, 735, 112, 113, 254, 255,
+ 258, 639, 640, 32, 33, 34, 254, 710, 133, 642,
+ 168, 169, 796, 112, 113, 114, 737, 114, 116, 117,
+ 118, 119, 739, 112, 113, 121, 122, 123, 124, 125,
+ 741, 112, 113, 116, 127, 128, 129, 130, 131, 132,
+ 133, 134, 135, 177, 743, 114, 116, 135, 143, 144,
+ 145, 146, 747, 114, 135, 148, 306, 749, 112, 113,
+ 127, 129, 130, 131, 152, 153, 154, 751, 113, 114,
+ 116, 135, 143, 144, 146, 156, 157, 158, 753, 128,
+ 144, 153, 160, 161, 755, 144, 161, 757, 153, 164,
+ 165, 759, 131, 135, 168, 169, 761, 135, 168, 169,
+ 171, 763, 135, 144, 160, 164, 168, 169, 173, 174,
+ 175, 176, 177, 776, 114, 168, 169, 177, 786, 164,
+ 199, 736, 738, 740, 742, 746, 748, 750, 752, 754,
+ 756, 758, 760, 762, 764, 765, 766, 767, 769, 785,
+ 793, 795, 127, 134, 164, 393, 773, 393, 114, 199,
+ 767, 771, 135, 168, 169, 204, 237, 794, 114, 126,
+ 128, 146, 150, 153, 242, 275, 276, 357, 720, 722,
+ 801, 243, 803, 243, 805, 164, 244, 245, 246, 807,
+ 128, 153, 799, 116, 132, 153, 160, 249, 250, 809,
+ 128, 153, 811, 114, 128, 135, 153, 160, 813, 104,
+ 131, 134, 151, 317, 331, 357, 705, 706, 707, 112,
+ 113, 116, 134, 254, 278, 279, 280, 281, 282, 283,
+ 285, 286, 287, 288, 289, 290, 291, 294, 295, 296,
+ 317, 724, 725, 728, 331, 341, 712, 648, 653, 342,
+ 238, 247, 248, 251, 252, 815, 360, 361, 402, 715,
+ 647, 504, 421, 456, 351, 401, 456, 389, 440, 437,
+ 438, 512, 528, 439, 515, 515, 518, 519, 677, 440,
+ 440, 440, 440, 384, 407, 46, 48, 50, 51, 58,
+ 59, 92, 454, 521, 521, 521, 381, 672, 687, 674,
+ 676, 103, 103, 103, 85, 720, 293, 623, 172, 504,
+ 631, 703, 703, 62, 99, 504, 104, 705, 90, 191,
+ 284, 724, 725, 293, 316, 293, 311, 293, 313, 314,
+ 560, 85, 164, 85, 85, 720, 104, 4, 375, 655,
+ 656, 349, 529, 536, 429, 461, 381, 294, 295, 548,
+ 549, 382, 427, 164, 305, 306, 307, 308, 309, 553,
+ 554, 414, 325, 574, 408, 5, 70, 76, 85, 87,
+ 111, 115, 120, 126, 130, 150, 238, 287, 290, 291,
+ 297, 305, 327, 328, 354, 355, 366, 586, 587, 588,
+ 589, 590, 591, 592, 594, 595, 596, 597, 598, 599,
+ 632, 635, 641, 697, 698, 699, 704, 709, 713, 719,
+ 720, 721, 723, 729, 730, 733, 422, 428, 38, 39,
+ 187, 190, 580, 581, 408, 85, 331, 332, 333, 602,
+ 608, 609, 408, 85, 605, 608, 386, 392, 413, 335,
+ 336, 337, 613, 614, 618, 619, 23, 631, 633, 634,
+ 45, 627, 628, 15, 16, 17, 18, 368, 8, 24,
+ 54, 9, 10, 11, 12, 13, 14, 19, 111, 115,
+ 120, 126, 142, 147, 150, 155, 159, 162, 163, 167,
+ 170, 172, 197, 200, 203, 330, 366, 632, 634, 635,
+ 649, 650, 651, 654, 689, 690, 691, 692, 693, 694,
+ 695, 696, 698, 699, 700, 701, 52, 52, 22, 364,
+ 670, 689, 690, 695, 670, 38, 364, 582, 364, 364,
+ 364, 364, 364, 524, 531, 583, 458, 461, 466, 468,
+ 471, 477, 521, 521, 521, 381, 672, 687, 674, 676,
+ 531, 428, 57, 57, 57, 461, 57, 468, 57, 477,
+ 521, 381, 404, 412, 419, 468, 428, 43, 445, 510,
+ 515, 530, 521, 45, 381, 510, 510, 510, 510, 404,
+ 412, 419, 510, 510, 512, 468, 381, 510, 510, 412,
+ 515, 504, 424, 7, 8, 114, 258, 259, 638, 309,
+ 420, 104, 127, 293, 424, 423, 388, 423, 398, 111,
+ 126, 111, 126, 377, 138, 139, 140, 141, 744, 396,
+ 423, 399, 423, 400, 397, 423, 399, 376, 387, 379,
+ 425, 426, 23, 38, 103, 175, 178, 179, 180, 181,
+ 182, 183, 184, 185, 186, 187, 188, 189, 190, 777,
+ 778, 779, 423, 103, 383, 421, 765, 393, 767, 182,
+ 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, 787, 792, 417,
+ 423, 396, 397, 402, 722, 416, 416, 370, 416, 416,
+ 370, 416, 395, 391, 385, 423, 406, 405, 419, 405,
+ 419, 112, 113, 126, 134, 150, 278, 279, 280, 726,
+ 727, 728, 380, 342, 342, 103, 416, 395, 391, 385,
+ 406, 359, 714, 367, 428, 468, 477, 521, 381, 404,
+ 412, 419, 455, 456, 685, 685, 685, 294, 364, 671,
+ 311, 364, 686, 364, 560, 673, 364, 505, 675, 5,
+ 126, 150, 598, 85, 598, 620, 621, 648, 177, 23,
+ 23, 97, 364, 52, 52, 52, 103, 313, 52, 728,
+ 52, 598, 104, 298, 506, 598, 313, 314, 564, 598,
+ 103, 615, 616, 617, 631, 635, 648, 652, 713, 719,
+ 618, 598, 598, 85, 505, 21, 654, 659, 660, 661,
+ 668, 695, 696, 7, 365, 505, 364, 103, 103, 549,
+ 78, 111, 126, 172, 261, 556, 505, 103, 103, 103,
+ 505, 555, 554, 142, 155, 172, 326, 598, 415, 384,
+ 5, 598, 85, 388, 398, 377, 396, 397, 382, 85,
+ 408, 408, 591, 632, 699, 15, 16, 17, 18, 368,
+ 20, 22, 8, 54, 5, 608, 85, 87, 243, 305,
+ 7, 7, 103, 103, 581, 5, 7, 5, 598, 616,
+ 631, 635, 614, 7, 504, 364, 504, 364, 628, 700,
+ 700, 691, 692, 693, 647, 364, 542, 633, 690, 396,
+ 399, 397, 399, 376, 387, 379, 425, 426, 421, 383,
+ 393, 417, 408, 695, 7, 20, 15, 16, 17, 18,
+ 368, 7, 20, 22, 8, 689, 690, 695, 598, 598,
+ 103, 365, 374, 20, 374, 103, 492, 428, 460, 462,
+ 467, 474, 478, 582, 364, 364, 364, 364, 364, 685,
+ 685, 685, 671, 686, 673, 675, 103, 103, 103, 364,
+ 103, 103, 364, 685, 104, 380, 510, 103, 640, 423,
+ 390, 103, 410, 410, 388, 396, 388, 396, 114, 131,
+ 136, 137, 243, 396, 745, 378, 97, 783, 191, 781,
+ 196, 784, 194, 195, 782, 192, 193, 780, 131, 383,
+ 227, 231, 232, 233, 791, 222, 223, 224, 225, 789,
+ 226, 227, 228, 229, 230, 790, 790, 231, 234, 234,
+ 235, 236, 235, 114, 131, 164, 788, 418, 416, 103,
+ 103, 112, 113, 112, 113, 380, 380, 103, 103, 343,
+ 711, 103, 161, 358, 716, 720, 364, 685, 364, 364,
+ 364, 103, 485, 381, 564, 490, 404, 486, 103, 412,
+ 491, 419, 598, 5, 5, 598, 633, 90, 93, 529,
+ 662, 663, 38, 175, 180, 190, 778, 779, 505, 505,
+ 103, 648, 657, 658, 598, 598, 598, 380, 103, 598,
+ 52, 598, 404, 103, 566, 568, 569, 412, 104, 295,
+ 561, 22, 413, 85, 335, 43, 598, 375, 5, 375,
+ 277, 292, 297, 310, 315, 665, 666, 90, 93, 529,
+ 664, 667, 375, 656, 463, 388, 149, 144, 149, 557,
+ 558, 104, 114, 573, 635, 114, 573, 421, 114, 573,
+ 598, 5, 598, 598, 367, 586, 586, 587, 588, 589,
+ 103, 591, 586, 593, 633, 654, 598, 598, 85, 8,
+ 85, 632, 699, 729, 729, 598, 609, 598, 608, 619,
+ 378, 620, 657, 375, 543, 544, 367, 695, 689, 695,
+ 700, 700, 691, 692, 693, 695, 103, 689, 695, 651,
+ 695, 20, 20, 103, 39, 374, 365, 374, 430, 529,
+ 582, 37, 47, 52, 54, 56, 164, 277, 292, 310,
+ 315, 317, 365, 374, 430, 459, 529, 44, 94, 114,
+ 164, 365, 374, 430, 494, 500, 501, 529, 531, 40,
+ 89, 90, 91, 92, 94, 97, 114, 164, 277, 365,
+ 374, 430, 475, 529, 534, 535, 40, 90, 91, 92,
+ 114, 164, 365, 374, 430, 475, 529, 534, 41, 44,
+ 164, 292, 365, 374, 430, 428, 460, 462, 467, 474,
+ 478, 364, 364, 364, 381, 404, 412, 419, 462, 478,
+ 380, 380, 7, 420, 423, 396, 779, 423, 417, 371,
+ 371, 396, 396, 397, 397, 711, 346, 711, 103, 394,
+ 402, 112, 113, 717, 478, 380, 488, 489, 487, 295,
+ 365, 374, 430, 529, 671, 566, 568, 365, 374, 430,
+ 529, 686, 365, 374, 430, 529, 673, 561, 365, 374,
+ 430, 529, 675, 598, 598, 5, 506, 506, 663, 421,
+ 378, 378, 364, 536, 662, 405, 405, 380, 380, 380,
+ 598, 380, 20, 104, 295, 312, 565, 312, 567, 20,
+ 316, 562, 615, 631, 635, 617, 616, 598, 43, 82,
+ 83, 669, 696, 702, 191, 294, 381, 316, 311, 560,
+ 666, 506, 506, 667, 365, 374, 531, 396, 7, 421,
+ 573, 573, 70, 573, 598, 5, 598, 166, 598, 608,
+ 608, 5, 365, 534, 536, 659, 7, 365, 689, 689,
+ 103, 39, 428, 504, 523, 504, 514, 504, 517, 517,
+ 504, 520, 104, 90, 284, 286, 523, 523, 523, 523,
+ 374, 363, 79, 80, 502, 503, 631, 423, 99, 374,
+ 374, 374, 374, 374, 465, 636, 506, 506, 363, 95,
+ 96, 476, 103, 104, 129, 130, 254, 274, 275, 482,
+ 483, 493, 86, 87, 88, 90, 469, 470, 374, 374,
+ 374, 535, 465, 506, 506, 363, 483, 469, 374, 374,
+ 374, 104, 363, 99, 381, 365, 365, 365, 365, 365,
+ 488, 489, 487, 365, 365, 103, 7, 409, 103, 394,
+ 402, 365, 94, 134, 278, 365, 374, 430, 529, 683,
+ 90, 97, 134, 169, 278, 365, 374, 430, 529, 684,
+ 114, 278, 365, 374, 430, 529, 680, 103, 381, 565,
+ 567, 404, 412, 562, 419, 598, 657, 365, 380, 319,
+ 320, 321, 322, 323, 570, 103, 404, 103, 569, 404,
+ 570, 103, 412, 413, 413, 598, 375, 103, 313, 103,
+ 298, 506, 564, 103, 374, 558, 423, 423, 415, 423,
+ 598, 85, 620, 5, 365, 365, 5, 375, 544, 190,
+ 584, 103, 484, 461, 466, 471, 477, 523, 523, 523,
+ 484, 484, 484, 484, 364, 479, 631, 411, 104, 8,
+ 374, 374, 374, 468, 411, 8, 374, 7, 374, 5,
+ 374, 374, 468, 5, 374, 151, 495, 479, 374, 365,
+ 365, 365, 378, 103, 711, 363, 167, 172, 679, 509,
+ 380, 506, 103, 679, 103, 509, 380, 105, 509, 380,
+ 536, 294, 104, 561, 380, 103, 295, 382, 382, 566,
+ 568, 561, 399, 399, 598, 365, 620, 702, 187, 585,
+ 374, 364, 364, 364, 364, 364, 484, 484, 484, 364,
+ 364, 364, 364, 104, 105, 480, 481, 631, 374, 41,
+ 636, 482, 423, 470, 87, 464, 465, 636, 37, 87,
+ 292, 310, 315, 317, 472, 473, 22, 103, 104, 361,
+ 496, 497, 498, 631, 374, 374, 380, 380, 380, 7,
+ 394, 364, 425, 421, 374, 374, 374, 374, 374, 374,
+ 374, 134, 374, 365, 380, 103, 565, 567, 562, 365,
+ 375, 584, 492, 462, 467, 474, 478, 364, 364, 364,
+ 485, 490, 486, 491, 7, 365, 104, 465, 374, 8,
+ 428, 381, 404, 412, 419, 374, 483, 103, 22, 25,
+ 103, 104, 681, 682, 679, 381, 404, 404, 412, 585,
+ 365, 365, 365, 365, 365, 488, 489, 487, 365, 365,
+ 365, 365, 375, 481, 43, 44, 499, 374, 636, 423,
+ 374, 103, 103, 5, 7, 365, 374, 374, 374, 374,
+ 374, 374, 365, 365, 365, 374, 374, 374, 374, 505,
+ 631, 363, 495, 423, 103, 506, 507, 682, 374, 423,
+ 428, 380, 380, 380, 381, 404, 412, 419, 479, 411,
+ 374, 374, 374
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_int16 yyr1[] =
+{
+ 0, 372, 373, 373, 374, 374, 375, 375, 376, 377,
+ 378, 379, 380, 381, 382, 383, 384, 385, 386, 387,
+ 388, 389, 390, 391, 392, 393, 394, 395, 396, 397,
+ 398, 399, 400, 401, 402, 403, 404, 405, 406, 407,
+ 408, 409, 410, 411, 412, 413, 414, 415, 416, 417,
+ 418, 419, 420, 421, 422, 423, 424, 425, 426, 427,
+ 428, 429, 430, 430, 430, 430, 430, 431, 431, 431,
+ 431, 432, 432, 432, 432, 432, 432, 432, 432, 432,
+ 432, 432, 432, 432, 432, 432, 432, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 433, 433, 433, 433, 433, 433, 433, 433, 433,
+ 433, 434, 435, 435, 435, 435, 435, 435, 435, 435,
+ 435, 435, 435, 435, 435, 435, 435, 435, 435, 436,
+ 437, 437, 438, 438, 439, 439, 440, 440, 441, 441,
+ 441, 441, 441, 441, 441, 441, 441, 441, 441, 441,
+ 441, 441, 441, 441, 442, 442, 442, 442, 442, 442,
+ 442, 442, 442, 442, 442, 442, 442, 442, 442, 443,
+ 444, 444, 444, 444, 444, 444, 444, 444, 444, 444,
+ 444, 444, 444, 444, 444, 444, 444, 444, 444, 444,
+ 444, 444, 444, 444, 444, 444, 444, 444, 444, 444,
+ 444, 444, 444, 444, 445, 446, 446, 447, 447, 447,
+ 447, 447, 447, 447, 447, 447, 447, 447, 447, 447,
+ 447, 447, 447, 447, 448, 448, 448, 448, 448, 448,
+ 448, 449, 450, 450, 451, 451, 452, 453, 453, 454,
+ 454, 454, 454, 454, 454, 454, 454, 455, 455, 456,
+ 456, 456, 457, 458, 459, 459, 460, 460, 460, 460,
+ 460, 460, 460, 460, 460, 460, 460, 460, 460, 460,
+ 460, 460, 461, 462, 462, 462, 462, 462, 462, 462,
+ 462, 462, 463, 463, 463, 464, 464, 465, 465, 466,
+ 467, 467, 467, 467, 467, 467, 467, 467, 467, 467,
+ 467, 467, 467, 468, 468, 469, 469, 470, 470, 470,
+ 470, 471, 472, 472, 472, 472, 472, 473, 473, 474,
+ 474, 474, 474, 474, 474, 474, 474, 474, 474, 474,
+ 474, 474, 474, 475, 475, 476, 476, 477, 478, 478,
+ 478, 478, 478, 478, 478, 479, 479, 480, 480, 480,
+ 481, 481, 481, 482, 482, 483, 483, 484, 485, 485,
+ 485, 485, 485, 486, 486, 486, 486, 486, 487, 487,
+ 487, 487, 487, 488, 488, 488, 488, 488, 489, 489,
+ 489, 489, 489, 490, 490, 490, 490, 490, 491, 491,
+ 491, 491, 491, 492, 492, 492, 492, 492, 493, 493,
+ 493, 493, 493, 494, 495, 496, 496, 497, 497, 497,
+ 497, 497, 498, 498, 499, 499, 499, 499, 500, 501,
+ 502, 502, 503, 503, 504, 504, 505, 505, 505, 506,
+ 507, 507, 508, 508, 509, 509, 509, 509, 509, 509,
+ 510, 511, 512, 513, 514, 515, 516, 517, 518, 519,
+ 520, 521, 522, 523, 524, 525, 526, 527, 527, 527,
+ 527, 528, 529, 530, 530, 531, 531, 532, 533, 533,
+ 534, 534, 535, 535, 535, 535, 535, 536, 536, 536,
+ 536, 536, 536, 536, 536, 536, 536, 536, 536, 536,
+ 536, 536, 536, 536, 536, 536, 536, 536, 536, 537,
+ 538, 538, 539, 540, 540, 541, 542, 542, 543, 543,
+ 543, 544, 545, 545, 546, 546, 547, 547, 548, 548,
+ 549, 549, 550, 550, 550, 551, 551, 552, 553, 553,
+ 554, 554, 554, 554, 554, 554, 555, 556, 556, 556,
+ 556, 556, 557, 557, 558, 558, 559, 559, 559, 560,
+ 560, 560, 561, 561, 562, 562, 563, 563, 564, 564,
+ 564, 565, 565, 566, 567, 567, 568, 568, 569, 569,
+ 570, 570, 570, 570, 570, 571, 572, 573, 573, 574,
+ 574, 574, 574, 574, 574, 574, 574, 575, 576, 576,
+ 577, 577, 577, 577, 577, 577, 578, 578, 579, 579,
+ 580, 580, 581, 581, 581, 581, 582, 582, 583, 584,
+ 584, 585, 585, 586, 586, 586, 586, 586, 586, 586,
+ 586, 586, 586, 586, 586, 586, 587, 587, 587, 588,
+ 588, 589, 589, 590, 590, 591, 592, 592, 593, 593,
+ 594, 594, 595, 596, 597, 597, 598, 598, 598, 599,
+ 599, 599, 599, 599, 599, 599, 599, 599, 599, 599,
+ 599, 599, 599, 600, 600, 601, 602, 602, 602, 603,
+ 603, 604, 605, 605, 605, 605, 605, 606, 606, 607,
+ 607, 608, 608, 609, 609, 609, 610, 610, 610, 610,
+ 611, 611, 612, 613, 613, 614, 614, 615, 615, 616,
+ 616, 616, 617, 617, 617, 617, 618, 618, 619, 619,
+ 620, 620, 621, 622, 622, 622, 623, 623, 623, 624,
+ 624, 625, 625, 626, 627, 627, 628, 629, 629, 630,
+ 631, 632, 632, 633, 633, 634, 635, 636, 636, 636,
+ 636, 636, 636, 636, 636, 636, 636, 636, 636, 636,
+ 636, 636, 637, 638, 638, 638, 639, 639, 639, 639,
+ 639, 640, 640, 641, 641, 642, 642, 643, 643, 643,
+ 644, 644, 645, 645, 646, 646, 647, 648, 648, 649,
+ 650, 651, 651, 652, 653, 653, 653, 654, 655, 655,
+ 655, 656, 656, 656, 657, 657, 658, 659, 659, 660,
+ 660, 661, 661, 662, 662, 663, 663, 663, 664, 664,
+ 665, 665, 666, 666, 666, 666, 666, 666, 666, 666,
+ 666, 667, 667, 667, 668, 669, 669, 670, 670, 670,
+ 670, 671, 672, 673, 674, 675, 676, 677, 677, 677,
+ 678, 678, 678, 679, 679, 680, 680, 681, 681, 682,
+ 683, 683, 683, 684, 684, 684, 684, 684, 685, 686,
+ 686, 687, 688, 688, 688, 688, 688, 688, 688, 688,
+ 689, 689, 690, 690, 690, 691, 691, 691, 692, 692,
+ 693, 693, 694, 694, 695, 696, 696, 696, 696, 697,
+ 697, 698, 699, 699, 699, 699, 699, 699, 699, 699,
+ 699, 699, 699, 699, 699, 699, 700, 700, 700, 700,
+ 700, 700, 700, 700, 700, 700, 700, 700, 700, 700,
+ 700, 700, 700, 700, 701, 701, 701, 701, 701, 701,
+ 701, 702, 702, 702, 702, 702, 702, 703, 703, 704,
+ 704, 704, 705, 705, 706, 706, 706, 706, 706, 707,
+ 707, 707, 707, 707, 707, 707, 707, 707, 707, 707,
+ 707, 707, 707, 707, 707, 707, 707, 707, 707, 707,
+ 707, 707, 707, 708, 708, 708, 708, 708, 708, 709,
+ 709, 710, 710, 710, 711, 711, 712, 712, 713, 714,
+ 714, 715, 715, 716, 716, 717, 717, 718, 718, 719,
+ 719, 719, 720, 720, 721, 721, 722, 722, 722, 722,
+ 723, 723, 723, 724, 724, 725, 725, 725, 725, 725,
+ 725, 725, 725, 725, 725, 725, 725, 725, 725, 725,
+ 725, 725, 726, 726, 726, 726, 726, 726, 726, 727,
+ 727, 727, 727, 728, 728, 728, 728, 729, 729, 730,
+ 730, 731, 731, 731, 731, 732, 733, 733, 733, 733,
+ 733, 733, 733, 733, 733, 733, 733, 733, 733, 733,
+ 733, 733, 733, 733, 733, 733, 733, 733, 734, 735,
+ 735, 735, 735, 736, 737, 737, 737, 738, 739, 739,
+ 739, 739, 739, 740, 741, 741, 741, 741, 741, 741,
+ 741, 741, 741, 742, 742, 742, 743, 743, 743, 743,
+ 743, 743, 743, 743, 743, 743, 743, 743, 744, 744,
+ 744, 744, 745, 745, 745, 745, 745, 746, 747, 747,
+ 747, 747, 747, 747, 747, 748, 749, 749, 749, 749,
+ 750, 751, 751, 751, 751, 751, 751, 751, 751, 751,
+ 752, 753, 753, 753, 753, 753, 753, 753, 753, 753,
+ 753, 754, 755, 755, 755, 755, 755, 756, 757, 757,
+ 758, 759, 759, 759, 760, 761, 761, 761, 761, 762,
+ 763, 763, 763, 763, 764, 764, 764, 764, 765, 765,
+ 765, 765, 765, 765, 765, 765, 765, 765, 765, 765,
+ 765, 765, 766, 766, 766, 767, 767, 768, 768, 769,
+ 769, 770, 770, 771, 771, 772, 772, 773, 773, 773,
+ 774, 775, 776, 776, 776, 776, 776, 776, 776, 776,
+ 776, 776, 777, 777, 777, 777, 777, 777, 778, 778,
+ 778, 778, 778, 779, 779, 779, 779, 779, 779, 779,
+ 779, 779, 779, 779, 779, 780, 780, 781, 782, 782,
+ 783, 784, 785, 785, 786, 786, 786, 787, 787, 787,
+ 787, 787, 787, 787, 787, 787, 787, 787, 787, 787,
+ 787, 787, 787, 787, 787, 788, 788, 788, 789, 789,
+ 789, 789, 790, 790, 790, 790, 790, 791, 791, 791,
+ 791, 792, 792, 792, 792, 792, 792, 792, 792, 792,
+ 792, 792, 792, 793, 793, 794, 794, 794, 794, 795,
+ 796, 796, 797, 797, 797, 797, 797, 797, 797, 797,
+ 798, 799, 799, 800, 801, 801, 801, 801, 802, 803,
+ 804, 805, 806, 807, 807, 807, 807, 808, 809, 809,
+ 809, 809, 809, 809, 810, 811, 811, 812, 813, 813,
+ 813, 813, 813, 814, 815, 815, 815, 815, 815
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_int8 yyr2[] =
+{
+ 0, 2, 0, 2, 1, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 5, 5, 3, 2, 1, 1, 2,
+ 2, 1, 2, 2, 2, 2, 2, 2, 3, 3,
+ 2, 2, 3, 3, 3, 2, 3, 2, 6, 2,
+ 6, 3, 2, 6, 6, 3, 6, 3, 5, 7,
+ 5, 7, 8, 8, 8, 5, 7, 5, 7, 5,
+ 7, 3, 2, 6, 2, 6, 6, 6, 3, 6,
+ 3, 5, 5, 8, 8, 8, 5, 5, 5, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 6, 2, 2, 2, 3, 2, 2, 6, 3, 3,
+ 5, 3, 3, 3, 2, 2, 2, 2, 2, 3,
+ 2, 2, 6, 3, 3, 5, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 3, 2, 2, 3, 3,
+ 2, 3, 3, 2, 3, 3, 2, 3, 3, 2,
+ 3, 3, 2, 3, 3, 2, 2, 2, 2, 2,
+ 2, 4, 5, 2, 2, 1, 2, 2, 2, 3,
+ 3, 2, 3, 2, 3, 2, 2, 3, 2, 3,
+ 2, 3, 2, 2, 2, 2, 2, 2, 3, 2,
+ 2, 3, 2, 1, 2, 1, 3, 0, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
+ 1, 2, 1, 0, 2, 1, 0, 2, 2, 3,
+ 8, 8, 8, 8, 9, 9, 10, 10, 10, 9,
+ 9, 9, 0, 0, 2, 2, 3, 3, 3, 3,
+ 5, 3, 0, 2, 3, 1, 3, 1, 3, 0,
+ 0, 2, 2, 5, 4, 4, 4, 4, 3, 4,
+ 2, 3, 3, 1, 1, 3, 1, 1, 1, 1,
+ 1, 0, 2, 2, 2, 2, 2, 1, 0, 0,
+ 2, 2, 4, 4, 8, 6, 7, 7, 4, 3,
+ 4, 3, 3, 3, 2, 1, 1, 0, 0, 2,
+ 2, 5, 5, 3, 4, 3, 1, 1, 3, 3,
+ 1, 1, 1, 1, 1, 1, 3, 0, 0, 2,
+ 2, 2, 2, 0, 2, 2, 2, 2, 0, 2,
+ 2, 2, 2, 0, 2, 2, 2, 2, 0, 2,
+ 2, 2, 2, 0, 2, 2, 2, 2, 0, 2,
+ 2, 2, 2, 0, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 7, 2, 1, 1, 1, 1, 1,
+ 3, 3, 1, 2, 2, 2, 3, 0, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 1, 2, 2, 1, 2, 1, 1,
+ 2, 3, 2, 3, 1, 2, 3, 1, 2, 3,
+ 1, 2, 3, 1, 2, 2, 2, 1, 2, 2,
+ 2, 2, 2, 0, 1, 1, 2, 1, 1, 2,
+ 1, 2, 2, 1, 1, 1, 2, 1, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 1, 1, 2,
+ 2, 2, 2, 1, 1, 2, 1, 1, 2, 3,
+ 1, 1, 5, 1, 1, 3, 3, 1, 1, 3,
+ 3, 5, 4, 5, 1, 2, 1, 3, 1, 2,
+ 2, 2, 1, 3, 3, 1, 2, 1, 1, 2,
+ 2, 2, 2, 2, 2, 2, 1, 3, 3, 1,
+ 2, 1, 3, 1, 1, 1, 6, 6, 4, 1,
+ 1, 0, 1, 1, 0, 3, 6, 4, 1, 1,
+ 0, 0, 3, 3, 0, 2, 2, 3, 2, 2,
+ 1, 1, 1, 1, 1, 2, 1, 1, 1, 0,
+ 6, 3, 6, 3, 5, 3, 5, 2, 1, 1,
+ 3, 4, 4, 5, 6, 5, 1, 2, 1, 3,
+ 1, 2, 2, 2, 1, 1, 6, 8, 0, 0,
+ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 3, 1, 3, 3, 1,
+ 3, 1, 3, 1, 3, 1, 1, 3, 1, 1,
+ 3, 1, 3, 3, 1, 1, 1, 1, 1, 1,
+ 2, 3, 3, 4, 5, 2, 3, 2, 6, 4,
+ 3, 4, 3, 2, 1, 1, 3, 4, 1, 2,
+ 1, 1, 2, 3, 1, 3, 4, 3, 5, 3,
+ 6, 1, 3, 1, 1, 1, 2, 4, 6, 6,
+ 1, 2, 1, 1, 2, 2, 1, 1, 1, 1,
+ 1, 3, 1, 1, 1, 1, 1, 3, 1, 1,
+ 1, 2, 1, 4, 5, 6, 1, 1, 1, 7,
+ 8, 6, 1, 1, 1, 2, 2, 6, 8, 1,
+ 2, 1, 1, 1, 1, 3, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 4, 1, 1, 2, 1, 1, 1, 1,
+ 1, 3, 1, 4, 4, 0, 2, 1, 3, 3,
+ 1, 3, 1, 3, 1, 3, 1, 1, 3, 3,
+ 3, 1, 1, 3, 1, 1, 1, 3, 1, 3,
+ 3, 3, 3, 5, 1, 2, 1, 1, 2, 1,
+ 1, 2, 1, 1, 2, 2, 2, 1, 1, 2,
+ 1, 2, 2, 6, 6, 6, 4, 5, 6, 4,
+ 4, 2, 2, 1, 1, 1, 1, 1, 1, 2,
+ 2, 4, 0, 4, 0, 1, 0, 1, 1, 1,
+ 1, 1, 1, 2, 2, 6, 3, 1, 3, 3,
+ 3, 7, 3, 3, 3, 3, 3, 3, 0, 4,
+ 4, 0, 2, 2, 4, 4, 5, 5, 3, 3,
+ 3, 3, 1, 1, 1, 1, 3, 3, 1, 3,
+ 1, 3, 1, 3, 1, 1, 1, 3, 3, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 1,
+ 2, 2, 1, 1, 1, 2, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,
+ 2, 2, 2, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 1, 1, 1, 3,
+ 1, 3, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 5, 3, 5, 1, 5, 5, 3,
+ 5, 1, 1, 1, 0, 2, 1, 1, 6, 2,
+ 0, 1, 1, 1, 1, 1, 1, 5, 6, 8,
+ 6, 5, 2, 2, 3, 4, 1, 1, 1, 2,
+ 3, 4, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
+ 3, 3, 3, 1, 1, 1, 1, 1, 1, 3,
+ 3, 5, 5, 5, 6, 3, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 1, 1, 1, 1, 1, 1, 1, 7, 1,
+ 1, 2, 1, 3, 1, 1, 2, 3, 1, 1,
+ 1, 1, 2, 3, 1, 1, 1, 1, 1, 3,
+ 3, 3, 3, 3, 5, 4, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 1, 1, 1, 1, 3, 2, 1,
+ 1, 1, 1, 1, 1, 3, 2, 1, 1, 1,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 2, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 3, 1, 1, 1, 1, 1, 3, 1, 1,
+ 3, 1, 1, 1, 3, 1, 1, 1, 1, 3,
+ 1, 1, 1, 1, 2, 3, 3, 9, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 1,
+ 1, 2, 2, 1, 1, 3, 3, 1, 1, 1,
+ 3, 5, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 3, 4, 1, 1, 2, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 3, 5, 1, 1, 1, 1, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 1, 1, 3, 1, 1, 2, 1, 3, 4,
+ 3, 1, 3, 1, 1, 1, 4, 3, 1, 1,
+ 1, 1, 1, 1, 3, 1, 1, 3, 1, 1,
+ 2, 1, 1, 2, 2, 2, 2, 2, 2
+};
+
+
+enum { YYENOMEM = -2 };
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+ do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (&yylloc, nft, scanner, state, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+ while (0)
+
+/* Backward compatibility with an undocumented macro.
+ Use YYerror or YYUNDEF. */
+#define YYERRCODE YYUNDEF
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (N) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (0)
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+# ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+
+/* Print *YYLOCP on YYO. Private, do not rely on its existence. */
+
+YY_ATTRIBUTE_UNUSED
+static int
+yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp)
+{
+ int res = 0;
+ int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0;
+ if (0 <= yylocp->first_line)
+ {
+ res += YYFPRINTF (yyo, "%d", yylocp->first_line);
+ if (0 <= yylocp->first_column)
+ res += YYFPRINTF (yyo, ".%d", yylocp->first_column);
+ }
+ if (0 <= yylocp->last_line)
+ {
+ if (yylocp->first_line < yylocp->last_line)
+ {
+ res += YYFPRINTF (yyo, "-%d", yylocp->last_line);
+ if (0 <= end_col)
+ res += YYFPRINTF (yyo, ".%d", end_col);
+ }
+ else if (0 <= end_col && yylocp->first_column < end_col)
+ res += YYFPRINTF (yyo, "-%d", end_col);
+ }
+ return res;
+ }
+
+# define YY_LOCATION_PRINT(File, Loc) \
+ yy_location_print_ (File, &(Loc))
+
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+# endif /* !defined YY_LOCATION_PRINT */
+
+
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Kind, Value, Location, nft, scanner, state); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*-----------------------------------.
+| Print this symbol's value on YYO. |
+`-----------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct nft_ctx *nft, void *scanner, struct parser_state *state)
+{
+ FILE *yyoutput = yyo;
+ YY_USE (yyoutput);
+ YY_USE (yylocationp);
+ YY_USE (nft);
+ YY_USE (scanner);
+ YY_USE (state);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yykind < YYNTOKENS)
+ YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
+# endif
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YY_USE (yykind);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+/*---------------------------.
+| Print this symbol on YYO. |
+`---------------------------*/
+
+static void
+yy_symbol_print (FILE *yyo,
+ yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct nft_ctx *nft, void *scanner, struct parser_state *state)
+{
+ YYFPRINTF (yyo, "%s %s (",
+ yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind));
+
+ YY_LOCATION_PRINT (yyo, *yylocationp);
+ YYFPRINTF (yyo, ": ");
+ yy_symbol_value_print (yyo, yykind, yyvaluep, yylocationp, nft, scanner, state);
+ YYFPRINTF (yyo, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp,
+ int yyrule, struct nft_ctx *nft, void *scanner, struct parser_state *state)
+{
+ int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]),
+ &yyvsp[(yyi + 1) - (yynrhs)],
+ &(yylsp[(yyi + 1) - (yynrhs)]), nft, scanner, state);
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, yylsp, Rule, nft, scanner, state); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args) ((void) 0)
+# define YY_SYMBOL_PRINT(Title, Kind, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+/* Context of a parse error. */
+typedef struct
+{
+ yy_state_t *yyssp;
+ yysymbol_kind_t yytoken;
+ YYLTYPE *yylloc;
+} yypcontext_t;
+
+/* Put in YYARG at most YYARGN of the expected tokens given the
+ current YYCTX, and return the number of tokens stored in YYARG. If
+ YYARG is null, return the number of expected tokens (guaranteed to
+ be less than YYNTOKENS). Return YYENOMEM on memory exhaustion.
+ Return 0 if there are more than YYARGN expected tokens, yet fill
+ YYARG up to YYARGN. */
+static int
+yypcontext_expected_tokens (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ int yyn = yypact[+*yyctx->yyssp];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (!yyarg)
+ ++yycount;
+ else if (yycount == yyargn)
+ return 0;
+ else
+ yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx);
+ }
+ }
+ if (yyarg && yycount == 0 && 0 < yyargn)
+ yyarg[0] = YYSYMBOL_YYEMPTY;
+ return yycount;
+}
+
+
+
+
+#ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S)))
+# else
+/* Return the length of YYSTR. */
+static YYPTRDIFF_T
+yystrlen (const char *yystr)
+{
+ YYPTRDIFF_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+#endif
+
+#ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+#endif
+
+#ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYPTRDIFF_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYPTRDIFF_T yyn = 0;
+ char const *yyp = yystr;
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ else
+ goto append;
+
+ append:
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (yyres)
+ return yystpcpy (yyres, yystr) - yyres;
+ else
+ return yystrlen (yystr);
+}
+#endif
+
+
+static int
+yy_syntax_error_arguments (const yypcontext_t *yyctx,
+ yysymbol_kind_t yyarg[], int yyargn)
+{
+ /* Actual size of YYARG. */
+ int yycount = 0;
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yyctx->yytoken != YYSYMBOL_YYEMPTY)
+ {
+ int yyn;
+ if (yyarg)
+ yyarg[yycount] = yyctx->yytoken;
+ ++yycount;
+ yyn = yypcontext_expected_tokens (yyctx,
+ yyarg ? yyarg + 1 : yyarg, yyargn - 1);
+ if (yyn == YYENOMEM)
+ return YYENOMEM;
+ else
+ yycount += yyn;
+ }
+ return yycount;
+}
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg,
+ const yypcontext_t *yyctx)
+{
+ enum { YYARGS_MAX = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat: reported tokens (one for the "unexpected",
+ one per "expected"). */
+ yysymbol_kind_t yyarg[YYARGS_MAX];
+ /* Cumulated lengths of YYARG. */
+ YYPTRDIFF_T yysize = 0;
+
+ /* Actual size of YYARG. */
+ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX);
+ if (yycount == YYENOMEM)
+ return YYENOMEM;
+
+ switch (yycount)
+ {
+#define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ default: /* Avoid compiler warnings. */
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+#undef YYCASE_
+ }
+
+ /* Compute error message size. Don't count the "%s"s, but reserve
+ room for the terminator. */
+ yysize = yystrlen (yyformat) - 2 * yycount + 1;
+ {
+ int yyi;
+ for (yyi = 0; yyi < yycount; ++yyi)
+ {
+ YYPTRDIFF_T yysize1
+ = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]);
+ if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)
+ yysize = yysize1;
+ else
+ return YYENOMEM;
+ }
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return -1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]);
+ yyformat += 2;
+ }
+ else
+ {
+ ++yyp;
+ ++yyformat;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg,
+ yysymbol_kind_t yykind, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct nft_ctx *nft, void *scanner, struct parser_state *state)
+{
+ YY_USE (yyvaluep);
+ YY_USE (yylocationp);
+ YY_USE (nft);
+ YY_USE (scanner);
+ YY_USE (state);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ switch (yykind)
+ {
+ case YYSYMBOL_STRING: /* "string" */
+#line 360 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6179 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_QUOTED_STRING: /* "quoted string" */
+#line 360 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6185 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ASTERISK_STRING: /* "string with a trailing asterisk" */
+#line 360 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6191 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_line: /* line */
+#line 684 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6197 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_base_cmd: /* base_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6203 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_add_cmd: /* add_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6209 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_replace_cmd: /* replace_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6215 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_create_cmd: /* create_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6221 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_insert_cmd: /* insert_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6227 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_table_or_id_spec: /* table_or_id_spec */
+#line 690 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6233 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_chain_or_id_spec: /* chain_or_id_spec */
+#line 692 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6239 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_or_id_spec: /* set_or_id_spec */
+#line 697 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6245 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_obj_or_id_spec: /* obj_or_id_spec */
+#line 699 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6251 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_delete_cmd: /* delete_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6257 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_destroy_cmd: /* destroy_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6263 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_get_cmd: /* get_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6269 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_list_cmd: /* list_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6275 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_basehook_device_name: /* basehook_device_name */
+#line 711 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6281 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_basehook_spec: /* basehook_spec */
+#line 705 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6287 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_reset_cmd: /* reset_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6293 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flush_cmd: /* flush_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6299 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rename_cmd: /* rename_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6305 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_import_cmd: /* import_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6311 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_export_cmd: /* export_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6317 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_monitor_cmd: /* monitor_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6323 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_monitor_event: /* monitor_event */
+#line 930 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6329 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_describe_cmd: /* describe_cmd */
+#line 687 "parser_bison.y"
+ { cmd_free(((*yyvaluep).cmd)); }
+#line 6335 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_table_block_alloc: /* table_block_alloc */
+#line 717 "parser_bison.y"
+ { close_scope(state); table_free(((*yyvaluep).table)); }
+#line 6341 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_chain_block_alloc: /* chain_block_alloc */
+#line 719 "parser_bison.y"
+ { close_scope(state); chain_free(((*yyvaluep).chain)); }
+#line 6347 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_typeof_data_expr: /* typeof_data_expr */
+#line 791 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6353 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_typeof_expr: /* typeof_expr */
+#line 791 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6359 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_block_alloc: /* set_block_alloc */
+#line 728 "parser_bison.y"
+ { set_free(((*yyvaluep).set)); }
+#line 6365 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_block_expr: /* set_block_expr */
+#line 832 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6371 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_map_block_alloc: /* map_block_alloc */
+#line 731 "parser_bison.y"
+ { set_free(((*yyvaluep).set)); }
+#line 6377 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flowtable_block_alloc: /* flowtable_block_alloc */
+#line 735 "parser_bison.y"
+ { flowtable_free(((*yyvaluep).flowtable)); }
+#line 6383 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flowtable_expr: /* flowtable_expr */
+#line 832 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6389 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flowtable_list_expr: /* flowtable_list_expr */
+#line 832 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6395 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flowtable_expr_member: /* flowtable_expr_member */
+#line 832 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6401 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_data_type_atom_expr: /* data_type_atom_expr */
+#line 681 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6407 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_data_type_expr: /* data_type_expr */
+#line 681 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6413 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_obj_block_alloc: /* obj_block_alloc */
+#line 738 "parser_bison.y"
+ { obj_free(((*yyvaluep).obj)); }
+#line 6419 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_type_identifier: /* type_identifier */
+#line 676 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6425 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_extended_prio_name: /* extended_prio_name */
+#line 711 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6431 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_dev_spec: /* dev_spec */
+#line 714 "parser_bison.y"
+ { xfree(((*yyvaluep).expr)); }
+#line 6437 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_policy_expr: /* policy_expr */
+#line 789 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6443 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_identifier: /* identifier */
+#line 676 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6449 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_string: /* string */
+#line 676 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6455 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_table_spec: /* table_spec */
+#line 690 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6461 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_tableid_spec: /* tableid_spec */
+#line 690 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6467 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_chain_spec: /* chain_spec */
+#line 692 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6473 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_chainid_spec: /* chainid_spec */
+#line 692 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6479 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_chain_identifier: /* chain_identifier */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6485 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_spec: /* set_spec */
+#line 697 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6491 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_setid_spec: /* setid_spec */
+#line 697 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6497 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_identifier: /* set_identifier */
+#line 702 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6503 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flowtable_spec: /* flowtable_spec */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6509 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flowtableid_spec: /* flowtableid_spec */
+#line 702 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6515 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_obj_spec: /* obj_spec */
+#line 699 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6521 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_objid_spec: /* objid_spec */
+#line 699 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6527 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_obj_identifier: /* obj_identifier */
+#line 702 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6533 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_handle_spec: /* handle_spec */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6539 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_position_spec: /* position_spec */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6545 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_index_spec: /* index_spec */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6551 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rule_position: /* rule_position */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6557 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ruleid_spec: /* ruleid_spec */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6563 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_comment_spec: /* comment_spec */
+#line 676 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6569 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ruleset_spec: /* ruleset_spec */
+#line 695 "parser_bison.y"
+ { handle_free(&((*yyvaluep).handle)); }
+#line 6575 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rule: /* rule */
+#line 721 "parser_bison.y"
+ { rule_free(((*yyvaluep).rule)); }
+#line 6581 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_stmt_list: /* stmt_list */
+#line 741 "parser_bison.y"
+ { stmt_list_free(((*yyvaluep).list)); xfree(((*yyvaluep).list)); }
+#line 6587 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_stateful_stmt_list: /* stateful_stmt_list */
+#line 741 "parser_bison.y"
+ { stmt_list_free(((*yyvaluep).list)); xfree(((*yyvaluep).list)); }
+#line 6593 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_stateful_stmt: /* stateful_stmt */
+#line 745 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6599 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_stmt: /* stmt */
+#line 743 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6605 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_xt_stmt: /* xt_stmt */
+#line 954 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6611 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_chain_stmt: /* chain_stmt */
+#line 768 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6617 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_verdict_stmt: /* verdict_stmt */
+#line 743 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6623 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_verdict_map_stmt: /* verdict_map_stmt */
+#line 826 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6629 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_verdict_map_expr: /* verdict_map_expr */
+#line 829 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6635 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_verdict_map_list_expr: /* verdict_map_list_expr */
+#line 829 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6641 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_verdict_map_list_member_expr: /* verdict_map_list_member_expr */
+#line 829 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6647 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_connlimit_stmt: /* connlimit_stmt */
+#line 756 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6653 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_counter_stmt: /* counter_stmt */
+#line 745 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6659 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_counter_stmt_alloc: /* counter_stmt_alloc */
+#line 745 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6665 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_last_stmt: /* last_stmt */
+#line 745 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6671 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_log_stmt: /* log_stmt */
+#line 753 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6677 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_log_stmt_alloc: /* log_stmt_alloc */
+#line 753 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6683 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_limit_stmt: /* limit_stmt */
+#line 756 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6689 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_quota_unit: /* quota_unit */
+#line 711 "parser_bison.y"
+ { xfree(((*yyvaluep).string)); }
+#line 6695 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_quota_stmt: /* quota_stmt */
+#line 756 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6701 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_reject_stmt: /* reject_stmt */
+#line 759 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6707 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_reject_stmt_alloc: /* reject_stmt_alloc */
+#line 759 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6713 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_reject_with_expr: /* reject_with_expr */
+#line 774 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6719 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_nat_stmt: /* nat_stmt */
+#line 761 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6725 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_nat_stmt_alloc: /* nat_stmt_alloc */
+#line 761 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6731 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_tproxy_stmt: /* tproxy_stmt */
+#line 764 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6737 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_synproxy_stmt: /* synproxy_stmt */
+#line 766 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6743 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_synproxy_stmt_alloc: /* synproxy_stmt_alloc */
+#line 766 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6749 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_synproxy_obj: /* synproxy_obj */
+#line 852 "parser_bison.y"
+ { obj_free(((*yyvaluep).obj)); }
+#line 6755 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_primary_stmt_expr: /* primary_stmt_expr */
+#line 813 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6761 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_shift_stmt_expr: /* shift_stmt_expr */
+#line 815 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6767 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_and_stmt_expr: /* and_stmt_expr */
+#line 817 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6773 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_exclusive_or_stmt_expr: /* exclusive_or_stmt_expr */
+#line 817 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6779 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_inclusive_or_stmt_expr: /* inclusive_or_stmt_expr */
+#line 817 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6785 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_basic_stmt_expr: /* basic_stmt_expr */
+#line 813 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6791 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_concat_stmt_expr: /* concat_stmt_expr */
+#line 805 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6797 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_map_stmt_expr_set: /* map_stmt_expr_set */
+#line 805 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6803 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_map_stmt_expr: /* map_stmt_expr */
+#line 805 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6809 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_prefix_stmt_expr: /* prefix_stmt_expr */
+#line 810 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6815 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_range_stmt_expr: /* range_stmt_expr */
+#line 810 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6821 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_multiton_stmt_expr: /* multiton_stmt_expr */
+#line 808 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6827 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_stmt_expr: /* stmt_expr */
+#line 805 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6833 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_masq_stmt: /* masq_stmt */
+#line 761 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6839 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_masq_stmt_alloc: /* masq_stmt_alloc */
+#line 761 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6845 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_redir_stmt: /* redir_stmt */
+#line 761 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6851 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_redir_stmt_alloc: /* redir_stmt_alloc */
+#line 761 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6857 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_dup_stmt: /* dup_stmt */
+#line 777 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6863 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_fwd_stmt: /* fwd_stmt */
+#line 779 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6869 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_queue_stmt: /* queue_stmt */
+#line 772 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6875 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_queue_stmt_compat: /* queue_stmt_compat */
+#line 772 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6881 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_queue_stmt_alloc: /* queue_stmt_alloc */
+#line 772 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6887 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_queue_expr: /* queue_expr */
+#line 774 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6893 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_queue_stmt_expr_simple: /* queue_stmt_expr_simple */
+#line 774 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6899 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_queue_stmt_expr: /* queue_stmt_expr */
+#line 774 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6905 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_elem_expr_stmt: /* set_elem_expr_stmt */
+#line 836 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6911 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_elem_expr_stmt_alloc: /* set_elem_expr_stmt_alloc */
+#line 836 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6917 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_stmt: /* set_stmt */
+#line 781 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6923 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_map_stmt: /* map_stmt */
+#line 784 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6929 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_meter_stmt: /* meter_stmt */
+#line 786 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6935 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_flow_stmt_legacy_alloc: /* flow_stmt_legacy_alloc */
+#line 786 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6941 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_meter_stmt_alloc: /* meter_stmt_alloc */
+#line 786 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6947 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_match_stmt: /* match_stmt */
+#line 743 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 6953 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_variable_expr: /* variable_expr */
+#line 789 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6959 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_symbol_expr: /* symbol_expr */
+#line 789 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6965 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_ref_expr: /* set_ref_expr */
+#line 797 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6971 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_ref_symbol_expr: /* set_ref_symbol_expr */
+#line 797 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6977 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_integer_expr: /* integer_expr */
+#line 789 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6983 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_primary_expr: /* primary_expr */
+#line 791 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6989 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_fib_expr: /* fib_expr */
+#line 921 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 6995 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_osf_expr: /* osf_expr */
+#line 926 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7001 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_shift_expr: /* shift_expr */
+#line 791 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7007 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_and_expr: /* and_expr */
+#line 791 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7013 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_exclusive_or_expr: /* exclusive_or_expr */
+#line 793 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7019 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_inclusive_or_expr: /* inclusive_or_expr */
+#line 793 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7025 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_basic_expr: /* basic_expr */
+#line 795 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7031 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_concat_expr: /* concat_expr */
+#line 820 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7037 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_prefix_rhs_expr: /* prefix_rhs_expr */
+#line 802 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7043 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_range_rhs_expr: /* range_rhs_expr */
+#line 802 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7049 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_multiton_rhs_expr: /* multiton_rhs_expr */
+#line 800 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7055 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_map_expr: /* map_expr */
+#line 823 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7061 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_expr: /* expr */
+#line 842 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7067 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_expr: /* set_expr */
+#line 832 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7073 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_list_expr: /* set_list_expr */
+#line 832 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7079 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_list_member_expr: /* set_list_member_expr */
+#line 832 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7085 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_meter_key_expr: /* meter_key_expr */
+#line 839 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7091 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_meter_key_expr_alloc: /* meter_key_expr_alloc */
+#line 839 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7097 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_elem_expr: /* set_elem_expr */
+#line 834 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7103 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_elem_key_expr: /* set_elem_key_expr */
+#line 974 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7109 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_elem_expr_alloc: /* set_elem_expr_alloc */
+#line 834 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7115 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_elem_stmt_list: /* set_elem_stmt_list */
+#line 741 "parser_bison.y"
+ { stmt_list_free(((*yyvaluep).list)); xfree(((*yyvaluep).list)); }
+#line 7121 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_elem_stmt: /* set_elem_stmt */
+#line 743 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 7127 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_lhs_expr: /* set_lhs_expr */
+#line 834 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7133 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_set_rhs_expr: /* set_rhs_expr */
+#line 834 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7139 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_initializer_expr: /* initializer_expr */
+#line 842 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7145 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_counter_obj: /* counter_obj */
+#line 852 "parser_bison.y"
+ { obj_free(((*yyvaluep).obj)); }
+#line 7151 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_quota_obj: /* quota_obj */
+#line 852 "parser_bison.y"
+ { obj_free(((*yyvaluep).obj)); }
+#line 7157 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_secmark_obj: /* secmark_obj */
+#line 852 "parser_bison.y"
+ { obj_free(((*yyvaluep).obj)); }
+#line 7163 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_timeout_states: /* timeout_states */
+#line 967 "parser_bison.y"
+ { xfree(((*yyvaluep).list)); }
+#line 7169 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_timeout_state: /* timeout_state */
+#line 967 "parser_bison.y"
+ { xfree(((*yyvaluep).list)); }
+#line 7175 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ct_obj_alloc: /* ct_obj_alloc */
+#line 852 "parser_bison.y"
+ { obj_free(((*yyvaluep).obj)); }
+#line 7181 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_limit_obj: /* limit_obj */
+#line 852 "parser_bison.y"
+ { obj_free(((*yyvaluep).obj)); }
+#line 7187 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_relational_expr: /* relational_expr */
+#line 855 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7193 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_list_rhs_expr: /* list_rhs_expr */
+#line 847 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7199 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rhs_expr: /* rhs_expr */
+#line 845 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7205 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_shift_rhs_expr: /* shift_rhs_expr */
+#line 847 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7211 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_and_rhs_expr: /* and_rhs_expr */
+#line 849 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7217 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_exclusive_or_rhs_expr: /* exclusive_or_rhs_expr */
+#line 849 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7223 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_inclusive_or_rhs_expr: /* inclusive_or_rhs_expr */
+#line 849 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7229 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_basic_rhs_expr: /* basic_rhs_expr */
+#line 845 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7235 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_concat_rhs_expr: /* concat_rhs_expr */
+#line 845 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7241 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_boolean_expr: /* boolean_expr */
+#line 957 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7247 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_keyword_expr: /* keyword_expr */
+#line 842 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7253 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_primary_rhs_expr: /* primary_rhs_expr */
+#line 847 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7259 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_verdict_expr: /* verdict_expr */
+#line 789 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7265 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_chain_expr: /* chain_expr */
+#line 789 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7271 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_meta_expr: /* meta_expr */
+#line 903 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7277 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_meta_stmt: /* meta_stmt */
+#line 751 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 7283 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_socket_expr: /* socket_expr */
+#line 907 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7289 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_numgen_expr: /* numgen_expr */
+#line 868 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7295 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_xfrm_expr: /* xfrm_expr */
+#line 971 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7301 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_hash_expr: /* hash_expr */
+#line 868 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7307 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rt_expr: /* rt_expr */
+#line 913 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7313 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ct_expr: /* ct_expr */
+#line 917 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7319 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_symbol_stmt_expr: /* symbol_stmt_expr */
+#line 847 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7325 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_list_stmt_expr: /* list_stmt_expr */
+#line 815 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7331 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ct_stmt: /* ct_stmt */
+#line 749 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 7337 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_payload_stmt: /* payload_stmt */
+#line 747 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 7343 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_payload_expr: /* payload_expr */
+#line 859 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7349 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_payload_raw_expr: /* payload_raw_expr */
+#line 859 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7355 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_eth_hdr_expr: /* eth_hdr_expr */
+#line 862 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7361 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_vlan_hdr_expr: /* vlan_hdr_expr */
+#line 862 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7367 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_arp_hdr_expr: /* arp_hdr_expr */
+#line 865 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7373 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ip_hdr_expr: /* ip_hdr_expr */
+#line 868 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7379 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_icmp_hdr_expr: /* icmp_hdr_expr */
+#line 868 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7385 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_igmp_hdr_expr: /* igmp_hdr_expr */
+#line 868 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7391 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_ip6_hdr_expr: /* ip6_hdr_expr */
+#line 872 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7397 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_icmp6_hdr_expr: /* icmp6_hdr_expr */
+#line 872 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7403 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_auth_hdr_expr: /* auth_hdr_expr */
+#line 875 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7409 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_esp_hdr_expr: /* esp_hdr_expr */
+#line 875 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7415 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_comp_hdr_expr: /* comp_hdr_expr */
+#line 875 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7421 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_udp_hdr_expr: /* udp_hdr_expr */
+#line 878 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7427 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_udplite_hdr_expr: /* udplite_hdr_expr */
+#line 878 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7433 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_tcp_hdr_expr: /* tcp_hdr_expr */
+#line 936 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7439 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_inner_inet_expr: /* inner_inet_expr */
+#line 944 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7445 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_inner_eth_expr: /* inner_eth_expr */
+#line 944 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7451 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_inner_expr: /* inner_expr */
+#line 944 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7457 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_vxlan_hdr_expr: /* vxlan_hdr_expr */
+#line 947 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7463 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_geneve_hdr_expr: /* geneve_hdr_expr */
+#line 947 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7469 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_gre_hdr_expr: /* gre_hdr_expr */
+#line 947 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7475 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_gretap_hdr_expr: /* gretap_hdr_expr */
+#line 947 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7481 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_optstrip_stmt: /* optstrip_stmt */
+#line 951 "parser_bison.y"
+ { stmt_free(((*yyvaluep).stmt)); }
+#line 7487 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_dccp_hdr_expr: /* dccp_hdr_expr */
+#line 881 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7493 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_sctp_chunk_alloc: /* sctp_chunk_alloc */
+#line 881 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7499 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_sctp_hdr_expr: /* sctp_hdr_expr */
+#line 881 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7505 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_th_hdr_expr: /* th_hdr_expr */
+#line 887 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7511 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_exthdr_expr: /* exthdr_expr */
+#line 891 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7517 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_hbh_hdr_expr: /* hbh_hdr_expr */
+#line 893 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7523 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rt_hdr_expr: /* rt_hdr_expr */
+#line 896 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7529 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rt0_hdr_expr: /* rt0_hdr_expr */
+#line 896 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7535 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rt2_hdr_expr: /* rt2_hdr_expr */
+#line 896 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7541 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_rt4_hdr_expr: /* rt4_hdr_expr */
+#line 896 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7547 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_frag_hdr_expr: /* frag_hdr_expr */
+#line 893 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7553 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_dst_hdr_expr: /* dst_hdr_expr */
+#line 893 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7559 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_mh_hdr_expr: /* mh_hdr_expr */
+#line 899 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7565 "parser_bison.c"
+ break;
+
+ case YYSYMBOL_exthdr_exists_expr: /* exthdr_exists_expr */
+#line 961 "parser_bison.y"
+ { expr_free(((*yyvaluep).expr)); }
+#line 7571 "parser_bison.c"
+ break;
+
+ default:
+ break;
+ }
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (struct nft_ctx *nft, void *scanner, struct parser_state *state)
+{
+/* Lookahead token kind. */
+int yychar;
+
+
+/* The semantic value of the lookahead symbol. */
+/* Default value used for initialization, for pacifying older GCCs
+ or non-GCC compilers. */
+YY_INITIAL_VALUE (static YYSTYPE yyval_default;)
+YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default);
+
+/* Location data for the lookahead symbol. */
+static YYLTYPE yyloc_default
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+ = { 1, 1, 1, 1 }
+# endif
+;
+YYLTYPE yylloc = yyloc_default;
+
+ /* Number of syntax errors so far. */
+ int yynerrs = 0;
+
+ yy_state_fast_t yystate = 0;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus = 0;
+
+ /* Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* Their size. */
+ YYPTRDIFF_T yystacksize = YYINITDEPTH;
+
+ /* The state stack: array, bottom, top. */
+ yy_state_t yyssa[YYINITDEPTH];
+ yy_state_t *yyss = yyssa;
+ yy_state_t *yyssp = yyss;
+
+ /* The semantic value stack: array, bottom, top. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp = yyvs;
+
+ /* The location stack: array, bottom, top. */
+ YYLTYPE yylsa[YYINITDEPTH];
+ YYLTYPE *yyls = yylsa;
+ YYLTYPE *yylsp = yyls;
+
+ int yyn;
+ /* The return value of yyparse. */
+ int yyresult;
+ /* Lookahead symbol kind. */
+ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+ YYLTYPE yyloc;
+
+ /* The locations where the error started and ended. */
+ YYLTYPE yyerror_range[3];
+
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf;
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+/* User initialization code. */
+#line 197 "parser_bison.y"
+{
+ location_init(scanner, state, &yylloc);
+ if (nft->debug_mask & NFT_DEBUG_SCANNER)
+ nft_set_debug(1, scanner);
+ if (nft->debug_mask & NFT_DEBUG_PARSER)
+ yydebug = 1;
+}
+
+#line 7676 "parser_bison.c"
+
+ yylsp[0] = yylloc;
+ goto yysetstate;
+
+
+/*------------------------------------------------------------.
+| yynewstate -- push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+
+/*--------------------------------------------------------------------.
+| yysetstate -- set current state (the top of the stack) to yystate. |
+`--------------------------------------------------------------------*/
+yysetstate:
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+ YY_ASSERT (0 <= yystate && yystate < YYNSTATES);
+ YY_IGNORE_USELESS_CAST_BEGIN
+ *yyssp = YY_CAST (yy_state_t, yystate);
+ YY_IGNORE_USELESS_CAST_END
+ YY_STACK_PRINT (yyss, yyssp);
+
+ if (yyss + yystacksize - 1 <= yyssp)
+#if !defined yyoverflow && !defined YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+#else
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYPTRDIFF_T yysize = yyssp - yyss + 1;
+
+# if defined yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ yy_state_t *yyss1 = yyss;
+ YYSTYPE *yyvs1 = yyvs;
+ YYLTYPE *yyls1 = yyls;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * YYSIZEOF (*yyssp),
+ &yyvs1, yysize * YYSIZEOF (*yyvsp),
+ &yyls1, yysize * YYSIZEOF (*yylsp),
+ &yystacksize);
+ yyss = yyss1;
+ yyvs = yyvs1;
+ yyls = yyls1;
+ }
+# else /* defined YYSTACK_RELOCATE */
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yy_state_t *yyss1 = yyss;
+ union yyalloc *yyptr =
+ YY_CAST (union yyalloc *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+ YYSTACK_RELOCATE (yyls_alloc, yyls);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+ yylsp = yyls + yysize - 1;
+
+ YY_IGNORE_USELESS_CAST_BEGIN
+ YYDPRINTF ((stderr, "Stack size increased to %ld\n",
+ YY_CAST (long, yystacksize)));
+ YY_IGNORE_USELESS_CAST_END
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token\n"));
+ yychar = yylex (&yylval, &yylloc, scanner);
+ }
+
+ if (yychar <= TOKEN_EOF)
+ {
+ yychar = TOKEN_EOF;
+ yytoken = YYSYMBOL_YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else if (yychar == YYerror)
+ {
+ /* The scanner already issued an error message, process directly
+ to error recovery. But do not keep the error token as
+ lookahead, it is too special and may lead us to an endless
+ loop in error recovery. */
+ yychar = YYUNDEF;
+ yytoken = YYSYMBOL_YYerror;
+ yyerror_range[1] = yylloc;
+ goto yyerrlab1;
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+ *++yylsp = yylloc;
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+ /* Default location. */
+ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+ yyerror_range[1] = yyloc;
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 3: /* input: input line */
+#line 980 "parser_bison.y"
+ {
+ if ((yyvsp[0].cmd) != NULL) {
+ (yyvsp[0].cmd)->location = (yylsp[0]);
+ list_add_tail(&(yyvsp[0].cmd)->list, state->cmds);
+ }
+ }
+#line 7893 "parser_bison.c"
+ break;
+
+ case 8: /* close_scope_ah: %empty */
+#line 996 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_AH); }
+#line 7899 "parser_bison.c"
+ break;
+
+ case 9: /* close_scope_arp: %empty */
+#line 997 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_ARP); }
+#line 7905 "parser_bison.c"
+ break;
+
+ case 10: /* close_scope_at: %empty */
+#line 998 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_AT); }
+#line 7911 "parser_bison.c"
+ break;
+
+ case 11: /* close_scope_comp: %empty */
+#line 999 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_COMP); }
+#line 7917 "parser_bison.c"
+ break;
+
+ case 12: /* close_scope_ct: %empty */
+#line 1000 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_CT); }
+#line 7923 "parser_bison.c"
+ break;
+
+ case 13: /* close_scope_counter: %empty */
+#line 1001 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_COUNTER); }
+#line 7929 "parser_bison.c"
+ break;
+
+ case 14: /* close_scope_last: %empty */
+#line 1002 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_LAST); }
+#line 7935 "parser_bison.c"
+ break;
+
+ case 15: /* close_scope_dccp: %empty */
+#line 1003 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DCCP); }
+#line 7941 "parser_bison.c"
+ break;
+
+ case 16: /* close_scope_destroy: %empty */
+#line 1004 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_DESTROY); }
+#line 7947 "parser_bison.c"
+ break;
+
+ case 17: /* close_scope_dst: %empty */
+#line 1005 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DST); }
+#line 7953 "parser_bison.c"
+ break;
+
+ case 18: /* close_scope_dup: %empty */
+#line 1006 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_DUP); }
+#line 7959 "parser_bison.c"
+ break;
+
+ case 19: /* close_scope_esp: %empty */
+#line 1007 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_ESP); }
+#line 7965 "parser_bison.c"
+ break;
+
+ case 20: /* close_scope_eth: %empty */
+#line 1008 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_ETH); }
+#line 7971 "parser_bison.c"
+ break;
+
+ case 21: /* close_scope_export: %empty */
+#line 1009 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_EXPORT); }
+#line 7977 "parser_bison.c"
+ break;
+
+ case 22: /* close_scope_fib: %empty */
+#line 1010 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FIB); }
+#line 7983 "parser_bison.c"
+ break;
+
+ case 23: /* close_scope_frag: %empty */
+#line 1011 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FRAG); }
+#line 7989 "parser_bison.c"
+ break;
+
+ case 24: /* close_scope_fwd: %empty */
+#line 1012 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_FWD); }
+#line 7995 "parser_bison.c"
+ break;
+
+ case 25: /* close_scope_gre: %empty */
+#line 1013 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_GRE); }
+#line 8001 "parser_bison.c"
+ break;
+
+ case 26: /* close_scope_hash: %empty */
+#line 1014 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }
+#line 8007 "parser_bison.c"
+ break;
+
+ case 27: /* close_scope_hbh: %empty */
+#line 1015 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HBH); }
+#line 8013 "parser_bison.c"
+ break;
+
+ case 28: /* close_scope_ip: %empty */
+#line 1016 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP); }
+#line 8019 "parser_bison.c"
+ break;
+
+ case 29: /* close_scope_ip6: %empty */
+#line 1017 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP6); }
+#line 8025 "parser_bison.c"
+ break;
+
+ case 30: /* close_scope_vlan: %empty */
+#line 1018 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_VLAN); }
+#line 8031 "parser_bison.c"
+ break;
+
+ case 31: /* close_scope_icmp: %empty */
+#line 1019 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_ICMP); }
+#line 8037 "parser_bison.c"
+ break;
+
+ case 32: /* close_scope_igmp: %empty */
+#line 1020 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_IGMP); }
+#line 8043 "parser_bison.c"
+ break;
+
+ case 33: /* close_scope_import: %empty */
+#line 1021 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_IMPORT); }
+#line 8049 "parser_bison.c"
+ break;
+
+ case 34: /* close_scope_ipsec: %empty */
+#line 1022 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_IPSEC); }
+#line 8055 "parser_bison.c"
+ break;
+
+ case 35: /* close_scope_list: %empty */
+#line 1023 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_LIST); }
+#line 8061 "parser_bison.c"
+ break;
+
+ case 36: /* close_scope_limit: %empty */
+#line 1024 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_LIMIT); }
+#line 8067 "parser_bison.c"
+ break;
+
+ case 37: /* close_scope_meta: %empty */
+#line 1025 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_META); }
+#line 8073 "parser_bison.c"
+ break;
+
+ case 38: /* close_scope_mh: %empty */
+#line 1026 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_MH); }
+#line 8079 "parser_bison.c"
+ break;
+
+ case 39: /* close_scope_monitor: %empty */
+#line 1027 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_MONITOR); }
+#line 8085 "parser_bison.c"
+ break;
+
+ case 40: /* close_scope_nat: %empty */
+#line 1028 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_NAT); }
+#line 8091 "parser_bison.c"
+ break;
+
+ case 41: /* close_scope_numgen: %empty */
+#line 1029 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); }
+#line 8097 "parser_bison.c"
+ break;
+
+ case 42: /* close_scope_osf: %empty */
+#line 1030 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_OSF); }
+#line 8103 "parser_bison.c"
+ break;
+
+ case 43: /* close_scope_policy: %empty */
+#line 1031 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_POLICY); }
+#line 8109 "parser_bison.c"
+ break;
+
+ case 44: /* close_scope_quota: %empty */
+#line 1032 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_QUOTA); }
+#line 8115 "parser_bison.c"
+ break;
+
+ case 45: /* close_scope_queue: %empty */
+#line 1033 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_QUEUE); }
+#line 8121 "parser_bison.c"
+ break;
+
+ case 46: /* close_scope_reject: %empty */
+#line 1034 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_REJECT); }
+#line 8127 "parser_bison.c"
+ break;
+
+ case 47: /* close_scope_reset: %empty */
+#line 1035 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_RESET); }
+#line 8133 "parser_bison.c"
+ break;
+
+ case 48: /* close_scope_rt: %empty */
+#line 1036 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_RT); }
+#line 8139 "parser_bison.c"
+ break;
+
+ case 49: /* close_scope_sctp: %empty */
+#line 1037 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); }
+#line 8145 "parser_bison.c"
+ break;
+
+ case 50: /* close_scope_sctp_chunk: %empty */
+#line 1038 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SCTP_CHUNK); }
+#line 8151 "parser_bison.c"
+ break;
+
+ case 51: /* close_scope_secmark: %empty */
+#line 1039 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_SECMARK); }
+#line 8157 "parser_bison.c"
+ break;
+
+ case 52: /* close_scope_socket: %empty */
+#line 1040 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SOCKET); }
+#line 8163 "parser_bison.c"
+ break;
+
+ case 53: /* close_scope_tcp: %empty */
+#line 1041 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_TCP); }
+#line 8169 "parser_bison.c"
+ break;
+
+ case 54: /* close_scope_tproxy: %empty */
+#line 1042 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_TPROXY); }
+#line 8175 "parser_bison.c"
+ break;
+
+ case 55: /* close_scope_type: %empty */
+#line 1043 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_TYPE); }
+#line 8181 "parser_bison.c"
+ break;
+
+ case 56: /* close_scope_th: %empty */
+#line 1044 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_TH); }
+#line 8187 "parser_bison.c"
+ break;
+
+ case 57: /* close_scope_udp: %empty */
+#line 1045 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDP); }
+#line 8193 "parser_bison.c"
+ break;
+
+ case 58: /* close_scope_udplite: %empty */
+#line 1046 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDPLITE); }
+#line 8199 "parser_bison.c"
+ break;
+
+ case 59: /* close_scope_log: %empty */
+#line 1048 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_LOG); }
+#line 8205 "parser_bison.c"
+ break;
+
+ case 60: /* close_scope_synproxy: %empty */
+#line 1049 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_SYNPROXY); }
+#line 8211 "parser_bison.c"
+ break;
+
+ case 61: /* close_scope_xt: %empty */
+#line 1050 "parser_bison.y"
+ { scanner_pop_start_cond(nft->scanner, PARSER_SC_XT); }
+#line 8217 "parser_bison.c"
+ break;
+
+ case 62: /* common_block: "include" "quoted string" stmt_separator */
+#line 1053 "parser_bison.y"
+ {
+ if (scanner_include_file(nft, scanner, (yyvsp[-1].string), &(yyloc)) < 0) {
+ xfree((yyvsp[-1].string));
+ YYERROR;
+ }
+ xfree((yyvsp[-1].string));
+ }
+#line 8229 "parser_bison.c"
+ break;
+
+ case 63: /* common_block: "define" identifier '=' initializer_expr stmt_separator */
+#line 1061 "parser_bison.y"
+ {
+ struct scope *scope = current_scope(state);
+
+ if (symbol_lookup(scope, (yyvsp[-3].string)) != NULL) {
+ erec_queue(error(&(yylsp[-3]), "redefinition of symbol '%s'", (yyvsp[-3].string)),
+ state->msgs);
+ expr_free((yyvsp[-1].expr));
+ xfree((yyvsp[-3].string));
+ YYERROR;
+ }
+
+ symbol_bind(scope, (yyvsp[-3].string), (yyvsp[-1].expr));
+ xfree((yyvsp[-3].string));
+ }
+#line 8248 "parser_bison.c"
+ break;
+
+ case 64: /* common_block: "redefine" identifier '=' initializer_expr stmt_separator */
+#line 1076 "parser_bison.y"
+ {
+ struct scope *scope = current_scope(state);
+
+ symbol_bind(scope, (yyvsp[-3].string), (yyvsp[-1].expr));
+ xfree((yyvsp[-3].string));
+ }
+#line 8259 "parser_bison.c"
+ break;
+
+ case 65: /* common_block: "undefine" identifier stmt_separator */
+#line 1083 "parser_bison.y"
+ {
+ struct scope *scope = current_scope(state);
+
+ if (symbol_unbind(scope, (yyvsp[-1].string)) < 0) {
+ erec_queue(error(&(yylsp[-1]), "undefined symbol '%s'", (yyvsp[-1].string)),
+ state->msgs);
+ xfree((yyvsp[-1].string));
+ YYERROR;
+ }
+ xfree((yyvsp[-1].string));
+ }
+#line 8275 "parser_bison.c"
+ break;
+
+ case 66: /* common_block: error stmt_separator */
+#line 1095 "parser_bison.y"
+ {
+ if (++state->nerrs == nft->parser_max_errors)
+ YYABORT;
+ yyerrok;
+ }
+#line 8285 "parser_bison.c"
+ break;
+
+ case 67: /* line: common_block */
+#line 1102 "parser_bison.y"
+ { (yyval.cmd) = NULL; }
+#line 8291 "parser_bison.c"
+ break;
+
+ case 68: /* line: stmt_separator */
+#line 1103 "parser_bison.y"
+ { (yyval.cmd) = NULL; }
+#line 8297 "parser_bison.c"
+ break;
+
+ case 69: /* line: base_cmd stmt_separator */
+#line 1104 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[-1].cmd); }
+#line 8303 "parser_bison.c"
+ break;
+
+ case 70: /* line: base_cmd "end of file" */
+#line 1106 "parser_bison.y"
+ {
+ /*
+ * Very hackish workaround for bison >= 2.4: previous versions
+ * terminated parsing after EOF, 2.4+ tries to get further input
+ * in 'input' and calls the scanner again, causing a crash when
+ * the final input buffer has been popped. Terminate manually to
+ * avoid this. The correct fix should be to adjust the grammar
+ * to accept EOF in input, but for unknown reasons it does not
+ * work.
+ */
+ if ((yyvsp[-1].cmd) != NULL) {
+ (yyvsp[-1].cmd)->location = (yylsp[-1]);
+ list_add_tail(&(yyvsp[-1].cmd)->list, state->cmds);
+ }
+ (yyval.cmd) = NULL;
+ YYACCEPT;
+ }
+#line 8325 "parser_bison.c"
+ break;
+
+ case 71: /* base_cmd: add_cmd */
+#line 1125 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8331 "parser_bison.c"
+ break;
+
+ case 72: /* base_cmd: "add" add_cmd */
+#line 1126 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8337 "parser_bison.c"
+ break;
+
+ case 73: /* base_cmd: "replace" replace_cmd */
+#line 1127 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8343 "parser_bison.c"
+ break;
+
+ case 74: /* base_cmd: "create" create_cmd */
+#line 1128 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8349 "parser_bison.c"
+ break;
+
+ case 75: /* base_cmd: "insert" insert_cmd */
+#line 1129 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8355 "parser_bison.c"
+ break;
+
+ case 76: /* base_cmd: "delete" delete_cmd */
+#line 1130 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8361 "parser_bison.c"
+ break;
+
+ case 77: /* base_cmd: "get" get_cmd */
+#line 1131 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8367 "parser_bison.c"
+ break;
+
+ case 78: /* base_cmd: "list" list_cmd close_scope_list */
+#line 1132 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[-1].cmd); }
+#line 8373 "parser_bison.c"
+ break;
+
+ case 79: /* base_cmd: "reset" reset_cmd close_scope_reset */
+#line 1133 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[-1].cmd); }
+#line 8379 "parser_bison.c"
+ break;
+
+ case 80: /* base_cmd: "flush" flush_cmd */
+#line 1134 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8385 "parser_bison.c"
+ break;
+
+ case 81: /* base_cmd: "rename" rename_cmd */
+#line 1135 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8391 "parser_bison.c"
+ break;
+
+ case 82: /* base_cmd: "import" import_cmd close_scope_import */
+#line 1136 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[-1].cmd); }
+#line 8397 "parser_bison.c"
+ break;
+
+ case 83: /* base_cmd: "export" export_cmd close_scope_export */
+#line 1137 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[-1].cmd); }
+#line 8403 "parser_bison.c"
+ break;
+
+ case 84: /* base_cmd: "monitor" monitor_cmd close_scope_monitor */
+#line 1138 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[-1].cmd); }
+#line 8409 "parser_bison.c"
+ break;
+
+ case 85: /* base_cmd: "describe" describe_cmd */
+#line 1139 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[0].cmd); }
+#line 8415 "parser_bison.c"
+ break;
+
+ case 86: /* base_cmd: "destroy" destroy_cmd close_scope_destroy */
+#line 1140 "parser_bison.y"
+ { (yyval.cmd) = (yyvsp[-1].cmd); }
+#line 8421 "parser_bison.c"
+ break;
+
+ case 87: /* add_cmd: "table" table_spec */
+#line 1144 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8429 "parser_bison.c"
+ break;
+
+ case 88: /* add_cmd: "table" table_spec table_block_alloc '{' table_block '}' */
+#line 1149 "parser_bison.y"
+ {
+ handle_merge(&(yyvsp[-3].table)->handle, &(yyvsp[-4].handle));
+ close_scope(state);
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].table));
+ }
+#line 8439 "parser_bison.c"
+ break;
+
+ case 89: /* add_cmd: "chain" chain_spec */
+#line 1155 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8447 "parser_bison.c"
+ break;
+
+ case 90: /* add_cmd: "chain" chain_spec chain_block_alloc '{' chain_block '}' */
+#line 1160 "parser_bison.y"
+ {
+ (yyvsp[-1].chain)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].chain)->handle, &(yyvsp[-4].handle));
+ close_scope(state);
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].chain));
+ }
+#line 8458 "parser_bison.c"
+ break;
+
+ case 91: /* add_cmd: "rule" rule_position rule */
+#line 1167 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].rule));
+ }
+#line 8466 "parser_bison.c"
+ break;
+
+ case 92: /* add_cmd: rule_position rule */
+#line 1171 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].rule));
+ }
+#line 8474 "parser_bison.c"
+ break;
+
+ case 93: /* add_cmd: "set" set_spec set_block_alloc '{' set_block '}' */
+#line 1176 "parser_bison.y"
+ {
+ (yyvsp[-1].set)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].set)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].set));
+ }
+#line 8484 "parser_bison.c"
+ break;
+
+ case 94: /* add_cmd: "map" set_spec map_block_alloc '{' map_block '}' */
+#line 1183 "parser_bison.y"
+ {
+ (yyvsp[-1].set)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].set)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].set));
+ }
+#line 8494 "parser_bison.c"
+ break;
+
+ case 95: /* add_cmd: "element" set_spec set_block_expr */
+#line 1189 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].expr));
+ }
+#line 8502 "parser_bison.c"
+ break;
+
+ case 96: /* add_cmd: "flowtable" flowtable_spec flowtable_block_alloc '{' flowtable_block '}' */
+#line 1194 "parser_bison.y"
+ {
+ (yyvsp[-1].flowtable)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].flowtable)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].flowtable));
+ }
+#line 8512 "parser_bison.c"
+ break;
+
+ case 97: /* add_cmd: "counter" obj_spec close_scope_counter */
+#line 1200 "parser_bison.y"
+ {
+ struct obj *obj;
+
+ obj = obj_alloc(&(yyloc));
+ obj->type = NFT_OBJECT_COUNTER;
+ handle_merge(&obj->handle, &(yyvsp[-1].handle));
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &(yyvsp[-1].handle), &(yyloc), obj);
+ }
+#line 8525 "parser_bison.c"
+ break;
+
+ case 98: /* add_cmd: "counter" obj_spec counter_obj counter_config close_scope_counter */
+#line 1209 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8533 "parser_bison.c"
+ break;
+
+ case 99: /* add_cmd: "counter" obj_spec counter_obj '{' counter_block '}' close_scope_counter */
+#line 1213 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8541 "parser_bison.c"
+ break;
+
+ case 100: /* add_cmd: "quota" obj_spec quota_obj quota_config close_scope_quota */
+#line 1217 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8549 "parser_bison.c"
+ break;
+
+ case 101: /* add_cmd: "quota" obj_spec quota_obj '{' quota_block '}' close_scope_quota */
+#line 1221 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8557 "parser_bison.c"
+ break;
+
+ case 102: /* add_cmd: "ct" "helper" obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct */
+#line 1225 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_HELPER, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8565 "parser_bison.c"
+ break;
+
+ case 103: /* add_cmd: "ct" "timeout" obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct */
+#line 1229 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_TIMEOUT, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8573 "parser_bison.c"
+ break;
+
+ case 104: /* add_cmd: "ct" "expectation" obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct */
+#line 1233 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_EXPECT, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8581 "parser_bison.c"
+ break;
+
+ case 105: /* add_cmd: "limit" obj_spec limit_obj limit_config close_scope_limit */
+#line 1237 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8589 "parser_bison.c"
+ break;
+
+ case 106: /* add_cmd: "limit" obj_spec limit_obj '{' limit_block '}' close_scope_limit */
+#line 1241 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8597 "parser_bison.c"
+ break;
+
+ case 107: /* add_cmd: "secmark" obj_spec secmark_obj secmark_config close_scope_secmark */
+#line 1245 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8605 "parser_bison.c"
+ break;
+
+ case 108: /* add_cmd: "secmark" obj_spec secmark_obj '{' secmark_block '}' close_scope_secmark */
+#line 1249 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8613 "parser_bison.c"
+ break;
+
+ case 109: /* add_cmd: "synproxy" obj_spec synproxy_obj synproxy_config close_scope_synproxy */
+#line 1253 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8621 "parser_bison.c"
+ break;
+
+ case 110: /* add_cmd: "synproxy" obj_spec synproxy_obj '{' synproxy_block '}' close_scope_synproxy */
+#line 1257 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8629 "parser_bison.c"
+ break;
+
+ case 111: /* replace_cmd: "rule" ruleid_spec rule */
+#line 1263 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_REPLACE, CMD_OBJ_RULE, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].rule));
+ }
+#line 8637 "parser_bison.c"
+ break;
+
+ case 112: /* create_cmd: "table" table_spec */
+#line 1269 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_TABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8645 "parser_bison.c"
+ break;
+
+ case 113: /* create_cmd: "table" table_spec table_block_alloc '{' table_block '}' */
+#line 1274 "parser_bison.y"
+ {
+ handle_merge(&(yyvsp[-3].table)->handle, &(yyvsp[-4].handle));
+ close_scope(state);
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_TABLE, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].table));
+ }
+#line 8655 "parser_bison.c"
+ break;
+
+ case 114: /* create_cmd: "chain" chain_spec */
+#line 1280 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_CHAIN, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8663 "parser_bison.c"
+ break;
+
+ case 115: /* create_cmd: "chain" chain_spec chain_block_alloc '{' chain_block '}' */
+#line 1285 "parser_bison.y"
+ {
+ (yyvsp[-1].chain)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].chain)->handle, &(yyvsp[-4].handle));
+ close_scope(state);
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_CHAIN, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].chain));
+ }
+#line 8674 "parser_bison.c"
+ break;
+
+ case 116: /* create_cmd: "set" set_spec set_block_alloc '{' set_block '}' */
+#line 1293 "parser_bison.y"
+ {
+ (yyvsp[-1].set)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].set)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_SET, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].set));
+ }
+#line 8684 "parser_bison.c"
+ break;
+
+ case 117: /* create_cmd: "map" set_spec map_block_alloc '{' map_block '}' */
+#line 1300 "parser_bison.y"
+ {
+ (yyvsp[-1].set)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].set)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_SET, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].set));
+ }
+#line 8694 "parser_bison.c"
+ break;
+
+ case 118: /* create_cmd: "element" set_spec set_block_expr */
+#line 1306 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_ELEMENTS, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].expr));
+ }
+#line 8702 "parser_bison.c"
+ break;
+
+ case 119: /* create_cmd: "flowtable" flowtable_spec flowtable_block_alloc '{' flowtable_block '}' */
+#line 1311 "parser_bison.y"
+ {
+ (yyvsp[-1].flowtable)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].flowtable)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_FLOWTABLE, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].flowtable));
+ }
+#line 8712 "parser_bison.c"
+ break;
+
+ case 120: /* create_cmd: "counter" obj_spec close_scope_counter */
+#line 1317 "parser_bison.y"
+ {
+ struct obj *obj;
+
+ obj = obj_alloc(&(yyloc));
+ obj->type = NFT_OBJECT_COUNTER;
+ handle_merge(&obj->handle, &(yyvsp[-1].handle));
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &(yyvsp[-1].handle), &(yyloc), obj);
+ }
+#line 8725 "parser_bison.c"
+ break;
+
+ case 121: /* create_cmd: "counter" obj_spec counter_obj counter_config close_scope_counter */
+#line 1326 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8733 "parser_bison.c"
+ break;
+
+ case 122: /* create_cmd: "quota" obj_spec quota_obj quota_config close_scope_quota */
+#line 1330 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8741 "parser_bison.c"
+ break;
+
+ case 123: /* create_cmd: "ct" "helper" obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct */
+#line 1334 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_HELPER, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8749 "parser_bison.c"
+ break;
+
+ case 124: /* create_cmd: "ct" "timeout" obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct */
+#line 1338 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_TIMEOUT, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8757 "parser_bison.c"
+ break;
+
+ case 125: /* create_cmd: "ct" "expectation" obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct */
+#line 1342 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_EXPECT, &(yyvsp[-5].handle), &(yyloc), (yyvsp[-4].obj));
+ }
+#line 8765 "parser_bison.c"
+ break;
+
+ case 126: /* create_cmd: "limit" obj_spec limit_obj limit_config close_scope_limit */
+#line 1346 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8773 "parser_bison.c"
+ break;
+
+ case 127: /* create_cmd: "secmark" obj_spec secmark_obj secmark_config close_scope_secmark */
+#line 1350 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_SECMARK, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8781 "parser_bison.c"
+ break;
+
+ case 128: /* create_cmd: "synproxy" obj_spec synproxy_obj synproxy_config close_scope_synproxy */
+#line 1354 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_CREATE, CMD_OBJ_SYNPROXY, &(yyvsp[-3].handle), &(yyloc), (yyvsp[-2].obj));
+ }
+#line 8789 "parser_bison.c"
+ break;
+
+ case 129: /* insert_cmd: "rule" rule_position rule */
+#line 1360 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_INSERT, CMD_OBJ_RULE, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].rule));
+ }
+#line 8797 "parser_bison.c"
+ break;
+
+ case 138: /* delete_cmd: "table" table_or_id_spec */
+#line 1382 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8805 "parser_bison.c"
+ break;
+
+ case 139: /* delete_cmd: "chain" chain_or_id_spec */
+#line 1386 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8813 "parser_bison.c"
+ break;
+
+ case 140: /* delete_cmd: "chain" chain_spec chain_block_alloc '{' chain_block '}' */
+#line 1391 "parser_bison.y"
+ {
+ (yyvsp[-1].chain)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].chain)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].chain));
+ }
+#line 8823 "parser_bison.c"
+ break;
+
+ case 141: /* delete_cmd: "rule" ruleid_spec */
+#line 1397 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8831 "parser_bison.c"
+ break;
+
+ case 142: /* delete_cmd: "set" set_or_id_spec */
+#line 1401 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8839 "parser_bison.c"
+ break;
+
+ case 143: /* delete_cmd: "map" set_spec */
+#line 1405 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8847 "parser_bison.c"
+ break;
+
+ case 144: /* delete_cmd: "element" set_spec set_block_expr */
+#line 1409 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_ELEMENTS, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].expr));
+ }
+#line 8855 "parser_bison.c"
+ break;
+
+ case 145: /* delete_cmd: "flowtable" flowtable_spec */
+#line 1413 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8863 "parser_bison.c"
+ break;
+
+ case 146: /* delete_cmd: "flowtable" flowtableid_spec */
+#line 1417 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8871 "parser_bison.c"
+ break;
+
+ case 147: /* delete_cmd: "flowtable" flowtable_spec flowtable_block_alloc '{' flowtable_block '}' */
+#line 1422 "parser_bison.y"
+ {
+ (yyvsp[-1].flowtable)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].flowtable)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].flowtable));
+ }
+#line 8881 "parser_bison.c"
+ break;
+
+ case 148: /* delete_cmd: "counter" obj_or_id_spec close_scope_counter */
+#line 1428 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 8889 "parser_bison.c"
+ break;
+
+ case 149: /* delete_cmd: "quota" obj_or_id_spec close_scope_quota */
+#line 1432 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 8897 "parser_bison.c"
+ break;
+
+ case 150: /* delete_cmd: "ct" ct_obj_type obj_spec ct_obj_alloc close_scope_ct */
+#line 1436 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_DELETE, (yyvsp[-3].val), &(yyvsp[-2].handle), &(yyloc), (yyvsp[-1].obj));
+ if ((yyvsp[-3].val) == NFT_OBJECT_CT_TIMEOUT)
+ init_list_head(&(yyvsp[-1].obj)->ct_timeout.timeout_list);
+ }
+#line 8907 "parser_bison.c"
+ break;
+
+ case 151: /* delete_cmd: "limit" obj_or_id_spec close_scope_limit */
+#line 1442 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 8915 "parser_bison.c"
+ break;
+
+ case 152: /* delete_cmd: "secmark" obj_or_id_spec close_scope_secmark */
+#line 1446 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 8923 "parser_bison.c"
+ break;
+
+ case 153: /* delete_cmd: "synproxy" obj_or_id_spec close_scope_synproxy */
+#line 1450 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 8931 "parser_bison.c"
+ break;
+
+ case 154: /* destroy_cmd: "table" table_or_id_spec */
+#line 1456 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_TABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8939 "parser_bison.c"
+ break;
+
+ case 155: /* destroy_cmd: "chain" chain_or_id_spec */
+#line 1460 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_CHAIN, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8947 "parser_bison.c"
+ break;
+
+ case 156: /* destroy_cmd: "rule" ruleid_spec */
+#line 1464 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_RULE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8955 "parser_bison.c"
+ break;
+
+ case 157: /* destroy_cmd: "set" set_or_id_spec */
+#line 1468 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_SET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8963 "parser_bison.c"
+ break;
+
+ case 158: /* destroy_cmd: "map" set_spec */
+#line 1472 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_SET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8971 "parser_bison.c"
+ break;
+
+ case 159: /* destroy_cmd: "element" set_spec set_block_expr */
+#line 1476 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_ELEMENTS, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].expr));
+ }
+#line 8979 "parser_bison.c"
+ break;
+
+ case 160: /* destroy_cmd: "flowtable" flowtable_spec */
+#line 1480 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8987 "parser_bison.c"
+ break;
+
+ case 161: /* destroy_cmd: "flowtable" flowtableid_spec */
+#line 1484 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 8995 "parser_bison.c"
+ break;
+
+ case 162: /* destroy_cmd: "flowtable" flowtable_spec flowtable_block_alloc '{' flowtable_block '}' */
+#line 1489 "parser_bison.y"
+ {
+ (yyvsp[-1].flowtable)->location = (yylsp[-1]);
+ handle_merge(&(yyvsp[-3].flowtable)->handle, &(yyvsp[-4].handle));
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &(yyvsp[-4].handle), &(yyloc), (yyvsp[-1].flowtable));
+ }
+#line 9005 "parser_bison.c"
+ break;
+
+ case 163: /* destroy_cmd: "counter" obj_or_id_spec close_scope_counter */
+#line 1495 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_COUNTER, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9013 "parser_bison.c"
+ break;
+
+ case 164: /* destroy_cmd: "quota" obj_or_id_spec close_scope_quota */
+#line 1499 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_QUOTA, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9021 "parser_bison.c"
+ break;
+
+ case 165: /* destroy_cmd: "ct" ct_obj_type obj_spec ct_obj_alloc close_scope_ct */
+#line 1503 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_DESTROY, (yyvsp[-3].val), &(yyvsp[-2].handle), &(yyloc), (yyvsp[-1].obj));
+ if ((yyvsp[-3].val) == NFT_OBJECT_CT_TIMEOUT)
+ init_list_head(&(yyvsp[-1].obj)->ct_timeout.timeout_list);
+ }
+#line 9031 "parser_bison.c"
+ break;
+
+ case 166: /* destroy_cmd: "limit" obj_or_id_spec close_scope_limit */
+#line 1509 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_LIMIT, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9039 "parser_bison.c"
+ break;
+
+ case 167: /* destroy_cmd: "secmark" obj_or_id_spec close_scope_secmark */
+#line 1513 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_SECMARK, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9047 "parser_bison.c"
+ break;
+
+ case 168: /* destroy_cmd: "synproxy" obj_or_id_spec close_scope_synproxy */
+#line 1517 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_DESTROY, CMD_OBJ_SYNPROXY, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9055 "parser_bison.c"
+ break;
+
+ case 169: /* get_cmd: "element" set_spec set_block_expr */
+#line 1524 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_GET, CMD_OBJ_ELEMENTS, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].expr));
+ }
+#line 9063 "parser_bison.c"
+ break;
+
+ case 170: /* list_cmd: "table" table_spec */
+#line 1530 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9071 "parser_bison.c"
+ break;
+
+ case 171: /* list_cmd: "tables" ruleset_spec */
+#line 1534 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9079 "parser_bison.c"
+ break;
+
+ case 172: /* list_cmd: "chain" chain_spec */
+#line 1538 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_CHAIN, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9087 "parser_bison.c"
+ break;
+
+ case 173: /* list_cmd: "chains" ruleset_spec */
+#line 1542 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_CHAINS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9095 "parser_bison.c"
+ break;
+
+ case 174: /* list_cmd: "sets" ruleset_spec */
+#line 1546 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9103 "parser_bison.c"
+ break;
+
+ case 175: /* list_cmd: "sets" "table" table_spec */
+#line 1550 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9111 "parser_bison.c"
+ break;
+
+ case 176: /* list_cmd: "set" set_spec */
+#line 1554 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9119 "parser_bison.c"
+ break;
+
+ case 177: /* list_cmd: "counters" ruleset_spec */
+#line 1558 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9127 "parser_bison.c"
+ break;
+
+ case 178: /* list_cmd: "counters" "table" table_spec */
+#line 1562 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9135 "parser_bison.c"
+ break;
+
+ case 179: /* list_cmd: "counter" obj_spec close_scope_counter */
+#line 1566 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTER, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9143 "parser_bison.c"
+ break;
+
+ case 180: /* list_cmd: "quotas" ruleset_spec */
+#line 1570 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9151 "parser_bison.c"
+ break;
+
+ case 181: /* list_cmd: "quotas" "table" table_spec */
+#line 1574 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9159 "parser_bison.c"
+ break;
+
+ case 182: /* list_cmd: "quota" obj_spec close_scope_quota */
+#line 1578 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTA, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9167 "parser_bison.c"
+ break;
+
+ case 183: /* list_cmd: "limits" ruleset_spec */
+#line 1582 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9175 "parser_bison.c"
+ break;
+
+ case 184: /* list_cmd: "limits" "table" table_spec */
+#line 1586 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9183 "parser_bison.c"
+ break;
+
+ case 185: /* list_cmd: "limit" obj_spec close_scope_limit */
+#line 1590 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_LIMIT, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9191 "parser_bison.c"
+ break;
+
+ case 186: /* list_cmd: "secmarks" ruleset_spec */
+#line 1594 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9199 "parser_bison.c"
+ break;
+
+ case 187: /* list_cmd: "secmarks" "table" table_spec */
+#line 1598 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9207 "parser_bison.c"
+ break;
+
+ case 188: /* list_cmd: "secmark" obj_spec close_scope_secmark */
+#line 1602 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARK, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9215 "parser_bison.c"
+ break;
+
+ case 189: /* list_cmd: "synproxys" ruleset_spec */
+#line 1606 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9223 "parser_bison.c"
+ break;
+
+ case 190: /* list_cmd: "synproxys" "table" table_spec */
+#line 1610 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9231 "parser_bison.c"
+ break;
+
+ case 191: /* list_cmd: "synproxy" obj_spec close_scope_synproxy */
+#line 1614 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXY, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9239 "parser_bison.c"
+ break;
+
+ case 192: /* list_cmd: "ruleset" ruleset_spec */
+#line 1618 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_RULESET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9247 "parser_bison.c"
+ break;
+
+ case 193: /* list_cmd: "flow" "tables" ruleset_spec */
+#line 1622 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_METERS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9255 "parser_bison.c"
+ break;
+
+ case 194: /* list_cmd: "flow" "table" set_spec */
+#line 1626 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9263 "parser_bison.c"
+ break;
+
+ case 195: /* list_cmd: "meters" ruleset_spec */
+#line 1630 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_METERS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9271 "parser_bison.c"
+ break;
+
+ case 196: /* list_cmd: "meter" set_spec */
+#line 1634 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9279 "parser_bison.c"
+ break;
+
+ case 197: /* list_cmd: "flowtables" ruleset_spec */
+#line 1638 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLES, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9287 "parser_bison.c"
+ break;
+
+ case 198: /* list_cmd: "flowtable" flowtable_spec */
+#line 1642 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9295 "parser_bison.c"
+ break;
+
+ case 199: /* list_cmd: "maps" ruleset_spec */
+#line 1646 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_MAPS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9303 "parser_bison.c"
+ break;
+
+ case 200: /* list_cmd: "map" set_spec */
+#line 1650 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_MAP, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9311 "parser_bison.c"
+ break;
+
+ case 201: /* list_cmd: "ct" ct_obj_type obj_spec close_scope_ct */
+#line 1654 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc_obj_ct(CMD_LIST, (yyvsp[-2].val), &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9319 "parser_bison.c"
+ break;
+
+ case 202: /* list_cmd: "ct" ct_cmd_type "table" table_spec close_scope_ct */
+#line 1658 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, (yyvsp[-3].val), &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9327 "parser_bison.c"
+ break;
+
+ case 203: /* list_cmd: "hooks" basehook_spec */
+#line 1662 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_LIST, CMD_OBJ_HOOKS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9335 "parser_bison.c"
+ break;
+
+ case 204: /* basehook_device_name: "device" "string" */
+#line 1668 "parser_bison.y"
+ {
+ (yyval.string) = (yyvsp[0].string);
+ }
+#line 9343 "parser_bison.c"
+ break;
+
+ case 205: /* basehook_spec: ruleset_spec */
+#line 1674 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[0].handle);
+ }
+#line 9351 "parser_bison.c"
+ break;
+
+ case 206: /* basehook_spec: ruleset_spec basehook_device_name */
+#line 1678 "parser_bison.y"
+ {
+ if ((yyvsp[0].string)) {
+ (yyvsp[-1].handle).obj.name = (yyvsp[0].string);
+ (yyvsp[-1].handle).obj.location = (yylsp[0]);
+ }
+ (yyval.handle) = (yyvsp[-1].handle);
+ }
+#line 9363 "parser_bison.c"
+ break;
+
+ case 207: /* reset_cmd: "counters" ruleset_spec */
+#line 1688 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9371 "parser_bison.c"
+ break;
+
+ case 208: /* reset_cmd: "counters" table_spec */
+#line 1692 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9379 "parser_bison.c"
+ break;
+
+ case 209: /* reset_cmd: "counters" "table" table_spec */
+#line 1696 "parser_bison.y"
+ {
+ /* alias of previous rule. */
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9388 "parser_bison.c"
+ break;
+
+ case 210: /* reset_cmd: "counter" obj_spec close_scope_counter */
+#line 1701 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTER, &(yyvsp[-1].handle),&(yyloc), NULL);
+ }
+#line 9396 "parser_bison.c"
+ break;
+
+ case 211: /* reset_cmd: "quotas" ruleset_spec */
+#line 1705 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9404 "parser_bison.c"
+ break;
+
+ case 212: /* reset_cmd: "quotas" "table" table_spec */
+#line 1709 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9412 "parser_bison.c"
+ break;
+
+ case 213: /* reset_cmd: "quotas" table_spec */
+#line 1713 "parser_bison.y"
+ {
+ /* alias of previous rule. */
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9421 "parser_bison.c"
+ break;
+
+ case 214: /* reset_cmd: "quota" obj_spec close_scope_quota */
+#line 1718 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTA, &(yyvsp[-1].handle), &(yyloc), NULL);
+ }
+#line 9429 "parser_bison.c"
+ break;
+
+ case 215: /* reset_cmd: "rules" ruleset_spec */
+#line 1722 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9437 "parser_bison.c"
+ break;
+
+ case 216: /* reset_cmd: "rules" table_spec */
+#line 1726 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9445 "parser_bison.c"
+ break;
+
+ case 217: /* reset_cmd: "rules" "table" table_spec */
+#line 1730 "parser_bison.y"
+ {
+ /* alias of previous rule. */
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9454 "parser_bison.c"
+ break;
+
+ case 218: /* reset_cmd: "rules" chain_spec */
+#line 1735 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9462 "parser_bison.c"
+ break;
+
+ case 219: /* reset_cmd: "rules" "chain" chain_spec */
+#line 1739 "parser_bison.y"
+ {
+ /* alias of previous rule. */
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9471 "parser_bison.c"
+ break;
+
+ case 220: /* reset_cmd: "rule" ruleid_spec */
+#line 1744 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_RULE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9479 "parser_bison.c"
+ break;
+
+ case 221: /* reset_cmd: "element" set_spec set_block_expr */
+#line 1748 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_ELEMENTS, &(yyvsp[-1].handle), &(yyloc), (yyvsp[0].expr));
+ }
+#line 9487 "parser_bison.c"
+ break;
+
+ case 222: /* reset_cmd: "set" set_or_id_spec */
+#line 1752 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_SET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9495 "parser_bison.c"
+ break;
+
+ case 223: /* reset_cmd: "map" set_or_id_spec */
+#line 1756 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RESET, CMD_OBJ_MAP, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9503 "parser_bison.c"
+ break;
+
+ case 224: /* flush_cmd: "table" table_spec */
+#line 1762 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_FLUSH, CMD_OBJ_TABLE, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9511 "parser_bison.c"
+ break;
+
+ case 225: /* flush_cmd: "chain" chain_spec */
+#line 1766 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_FLUSH, CMD_OBJ_CHAIN, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9519 "parser_bison.c"
+ break;
+
+ case 226: /* flush_cmd: "set" set_spec */
+#line 1770 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_FLUSH, CMD_OBJ_SET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9527 "parser_bison.c"
+ break;
+
+ case 227: /* flush_cmd: "map" set_spec */
+#line 1774 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_FLUSH, CMD_OBJ_MAP, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9535 "parser_bison.c"
+ break;
+
+ case 228: /* flush_cmd: "flow" "table" set_spec */
+#line 1778 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_FLUSH, CMD_OBJ_METER, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9543 "parser_bison.c"
+ break;
+
+ case 229: /* flush_cmd: "meter" set_spec */
+#line 1782 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_FLUSH, CMD_OBJ_METER, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9551 "parser_bison.c"
+ break;
+
+ case 230: /* flush_cmd: "ruleset" ruleset_spec */
+#line 1786 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_FLUSH, CMD_OBJ_RULESET, &(yyvsp[0].handle), &(yyloc), NULL);
+ }
+#line 9559 "parser_bison.c"
+ break;
+
+ case 231: /* rename_cmd: "chain" chain_spec identifier */
+#line 1792 "parser_bison.y"
+ {
+ (yyval.cmd) = cmd_alloc(CMD_RENAME, CMD_OBJ_CHAIN, &(yyvsp[-1].handle), &(yyloc), NULL);
+ (yyval.cmd)->arg = (yyvsp[0].string);
+ }
+#line 9568 "parser_bison.c"
+ break;
+
+ case 232: /* import_cmd: "ruleset" markup_format */
+#line 1799 "parser_bison.y"
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc((yyvsp[0].val));
+ (yyval.cmd) = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &(yyloc), markup);
+ }
+#line 9578 "parser_bison.c"
+ break;
+
+ case 233: /* import_cmd: markup_format */
+#line 1805 "parser_bison.y"
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc((yyvsp[0].val));
+ (yyval.cmd) = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &(yyloc), markup);
+ }
+#line 9588 "parser_bison.c"
+ break;
+
+ case 234: /* export_cmd: "ruleset" markup_format */
+#line 1813 "parser_bison.y"
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc((yyvsp[0].val));
+ (yyval.cmd) = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &(yyloc), markup);
+ }
+#line 9598 "parser_bison.c"
+ break;
+
+ case 235: /* export_cmd: markup_format */
+#line 1819 "parser_bison.y"
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc((yyvsp[0].val));
+ (yyval.cmd) = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &(yyloc), markup);
+ }
+#line 9608 "parser_bison.c"
+ break;
+
+ case 236: /* monitor_cmd: monitor_event monitor_object monitor_format */
+#line 1827 "parser_bison.y"
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct monitor *m = monitor_alloc((yyvsp[0].val), (yyvsp[-1].val), (yyvsp[-2].string));
+ m->location = (yylsp[-2]);
+ (yyval.cmd) = cmd_alloc(CMD_MONITOR, CMD_OBJ_MONITOR, &h, &(yyloc), m);
+ }
+#line 9619 "parser_bison.c"
+ break;
+
+ case 237: /* monitor_event: %empty */
+#line 1835 "parser_bison.y"
+ { (yyval.string) = NULL; }
+#line 9625 "parser_bison.c"
+ break;
+
+ case 238: /* monitor_event: "string" */
+#line 1836 "parser_bison.y"
+ { (yyval.string) = (yyvsp[0].string); }
+#line 9631 "parser_bison.c"
+ break;
+
+ case 239: /* monitor_object: %empty */
+#line 1839 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_ANY; }
+#line 9637 "parser_bison.c"
+ break;
+
+ case 240: /* monitor_object: "tables" */
+#line 1840 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_TABLES; }
+#line 9643 "parser_bison.c"
+ break;
+
+ case 241: /* monitor_object: "chains" */
+#line 1841 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_CHAINS; }
+#line 9649 "parser_bison.c"
+ break;
+
+ case 242: /* monitor_object: "sets" */
+#line 1842 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_SETS; }
+#line 9655 "parser_bison.c"
+ break;
+
+ case 243: /* monitor_object: "rules" */
+#line 1843 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_RULES; }
+#line 9661 "parser_bison.c"
+ break;
+
+ case 244: /* monitor_object: "elements" */
+#line 1844 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_ELEMS; }
+#line 9667 "parser_bison.c"
+ break;
+
+ case 245: /* monitor_object: "ruleset" */
+#line 1845 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_RULESET; }
+#line 9673 "parser_bison.c"
+ break;
+
+ case 246: /* monitor_object: "trace" */
+#line 1846 "parser_bison.y"
+ { (yyval.val) = CMD_MONITOR_OBJ_TRACE; }
+#line 9679 "parser_bison.c"
+ break;
+
+ case 247: /* monitor_format: %empty */
+#line 1849 "parser_bison.y"
+ { (yyval.val) = NFTNL_OUTPUT_DEFAULT; }
+#line 9685 "parser_bison.c"
+ break;
+
+ case 249: /* markup_format: "xml" */
+#line 1853 "parser_bison.y"
+ { (yyval.val) = __NFT_OUTPUT_NOTSUPP; }
+#line 9691 "parser_bison.c"
+ break;
+
+ case 250: /* markup_format: "json" */
+#line 1854 "parser_bison.y"
+ { (yyval.val) = NFTNL_OUTPUT_JSON; }
+#line 9697 "parser_bison.c"
+ break;
+
+ case 251: /* markup_format: "vm" "json" */
+#line 1855 "parser_bison.y"
+ { (yyval.val) = NFTNL_OUTPUT_JSON; }
+#line 9703 "parser_bison.c"
+ break;
+
+ case 252: /* describe_cmd: primary_expr */
+#line 1859 "parser_bison.y"
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ (yyval.cmd) = cmd_alloc(CMD_DESCRIBE, CMD_OBJ_EXPR, &h, &(yyloc), NULL);
+ (yyval.cmd)->expr = (yyvsp[0].expr);
+ }
+#line 9713 "parser_bison.c"
+ break;
+
+ case 253: /* table_block_alloc: %empty */
+#line 1867 "parser_bison.y"
+ {
+ (yyval.table) = table_alloc();
+ if (open_scope(state, &(yyval.table)->scope) < 0) {
+ erec_queue(error(&(yyloc), "too many levels of nesting"),
+ state->msgs);
+ state->nerrs++;
+ }
+ }
+#line 9726 "parser_bison.c"
+ break;
+
+ case 254: /* table_options: "flags" "string" */
+#line 1878 "parser_bison.y"
+ {
+ if (strcmp((yyvsp[0].string), "dormant") == 0) {
+ (yyvsp[-2].table)->flags |= TABLE_F_DORMANT;
+ xfree((yyvsp[0].string));
+ } else if (strcmp((yyvsp[0].string), "owner") == 0) {
+ (yyvsp[-2].table)->flags |= TABLE_F_OWNER;
+ xfree((yyvsp[0].string));
+ } else {
+ erec_queue(error(&(yylsp[0]), "unknown table option %s", (yyvsp[0].string)),
+ state->msgs);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ }
+#line 9745 "parser_bison.c"
+ break;
+
+ case 255: /* table_options: comment_spec */
+#line 1893 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].table)->comment, &(yyloc), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].table)->comment = (yyvsp[0].string);
+ }
+#line 9757 "parser_bison.c"
+ break;
+
+ case 256: /* table_block: %empty */
+#line 1902 "parser_bison.y"
+ { (yyval.table) = (yyvsp[(-1) - (0)].table); }
+#line 9763 "parser_bison.c"
+ break;
+
+ case 260: /* table_block: table_block "chain" chain_identifier chain_block_alloc '{' chain_block '}' stmt_separator */
+#line 1909 "parser_bison.y"
+ {
+ (yyvsp[-4].chain)->location = (yylsp[-5]);
+ handle_merge(&(yyvsp[-4].chain)->handle, &(yyvsp[-5].handle));
+ handle_free(&(yyvsp[-5].handle));
+ close_scope(state);
+ list_add_tail(&(yyvsp[-4].chain)->list, &(yyvsp[-7].table)->chains);
+ (yyval.table) = (yyvsp[-7].table);
+ }
+#line 9776 "parser_bison.c"
+ break;
+
+ case 261: /* table_block: table_block "set" set_identifier set_block_alloc '{' set_block '}' stmt_separator */
+#line 1920 "parser_bison.y"
+ {
+ (yyvsp[-4].set)->location = (yylsp[-5]);
+ handle_merge(&(yyvsp[-4].set)->handle, &(yyvsp[-5].handle));
+ handle_free(&(yyvsp[-5].handle));
+ list_add_tail(&(yyvsp[-4].set)->list, &(yyvsp[-7].table)->sets);
+ (yyval.table) = (yyvsp[-7].table);
+ }
+#line 9788 "parser_bison.c"
+ break;
+
+ case 262: /* table_block: table_block "map" set_identifier map_block_alloc '{' map_block '}' stmt_separator */
+#line 1930 "parser_bison.y"
+ {
+ (yyvsp[-4].set)->location = (yylsp[-5]);
+ handle_merge(&(yyvsp[-4].set)->handle, &(yyvsp[-5].handle));
+ handle_free(&(yyvsp[-5].handle));
+ list_add_tail(&(yyvsp[-4].set)->list, &(yyvsp[-7].table)->sets);
+ (yyval.table) = (yyvsp[-7].table);
+ }
+#line 9800 "parser_bison.c"
+ break;
+
+ case 263: /* table_block: table_block "flowtable" flowtable_identifier flowtable_block_alloc '{' flowtable_block '}' stmt_separator */
+#line 1941 "parser_bison.y"
+ {
+ (yyvsp[-4].flowtable)->location = (yylsp[-5]);
+ handle_merge(&(yyvsp[-4].flowtable)->handle, &(yyvsp[-5].handle));
+ handle_free(&(yyvsp[-5].handle));
+ list_add_tail(&(yyvsp[-4].flowtable)->list, &(yyvsp[-7].table)->flowtables);
+ (yyval.table) = (yyvsp[-7].table);
+ }
+#line 9812 "parser_bison.c"
+ break;
+
+ case 264: /* table_block: table_block "counter" obj_identifier obj_block_alloc '{' counter_block '}' stmt_separator close_scope_counter */
+#line 1951 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_COUNTER;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-8].table)->objs);
+ (yyval.table) = (yyvsp[-8].table);
+ }
+#line 9825 "parser_bison.c"
+ break;
+
+ case 265: /* table_block: table_block "quota" obj_identifier obj_block_alloc '{' quota_block '}' stmt_separator close_scope_quota */
+#line 1962 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_QUOTA;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-8].table)->objs);
+ (yyval.table) = (yyvsp[-8].table);
+ }
+#line 9838 "parser_bison.c"
+ break;
+
+ case 266: /* table_block: table_block "ct" "helper" obj_identifier obj_block_alloc '{' ct_helper_block '}' close_scope_ct stmt_separator */
+#line 1971 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_CT_HELPER;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-9].table)->objs);
+ (yyval.table) = (yyvsp[-9].table);
+ }
+#line 9851 "parser_bison.c"
+ break;
+
+ case 267: /* table_block: table_block "ct" "timeout" obj_identifier obj_block_alloc '{' ct_timeout_block '}' close_scope_ct stmt_separator */
+#line 1980 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_CT_TIMEOUT;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-9].table)->objs);
+ (yyval.table) = (yyvsp[-9].table);
+ }
+#line 9864 "parser_bison.c"
+ break;
+
+ case 268: /* table_block: table_block "ct" "expectation" obj_identifier obj_block_alloc '{' ct_expect_block '}' close_scope_ct stmt_separator */
+#line 1989 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_CT_EXPECT;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-9].table)->objs);
+ (yyval.table) = (yyvsp[-9].table);
+ }
+#line 9877 "parser_bison.c"
+ break;
+
+ case 269: /* table_block: table_block "limit" obj_identifier obj_block_alloc '{' limit_block '}' stmt_separator close_scope_limit */
+#line 2000 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_LIMIT;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-8].table)->objs);
+ (yyval.table) = (yyvsp[-8].table);
+ }
+#line 9890 "parser_bison.c"
+ break;
+
+ case 270: /* table_block: table_block "secmark" obj_identifier obj_block_alloc '{' secmark_block '}' stmt_separator close_scope_secmark */
+#line 2011 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_SECMARK;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-8].table)->objs);
+ (yyval.table) = (yyvsp[-8].table);
+ }
+#line 9903 "parser_bison.c"
+ break;
+
+ case 271: /* table_block: table_block "synproxy" obj_identifier obj_block_alloc '{' synproxy_block '}' stmt_separator close_scope_synproxy */
+#line 2022 "parser_bison.y"
+ {
+ (yyvsp[-5].obj)->location = (yylsp[-6]);
+ (yyvsp[-5].obj)->type = NFT_OBJECT_SYNPROXY;
+ handle_merge(&(yyvsp[-5].obj)->handle, &(yyvsp[-6].handle));
+ handle_free(&(yyvsp[-6].handle));
+ list_add_tail(&(yyvsp[-5].obj)->list, &(yyvsp[-8].table)->objs);
+ (yyval.table) = (yyvsp[-8].table);
+ }
+#line 9916 "parser_bison.c"
+ break;
+
+ case 272: /* chain_block_alloc: %empty */
+#line 2033 "parser_bison.y"
+ {
+ (yyval.chain) = chain_alloc();
+ if (open_scope(state, &(yyval.chain)->scope) < 0) {
+ erec_queue(error(&(yyloc), "too many levels of nesting"),
+ state->msgs);
+ state->nerrs++;
+ }
+ }
+#line 9929 "parser_bison.c"
+ break;
+
+ case 273: /* chain_block: %empty */
+#line 2043 "parser_bison.y"
+ { (yyval.chain) = (yyvsp[(-1) - (0)].chain); }
+#line 9935 "parser_bison.c"
+ break;
+
+ case 279: /* chain_block: chain_block rule stmt_separator */
+#line 2050 "parser_bison.y"
+ {
+ list_add_tail(&(yyvsp[-1].rule)->list, &(yyvsp[-2].chain)->rules);
+ (yyval.chain) = (yyvsp[-2].chain);
+ }
+#line 9944 "parser_bison.c"
+ break;
+
+ case 280: /* chain_block: chain_block "devices" '=' flowtable_expr stmt_separator */
+#line 2055 "parser_bison.y"
+ {
+ if ((yyval.chain)->dev_expr) {
+ list_splice_init(&(yyvsp[-1].expr)->expressions, &(yyval.chain)->dev_expr->expressions);
+ expr_free((yyvsp[-1].expr));
+ break;
+ }
+ (yyval.chain)->dev_expr = (yyvsp[-1].expr);
+ }
+#line 9957 "parser_bison.c"
+ break;
+
+ case 281: /* chain_block: chain_block comment_spec stmt_separator */
+#line 2064 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-2].chain)->comment, &(yylsp[-1]), state)) {
+ xfree((yyvsp[-1].string));
+ YYERROR;
+ }
+ (yyvsp[-2].chain)->comment = (yyvsp[-1].string);
+ }
+#line 9969 "parser_bison.c"
+ break;
+
+ case 282: /* subchain_block: %empty */
+#line 2073 "parser_bison.y"
+ { (yyval.chain) = (yyvsp[(-1) - (0)].chain); }
+#line 9975 "parser_bison.c"
+ break;
+
+ case 284: /* subchain_block: subchain_block rule stmt_separator */
+#line 2076 "parser_bison.y"
+ {
+ list_add_tail(&(yyvsp[-1].rule)->list, &(yyvsp[-2].chain)->rules);
+ (yyval.chain) = (yyvsp[-2].chain);
+ }
+#line 9984 "parser_bison.c"
+ break;
+
+ case 285: /* typeof_data_expr: primary_expr */
+#line 2083 "parser_bison.y"
+ {
+ struct expr *e = (yyvsp[0].expr);
+
+ if (e->etype == EXPR_SYMBOL &&
+ strcmp("verdict", e->identifier) == 0) {
+ struct expr *v = verdict_expr_alloc(&(yylsp[0]), NF_ACCEPT, NULL);
+
+ expr_free(e);
+ v->flags &= ~EXPR_F_CONSTANT;
+ e = v;
+ }
+
+ if (expr_ops(e)->build_udata == NULL) {
+ erec_queue(error(&(yylsp[0]), "map data type '%s' lacks typeof serialization", expr_ops(e)->name),
+ state->msgs);
+ expr_free(e);
+ YYERROR;
+ }
+ (yyval.expr) = e;
+ }
+#line 10009 "parser_bison.c"
+ break;
+
+ case 286: /* typeof_data_expr: typeof_expr "." primary_expr */
+#line 2104 "parser_bison.y"
+ {
+ struct location rhs[] = {
+ [1] = (yylsp[-1]),
+ [2] = (yylsp[0]),
+ };
+
+ (yyval.expr) = handle_concat_expr(&(yyloc), (yyval.expr), (yyvsp[-2].expr), (yyvsp[0].expr), rhs);
+ }
+#line 10022 "parser_bison.c"
+ break;
+
+ case 287: /* typeof_expr: primary_expr */
+#line 2115 "parser_bison.y"
+ {
+ if (expr_ops((yyvsp[0].expr))->build_udata == NULL) {
+ erec_queue(error(&(yylsp[0]), "primary expression type '%s' lacks typeof serialization", expr_ops((yyvsp[0].expr))->name),
+ state->msgs);
+ expr_free((yyvsp[0].expr));
+ YYERROR;
+ }
+
+ (yyval.expr) = (yyvsp[0].expr);
+ }
+#line 10037 "parser_bison.c"
+ break;
+
+ case 288: /* typeof_expr: typeof_expr "." primary_expr */
+#line 2126 "parser_bison.y"
+ {
+ struct location rhs[] = {
+ [1] = (yylsp[-1]),
+ [2] = (yylsp[0]),
+ };
+
+ (yyval.expr) = handle_concat_expr(&(yyloc), (yyval.expr), (yyvsp[-2].expr), (yyvsp[0].expr), rhs);
+ }
+#line 10050 "parser_bison.c"
+ break;
+
+ case 289: /* set_block_alloc: %empty */
+#line 2138 "parser_bison.y"
+ {
+ (yyval.set) = set_alloc(&internal_location);
+ }
+#line 10058 "parser_bison.c"
+ break;
+
+ case 290: /* set_block: %empty */
+#line 2143 "parser_bison.y"
+ { (yyval.set) = (yyvsp[(-1) - (0)].set); }
+#line 10064 "parser_bison.c"
+ break;
+
+ case 293: /* set_block: set_block "type" data_type_expr stmt_separator close_scope_type */
+#line 2147 "parser_bison.y"
+ {
+ (yyvsp[-4].set)->key = (yyvsp[-2].expr);
+ (yyval.set) = (yyvsp[-4].set);
+ }
+#line 10073 "parser_bison.c"
+ break;
+
+ case 294: /* set_block: set_block "typeof" typeof_expr stmt_separator */
+#line 2152 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->key = (yyvsp[-1].expr);
+ datatype_set((yyvsp[-3].set)->key, (yyvsp[-1].expr)->dtype);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10083 "parser_bison.c"
+ break;
+
+ case 295: /* set_block: set_block "flags" set_flag_list stmt_separator */
+#line 2158 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->flags = (yyvsp[-1].val);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10092 "parser_bison.c"
+ break;
+
+ case 296: /* set_block: set_block "timeout" time_spec stmt_separator */
+#line 2163 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->timeout = (yyvsp[-1].val);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10101 "parser_bison.c"
+ break;
+
+ case 297: /* set_block: set_block "gc-interval" time_spec stmt_separator */
+#line 2168 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->gc_int = (yyvsp[-1].val);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10110 "parser_bison.c"
+ break;
+
+ case 298: /* set_block: set_block stateful_stmt_list stmt_separator */
+#line 2173 "parser_bison.y"
+ {
+ list_splice_tail((yyvsp[-1].list), &(yyvsp[-2].set)->stmt_list);
+ (yyval.set) = (yyvsp[-2].set);
+ free((yyvsp[-1].list));
+ }
+#line 10120 "parser_bison.c"
+ break;
+
+ case 299: /* set_block: set_block "elements" '=' set_block_expr */
+#line 2179 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->init = (yyvsp[0].expr);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10129 "parser_bison.c"
+ break;
+
+ case 300: /* set_block: set_block "auto-merge" */
+#line 2184 "parser_bison.y"
+ {
+ (yyvsp[-1].set)->automerge = true;
+ (yyval.set) = (yyvsp[-1].set);
+ }
+#line 10138 "parser_bison.c"
+ break;
+
+ case 302: /* set_block: set_block comment_spec stmt_separator */
+#line 2190 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-2].set)->comment, &(yylsp[-1]), state)) {
+ xfree((yyvsp[-1].string));
+ YYERROR;
+ }
+ (yyvsp[-2].set)->comment = (yyvsp[-1].string);
+ (yyval.set) = (yyvsp[-2].set);
+ }
+#line 10151 "parser_bison.c"
+ break;
+
+ case 305: /* set_flag_list: set_flag_list "comma" set_flag */
+#line 2205 "parser_bison.y"
+ {
+ (yyval.val) = (yyvsp[-2].val) | (yyvsp[0].val);
+ }
+#line 10159 "parser_bison.c"
+ break;
+
+ case 307: /* set_flag: "constant" */
+#line 2211 "parser_bison.y"
+ { (yyval.val) = NFT_SET_CONSTANT; }
+#line 10165 "parser_bison.c"
+ break;
+
+ case 308: /* set_flag: "interval" */
+#line 2212 "parser_bison.y"
+ { (yyval.val) = NFT_SET_INTERVAL; }
+#line 10171 "parser_bison.c"
+ break;
+
+ case 309: /* set_flag: "timeout" */
+#line 2213 "parser_bison.y"
+ { (yyval.val) = NFT_SET_TIMEOUT; }
+#line 10177 "parser_bison.c"
+ break;
+
+ case 310: /* set_flag: "dynamic" */
+#line 2214 "parser_bison.y"
+ { (yyval.val) = NFT_SET_EVAL; }
+#line 10183 "parser_bison.c"
+ break;
+
+ case 311: /* map_block_alloc: %empty */
+#line 2218 "parser_bison.y"
+ {
+ (yyval.set) = set_alloc(&internal_location);
+ }
+#line 10191 "parser_bison.c"
+ break;
+
+ case 312: /* map_block_obj_type: "counter" close_scope_counter */
+#line 2223 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_COUNTER; }
+#line 10197 "parser_bison.c"
+ break;
+
+ case 313: /* map_block_obj_type: "quota" close_scope_quota */
+#line 2224 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_QUOTA; }
+#line 10203 "parser_bison.c"
+ break;
+
+ case 314: /* map_block_obj_type: "limit" close_scope_limit */
+#line 2225 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_LIMIT; }
+#line 10209 "parser_bison.c"
+ break;
+
+ case 315: /* map_block_obj_type: "secmark" close_scope_secmark */
+#line 2226 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_SECMARK; }
+#line 10215 "parser_bison.c"
+ break;
+
+ case 316: /* map_block_obj_type: "synproxy" close_scope_synproxy */
+#line 2227 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_SYNPROXY; }
+#line 10221 "parser_bison.c"
+ break;
+
+ case 317: /* map_block_data_interval: "interval" */
+#line 2230 "parser_bison.y"
+ { (yyval.val) = EXPR_F_INTERVAL; }
+#line 10227 "parser_bison.c"
+ break;
+
+ case 318: /* map_block_data_interval: %empty */
+#line 2231 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 10233 "parser_bison.c"
+ break;
+
+ case 319: /* map_block: %empty */
+#line 2234 "parser_bison.y"
+ { (yyval.set) = (yyvsp[(-1) - (0)].set); }
+#line 10239 "parser_bison.c"
+ break;
+
+ case 322: /* map_block: map_block "timeout" time_spec stmt_separator */
+#line 2238 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->timeout = (yyvsp[-1].val);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10248 "parser_bison.c"
+ break;
+
+ case 323: /* map_block: map_block "gc-interval" time_spec stmt_separator */
+#line 2243 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->gc_int = (yyvsp[-1].val);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10257 "parser_bison.c"
+ break;
+
+ case 324: /* map_block: map_block "type" data_type_expr "colon" map_block_data_interval data_type_expr stmt_separator close_scope_type */
+#line 2250 "parser_bison.y"
+ {
+ (yyvsp[-7].set)->key = (yyvsp[-5].expr);
+ (yyvsp[-7].set)->data = (yyvsp[-2].expr);
+ (yyvsp[-7].set)->data->flags |= (yyvsp[-3].val);
+
+ (yyvsp[-7].set)->flags |= NFT_SET_MAP;
+ (yyval.set) = (yyvsp[-7].set);
+ }
+#line 10270 "parser_bison.c"
+ break;
+
+ case 325: /* map_block: map_block "typeof" typeof_expr "colon" typeof_data_expr stmt_separator */
+#line 2261 "parser_bison.y"
+ {
+ (yyvsp[-5].set)->key = (yyvsp[-3].expr);
+ datatype_set((yyvsp[-5].set)->key, (yyvsp[-3].expr)->dtype);
+ (yyvsp[-5].set)->data = (yyvsp[-1].expr);
+
+ (yyvsp[-5].set)->flags |= NFT_SET_MAP;
+ (yyval.set) = (yyvsp[-5].set);
+ }
+#line 10283 "parser_bison.c"
+ break;
+
+ case 326: /* map_block: map_block "typeof" typeof_expr "colon" "interval" typeof_expr stmt_separator */
+#line 2272 "parser_bison.y"
+ {
+ (yyvsp[-6].set)->key = (yyvsp[-4].expr);
+ datatype_set((yyvsp[-6].set)->key, (yyvsp[-4].expr)->dtype);
+ (yyvsp[-6].set)->data = (yyvsp[-1].expr);
+ (yyvsp[-6].set)->data->flags |= EXPR_F_INTERVAL;
+
+ (yyvsp[-6].set)->flags |= NFT_SET_MAP;
+ (yyval.set) = (yyvsp[-6].set);
+ }
+#line 10297 "parser_bison.c"
+ break;
+
+ case 327: /* map_block: map_block "type" data_type_expr "colon" map_block_obj_type stmt_separator close_scope_type */
+#line 2284 "parser_bison.y"
+ {
+ (yyvsp[-6].set)->key = (yyvsp[-4].expr);
+ (yyvsp[-6].set)->objtype = (yyvsp[-2].val);
+ (yyvsp[-6].set)->flags |= NFT_SET_OBJECT;
+ (yyval.set) = (yyvsp[-6].set);
+ }
+#line 10308 "parser_bison.c"
+ break;
+
+ case 328: /* map_block: map_block "flags" set_flag_list stmt_separator */
+#line 2291 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->flags |= (yyvsp[-1].val);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10317 "parser_bison.c"
+ break;
+
+ case 329: /* map_block: map_block stateful_stmt_list stmt_separator */
+#line 2296 "parser_bison.y"
+ {
+ list_splice_tail((yyvsp[-1].list), &(yyvsp[-2].set)->stmt_list);
+ (yyval.set) = (yyvsp[-2].set);
+ free((yyvsp[-1].list));
+ }
+#line 10327 "parser_bison.c"
+ break;
+
+ case 330: /* map_block: map_block "elements" '=' set_block_expr */
+#line 2302 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->init = (yyvsp[0].expr);
+ (yyval.set) = (yyvsp[-3].set);
+ }
+#line 10336 "parser_bison.c"
+ break;
+
+ case 331: /* map_block: map_block comment_spec stmt_separator */
+#line 2307 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-2].set)->comment, &(yylsp[-1]), state)) {
+ xfree((yyvsp[-1].string));
+ YYERROR;
+ }
+ (yyvsp[-2].set)->comment = (yyvsp[-1].string);
+ (yyval.set) = (yyvsp[-2].set);
+ }
+#line 10349 "parser_bison.c"
+ break;
+
+ case 333: /* set_mechanism: "policy" set_policy_spec close_scope_policy */
+#line 2319 "parser_bison.y"
+ {
+ (yyvsp[-3].set)->policy = (yyvsp[-1].val);
+ }
+#line 10357 "parser_bison.c"
+ break;
+
+ case 334: /* set_mechanism: "size" "number" */
+#line 2323 "parser_bison.y"
+ {
+ (yyvsp[-2].set)->desc.size = (yyvsp[0].val);
+ }
+#line 10365 "parser_bison.c"
+ break;
+
+ case 335: /* set_policy_spec: "performance" */
+#line 2328 "parser_bison.y"
+ { (yyval.val) = NFT_SET_POL_PERFORMANCE; }
+#line 10371 "parser_bison.c"
+ break;
+
+ case 336: /* set_policy_spec: "memory" */
+#line 2329 "parser_bison.y"
+ { (yyval.val) = NFT_SET_POL_MEMORY; }
+#line 10377 "parser_bison.c"
+ break;
+
+ case 337: /* flowtable_block_alloc: %empty */
+#line 2333 "parser_bison.y"
+ {
+ (yyval.flowtable) = flowtable_alloc(&internal_location);
+ }
+#line 10385 "parser_bison.c"
+ break;
+
+ case 338: /* flowtable_block: %empty */
+#line 2338 "parser_bison.y"
+ { (yyval.flowtable) = (yyvsp[(-1) - (0)].flowtable); }
+#line 10391 "parser_bison.c"
+ break;
+
+ case 341: /* flowtable_block: flowtable_block "hook" "string" prio_spec stmt_separator */
+#line 2342 "parser_bison.y"
+ {
+ (yyval.flowtable)->hook.loc = (yylsp[-2]);
+ (yyval.flowtable)->hook.name = chain_hookname_lookup((yyvsp[-2].string));
+ if ((yyval.flowtable)->hook.name == NULL) {
+ erec_queue(error(&(yylsp[-2]), "unknown chain hook"),
+ state->msgs);
+ xfree((yyvsp[-2].string));
+ YYERROR;
+ }
+ xfree((yyvsp[-2].string));
+
+ (yyval.flowtable)->priority = (yyvsp[-1].prio_spec);
+ }
+#line 10409 "parser_bison.c"
+ break;
+
+ case 342: /* flowtable_block: flowtable_block "devices" '=' flowtable_expr stmt_separator */
+#line 2356 "parser_bison.y"
+ {
+ (yyval.flowtable)->dev_expr = (yyvsp[-1].expr);
+ }
+#line 10417 "parser_bison.c"
+ break;
+
+ case 343: /* flowtable_block: flowtable_block "counter" close_scope_counter */
+#line 2360 "parser_bison.y"
+ {
+ (yyval.flowtable)->flags |= NFT_FLOWTABLE_COUNTER;
+ }
+#line 10425 "parser_bison.c"
+ break;
+
+ case 344: /* flowtable_block: flowtable_block "flags" "offload" stmt_separator */
+#line 2364 "parser_bison.y"
+ {
+ (yyval.flowtable)->flags |= FLOWTABLE_F_HW_OFFLOAD;
+ }
+#line 10433 "parser_bison.c"
+ break;
+
+ case 345: /* flowtable_expr: '{' flowtable_list_expr '}' */
+#line 2370 "parser_bison.y"
+ {
+ (yyvsp[-1].expr)->location = (yyloc);
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 10442 "parser_bison.c"
+ break;
+
+ case 346: /* flowtable_expr: variable_expr */
+#line 2375 "parser_bison.y"
+ {
+ (yyvsp[0].expr)->location = (yyloc);
+ (yyval.expr) = (yyvsp[0].expr);
+ }
+#line 10451 "parser_bison.c"
+ break;
+
+ case 347: /* flowtable_list_expr: flowtable_expr_member */
+#line 2382 "parser_bison.y"
+ {
+ (yyval.expr) = compound_expr_alloc(&(yyloc), EXPR_LIST);
+ compound_expr_add((yyval.expr), (yyvsp[0].expr));
+ }
+#line 10460 "parser_bison.c"
+ break;
+
+ case 348: /* flowtable_list_expr: flowtable_list_expr "comma" flowtable_expr_member */
+#line 2387 "parser_bison.y"
+ {
+ compound_expr_add((yyvsp[-2].expr), (yyvsp[0].expr));
+ (yyval.expr) = (yyvsp[-2].expr);
+ }
+#line 10469 "parser_bison.c"
+ break;
+
+ case 350: /* flowtable_expr_member: "quoted string" */
+#line 2395 "parser_bison.y"
+ {
+ struct expr *expr = ifname_expr_alloc(&(yyloc), state->msgs, (yyvsp[0].string));
+
+ if (!expr)
+ YYERROR;
+
+ (yyval.expr) = expr;
+ }
+#line 10482 "parser_bison.c"
+ break;
+
+ case 351: /* flowtable_expr_member: "string" */
+#line 2404 "parser_bison.y"
+ {
+ struct expr *expr = ifname_expr_alloc(&(yyloc), state->msgs, (yyvsp[0].string));
+
+ if (!expr)
+ YYERROR;
+
+ (yyval.expr) = expr;
+ }
+#line 10495 "parser_bison.c"
+ break;
+
+ case 352: /* flowtable_expr_member: variable_expr */
+#line 2413 "parser_bison.y"
+ {
+ datatype_set((yyvsp[0].expr)->sym->expr, &ifname_type);
+ (yyval.expr) = (yyvsp[0].expr);
+ }
+#line 10504 "parser_bison.c"
+ break;
+
+ case 353: /* data_type_atom_expr: type_identifier */
+#line 2420 "parser_bison.y"
+ {
+ const struct datatype *dtype = datatype_lookup_byname((yyvsp[0].string));
+ if (dtype == NULL) {
+ erec_queue(error(&(yylsp[0]), "unknown datatype %s", (yyvsp[0].string)),
+ state->msgs);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyval.expr) = constant_expr_alloc(&(yylsp[0]), dtype, dtype->byteorder,
+ dtype->size, NULL);
+ xfree((yyvsp[0].string));
+ }
+#line 10521 "parser_bison.c"
+ break;
+
+ case 354: /* data_type_atom_expr: "time" */
+#line 2433 "parser_bison.y"
+ {
+ (yyval.expr) = constant_expr_alloc(&(yylsp[0]), &time_type, time_type.byteorder,
+ time_type.size, NULL);
+ }
+#line 10530 "parser_bison.c"
+ break;
+
+ case 356: /* data_type_expr: data_type_expr "." data_type_atom_expr */
+#line 2441 "parser_bison.y"
+ {
+ struct location rhs[] = {
+ [1] = (yylsp[-1]),
+ [2] = (yylsp[0]),
+ };
+
+ (yyval.expr) = handle_concat_expr(&(yyloc), (yyval.expr), (yyvsp[-2].expr), (yyvsp[0].expr), rhs);
+ }
+#line 10543 "parser_bison.c"
+ break;
+
+ case 357: /* obj_block_alloc: %empty */
+#line 2452 "parser_bison.y"
+ {
+ (yyval.obj) = obj_alloc(&internal_location);
+ }
+#line 10551 "parser_bison.c"
+ break;
+
+ case 358: /* counter_block: %empty */
+#line 2457 "parser_bison.y"
+ { (yyval.obj) = (yyvsp[(-1) - (0)].obj); }
+#line 10557 "parser_bison.c"
+ break;
+
+ case 361: /* counter_block: counter_block counter_config */
+#line 2461 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10565 "parser_bison.c"
+ break;
+
+ case 362: /* counter_block: counter_block comment_spec */
+#line 2465 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10577 "parser_bison.c"
+ break;
+
+ case 363: /* quota_block: %empty */
+#line 2474 "parser_bison.y"
+ { (yyval.obj) = (yyvsp[(-1) - (0)].obj); }
+#line 10583 "parser_bison.c"
+ break;
+
+ case 366: /* quota_block: quota_block quota_config */
+#line 2478 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10591 "parser_bison.c"
+ break;
+
+ case 367: /* quota_block: quota_block comment_spec */
+#line 2482 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10603 "parser_bison.c"
+ break;
+
+ case 368: /* ct_helper_block: %empty */
+#line 2491 "parser_bison.y"
+ { (yyval.obj) = (yyvsp[(-1) - (0)].obj); }
+#line 10609 "parser_bison.c"
+ break;
+
+ case 371: /* ct_helper_block: ct_helper_block ct_helper_config */
+#line 2495 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10617 "parser_bison.c"
+ break;
+
+ case 372: /* ct_helper_block: ct_helper_block comment_spec */
+#line 2499 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10629 "parser_bison.c"
+ break;
+
+ case 373: /* ct_timeout_block: %empty */
+#line 2509 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[(-1) - (0)].obj);
+ init_list_head(&(yyval.obj)->ct_timeout.timeout_list);
+ }
+#line 10638 "parser_bison.c"
+ break;
+
+ case 376: /* ct_timeout_block: ct_timeout_block ct_timeout_config */
+#line 2516 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10646 "parser_bison.c"
+ break;
+
+ case 377: /* ct_timeout_block: ct_timeout_block comment_spec */
+#line 2520 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10658 "parser_bison.c"
+ break;
+
+ case 378: /* ct_expect_block: %empty */
+#line 2529 "parser_bison.y"
+ { (yyval.obj) = (yyvsp[(-1) - (0)].obj); }
+#line 10664 "parser_bison.c"
+ break;
+
+ case 381: /* ct_expect_block: ct_expect_block ct_expect_config */
+#line 2533 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10672 "parser_bison.c"
+ break;
+
+ case 382: /* ct_expect_block: ct_expect_block comment_spec */
+#line 2537 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10684 "parser_bison.c"
+ break;
+
+ case 383: /* limit_block: %empty */
+#line 2546 "parser_bison.y"
+ { (yyval.obj) = (yyvsp[(-1) - (0)].obj); }
+#line 10690 "parser_bison.c"
+ break;
+
+ case 386: /* limit_block: limit_block limit_config */
+#line 2550 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10698 "parser_bison.c"
+ break;
+
+ case 387: /* limit_block: limit_block comment_spec */
+#line 2554 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10710 "parser_bison.c"
+ break;
+
+ case 388: /* secmark_block: %empty */
+#line 2563 "parser_bison.y"
+ { (yyval.obj) = (yyvsp[(-1) - (0)].obj); }
+#line 10716 "parser_bison.c"
+ break;
+
+ case 391: /* secmark_block: secmark_block secmark_config */
+#line 2567 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10724 "parser_bison.c"
+ break;
+
+ case 392: /* secmark_block: secmark_block comment_spec */
+#line 2571 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10736 "parser_bison.c"
+ break;
+
+ case 393: /* synproxy_block: %empty */
+#line 2580 "parser_bison.y"
+ { (yyval.obj) = (yyvsp[(-1) - (0)].obj); }
+#line 10742 "parser_bison.c"
+ break;
+
+ case 396: /* synproxy_block: synproxy_block synproxy_config */
+#line 2584 "parser_bison.y"
+ {
+ (yyval.obj) = (yyvsp[-1].obj);
+ }
+#line 10750 "parser_bison.c"
+ break;
+
+ case 397: /* synproxy_block: synproxy_block comment_spec */
+#line 2588 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].obj)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].obj)->comment = (yyvsp[0].string);
+ }
+#line 10762 "parser_bison.c"
+ break;
+
+ case 398: /* type_identifier: "string" */
+#line 2597 "parser_bison.y"
+ { (yyval.string) = (yyvsp[0].string); }
+#line 10768 "parser_bison.c"
+ break;
+
+ case 399: /* type_identifier: "mark" */
+#line 2598 "parser_bison.y"
+ { (yyval.string) = xstrdup("mark"); }
+#line 10774 "parser_bison.c"
+ break;
+
+ case 400: /* type_identifier: "dscp" */
+#line 2599 "parser_bison.y"
+ { (yyval.string) = xstrdup("dscp"); }
+#line 10780 "parser_bison.c"
+ break;
+
+ case 401: /* type_identifier: "ecn" */
+#line 2600 "parser_bison.y"
+ { (yyval.string) = xstrdup("ecn"); }
+#line 10786 "parser_bison.c"
+ break;
+
+ case 402: /* type_identifier: "classid" */
+#line 2601 "parser_bison.y"
+ { (yyval.string) = xstrdup("classid"); }
+#line 10792 "parser_bison.c"
+ break;
+
+ case 403: /* hook_spec: "type" close_scope_type "string" "hook" "string" dev_spec prio_spec */
+#line 2605 "parser_bison.y"
+ {
+ const char *chain_type = chain_type_name_lookup((yyvsp[-4].string));
+
+ if (chain_type == NULL) {
+ erec_queue(error(&(yylsp[-4]), "unknown chain type"),
+ state->msgs);
+ xfree((yyvsp[-4].string));
+ YYERROR;
+ }
+ (yyvsp[-7].chain)->type.loc = (yylsp[-4]);
+ (yyvsp[-7].chain)->type.str = xstrdup(chain_type);
+ xfree((yyvsp[-4].string));
+
+ (yyvsp[-7].chain)->loc = (yyloc);
+ (yyvsp[-7].chain)->hook.loc = (yylsp[-2]);
+ (yyvsp[-7].chain)->hook.name = chain_hookname_lookup((yyvsp[-2].string));
+ if ((yyvsp[-7].chain)->hook.name == NULL) {
+ erec_queue(error(&(yylsp[-2]), "unknown chain hook"),
+ state->msgs);
+ xfree((yyvsp[-2].string));
+ YYERROR;
+ }
+ xfree((yyvsp[-2].string));
+
+ (yyvsp[-7].chain)->dev_expr = (yyvsp[-1].expr);
+ (yyvsp[-7].chain)->priority = (yyvsp[0].prio_spec);
+ (yyvsp[-7].chain)->flags |= CHAIN_F_BASECHAIN;
+ }
+#line 10825 "parser_bison.c"
+ break;
+
+ case 404: /* prio_spec: "priority" extended_prio_spec */
+#line 2636 "parser_bison.y"
+ {
+ (yyval.prio_spec) = (yyvsp[0].prio_spec);
+ (yyval.prio_spec).loc = (yyloc);
+ }
+#line 10834 "parser_bison.c"
+ break;
+
+ case 405: /* extended_prio_name: "out" */
+#line 2643 "parser_bison.y"
+ {
+ (yyval.string) = strdup("out");
+ }
+#line 10842 "parser_bison.c"
+ break;
+
+ case 407: /* extended_prio_spec: int_num */
+#line 2650 "parser_bison.y"
+ {
+ struct prio_spec spec = {0};
+
+ spec.expr = constant_expr_alloc(&(yyloc), &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) *
+ BITS_PER_BYTE, &(yyvsp[0].val32));
+ (yyval.prio_spec) = spec;
+ }
+#line 10856 "parser_bison.c"
+ break;
+
+ case 408: /* extended_prio_spec: variable_expr */
+#line 2660 "parser_bison.y"
+ {
+ struct prio_spec spec = {0};
+
+ spec.expr = (yyvsp[0].expr);
+ (yyval.prio_spec) = spec;
+ }
+#line 10867 "parser_bison.c"
+ break;
+
+ case 409: /* extended_prio_spec: extended_prio_name */
+#line 2667 "parser_bison.y"
+ {
+ struct prio_spec spec = {0};
+
+ spec.expr = constant_expr_alloc(&(yyloc), &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen((yyvsp[0].string)) * BITS_PER_BYTE,
+ (yyvsp[0].string));
+ xfree((yyvsp[0].string));
+ (yyval.prio_spec) = spec;
+ }
+#line 10882 "parser_bison.c"
+ break;
+
+ case 410: /* extended_prio_spec: extended_prio_name "+" "number" */
+#line 2678 "parser_bison.y"
+ {
+ struct prio_spec spec = {0};
+
+ char str[NFT_NAME_MAXLEN];
+ snprintf(str, sizeof(str), "%s + %" PRIu64, (yyvsp[-2].string), (yyvsp[0].val));
+ spec.expr = constant_expr_alloc(&(yyloc), &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(str) * BITS_PER_BYTE,
+ str);
+ xfree((yyvsp[-2].string));
+ (yyval.prio_spec) = spec;
+ }
+#line 10899 "parser_bison.c"
+ break;
+
+ case 411: /* extended_prio_spec: extended_prio_name "-" "number" */
+#line 2691 "parser_bison.y"
+ {
+ struct prio_spec spec = {0};
+ char str[NFT_NAME_MAXLEN];
+
+ snprintf(str, sizeof(str), "%s - %" PRIu64, (yyvsp[-2].string), (yyvsp[0].val));
+ spec.expr = constant_expr_alloc(&(yyloc), &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(str) * BITS_PER_BYTE,
+ str);
+ xfree((yyvsp[-2].string));
+ (yyval.prio_spec) = spec;
+ }
+#line 10916 "parser_bison.c"
+ break;
+
+ case 412: /* int_num: "number" */
+#line 2705 "parser_bison.y"
+ { (yyval.val32) = (yyvsp[0].val); }
+#line 10922 "parser_bison.c"
+ break;
+
+ case 413: /* int_num: "-" "number" */
+#line 2706 "parser_bison.y"
+ { (yyval.val32) = -(yyvsp[0].val); }
+#line 10928 "parser_bison.c"
+ break;
+
+ case 414: /* dev_spec: "device" string */
+#line 2710 "parser_bison.y"
+ {
+ struct expr *expr = ifname_expr_alloc(&(yyloc), state->msgs, (yyvsp[0].string));
+
+ if (!expr)
+ YYERROR;
+
+ (yyval.expr) = compound_expr_alloc(&(yyloc), EXPR_LIST);
+ compound_expr_add((yyval.expr), expr);
+
+ }
+#line 10943 "parser_bison.c"
+ break;
+
+ case 415: /* dev_spec: "device" variable_expr */
+#line 2721 "parser_bison.y"
+ {
+ datatype_set((yyvsp[0].expr)->sym->expr, &ifname_type);
+ (yyval.expr) = compound_expr_alloc(&(yyloc), EXPR_LIST);
+ compound_expr_add((yyval.expr), (yyvsp[0].expr));
+ }
+#line 10953 "parser_bison.c"
+ break;
+
+ case 416: /* dev_spec: "devices" '=' flowtable_expr */
+#line 2727 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[0].expr);
+ }
+#line 10961 "parser_bison.c"
+ break;
+
+ case 417: /* dev_spec: %empty */
+#line 2730 "parser_bison.y"
+ { (yyval.expr) = NULL; }
+#line 10967 "parser_bison.c"
+ break;
+
+ case 418: /* flags_spec: "flags" "offload" */
+#line 2734 "parser_bison.y"
+ {
+ (yyvsp[-2].chain)->flags |= CHAIN_F_HW_OFFLOAD;
+ }
+#line 10975 "parser_bison.c"
+ break;
+
+ case 419: /* policy_spec: "policy" policy_expr close_scope_policy */
+#line 2740 "parser_bison.y"
+ {
+ if ((yyvsp[-3].chain)->policy) {
+ erec_queue(error(&(yyloc), "you cannot set chain policy twice"),
+ state->msgs);
+ expr_free((yyvsp[-1].expr));
+ YYERROR;
+ }
+ (yyvsp[-3].chain)->policy = (yyvsp[-1].expr);
+ (yyvsp[-3].chain)->policy->location = (yyloc);
+ }
+#line 10990 "parser_bison.c"
+ break;
+
+ case 420: /* policy_expr: variable_expr */
+#line 2753 "parser_bison.y"
+ {
+ datatype_set((yyvsp[0].expr)->sym->expr, &policy_type);
+ (yyval.expr) = (yyvsp[0].expr);
+ }
+#line 10999 "parser_bison.c"
+ break;
+
+ case 421: /* policy_expr: chain_policy */
+#line 2758 "parser_bison.y"
+ {
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) *
+ BITS_PER_BYTE, &(yyvsp[0].val32));
+ }
+#line 11010 "parser_bison.c"
+ break;
+
+ case 422: /* chain_policy: "accept" */
+#line 2766 "parser_bison.y"
+ { (yyval.val32) = NF_ACCEPT; }
+#line 11016 "parser_bison.c"
+ break;
+
+ case 423: /* chain_policy: "drop" */
+#line 2767 "parser_bison.y"
+ { (yyval.val32) = NF_DROP; }
+#line 11022 "parser_bison.c"
+ break;
+
+ case 425: /* identifier: "last" */
+#line 2771 "parser_bison.y"
+ { (yyval.string) = xstrdup("last"); }
+#line 11028 "parser_bison.c"
+ break;
+
+ case 429: /* time_spec: "string" */
+#line 2780 "parser_bison.y"
+ {
+ struct error_record *erec;
+ uint64_t res;
+
+ erec = time_parse(&(yylsp[0]), (yyvsp[0].string), &res);
+ xfree((yyvsp[0].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ (yyval.val) = res;
+ }
+#line 11045 "parser_bison.c"
+ break;
+
+ case 431: /* time_spec_or_num_s: time_spec */
+#line 2796 "parser_bison.y"
+ { (yyval.val) = (yyvsp[0].val) / 1000u; }
+#line 11051 "parser_bison.c"
+ break;
+
+ case 432: /* family_spec: %empty */
+#line 2799 "parser_bison.y"
+ { (yyval.val) = NFPROTO_IPV4; }
+#line 11057 "parser_bison.c"
+ break;
+
+ case 434: /* family_spec_explicit: "ip" close_scope_ip */
+#line 2803 "parser_bison.y"
+ { (yyval.val) = NFPROTO_IPV4; }
+#line 11063 "parser_bison.c"
+ break;
+
+ case 435: /* family_spec_explicit: "ip6" close_scope_ip6 */
+#line 2804 "parser_bison.y"
+ { (yyval.val) = NFPROTO_IPV6; }
+#line 11069 "parser_bison.c"
+ break;
+
+ case 436: /* family_spec_explicit: "inet" */
+#line 2805 "parser_bison.y"
+ { (yyval.val) = NFPROTO_INET; }
+#line 11075 "parser_bison.c"
+ break;
+
+ case 437: /* family_spec_explicit: "arp" close_scope_arp */
+#line 2806 "parser_bison.y"
+ { (yyval.val) = NFPROTO_ARP; }
+#line 11081 "parser_bison.c"
+ break;
+
+ case 438: /* family_spec_explicit: "bridge" */
+#line 2807 "parser_bison.y"
+ { (yyval.val) = NFPROTO_BRIDGE; }
+#line 11087 "parser_bison.c"
+ break;
+
+ case 439: /* family_spec_explicit: "netdev" */
+#line 2808 "parser_bison.y"
+ { (yyval.val) = NFPROTO_NETDEV; }
+#line 11093 "parser_bison.c"
+ break;
+
+ case 440: /* table_spec: family_spec identifier */
+#line 2812 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).family = (yyvsp[-1].val);
+ (yyval.handle).table.location = (yylsp[0]);
+ (yyval.handle).table.name = (yyvsp[0].string);
+ }
+#line 11104 "parser_bison.c"
+ break;
+
+ case 441: /* tableid_spec: family_spec "handle" "number" */
+#line 2821 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).family = (yyvsp[-2].val);
+ (yyval.handle).handle.id = (yyvsp[0].val);
+ (yyval.handle).handle.location = (yylsp[0]);
+ }
+#line 11115 "parser_bison.c"
+ break;
+
+ case 442: /* chain_spec: table_spec identifier */
+#line 2830 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-1].handle);
+ (yyval.handle).chain.name = (yyvsp[0].string);
+ (yyval.handle).chain.location = (yylsp[0]);
+ }
+#line 11125 "parser_bison.c"
+ break;
+
+ case 443: /* chainid_spec: table_spec "handle" "number" */
+#line 2838 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-2].handle);
+ (yyval.handle).handle.location = (yylsp[0]);
+ (yyval.handle).handle.id = (yyvsp[0].val);
+ }
+#line 11135 "parser_bison.c"
+ break;
+
+ case 444: /* chain_identifier: identifier */
+#line 2846 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).chain.name = (yyvsp[0].string);
+ (yyval.handle).chain.location = (yylsp[0]);
+ }
+#line 11145 "parser_bison.c"
+ break;
+
+ case 445: /* set_spec: table_spec identifier */
+#line 2854 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-1].handle);
+ (yyval.handle).set.name = (yyvsp[0].string);
+ (yyval.handle).set.location = (yylsp[0]);
+ }
+#line 11155 "parser_bison.c"
+ break;
+
+ case 446: /* setid_spec: table_spec "handle" "number" */
+#line 2862 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-2].handle);
+ (yyval.handle).handle.location = (yylsp[0]);
+ (yyval.handle).handle.id = (yyvsp[0].val);
+ }
+#line 11165 "parser_bison.c"
+ break;
+
+ case 447: /* set_identifier: identifier */
+#line 2870 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).set.name = (yyvsp[0].string);
+ (yyval.handle).set.location = (yylsp[0]);
+ }
+#line 11175 "parser_bison.c"
+ break;
+
+ case 448: /* flowtable_spec: table_spec identifier */
+#line 2878 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-1].handle);
+ (yyval.handle).flowtable.name = (yyvsp[0].string);
+ (yyval.handle).flowtable.location = (yylsp[0]);
+ }
+#line 11185 "parser_bison.c"
+ break;
+
+ case 449: /* flowtableid_spec: table_spec "handle" "number" */
+#line 2886 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-2].handle);
+ (yyval.handle).handle.location = (yylsp[0]);
+ (yyval.handle).handle.id = (yyvsp[0].val);
+ }
+#line 11195 "parser_bison.c"
+ break;
+
+ case 450: /* flowtable_identifier: identifier */
+#line 2894 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).flowtable.name = (yyvsp[0].string);
+ (yyval.handle).flowtable.location = (yylsp[0]);
+ }
+#line 11205 "parser_bison.c"
+ break;
+
+ case 451: /* obj_spec: table_spec identifier */
+#line 2902 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-1].handle);
+ (yyval.handle).obj.name = (yyvsp[0].string);
+ (yyval.handle).obj.location = (yylsp[0]);
+ }
+#line 11215 "parser_bison.c"
+ break;
+
+ case 452: /* objid_spec: table_spec "handle" "number" */
+#line 2910 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[-2].handle);
+ (yyval.handle).handle.location = (yylsp[0]);
+ (yyval.handle).handle.id = (yyvsp[0].val);
+ }
+#line 11225 "parser_bison.c"
+ break;
+
+ case 453: /* obj_identifier: identifier */
+#line 2918 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).obj.name = (yyvsp[0].string);
+ (yyval.handle).obj.location = (yylsp[0]);
+ }
+#line 11235 "parser_bison.c"
+ break;
+
+ case 454: /* handle_spec: "handle" "number" */
+#line 2926 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).handle.location = (yylsp[0]);
+ (yyval.handle).handle.id = (yyvsp[0].val);
+ }
+#line 11245 "parser_bison.c"
+ break;
+
+ case 455: /* position_spec: "position" "number" */
+#line 2934 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).position.location = (yyloc);
+ (yyval.handle).position.id = (yyvsp[0].val);
+ }
+#line 11255 "parser_bison.c"
+ break;
+
+ case 456: /* index_spec: "index" "number" */
+#line 2942 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).index.location = (yyloc);
+ (yyval.handle).index.id = (yyvsp[0].val) + 1;
+ }
+#line 11265 "parser_bison.c"
+ break;
+
+ case 457: /* rule_position: chain_spec */
+#line 2950 "parser_bison.y"
+ {
+ (yyval.handle) = (yyvsp[0].handle);
+ }
+#line 11273 "parser_bison.c"
+ break;
+
+ case 458: /* rule_position: chain_spec position_spec */
+#line 2954 "parser_bison.y"
+ {
+ handle_merge(&(yyvsp[-1].handle), &(yyvsp[0].handle));
+ (yyval.handle) = (yyvsp[-1].handle);
+ }
+#line 11282 "parser_bison.c"
+ break;
+
+ case 459: /* rule_position: chain_spec handle_spec */
+#line 2959 "parser_bison.y"
+ {
+ (yyvsp[0].handle).position.location = (yyvsp[0].handle).handle.location;
+ (yyvsp[0].handle).position.id = (yyvsp[0].handle).handle.id;
+ (yyvsp[0].handle).handle.id = 0;
+ handle_merge(&(yyvsp[-1].handle), &(yyvsp[0].handle));
+ (yyval.handle) = (yyvsp[-1].handle);
+ }
+#line 11294 "parser_bison.c"
+ break;
+
+ case 460: /* rule_position: chain_spec index_spec */
+#line 2967 "parser_bison.y"
+ {
+ handle_merge(&(yyvsp[-1].handle), &(yyvsp[0].handle));
+ (yyval.handle) = (yyvsp[-1].handle);
+ }
+#line 11303 "parser_bison.c"
+ break;
+
+ case 461: /* ruleid_spec: chain_spec handle_spec */
+#line 2974 "parser_bison.y"
+ {
+ handle_merge(&(yyvsp[-1].handle), &(yyvsp[0].handle));
+ (yyval.handle) = (yyvsp[-1].handle);
+ }
+#line 11312 "parser_bison.c"
+ break;
+
+ case 462: /* comment_spec: "comment" string */
+#line 2981 "parser_bison.y"
+ {
+ if (strlen((yyvsp[0].string)) > NFTNL_UDATA_COMMENT_MAXLEN) {
+ erec_queue(error(&(yylsp[0]), "comment too long, %d characters maximum allowed",
+ NFTNL_UDATA_COMMENT_MAXLEN),
+ state->msgs);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyval.string) = (yyvsp[0].string);
+ }
+#line 11327 "parser_bison.c"
+ break;
+
+ case 463: /* ruleset_spec: %empty */
+#line 2994 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).family = NFPROTO_UNSPEC;
+ }
+#line 11336 "parser_bison.c"
+ break;
+
+ case 464: /* ruleset_spec: family_spec_explicit */
+#line 2999 "parser_bison.y"
+ {
+ memset(&(yyval.handle), 0, sizeof((yyval.handle)));
+ (yyval.handle).family = (yyvsp[0].val);
+ }
+#line 11345 "parser_bison.c"
+ break;
+
+ case 465: /* rule: rule_alloc */
+#line 3006 "parser_bison.y"
+ {
+ (yyval.rule)->comment = NULL;
+ }
+#line 11353 "parser_bison.c"
+ break;
+
+ case 466: /* rule: rule_alloc comment_spec */
+#line 3010 "parser_bison.y"
+ {
+ (yyval.rule)->comment = (yyvsp[0].string);
+ }
+#line 11361 "parser_bison.c"
+ break;
+
+ case 467: /* rule_alloc: stmt_list */
+#line 3016 "parser_bison.y"
+ {
+ struct stmt *i;
+
+ (yyval.rule) = rule_alloc(&(yyloc), NULL);
+ list_for_each_entry(i, (yyvsp[0].list), list)
+ (yyval.rule)->num_stmts++;
+ list_splice_tail((yyvsp[0].list), &(yyval.rule)->stmts);
+ xfree((yyvsp[0].list));
+ }
+#line 11375 "parser_bison.c"
+ break;
+
+ case 468: /* stmt_list: stmt */
+#line 3028 "parser_bison.y"
+ {
+ (yyval.list) = xmalloc(sizeof(*(yyval.list)));
+ init_list_head((yyval.list));
+ list_add_tail(&(yyvsp[0].stmt)->list, (yyval.list));
+ }
+#line 11385 "parser_bison.c"
+ break;
+
+ case 469: /* stmt_list: stmt_list stmt */
+#line 3034 "parser_bison.y"
+ {
+ (yyval.list) = (yyvsp[-1].list);
+ list_add_tail(&(yyvsp[0].stmt)->list, (yyvsp[-1].list));
+ }
+#line 11394 "parser_bison.c"
+ break;
+
+ case 470: /* stateful_stmt_list: stateful_stmt */
+#line 3041 "parser_bison.y"
+ {
+ (yyval.list) = xmalloc(sizeof(*(yyval.list)));
+ init_list_head((yyval.list));
+ list_add_tail(&(yyvsp[0].stmt)->list, (yyval.list));
+ }
+#line 11404 "parser_bison.c"
+ break;
+
+ case 471: /* stateful_stmt_list: stateful_stmt_list stateful_stmt */
+#line 3047 "parser_bison.y"
+ {
+ (yyval.list) = (yyvsp[-1].list);
+ list_add_tail(&(yyvsp[0].stmt)->list, (yyvsp[-1].list));
+ }
+#line 11413 "parser_bison.c"
+ break;
+
+ case 499: /* xt_stmt: "xt" "string" string */
+#line 3085 "parser_bison.y"
+ {
+ (yyval.stmt) = NULL;
+ xfree((yyvsp[-1].string));
+ xfree((yyvsp[0].string));
+ erec_queue(error(&(yyloc), "unsupported xtables compat expression, use iptables-nft with this ruleset"),
+ state->msgs);
+ YYERROR;
+ }
+#line 11426 "parser_bison.c"
+ break;
+
+ case 500: /* chain_stmt_type: "jump" */
+#line 3095 "parser_bison.y"
+ { (yyval.val) = NFT_JUMP; }
+#line 11432 "parser_bison.c"
+ break;
+
+ case 501: /* chain_stmt_type: "goto" */
+#line 3096 "parser_bison.y"
+ { (yyval.val) = NFT_GOTO; }
+#line 11438 "parser_bison.c"
+ break;
+
+ case 502: /* chain_stmt: chain_stmt_type chain_block_alloc '{' subchain_block '}' */
+#line 3100 "parser_bison.y"
+ {
+ (yyvsp[-3].chain)->location = (yylsp[-3]);
+ close_scope(state);
+ (yyvsp[-1].chain)->location = (yylsp[-1]);
+ (yyval.stmt) = chain_stmt_alloc(&(yyloc), (yyvsp[-1].chain), (yyvsp[-4].val));
+ }
+#line 11449 "parser_bison.c"
+ break;
+
+ case 503: /* verdict_stmt: verdict_expr */
+#line 3109 "parser_bison.y"
+ {
+ (yyval.stmt) = verdict_stmt_alloc(&(yyloc), (yyvsp[0].expr));
+ }
+#line 11457 "parser_bison.c"
+ break;
+
+ case 504: /* verdict_stmt: verdict_map_stmt */
+#line 3113 "parser_bison.y"
+ {
+ (yyval.stmt) = verdict_stmt_alloc(&(yyloc), (yyvsp[0].expr));
+ }
+#line 11465 "parser_bison.c"
+ break;
+
+ case 505: /* verdict_map_stmt: concat_expr "vmap" verdict_map_expr */
+#line 3119 "parser_bison.y"
+ {
+ (yyval.expr) = map_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 11473 "parser_bison.c"
+ break;
+
+ case 506: /* verdict_map_expr: '{' verdict_map_list_expr '}' */
+#line 3125 "parser_bison.y"
+ {
+ (yyvsp[-1].expr)->location = (yyloc);
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 11482 "parser_bison.c"
+ break;
+
+ case 508: /* verdict_map_list_expr: verdict_map_list_member_expr */
+#line 3133 "parser_bison.y"
+ {
+ (yyval.expr) = set_expr_alloc(&(yyloc), NULL);
+ compound_expr_add((yyval.expr), (yyvsp[0].expr));
+ }
+#line 11491 "parser_bison.c"
+ break;
+
+ case 509: /* verdict_map_list_expr: verdict_map_list_expr "comma" verdict_map_list_member_expr */
+#line 3138 "parser_bison.y"
+ {
+ compound_expr_add((yyvsp[-2].expr), (yyvsp[0].expr));
+ (yyval.expr) = (yyvsp[-2].expr);
+ }
+#line 11500 "parser_bison.c"
+ break;
+
+ case 511: /* verdict_map_list_member_expr: opt_newline set_elem_expr "colon" verdict_expr opt_newline */
+#line 3146 "parser_bison.y"
+ {
+ (yyval.expr) = mapping_expr_alloc(&(yylsp[-3]), (yyvsp[-3].expr), (yyvsp[-1].expr));
+ }
+#line 11508 "parser_bison.c"
+ break;
+
+ case 512: /* connlimit_stmt: "ct" "count" "number" close_scope_ct */
+#line 3152 "parser_bison.y"
+ {
+ (yyval.stmt) = connlimit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->connlimit.count = (yyvsp[-1].val);
+ }
+#line 11517 "parser_bison.c"
+ break;
+
+ case 513: /* connlimit_stmt: "ct" "count" "over" "number" close_scope_ct */
+#line 3157 "parser_bison.y"
+ {
+ (yyval.stmt) = connlimit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->connlimit.count = (yyvsp[-1].val);
+ (yyval.stmt)->connlimit.flags = NFT_CONNLIMIT_F_INV;
+ }
+#line 11527 "parser_bison.c"
+ break;
+
+ case 516: /* counter_stmt_alloc: "counter" */
+#line 3168 "parser_bison.y"
+ {
+ (yyval.stmt) = counter_stmt_alloc(&(yyloc));
+ }
+#line 11535 "parser_bison.c"
+ break;
+
+ case 517: /* counter_stmt_alloc: "counter" "name" stmt_expr */
+#line 3172 "parser_bison.y"
+ {
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_COUNTER;
+ (yyval.stmt)->objref.expr = (yyvsp[0].expr);
+ }
+#line 11545 "parser_bison.c"
+ break;
+
+ case 518: /* counter_args: counter_arg */
+#line 3180 "parser_bison.y"
+ {
+ (yyval.stmt) = (yyvsp[-1].stmt);
+ }
+#line 11553 "parser_bison.c"
+ break;
+
+ case 520: /* counter_arg: "packets" "number" */
+#line 3187 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->counter.packets = (yyvsp[0].val);
+ }
+#line 11561 "parser_bison.c"
+ break;
+
+ case 521: /* counter_arg: "bytes" "number" */
+#line 3191 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->counter.bytes = (yyvsp[0].val);
+ }
+#line 11569 "parser_bison.c"
+ break;
+
+ case 522: /* last_stmt: "last" */
+#line 3197 "parser_bison.y"
+ {
+ (yyval.stmt) = last_stmt_alloc(&(yyloc));
+ }
+#line 11577 "parser_bison.c"
+ break;
+
+ case 523: /* last_stmt: "last" "used" "never" */
+#line 3201 "parser_bison.y"
+ {
+ (yyval.stmt) = last_stmt_alloc(&(yyloc));
+ }
+#line 11585 "parser_bison.c"
+ break;
+
+ case 524: /* last_stmt: "last" "used" time_spec */
+#line 3205 "parser_bison.y"
+ {
+ (yyval.stmt) = last_stmt_alloc(&(yyloc));
+ (yyval.stmt)->last.used = (yyvsp[0].val);
+ (yyval.stmt)->last.set = true;
+ }
+#line 11595 "parser_bison.c"
+ break;
+
+ case 527: /* log_stmt_alloc: "log" */
+#line 3217 "parser_bison.y"
+ {
+ (yyval.stmt) = log_stmt_alloc(&(yyloc));
+ }
+#line 11603 "parser_bison.c"
+ break;
+
+ case 528: /* log_args: log_arg */
+#line 3223 "parser_bison.y"
+ {
+ (yyval.stmt) = (yyvsp[-1].stmt);
+ }
+#line 11611 "parser_bison.c"
+ break;
+
+ case 530: /* log_arg: "prefix" string */
+#line 3230 "parser_bison.y"
+ {
+ struct scope *scope = current_scope(state);
+ bool done = false, another_var = false;
+ char *start, *end, scratch = '\0';
+ struct expr *expr, *item;
+ struct symbol *sym;
+ enum {
+ PARSE_TEXT,
+ PARSE_VAR,
+ } prefix_state;
+
+ /* No variables in log prefix, skip. */
+ if (!strchr((yyvsp[0].string), '$')) {
+ expr = constant_expr_alloc(&(yyloc), &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen((yyvsp[0].string)) + 1) * BITS_PER_BYTE, (yyvsp[0].string));
+ xfree((yyvsp[0].string));
+ (yyvsp[-2].stmt)->log.prefix = expr;
+ (yyvsp[-2].stmt)->log.flags |= STMT_LOG_PREFIX;
+ break;
+ }
+
+ /* Parse variables in log prefix string using a
+ * state machine parser with two states. This
+ * parser creates list of expressions composed
+ * of constant and variable expressions.
+ */
+ expr = compound_expr_alloc(&(yyloc), EXPR_LIST);
+
+ start = (char *)(yyvsp[0].string);
+
+ if (*start != '$') {
+ prefix_state = PARSE_TEXT;
+ } else {
+ prefix_state = PARSE_VAR;
+ start++;
+ }
+ end = start;
+
+ /* Not nice, but works. */
+ while (!done) {
+ switch (prefix_state) {
+ case PARSE_TEXT:
+ while (*end != '\0' && *end != '$')
+ end++;
+
+ if (*end == '\0')
+ done = true;
+
+ *end = '\0';
+ item = constant_expr_alloc(&(yyloc), &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(start) + 1) * BITS_PER_BYTE,
+ start);
+ compound_expr_add(expr, item);
+
+ if (done)
+ break;
+
+ start = end + 1;
+ end = start;
+
+ /* fall through */
+ case PARSE_VAR:
+ while (isalnum(*end) || *end == '_')
+ end++;
+
+ if (*end == '\0')
+ done = true;
+ else if (*end == '$')
+ another_var = true;
+ else
+ scratch = *end;
+
+ *end = '\0';
+
+ sym = symbol_get(scope, start);
+ if (!sym) {
+ sym = symbol_lookup_fuzzy(scope, start);
+ if (sym) {
+ erec_queue(error(&(yylsp[0]), "unknown identifier '%s'; "
+ "did you mean identifier ‘%s’?",
+ start, sym->identifier),
+ state->msgs);
+ } else {
+ erec_queue(error(&(yylsp[0]), "unknown identifier '%s'",
+ start),
+ state->msgs);
+ }
+ expr_free(expr);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ item = variable_expr_alloc(&(yyloc), scope, sym);
+ compound_expr_add(expr, item);
+
+ if (done)
+ break;
+
+ /* Restore original byte after
+ * symbol lookup.
+ */
+ if (scratch) {
+ *end = scratch;
+ scratch = '\0';
+ }
+
+ start = end;
+ if (another_var) {
+ another_var = false;
+ start++;
+ prefix_state = PARSE_VAR;
+ } else {
+ prefix_state = PARSE_TEXT;
+ }
+ end = start;
+ break;
+ }
+ }
+
+ xfree((yyvsp[0].string));
+ (yyvsp[-2].stmt)->log.prefix = expr;
+ (yyvsp[-2].stmt)->log.flags |= STMT_LOG_PREFIX;
+ }
+#line 11740 "parser_bison.c"
+ break;
+
+ case 531: /* log_arg: "group" "number" */
+#line 3355 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->log.group = (yyvsp[0].val);
+ (yyvsp[-2].stmt)->log.flags |= STMT_LOG_GROUP;
+ }
+#line 11749 "parser_bison.c"
+ break;
+
+ case 532: /* log_arg: "snaplen" "number" */
+#line 3360 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->log.snaplen = (yyvsp[0].val);
+ (yyvsp[-2].stmt)->log.flags |= STMT_LOG_SNAPLEN;
+ }
+#line 11758 "parser_bison.c"
+ break;
+
+ case 533: /* log_arg: "queue-threshold" "number" */
+#line 3365 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->log.qthreshold = (yyvsp[0].val);
+ (yyvsp[-2].stmt)->log.flags |= STMT_LOG_QTHRESHOLD;
+ }
+#line 11767 "parser_bison.c"
+ break;
+
+ case 534: /* log_arg: "level" level_type */
+#line 3370 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->log.level = (yyvsp[0].val);
+ (yyvsp[-2].stmt)->log.flags |= STMT_LOG_LEVEL;
+ }
+#line 11776 "parser_bison.c"
+ break;
+
+ case 535: /* log_arg: "flags" log_flags */
+#line 3375 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->log.logflags |= (yyvsp[0].val);
+ }
+#line 11784 "parser_bison.c"
+ break;
+
+ case 536: /* level_type: string */
+#line 3381 "parser_bison.y"
+ {
+ if (!strcmp("emerg", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_EMERG;
+ else if (!strcmp("alert", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_ALERT;
+ else if (!strcmp("crit", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_CRIT;
+ else if (!strcmp("err", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_ERR;
+ else if (!strcmp("warn", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_WARNING;
+ else if (!strcmp("notice", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_NOTICE;
+ else if (!strcmp("info", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_INFO;
+ else if (!strcmp("debug", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_DEBUG;
+ else if (!strcmp("audit", (yyvsp[0].string)))
+ (yyval.val) = NFT_LOGLEVEL_AUDIT;
+ else {
+ erec_queue(error(&(yylsp[0]), "invalid log level"),
+ state->msgs);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ xfree((yyvsp[0].string));
+ }
+#line 11816 "parser_bison.c"
+ break;
+
+ case 537: /* log_flags: "tcp" log_flags_tcp close_scope_tcp */
+#line 3411 "parser_bison.y"
+ {
+ (yyval.val) = (yyvsp[-1].val);
+ }
+#line 11824 "parser_bison.c"
+ break;
+
+ case 538: /* log_flags: "ip" "options" close_scope_ip */
+#line 3415 "parser_bison.y"
+ {
+ (yyval.val) = NF_LOG_IPOPT;
+ }
+#line 11832 "parser_bison.c"
+ break;
+
+ case 539: /* log_flags: "skuid" */
+#line 3419 "parser_bison.y"
+ {
+ (yyval.val) = NF_LOG_UID;
+ }
+#line 11840 "parser_bison.c"
+ break;
+
+ case 540: /* log_flags: "ether" close_scope_eth */
+#line 3423 "parser_bison.y"
+ {
+ (yyval.val) = NF_LOG_MACDECODE;
+ }
+#line 11848 "parser_bison.c"
+ break;
+
+ case 541: /* log_flags: "all" */
+#line 3427 "parser_bison.y"
+ {
+ (yyval.val) = NF_LOG_MASK;
+ }
+#line 11856 "parser_bison.c"
+ break;
+
+ case 542: /* log_flags_tcp: log_flags_tcp "comma" log_flag_tcp */
+#line 3433 "parser_bison.y"
+ {
+ (yyval.val) = (yyvsp[-2].val) | (yyvsp[0].val);
+ }
+#line 11864 "parser_bison.c"
+ break;
+
+ case 544: /* log_flag_tcp: "seq" */
+#line 3440 "parser_bison.y"
+ {
+ (yyval.val) = NF_LOG_TCPSEQ;
+ }
+#line 11872 "parser_bison.c"
+ break;
+
+ case 545: /* log_flag_tcp: "options" */
+#line 3444 "parser_bison.y"
+ {
+ (yyval.val) = NF_LOG_TCPOPT;
+ }
+#line 11880 "parser_bison.c"
+ break;
+
+ case 546: /* limit_stmt: "limit" "rate" limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit */
+#line 3450 "parser_bison.y"
+ {
+ if ((yyvsp[-1].val) == 0) {
+ erec_queue(error(&(yylsp[-1]), "packet limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ (yyval.stmt) = limit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->limit.rate = (yyvsp[-2].limit_rate).rate;
+ (yyval.stmt)->limit.unit = (yyvsp[-2].limit_rate).unit;
+ (yyval.stmt)->limit.burst = (yyvsp[-1].val);
+ (yyval.stmt)->limit.type = NFT_LIMIT_PKTS;
+ (yyval.stmt)->limit.flags = (yyvsp[-3].val);
+ }
+#line 11898 "parser_bison.c"
+ break;
+
+ case 547: /* limit_stmt: "limit" "rate" limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit */
+#line 3464 "parser_bison.y"
+ {
+ (yyval.stmt) = limit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->limit.rate = (yyvsp[-2].limit_rate).rate;
+ (yyval.stmt)->limit.unit = (yyvsp[-2].limit_rate).unit;
+ (yyval.stmt)->limit.burst = (yyvsp[-1].val);
+ (yyval.stmt)->limit.type = NFT_LIMIT_PKT_BYTES;
+ (yyval.stmt)->limit.flags = (yyvsp[-3].val);
+ }
+#line 11911 "parser_bison.c"
+ break;
+
+ case 548: /* limit_stmt: "limit" "name" stmt_expr close_scope_limit */
+#line 3473 "parser_bison.y"
+ {
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_LIMIT;
+ (yyval.stmt)->objref.expr = (yyvsp[-1].expr);
+ }
+#line 11921 "parser_bison.c"
+ break;
+
+ case 549: /* quota_mode: "over" */
+#line 3480 "parser_bison.y"
+ { (yyval.val) = NFT_QUOTA_F_INV; }
+#line 11927 "parser_bison.c"
+ break;
+
+ case 550: /* quota_mode: "until" */
+#line 3481 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 11933 "parser_bison.c"
+ break;
+
+ case 551: /* quota_mode: %empty */
+#line 3482 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 11939 "parser_bison.c"
+ break;
+
+ case 552: /* quota_unit: "bytes" */
+#line 3485 "parser_bison.y"
+ { (yyval.string) = xstrdup("bytes"); }
+#line 11945 "parser_bison.c"
+ break;
+
+ case 553: /* quota_unit: "string" */
+#line 3486 "parser_bison.y"
+ { (yyval.string) = (yyvsp[0].string); }
+#line 11951 "parser_bison.c"
+ break;
+
+ case 554: /* quota_used: %empty */
+#line 3489 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 11957 "parser_bison.c"
+ break;
+
+ case 555: /* quota_used: "used" "number" quota_unit */
+#line 3491 "parser_bison.y"
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&(yyloc), (yyvsp[0].string), &rate);
+ xfree((yyvsp[0].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ (yyval.val) = (yyvsp[-1].val) * rate;
+ }
+#line 11974 "parser_bison.c"
+ break;
+
+ case 556: /* quota_stmt: "quota" quota_mode "number" quota_unit quota_used close_scope_quota */
+#line 3506 "parser_bison.y"
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&(yyloc), (yyvsp[-2].string), &rate);
+ xfree((yyvsp[-2].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ (yyval.stmt) = quota_stmt_alloc(&(yyloc));
+ (yyval.stmt)->quota.bytes = (yyvsp[-3].val) * rate;
+ (yyval.stmt)->quota.used = (yyvsp[-1].val);
+ (yyval.stmt)->quota.flags = (yyvsp[-4].val);
+ }
+#line 11994 "parser_bison.c"
+ break;
+
+ case 557: /* quota_stmt: "quota" "name" stmt_expr close_scope_quota */
+#line 3522 "parser_bison.y"
+ {
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_QUOTA;
+ (yyval.stmt)->objref.expr = (yyvsp[-1].expr);
+ }
+#line 12004 "parser_bison.c"
+ break;
+
+ case 558: /* limit_mode: "over" */
+#line 3529 "parser_bison.y"
+ { (yyval.val) = NFT_LIMIT_F_INV; }
+#line 12010 "parser_bison.c"
+ break;
+
+ case 559: /* limit_mode: "until" */
+#line 3530 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 12016 "parser_bison.c"
+ break;
+
+ case 560: /* limit_mode: %empty */
+#line 3531 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 12022 "parser_bison.c"
+ break;
+
+ case 561: /* limit_burst_pkts: %empty */
+#line 3534 "parser_bison.y"
+ { (yyval.val) = 5; }
+#line 12028 "parser_bison.c"
+ break;
+
+ case 562: /* limit_burst_pkts: "burst" "number" "packets" */
+#line 3535 "parser_bison.y"
+ { (yyval.val) = (yyvsp[-1].val); }
+#line 12034 "parser_bison.c"
+ break;
+
+ case 563: /* limit_rate_pkts: "number" "/" time_unit */
+#line 3539 "parser_bison.y"
+ {
+ (yyval.limit_rate).rate = (yyvsp[-2].val);
+ (yyval.limit_rate).unit = (yyvsp[0].val);
+ }
+#line 12043 "parser_bison.c"
+ break;
+
+ case 564: /* limit_burst_bytes: %empty */
+#line 3545 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 12049 "parser_bison.c"
+ break;
+
+ case 565: /* limit_burst_bytes: "burst" limit_bytes */
+#line 3546 "parser_bison.y"
+ { (yyval.val) = (yyvsp[0].val); }
+#line 12055 "parser_bison.c"
+ break;
+
+ case 566: /* limit_rate_bytes: "number" "string" */
+#line 3550 "parser_bison.y"
+ {
+ struct error_record *erec;
+ uint64_t rate, unit;
+
+ erec = rate_parse(&(yyloc), (yyvsp[0].string), &rate, &unit);
+ xfree((yyvsp[0].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ (yyval.limit_rate).rate = rate * (yyvsp[-1].val);
+ (yyval.limit_rate).unit = unit;
+ }
+#line 12073 "parser_bison.c"
+ break;
+
+ case 567: /* limit_rate_bytes: limit_bytes "/" time_unit */
+#line 3564 "parser_bison.y"
+ {
+ (yyval.limit_rate).rate = (yyvsp[-2].val);
+ (yyval.limit_rate).unit = (yyvsp[0].val);
+ }
+#line 12082 "parser_bison.c"
+ break;
+
+ case 568: /* limit_bytes: "number" "bytes" */
+#line 3570 "parser_bison.y"
+ { (yyval.val) = (yyvsp[-1].val); }
+#line 12088 "parser_bison.c"
+ break;
+
+ case 569: /* limit_bytes: "number" "string" */
+#line 3572 "parser_bison.y"
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&(yyloc), (yyvsp[0].string), &rate);
+ xfree((yyvsp[0].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ (yyval.val) = (yyvsp[-1].val) * rate;
+ }
+#line 12105 "parser_bison.c"
+ break;
+
+ case 570: /* time_unit: "second" */
+#line 3586 "parser_bison.y"
+ { (yyval.val) = 1ULL; }
+#line 12111 "parser_bison.c"
+ break;
+
+ case 571: /* time_unit: "minute" */
+#line 3587 "parser_bison.y"
+ { (yyval.val) = 1ULL * 60; }
+#line 12117 "parser_bison.c"
+ break;
+
+ case 572: /* time_unit: "hour" */
+#line 3588 "parser_bison.y"
+ { (yyval.val) = 1ULL * 60 * 60; }
+#line 12123 "parser_bison.c"
+ break;
+
+ case 573: /* time_unit: "day" */
+#line 3589 "parser_bison.y"
+ { (yyval.val) = 1ULL * 60 * 60 * 24; }
+#line 12129 "parser_bison.c"
+ break;
+
+ case 574: /* time_unit: "week" */
+#line 3590 "parser_bison.y"
+ { (yyval.val) = 1ULL * 60 * 60 * 24 * 7; }
+#line 12135 "parser_bison.c"
+ break;
+
+ case 576: /* reject_stmt_alloc: "reject" */
+#line 3597 "parser_bison.y"
+ {
+ (yyval.stmt) = reject_stmt_alloc(&(yyloc));
+ }
+#line 12143 "parser_bison.c"
+ break;
+
+ case 577: /* reject_with_expr: "string" */
+#line 3603 "parser_bison.y"
+ {
+ (yyval.expr) = symbol_expr_alloc(&(yyloc), SYMBOL_VALUE,
+ current_scope(state), (yyvsp[0].string));
+ xfree((yyvsp[0].string));
+ }
+#line 12153 "parser_bison.c"
+ break;
+
+ case 578: /* reject_with_expr: integer_expr */
+#line 3608 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12159 "parser_bison.c"
+ break;
+
+ case 579: /* reject_opts: %empty */
+#line 3612 "parser_bison.y"
+ {
+ (yyvsp[0].stmt)->reject.type = -1;
+ (yyvsp[0].stmt)->reject.icmp_code = -1;
+ }
+#line 12168 "parser_bison.c"
+ break;
+
+ case 580: /* reject_opts: "with" "icmp" "type" reject_with_expr close_scope_type close_scope_icmp */
+#line 3617 "parser_bison.y"
+ {
+ (yyvsp[-6].stmt)->reject.family = NFPROTO_IPV4;
+ (yyvsp[-6].stmt)->reject.type = NFT_REJECT_ICMP_UNREACH;
+ (yyvsp[-6].stmt)->reject.expr = (yyvsp[-2].expr);
+ datatype_set((yyvsp[-6].stmt)->reject.expr, &icmp_code_type);
+ }
+#line 12179 "parser_bison.c"
+ break;
+
+ case 581: /* reject_opts: "with" "icmp" reject_with_expr */
+#line 3624 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->reject.family = NFPROTO_IPV4;
+ (yyvsp[-3].stmt)->reject.type = NFT_REJECT_ICMP_UNREACH;
+ (yyvsp[-3].stmt)->reject.expr = (yyvsp[0].expr);
+ datatype_set((yyvsp[-3].stmt)->reject.expr, &icmp_code_type);
+ }
+#line 12190 "parser_bison.c"
+ break;
+
+ case 582: /* reject_opts: "with" "icmpv6" "type" reject_with_expr close_scope_type close_scope_icmp */
+#line 3631 "parser_bison.y"
+ {
+ (yyvsp[-6].stmt)->reject.family = NFPROTO_IPV6;
+ (yyvsp[-6].stmt)->reject.type = NFT_REJECT_ICMP_UNREACH;
+ (yyvsp[-6].stmt)->reject.expr = (yyvsp[-2].expr);
+ datatype_set((yyvsp[-6].stmt)->reject.expr, &icmpv6_code_type);
+ }
+#line 12201 "parser_bison.c"
+ break;
+
+ case 583: /* reject_opts: "with" "icmpv6" reject_with_expr */
+#line 3638 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->reject.family = NFPROTO_IPV6;
+ (yyvsp[-3].stmt)->reject.type = NFT_REJECT_ICMP_UNREACH;
+ (yyvsp[-3].stmt)->reject.expr = (yyvsp[0].expr);
+ datatype_set((yyvsp[-3].stmt)->reject.expr, &icmpv6_code_type);
+ }
+#line 12212 "parser_bison.c"
+ break;
+
+ case 584: /* reject_opts: "with" "icmpx" "type" reject_with_expr close_scope_type */
+#line 3645 "parser_bison.y"
+ {
+ (yyvsp[-5].stmt)->reject.type = NFT_REJECT_ICMPX_UNREACH;
+ (yyvsp[-5].stmt)->reject.expr = (yyvsp[-1].expr);
+ datatype_set((yyvsp[-5].stmt)->reject.expr, &icmpx_code_type);
+ }
+#line 12222 "parser_bison.c"
+ break;
+
+ case 585: /* reject_opts: "with" "icmpx" reject_with_expr */
+#line 3651 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->reject.type = NFT_REJECT_ICMPX_UNREACH;
+ (yyvsp[-3].stmt)->reject.expr = (yyvsp[0].expr);
+ datatype_set((yyvsp[-3].stmt)->reject.expr, &icmpx_code_type);
+ }
+#line 12232 "parser_bison.c"
+ break;
+
+ case 586: /* reject_opts: "with" "tcp" close_scope_tcp "reset" close_scope_reset */
+#line 3657 "parser_bison.y"
+ {
+ (yyvsp[-5].stmt)->reject.type = NFT_REJECT_TCP_RST;
+ }
+#line 12240 "parser_bison.c"
+ break;
+
+ case 588: /* nat_stmt_alloc: "snat" */
+#line 3665 "parser_bison.y"
+ { (yyval.stmt) = nat_stmt_alloc(&(yyloc), __NFT_NAT_SNAT); }
+#line 12246 "parser_bison.c"
+ break;
+
+ case 589: /* nat_stmt_alloc: "dnat" */
+#line 3666 "parser_bison.y"
+ { (yyval.stmt) = nat_stmt_alloc(&(yyloc), __NFT_NAT_DNAT); }
+#line 12252 "parser_bison.c"
+ break;
+
+ case 590: /* tproxy_stmt: "tproxy" "to" stmt_expr */
+#line 3670 "parser_bison.y"
+ {
+ (yyval.stmt) = tproxy_stmt_alloc(&(yyloc));
+ (yyval.stmt)->tproxy.family = NFPROTO_UNSPEC;
+ (yyval.stmt)->tproxy.addr = (yyvsp[0].expr);
+ }
+#line 12262 "parser_bison.c"
+ break;
+
+ case 591: /* tproxy_stmt: "tproxy" nf_key_proto "to" stmt_expr */
+#line 3676 "parser_bison.y"
+ {
+ (yyval.stmt) = tproxy_stmt_alloc(&(yyloc));
+ (yyval.stmt)->tproxy.family = (yyvsp[-2].val);
+ (yyval.stmt)->tproxy.addr = (yyvsp[0].expr);
+ }
+#line 12272 "parser_bison.c"
+ break;
+
+ case 592: /* tproxy_stmt: "tproxy" "to" "colon" stmt_expr */
+#line 3682 "parser_bison.y"
+ {
+ (yyval.stmt) = tproxy_stmt_alloc(&(yyloc));
+ (yyval.stmt)->tproxy.family = NFPROTO_UNSPEC;
+ (yyval.stmt)->tproxy.port = (yyvsp[0].expr);
+ }
+#line 12282 "parser_bison.c"
+ break;
+
+ case 593: /* tproxy_stmt: "tproxy" "to" stmt_expr "colon" stmt_expr */
+#line 3688 "parser_bison.y"
+ {
+ (yyval.stmt) = tproxy_stmt_alloc(&(yyloc));
+ (yyval.stmt)->tproxy.family = NFPROTO_UNSPEC;
+ (yyval.stmt)->tproxy.addr = (yyvsp[-2].expr);
+ (yyval.stmt)->tproxy.port = (yyvsp[0].expr);
+ }
+#line 12293 "parser_bison.c"
+ break;
+
+ case 594: /* tproxy_stmt: "tproxy" nf_key_proto "to" stmt_expr "colon" stmt_expr */
+#line 3695 "parser_bison.y"
+ {
+ (yyval.stmt) = tproxy_stmt_alloc(&(yyloc));
+ (yyval.stmt)->tproxy.family = (yyvsp[-4].val);
+ (yyval.stmt)->tproxy.addr = (yyvsp[-2].expr);
+ (yyval.stmt)->tproxy.port = (yyvsp[0].expr);
+ }
+#line 12304 "parser_bison.c"
+ break;
+
+ case 595: /* tproxy_stmt: "tproxy" nf_key_proto "to" "colon" stmt_expr */
+#line 3702 "parser_bison.y"
+ {
+ (yyval.stmt) = tproxy_stmt_alloc(&(yyloc));
+ (yyval.stmt)->tproxy.family = (yyvsp[-3].val);
+ (yyval.stmt)->tproxy.port = (yyvsp[0].expr);
+ }
+#line 12314 "parser_bison.c"
+ break;
+
+ case 598: /* synproxy_stmt_alloc: "synproxy" */
+#line 3714 "parser_bison.y"
+ {
+ (yyval.stmt) = synproxy_stmt_alloc(&(yyloc));
+ }
+#line 12322 "parser_bison.c"
+ break;
+
+ case 599: /* synproxy_stmt_alloc: "synproxy" "name" stmt_expr */
+#line 3718 "parser_bison.y"
+ {
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_SYNPROXY;
+ (yyval.stmt)->objref.expr = (yyvsp[0].expr);
+ }
+#line 12332 "parser_bison.c"
+ break;
+
+ case 600: /* synproxy_args: synproxy_arg */
+#line 3726 "parser_bison.y"
+ {
+ (yyval.stmt) = (yyvsp[-1].stmt);
+ }
+#line 12340 "parser_bison.c"
+ break;
+
+ case 602: /* synproxy_arg: "mss" "number" */
+#line 3733 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->synproxy.mss = (yyvsp[0].val);
+ (yyvsp[-2].stmt)->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
+ }
+#line 12349 "parser_bison.c"
+ break;
+
+ case 603: /* synproxy_arg: "wscale" "number" */
+#line 3738 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->synproxy.wscale = (yyvsp[0].val);
+ (yyvsp[-2].stmt)->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
+ }
+#line 12358 "parser_bison.c"
+ break;
+
+ case 604: /* synproxy_arg: "timestamp" */
+#line 3743 "parser_bison.y"
+ {
+ (yyvsp[-1].stmt)->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP;
+ }
+#line 12366 "parser_bison.c"
+ break;
+
+ case 605: /* synproxy_arg: "sack-permitted" */
+#line 3747 "parser_bison.y"
+ {
+ (yyvsp[-1].stmt)->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM;
+ }
+#line 12374 "parser_bison.c"
+ break;
+
+ case 606: /* synproxy_config: "mss" "number" "wscale" "number" synproxy_ts synproxy_sack */
+#line 3753 "parser_bison.y"
+ {
+ struct synproxy *synproxy;
+ uint32_t flags = 0;
+
+ synproxy = &(yyvsp[-6].obj)->synproxy;
+ synproxy->mss = (yyvsp[-4].val);
+ flags |= NF_SYNPROXY_OPT_MSS;
+ synproxy->wscale = (yyvsp[-2].val);
+ flags |= NF_SYNPROXY_OPT_WSCALE;
+ if ((yyvsp[-1].val))
+ flags |= (yyvsp[-1].val);
+ if ((yyvsp[0].val))
+ flags |= (yyvsp[0].val);
+ synproxy->flags = flags;
+ }
+#line 12394 "parser_bison.c"
+ break;
+
+ case 607: /* synproxy_config: "mss" "number" stmt_separator "wscale" "number" stmt_separator synproxy_ts synproxy_sack */
+#line 3769 "parser_bison.y"
+ {
+ struct synproxy *synproxy;
+ uint32_t flags = 0;
+
+ synproxy = &(yyvsp[-8].obj)->synproxy;
+ synproxy->mss = (yyvsp[-6].val);
+ flags |= NF_SYNPROXY_OPT_MSS;
+ synproxy->wscale = (yyvsp[-3].val);
+ flags |= NF_SYNPROXY_OPT_WSCALE;
+ if ((yyvsp[-1].val))
+ flags |= (yyvsp[-1].val);
+ if ((yyvsp[0].val))
+ flags |= (yyvsp[0].val);
+ synproxy->flags = flags;
+ }
+#line 12414 "parser_bison.c"
+ break;
+
+ case 608: /* synproxy_obj: %empty */
+#line 3787 "parser_bison.y"
+ {
+ (yyval.obj) = obj_alloc(&(yyloc));
+ (yyval.obj)->type = NFT_OBJECT_SYNPROXY;
+ }
+#line 12423 "parser_bison.c"
+ break;
+
+ case 609: /* synproxy_ts: %empty */
+#line 3793 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 12429 "parser_bison.c"
+ break;
+
+ case 610: /* synproxy_ts: "timestamp" */
+#line 3795 "parser_bison.y"
+ {
+ (yyval.val) = NF_SYNPROXY_OPT_TIMESTAMP;
+ }
+#line 12437 "parser_bison.c"
+ break;
+
+ case 611: /* synproxy_sack: %empty */
+#line 3800 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 12443 "parser_bison.c"
+ break;
+
+ case 612: /* synproxy_sack: "sack-permitted" */
+#line 3802 "parser_bison.y"
+ {
+ (yyval.val) = NF_SYNPROXY_OPT_SACK_PERM;
+ }
+#line 12451 "parser_bison.c"
+ break;
+
+ case 613: /* primary_stmt_expr: symbol_expr */
+#line 3807 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12457 "parser_bison.c"
+ break;
+
+ case 614: /* primary_stmt_expr: integer_expr */
+#line 3808 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12463 "parser_bison.c"
+ break;
+
+ case 615: /* primary_stmt_expr: boolean_expr */
+#line 3809 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12469 "parser_bison.c"
+ break;
+
+ case 616: /* primary_stmt_expr: meta_expr */
+#line 3810 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12475 "parser_bison.c"
+ break;
+
+ case 617: /* primary_stmt_expr: rt_expr */
+#line 3811 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12481 "parser_bison.c"
+ break;
+
+ case 618: /* primary_stmt_expr: ct_expr */
+#line 3812 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12487 "parser_bison.c"
+ break;
+
+ case 619: /* primary_stmt_expr: numgen_expr */
+#line 3813 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12493 "parser_bison.c"
+ break;
+
+ case 620: /* primary_stmt_expr: hash_expr */
+#line 3814 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12499 "parser_bison.c"
+ break;
+
+ case 621: /* primary_stmt_expr: payload_expr */
+#line 3815 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12505 "parser_bison.c"
+ break;
+
+ case 622: /* primary_stmt_expr: keyword_expr */
+#line 3816 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12511 "parser_bison.c"
+ break;
+
+ case 623: /* primary_stmt_expr: socket_expr */
+#line 3817 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12517 "parser_bison.c"
+ break;
+
+ case 624: /* primary_stmt_expr: osf_expr */
+#line 3818 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12523 "parser_bison.c"
+ break;
+
+ case 625: /* primary_stmt_expr: '(' basic_stmt_expr ')' */
+#line 3819 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[-1].expr); }
+#line 12529 "parser_bison.c"
+ break;
+
+ case 627: /* shift_stmt_expr: shift_stmt_expr "<<" primary_stmt_expr */
+#line 3824 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_LSHIFT, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12537 "parser_bison.c"
+ break;
+
+ case 628: /* shift_stmt_expr: shift_stmt_expr ">>" primary_stmt_expr */
+#line 3828 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_RSHIFT, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12545 "parser_bison.c"
+ break;
+
+ case 630: /* and_stmt_expr: and_stmt_expr "&" shift_stmt_expr */
+#line 3835 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_AND, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12553 "parser_bison.c"
+ break;
+
+ case 632: /* exclusive_or_stmt_expr: exclusive_or_stmt_expr "^" and_stmt_expr */
+#line 3842 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_XOR, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12561 "parser_bison.c"
+ break;
+
+ case 634: /* inclusive_or_stmt_expr: inclusive_or_stmt_expr '|' exclusive_or_stmt_expr */
+#line 3849 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_OR, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12569 "parser_bison.c"
+ break;
+
+ case 637: /* concat_stmt_expr: concat_stmt_expr "." primary_stmt_expr */
+#line 3859 "parser_bison.y"
+ {
+ struct location rhs[] = {
+ [1] = (yylsp[-1]),
+ [2] = (yylsp[0]),
+ };
+
+ (yyval.expr) = handle_concat_expr(&(yyloc), (yyval.expr), (yyvsp[-2].expr), (yyvsp[0].expr), rhs);
+ }
+#line 12582 "parser_bison.c"
+ break;
+
+ case 640: /* map_stmt_expr: concat_stmt_expr "map" map_stmt_expr_set */
+#line 3874 "parser_bison.y"
+ {
+ (yyval.expr) = map_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12590 "parser_bison.c"
+ break;
+
+ case 641: /* map_stmt_expr: concat_stmt_expr */
+#line 3877 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 12596 "parser_bison.c"
+ break;
+
+ case 642: /* prefix_stmt_expr: basic_stmt_expr "/" "number" */
+#line 3881 "parser_bison.y"
+ {
+ (yyval.expr) = prefix_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].val));
+ }
+#line 12604 "parser_bison.c"
+ break;
+
+ case 643: /* range_stmt_expr: basic_stmt_expr "-" basic_stmt_expr */
+#line 3887 "parser_bison.y"
+ {
+ (yyval.expr) = range_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12612 "parser_bison.c"
+ break;
+
+ case 649: /* nat_stmt_args: stmt_expr */
+#line 3902 "parser_bison.y"
+ {
+ (yyvsp[-1].stmt)->nat.addr = (yyvsp[0].expr);
+ }
+#line 12620 "parser_bison.c"
+ break;
+
+ case 650: /* nat_stmt_args: "to" stmt_expr */
+#line 3906 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->nat.addr = (yyvsp[0].expr);
+ }
+#line 12628 "parser_bison.c"
+ break;
+
+ case 651: /* nat_stmt_args: nf_key_proto "to" stmt_expr */
+#line 3910 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.family = (yyvsp[-2].val);
+ (yyvsp[-3].stmt)->nat.addr = (yyvsp[0].expr);
+ }
+#line 12637 "parser_bison.c"
+ break;
+
+ case 652: /* nat_stmt_args: stmt_expr "colon" stmt_expr */
+#line 3915 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.addr = (yyvsp[-2].expr);
+ (yyvsp[-3].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12646 "parser_bison.c"
+ break;
+
+ case 653: /* nat_stmt_args: "to" stmt_expr "colon" stmt_expr */
+#line 3920 "parser_bison.y"
+ {
+ (yyvsp[-4].stmt)->nat.addr = (yyvsp[-2].expr);
+ (yyvsp[-4].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12655 "parser_bison.c"
+ break;
+
+ case 654: /* nat_stmt_args: nf_key_proto "to" stmt_expr "colon" stmt_expr */
+#line 3925 "parser_bison.y"
+ {
+ (yyvsp[-5].stmt)->nat.family = (yyvsp[-4].val);
+ (yyvsp[-5].stmt)->nat.addr = (yyvsp[-2].expr);
+ (yyvsp[-5].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12665 "parser_bison.c"
+ break;
+
+ case 655: /* nat_stmt_args: "colon" stmt_expr */
+#line 3931 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12673 "parser_bison.c"
+ break;
+
+ case 656: /* nat_stmt_args: "to" "colon" stmt_expr */
+#line 3935 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12681 "parser_bison.c"
+ break;
+
+ case 657: /* nat_stmt_args: nat_stmt_args nf_nat_flags */
+#line 3939 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->nat.flags = (yyvsp[0].val);
+ }
+#line 12689 "parser_bison.c"
+ break;
+
+ case 658: /* nat_stmt_args: nf_key_proto "addr" "." "port" "to" stmt_expr */
+#line 3943 "parser_bison.y"
+ {
+ (yyvsp[-6].stmt)->nat.family = (yyvsp[-5].val);
+ (yyvsp[-6].stmt)->nat.addr = (yyvsp[0].expr);
+ (yyvsp[-6].stmt)->nat.type_flags = STMT_NAT_F_CONCAT;
+ }
+#line 12699 "parser_bison.c"
+ break;
+
+ case 659: /* nat_stmt_args: nf_key_proto "interval" "to" stmt_expr */
+#line 3949 "parser_bison.y"
+ {
+ (yyvsp[-4].stmt)->nat.family = (yyvsp[-3].val);
+ (yyvsp[-4].stmt)->nat.addr = (yyvsp[0].expr);
+ }
+#line 12708 "parser_bison.c"
+ break;
+
+ case 660: /* nat_stmt_args: "interval" "to" stmt_expr */
+#line 3954 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.addr = (yyvsp[0].expr);
+ }
+#line 12716 "parser_bison.c"
+ break;
+
+ case 661: /* nat_stmt_args: nf_key_proto "prefix" "to" stmt_expr */
+#line 3958 "parser_bison.y"
+ {
+ (yyvsp[-4].stmt)->nat.family = (yyvsp[-3].val);
+ (yyvsp[-4].stmt)->nat.addr = (yyvsp[0].expr);
+ (yyvsp[-4].stmt)->nat.type_flags =
+ STMT_NAT_F_PREFIX;
+ (yyvsp[-4].stmt)->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
+#line 12728 "parser_bison.c"
+ break;
+
+ case 662: /* nat_stmt_args: "prefix" "to" stmt_expr */
+#line 3966 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.addr = (yyvsp[0].expr);
+ (yyvsp[-3].stmt)->nat.type_flags =
+ STMT_NAT_F_PREFIX;
+ (yyvsp[-3].stmt)->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
+#line 12739 "parser_bison.c"
+ break;
+
+ case 665: /* masq_stmt_alloc: "masquerade" */
+#line 3978 "parser_bison.y"
+ { (yyval.stmt) = nat_stmt_alloc(&(yyloc), NFT_NAT_MASQ); }
+#line 12745 "parser_bison.c"
+ break;
+
+ case 666: /* masq_stmt_args: "to" "colon" stmt_expr */
+#line 3982 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12753 "parser_bison.c"
+ break;
+
+ case 667: /* masq_stmt_args: "to" "colon" stmt_expr nf_nat_flags */
+#line 3986 "parser_bison.y"
+ {
+ (yyvsp[-4].stmt)->nat.proto = (yyvsp[-1].expr);
+ (yyvsp[-4].stmt)->nat.flags = (yyvsp[0].val);
+ }
+#line 12762 "parser_bison.c"
+ break;
+
+ case 668: /* masq_stmt_args: nf_nat_flags */
+#line 3991 "parser_bison.y"
+ {
+ (yyvsp[-1].stmt)->nat.flags = (yyvsp[0].val);
+ }
+#line 12770 "parser_bison.c"
+ break;
+
+ case 671: /* redir_stmt_alloc: "redirect" */
+#line 4000 "parser_bison.y"
+ { (yyval.stmt) = nat_stmt_alloc(&(yyloc), NFT_NAT_REDIR); }
+#line 12776 "parser_bison.c"
+ break;
+
+ case 672: /* redir_stmt_arg: "to" stmt_expr */
+#line 4004 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12784 "parser_bison.c"
+ break;
+
+ case 673: /* redir_stmt_arg: "to" "colon" stmt_expr */
+#line 4008 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.proto = (yyvsp[0].expr);
+ }
+#line 12792 "parser_bison.c"
+ break;
+
+ case 674: /* redir_stmt_arg: nf_nat_flags */
+#line 4012 "parser_bison.y"
+ {
+ (yyvsp[-1].stmt)->nat.flags = (yyvsp[0].val);
+ }
+#line 12800 "parser_bison.c"
+ break;
+
+ case 675: /* redir_stmt_arg: "to" stmt_expr nf_nat_flags */
+#line 4016 "parser_bison.y"
+ {
+ (yyvsp[-3].stmt)->nat.proto = (yyvsp[-1].expr);
+ (yyvsp[-3].stmt)->nat.flags = (yyvsp[0].val);
+ }
+#line 12809 "parser_bison.c"
+ break;
+
+ case 676: /* redir_stmt_arg: "to" "colon" stmt_expr nf_nat_flags */
+#line 4021 "parser_bison.y"
+ {
+ (yyvsp[-4].stmt)->nat.proto = (yyvsp[-1].expr);
+ (yyvsp[-4].stmt)->nat.flags = (yyvsp[0].val);
+ }
+#line 12818 "parser_bison.c"
+ break;
+
+ case 677: /* dup_stmt: "dup" "to" stmt_expr */
+#line 4028 "parser_bison.y"
+ {
+ (yyval.stmt) = dup_stmt_alloc(&(yyloc));
+ (yyval.stmt)->dup.to = (yyvsp[0].expr);
+ }
+#line 12827 "parser_bison.c"
+ break;
+
+ case 678: /* dup_stmt: "dup" "to" stmt_expr "device" stmt_expr */
+#line 4033 "parser_bison.y"
+ {
+ (yyval.stmt) = dup_stmt_alloc(&(yyloc));
+ (yyval.stmt)->dup.to = (yyvsp[-2].expr);
+ (yyval.stmt)->dup.dev = (yyvsp[0].expr);
+ }
+#line 12837 "parser_bison.c"
+ break;
+
+ case 679: /* fwd_stmt: "fwd" "to" stmt_expr */
+#line 4041 "parser_bison.y"
+ {
+ (yyval.stmt) = fwd_stmt_alloc(&(yyloc));
+ (yyval.stmt)->fwd.dev = (yyvsp[0].expr);
+ }
+#line 12846 "parser_bison.c"
+ break;
+
+ case 680: /* fwd_stmt: "fwd" nf_key_proto "to" stmt_expr "device" stmt_expr */
+#line 4046 "parser_bison.y"
+ {
+ (yyval.stmt) = fwd_stmt_alloc(&(yyloc));
+ (yyval.stmt)->fwd.family = (yyvsp[-4].val);
+ (yyval.stmt)->fwd.addr = (yyvsp[-2].expr);
+ (yyval.stmt)->fwd.dev = (yyvsp[0].expr);
+ }
+#line 12857 "parser_bison.c"
+ break;
+
+ case 682: /* nf_nat_flags: nf_nat_flags "comma" nf_nat_flag */
+#line 4056 "parser_bison.y"
+ {
+ (yyval.val) = (yyvsp[-2].val) | (yyvsp[0].val);
+ }
+#line 12865 "parser_bison.c"
+ break;
+
+ case 683: /* nf_nat_flag: "random" */
+#line 4061 "parser_bison.y"
+ { (yyval.val) = NF_NAT_RANGE_PROTO_RANDOM; }
+#line 12871 "parser_bison.c"
+ break;
+
+ case 684: /* nf_nat_flag: "fully-random" */
+#line 4062 "parser_bison.y"
+ { (yyval.val) = NF_NAT_RANGE_PROTO_RANDOM_FULLY; }
+#line 12877 "parser_bison.c"
+ break;
+
+ case 685: /* nf_nat_flag: "persistent" */
+#line 4063 "parser_bison.y"
+ { (yyval.val) = NF_NAT_RANGE_PERSISTENT; }
+#line 12883 "parser_bison.c"
+ break;
+
+ case 687: /* queue_stmt: "queue" "to" queue_stmt_expr close_scope_queue */
+#line 4068 "parser_bison.y"
+ {
+ (yyval.stmt) = queue_stmt_alloc(&(yyloc), (yyvsp[-1].expr), 0);
+ }
+#line 12891 "parser_bison.c"
+ break;
+
+ case 688: /* queue_stmt: "queue" "flags" queue_stmt_flags "to" queue_stmt_expr close_scope_queue */
+#line 4072 "parser_bison.y"
+ {
+ (yyval.stmt) = queue_stmt_alloc(&(yyloc), (yyvsp[-1].expr), (yyvsp[-3].val));
+ }
+#line 12899 "parser_bison.c"
+ break;
+
+ case 689: /* queue_stmt: "queue" "flags" queue_stmt_flags "num" queue_stmt_expr_simple close_scope_queue */
+#line 4076 "parser_bison.y"
+ {
+ (yyval.stmt) = queue_stmt_alloc(&(yyloc), (yyvsp[-1].expr), (yyvsp[-3].val));
+ }
+#line 12907 "parser_bison.c"
+ break;
+
+ case 692: /* queue_stmt_alloc: "queue" */
+#line 4086 "parser_bison.y"
+ {
+ (yyval.stmt) = queue_stmt_alloc(&(yyloc), NULL, 0);
+ }
+#line 12915 "parser_bison.c"
+ break;
+
+ case 693: /* queue_stmt_args: queue_stmt_arg */
+#line 4092 "parser_bison.y"
+ {
+ (yyval.stmt) = (yyvsp[-1].stmt);
+ }
+#line 12923 "parser_bison.c"
+ break;
+
+ case 695: /* queue_stmt_arg: "num" queue_stmt_expr_simple */
+#line 4099 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->queue.queue = (yyvsp[0].expr);
+ (yyvsp[-2].stmt)->queue.queue->location = (yyloc);
+ }
+#line 12932 "parser_bison.c"
+ break;
+
+ case 696: /* queue_stmt_arg: queue_stmt_flags */
+#line 4104 "parser_bison.y"
+ {
+ (yyvsp[-1].stmt)->queue.flags |= (yyvsp[0].val);
+ }
+#line 12940 "parser_bison.c"
+ break;
+
+ case 701: /* queue_stmt_expr_simple: queue_expr "-" queue_expr */
+#line 4116 "parser_bison.y"
+ {
+ (yyval.expr) = range_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 12948 "parser_bison.c"
+ break;
+
+ case 707: /* queue_stmt_flags: queue_stmt_flags "comma" queue_stmt_flag */
+#line 4129 "parser_bison.y"
+ {
+ (yyval.val) = (yyvsp[-2].val) | (yyvsp[0].val);
+ }
+#line 12956 "parser_bison.c"
+ break;
+
+ case 708: /* queue_stmt_flag: "bypass" */
+#line 4134 "parser_bison.y"
+ { (yyval.val) = NFT_QUEUE_FLAG_BYPASS; }
+#line 12962 "parser_bison.c"
+ break;
+
+ case 709: /* queue_stmt_flag: "fanout" */
+#line 4135 "parser_bison.y"
+ { (yyval.val) = NFT_QUEUE_FLAG_CPU_FANOUT; }
+#line 12968 "parser_bison.c"
+ break;
+
+ case 712: /* set_elem_expr_stmt_alloc: concat_expr */
+#line 4143 "parser_bison.y"
+ {
+ (yyval.expr) = set_elem_expr_alloc(&(yylsp[0]), (yyvsp[0].expr));
+ }
+#line 12976 "parser_bison.c"
+ break;
+
+ case 713: /* set_stmt: "set" set_stmt_op set_elem_expr_stmt set_ref_expr */
+#line 4149 "parser_bison.y"
+ {
+ (yyval.stmt) = set_stmt_alloc(&(yyloc));
+ (yyval.stmt)->set.op = (yyvsp[-2].val);
+ (yyval.stmt)->set.key = (yyvsp[-1].expr);
+ (yyval.stmt)->set.set = (yyvsp[0].expr);
+ }
+#line 12987 "parser_bison.c"
+ break;
+
+ case 714: /* set_stmt: set_stmt_op set_ref_expr '{' set_elem_expr_stmt '}' */
+#line 4156 "parser_bison.y"
+ {
+ (yyval.stmt) = set_stmt_alloc(&(yyloc));
+ (yyval.stmt)->set.op = (yyvsp[-4].val);
+ (yyval.stmt)->set.key = (yyvsp[-1].expr);
+ (yyval.stmt)->set.set = (yyvsp[-3].expr);
+ }
+#line 12998 "parser_bison.c"
+ break;
+
+ case 715: /* set_stmt: set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list '}' */
+#line 4163 "parser_bison.y"
+ {
+ (yyval.stmt) = set_stmt_alloc(&(yyloc));
+ (yyval.stmt)->set.op = (yyvsp[-5].val);
+ (yyval.stmt)->set.key = (yyvsp[-2].expr);
+ (yyval.stmt)->set.set = (yyvsp[-4].expr);
+ list_splice_tail((yyvsp[-1].list), &(yyval.stmt)->set.stmt_list);
+ free((yyvsp[-1].list));
+ }
+#line 13011 "parser_bison.c"
+ break;
+
+ case 716: /* set_stmt_op: "add" */
+#line 4173 "parser_bison.y"
+ { (yyval.val) = NFT_DYNSET_OP_ADD; }
+#line 13017 "parser_bison.c"
+ break;
+
+ case 717: /* set_stmt_op: "update" */
+#line 4174 "parser_bison.y"
+ { (yyval.val) = NFT_DYNSET_OP_UPDATE; }
+#line 13023 "parser_bison.c"
+ break;
+
+ case 718: /* set_stmt_op: "delete" */
+#line 4175 "parser_bison.y"
+ { (yyval.val) = NFT_DYNSET_OP_DELETE; }
+#line 13029 "parser_bison.c"
+ break;
+
+ case 719: /* map_stmt: set_stmt_op set_ref_expr '{' set_elem_expr_stmt "colon" set_elem_expr_stmt '}' */
+#line 4179 "parser_bison.y"
+ {
+ (yyval.stmt) = map_stmt_alloc(&(yyloc));
+ (yyval.stmt)->map.op = (yyvsp[-6].val);
+ (yyval.stmt)->map.key = (yyvsp[-3].expr);
+ (yyval.stmt)->map.data = (yyvsp[-1].expr);
+ (yyval.stmt)->map.set = (yyvsp[-5].expr);
+ }
+#line 13041 "parser_bison.c"
+ break;
+
+ case 720: /* map_stmt: set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list "colon" set_elem_expr_stmt '}' */
+#line 4187 "parser_bison.y"
+ {
+ (yyval.stmt) = map_stmt_alloc(&(yyloc));
+ (yyval.stmt)->map.op = (yyvsp[-7].val);
+ (yyval.stmt)->map.key = (yyvsp[-4].expr);
+ (yyval.stmt)->map.data = (yyvsp[-1].expr);
+ (yyval.stmt)->map.set = (yyvsp[-6].expr);
+ list_splice_tail((yyvsp[-3].list), &(yyval.stmt)->map.stmt_list);
+ free((yyvsp[-3].list));
+ }
+#line 13055 "parser_bison.c"
+ break;
+
+ case 721: /* meter_stmt: flow_stmt_legacy_alloc flow_stmt_opts '{' meter_key_expr stmt '}' */
+#line 4199 "parser_bison.y"
+ {
+ (yyvsp[-5].stmt)->meter.key = (yyvsp[-2].expr);
+ (yyvsp[-5].stmt)->meter.stmt = (yyvsp[-1].stmt);
+ (yyval.stmt)->location = (yyloc);
+ (yyval.stmt) = (yyvsp[-5].stmt);
+ }
+#line 13066 "parser_bison.c"
+ break;
+
+ case 722: /* meter_stmt: meter_stmt_alloc */
+#line 4205 "parser_bison.y"
+ { (yyval.stmt) = (yyvsp[0].stmt); }
+#line 13072 "parser_bison.c"
+ break;
+
+ case 723: /* flow_stmt_legacy_alloc: "flow" */
+#line 4209 "parser_bison.y"
+ {
+ (yyval.stmt) = meter_stmt_alloc(&(yyloc));
+ }
+#line 13080 "parser_bison.c"
+ break;
+
+ case 724: /* flow_stmt_opts: flow_stmt_opt */
+#line 4215 "parser_bison.y"
+ {
+ (yyval.stmt) = (yyvsp[-1].stmt);
+ }
+#line 13088 "parser_bison.c"
+ break;
+
+ case 726: /* flow_stmt_opt: "table" identifier */
+#line 4222 "parser_bison.y"
+ {
+ (yyvsp[-2].stmt)->meter.name = (yyvsp[0].string);
+ }
+#line 13096 "parser_bison.c"
+ break;
+
+ case 727: /* meter_stmt_alloc: "meter" identifier '{' meter_key_expr stmt '}' */
+#line 4228 "parser_bison.y"
+ {
+ (yyval.stmt) = meter_stmt_alloc(&(yyloc));
+ (yyval.stmt)->meter.name = (yyvsp[-4].string);
+ (yyval.stmt)->meter.size = 0;
+ (yyval.stmt)->meter.key = (yyvsp[-2].expr);
+ (yyval.stmt)->meter.stmt = (yyvsp[-1].stmt);
+ (yyval.stmt)->location = (yyloc);
+ }
+#line 13109 "parser_bison.c"
+ break;
+
+ case 728: /* meter_stmt_alloc: "meter" identifier "size" "number" '{' meter_key_expr stmt '}' */
+#line 4237 "parser_bison.y"
+ {
+ (yyval.stmt) = meter_stmt_alloc(&(yyloc));
+ (yyval.stmt)->meter.name = (yyvsp[-6].string);
+ (yyval.stmt)->meter.size = (yyvsp[-4].val);
+ (yyval.stmt)->meter.key = (yyvsp[-2].expr);
+ (yyval.stmt)->meter.stmt = (yyvsp[-1].stmt);
+ (yyval.stmt)->location = (yyloc);
+ }
+#line 13122 "parser_bison.c"
+ break;
+
+ case 729: /* match_stmt: relational_expr */
+#line 4248 "parser_bison.y"
+ {
+ (yyval.stmt) = expr_stmt_alloc(&(yyloc), (yyvsp[0].expr));
+ }
+#line 13130 "parser_bison.c"
+ break;
+
+ case 730: /* variable_expr: '$' identifier */
+#line 4254 "parser_bison.y"
+ {
+ struct scope *scope = current_scope(state);
+ struct symbol *sym;
+
+ sym = symbol_get(scope, (yyvsp[0].string));
+ if (!sym) {
+ sym = symbol_lookup_fuzzy(scope, (yyvsp[0].string));
+ if (sym) {
+ erec_queue(error(&(yylsp[0]), "unknown identifier '%s'; "
+ "did you mean identifier ‘%s’?",
+ (yyvsp[0].string), sym->identifier),
+ state->msgs);
+ } else {
+ erec_queue(error(&(yylsp[0]), "unknown identifier '%s'", (yyvsp[0].string)),
+ state->msgs);
+ }
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+
+ (yyval.expr) = variable_expr_alloc(&(yyloc), scope, sym);
+ xfree((yyvsp[0].string));
+ }
+#line 13158 "parser_bison.c"
+ break;
+
+ case 732: /* symbol_expr: string */
+#line 4281 "parser_bison.y"
+ {
+ (yyval.expr) = symbol_expr_alloc(&(yyloc), SYMBOL_VALUE,
+ current_scope(state),
+ (yyvsp[0].string));
+ xfree((yyvsp[0].string));
+ }
+#line 13169 "parser_bison.c"
+ break;
+
+ case 735: /* set_ref_symbol_expr: "@" identifier close_scope_at */
+#line 4294 "parser_bison.y"
+ {
+ (yyval.expr) = symbol_expr_alloc(&(yyloc), SYMBOL_SET,
+ current_scope(state),
+ (yyvsp[-1].string));
+ xfree((yyvsp[-1].string));
+ }
+#line 13180 "parser_bison.c"
+ break;
+
+ case 736: /* integer_expr: "number" */
+#line 4303 "parser_bison.y"
+ {
+ char str[64];
+
+ snprintf(str, sizeof(str), "%" PRIu64, (yyvsp[0].val));
+ (yyval.expr) = symbol_expr_alloc(&(yyloc), SYMBOL_VALUE,
+ current_scope(state),
+ str);
+ }
+#line 13193 "parser_bison.c"
+ break;
+
+ case 737: /* primary_expr: symbol_expr */
+#line 4313 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13199 "parser_bison.c"
+ break;
+
+ case 738: /* primary_expr: integer_expr */
+#line 4314 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13205 "parser_bison.c"
+ break;
+
+ case 739: /* primary_expr: payload_expr */
+#line 4315 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13211 "parser_bison.c"
+ break;
+
+ case 740: /* primary_expr: exthdr_expr */
+#line 4316 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13217 "parser_bison.c"
+ break;
+
+ case 741: /* primary_expr: exthdr_exists_expr */
+#line 4317 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13223 "parser_bison.c"
+ break;
+
+ case 742: /* primary_expr: meta_expr */
+#line 4318 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13229 "parser_bison.c"
+ break;
+
+ case 743: /* primary_expr: socket_expr */
+#line 4319 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13235 "parser_bison.c"
+ break;
+
+ case 744: /* primary_expr: rt_expr */
+#line 4320 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13241 "parser_bison.c"
+ break;
+
+ case 745: /* primary_expr: ct_expr */
+#line 4321 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13247 "parser_bison.c"
+ break;
+
+ case 746: /* primary_expr: numgen_expr */
+#line 4322 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13253 "parser_bison.c"
+ break;
+
+ case 747: /* primary_expr: hash_expr */
+#line 4323 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13259 "parser_bison.c"
+ break;
+
+ case 748: /* primary_expr: fib_expr */
+#line 4324 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13265 "parser_bison.c"
+ break;
+
+ case 749: /* primary_expr: osf_expr */
+#line 4325 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13271 "parser_bison.c"
+ break;
+
+ case 750: /* primary_expr: xfrm_expr */
+#line 4326 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13277 "parser_bison.c"
+ break;
+
+ case 751: /* primary_expr: '(' basic_expr ')' */
+#line 4327 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[-1].expr); }
+#line 13283 "parser_bison.c"
+ break;
+
+ case 752: /* fib_expr: "fib" fib_tuple fib_result close_scope_fib */
+#line 4331 "parser_bison.y"
+ {
+ if (((yyvsp[-2].val) & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) {
+ erec_queue(error(&(yylsp[-2]), "fib: need either saddr or daddr"), state->msgs);
+ YYERROR;
+ }
+
+ if (((yyvsp[-2].val) & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) ==
+ (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) {
+ erec_queue(error(&(yylsp[-2]), "fib: saddr and daddr are mutually exclusive"), state->msgs);
+ YYERROR;
+ }
+
+ if (((yyvsp[-2].val) & (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) ==
+ (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) {
+ erec_queue(error(&(yylsp[-2]), "fib: iif and oif are mutually exclusive"), state->msgs);
+ YYERROR;
+ }
+
+ (yyval.expr) = fib_expr_alloc(&(yyloc), (yyvsp[-2].val), (yyvsp[-1].val));
+ }
+#line 13308 "parser_bison.c"
+ break;
+
+ case 753: /* fib_result: "oif" */
+#line 4353 "parser_bison.y"
+ { (yyval.val) =NFT_FIB_RESULT_OIF; }
+#line 13314 "parser_bison.c"
+ break;
+
+ case 754: /* fib_result: "oifname" */
+#line 4354 "parser_bison.y"
+ { (yyval.val) =NFT_FIB_RESULT_OIFNAME; }
+#line 13320 "parser_bison.c"
+ break;
+
+ case 755: /* fib_result: "type" close_scope_type */
+#line 4355 "parser_bison.y"
+ { (yyval.val) =NFT_FIB_RESULT_ADDRTYPE; }
+#line 13326 "parser_bison.c"
+ break;
+
+ case 756: /* fib_flag: "saddr" */
+#line 4358 "parser_bison.y"
+ { (yyval.val) = NFTA_FIB_F_SADDR; }
+#line 13332 "parser_bison.c"
+ break;
+
+ case 757: /* fib_flag: "daddr" */
+#line 4359 "parser_bison.y"
+ { (yyval.val) = NFTA_FIB_F_DADDR; }
+#line 13338 "parser_bison.c"
+ break;
+
+ case 758: /* fib_flag: "mark" */
+#line 4360 "parser_bison.y"
+ { (yyval.val) = NFTA_FIB_F_MARK; }
+#line 13344 "parser_bison.c"
+ break;
+
+ case 759: /* fib_flag: "iif" */
+#line 4361 "parser_bison.y"
+ { (yyval.val) = NFTA_FIB_F_IIF; }
+#line 13350 "parser_bison.c"
+ break;
+
+ case 760: /* fib_flag: "oif" */
+#line 4362 "parser_bison.y"
+ { (yyval.val) = NFTA_FIB_F_OIF; }
+#line 13356 "parser_bison.c"
+ break;
+
+ case 761: /* fib_tuple: fib_flag "." fib_tuple */
+#line 4366 "parser_bison.y"
+ {
+ (yyval.val) = (yyvsp[-2].val) | (yyvsp[0].val);
+ }
+#line 13364 "parser_bison.c"
+ break;
+
+ case 763: /* osf_expr: "osf" osf_ttl "version" close_scope_osf */
+#line 4373 "parser_bison.y"
+ {
+ (yyval.expr) = osf_expr_alloc(&(yyloc), (yyvsp[-2].val), NFT_OSF_F_VERSION);
+ }
+#line 13372 "parser_bison.c"
+ break;
+
+ case 764: /* osf_expr: "osf" osf_ttl "name" close_scope_osf */
+#line 4377 "parser_bison.y"
+ {
+ (yyval.expr) = osf_expr_alloc(&(yyloc), (yyvsp[-2].val), 0);
+ }
+#line 13380 "parser_bison.c"
+ break;
+
+ case 765: /* osf_ttl: %empty */
+#line 4383 "parser_bison.y"
+ {
+ (yyval.val) = NF_OSF_TTL_TRUE;
+ }
+#line 13388 "parser_bison.c"
+ break;
+
+ case 766: /* osf_ttl: "ttl" "string" */
+#line 4387 "parser_bison.y"
+ {
+ if (!strcmp((yyvsp[0].string), "loose"))
+ (yyval.val) = NF_OSF_TTL_LESS;
+ else if (!strcmp((yyvsp[0].string), "skip"))
+ (yyval.val) = NF_OSF_TTL_NOCHECK;
+ else {
+ erec_queue(error(&(yylsp[0]), "invalid ttl option"),
+ state->msgs);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ xfree((yyvsp[0].string));
+ }
+#line 13406 "parser_bison.c"
+ break;
+
+ case 768: /* shift_expr: shift_expr "<<" primary_rhs_expr */
+#line 4404 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_LSHIFT, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 13414 "parser_bison.c"
+ break;
+
+ case 769: /* shift_expr: shift_expr ">>" primary_rhs_expr */
+#line 4408 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_RSHIFT, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 13422 "parser_bison.c"
+ break;
+
+ case 771: /* and_expr: and_expr "&" shift_rhs_expr */
+#line 4415 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_AND, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 13430 "parser_bison.c"
+ break;
+
+ case 773: /* exclusive_or_expr: exclusive_or_expr "^" and_rhs_expr */
+#line 4422 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_XOR, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 13438 "parser_bison.c"
+ break;
+
+ case 775: /* inclusive_or_expr: inclusive_or_expr '|' exclusive_or_rhs_expr */
+#line 4429 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_OR, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 13446 "parser_bison.c"
+ break;
+
+ case 778: /* concat_expr: concat_expr "." basic_expr */
+#line 4439 "parser_bison.y"
+ {
+ struct location rhs[] = {
+ [1] = (yylsp[-1]),
+ [2] = (yylsp[0]),
+ };
+
+ (yyval.expr) = handle_concat_expr(&(yyloc), (yyval.expr), (yyvsp[-2].expr), (yyvsp[0].expr), rhs);
+ }
+#line 13459 "parser_bison.c"
+ break;
+
+ case 779: /* prefix_rhs_expr: basic_rhs_expr "/" "number" */
+#line 4450 "parser_bison.y"
+ {
+ (yyval.expr) = prefix_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].val));
+ }
+#line 13467 "parser_bison.c"
+ break;
+
+ case 780: /* range_rhs_expr: basic_rhs_expr "-" basic_rhs_expr */
+#line 4456 "parser_bison.y"
+ {
+ (yyval.expr) = range_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 13475 "parser_bison.c"
+ break;
+
+ case 783: /* map_expr: concat_expr "map" rhs_expr */
+#line 4466 "parser_bison.y"
+ {
+ (yyval.expr) = map_expr_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 13483 "parser_bison.c"
+ break;
+
+ case 787: /* set_expr: '{' set_list_expr '}' */
+#line 4477 "parser_bison.y"
+ {
+ (yyvsp[-1].expr)->location = (yyloc);
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 13492 "parser_bison.c"
+ break;
+
+ case 788: /* set_list_expr: set_list_member_expr */
+#line 4484 "parser_bison.y"
+ {
+ (yyval.expr) = set_expr_alloc(&(yyloc), NULL);
+ compound_expr_add((yyval.expr), (yyvsp[0].expr));
+ }
+#line 13501 "parser_bison.c"
+ break;
+
+ case 789: /* set_list_expr: set_list_expr "comma" set_list_member_expr */
+#line 4489 "parser_bison.y"
+ {
+ compound_expr_add((yyvsp[-2].expr), (yyvsp[0].expr));
+ (yyval.expr) = (yyvsp[-2].expr);
+ }
+#line 13510 "parser_bison.c"
+ break;
+
+ case 791: /* set_list_member_expr: opt_newline set_expr opt_newline */
+#line 4497 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 13518 "parser_bison.c"
+ break;
+
+ case 792: /* set_list_member_expr: opt_newline set_elem_expr opt_newline */
+#line 4501 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 13526 "parser_bison.c"
+ break;
+
+ case 793: /* set_list_member_expr: opt_newline set_elem_expr "colon" set_rhs_expr opt_newline */
+#line 4505 "parser_bison.y"
+ {
+ (yyval.expr) = mapping_expr_alloc(&(yylsp[-3]), (yyvsp[-3].expr), (yyvsp[-1].expr));
+ }
+#line 13534 "parser_bison.c"
+ break;
+
+ case 795: /* meter_key_expr: meter_key_expr_alloc set_elem_options */
+#line 4512 "parser_bison.y"
+ {
+ (yyval.expr)->location = (yyloc);
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 13543 "parser_bison.c"
+ break;
+
+ case 796: /* meter_key_expr_alloc: concat_expr */
+#line 4519 "parser_bison.y"
+ {
+ (yyval.expr) = set_elem_expr_alloc(&(yylsp[0]), (yyvsp[0].expr));
+ }
+#line 13551 "parser_bison.c"
+ break;
+
+ case 799: /* set_elem_key_expr: set_lhs_expr */
+#line 4528 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 13557 "parser_bison.c"
+ break;
+
+ case 800: /* set_elem_key_expr: "*" */
+#line 4529 "parser_bison.y"
+ { (yyval.expr) = set_elem_catchall_expr_alloc(&(yylsp[0])); }
+#line 13563 "parser_bison.c"
+ break;
+
+ case 801: /* set_elem_expr_alloc: set_elem_key_expr set_elem_stmt_list */
+#line 4533 "parser_bison.y"
+ {
+ (yyval.expr) = set_elem_expr_alloc(&(yylsp[-1]), (yyvsp[-1].expr));
+ list_splice_tail((yyvsp[0].list), &(yyval.expr)->stmt_list);
+ xfree((yyvsp[0].list));
+ }
+#line 13573 "parser_bison.c"
+ break;
+
+ case 802: /* set_elem_expr_alloc: set_elem_key_expr */
+#line 4539 "parser_bison.y"
+ {
+ (yyval.expr) = set_elem_expr_alloc(&(yylsp[0]), (yyvsp[0].expr));
+ }
+#line 13581 "parser_bison.c"
+ break;
+
+ case 803: /* set_elem_options: set_elem_option */
+#line 4545 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 13589 "parser_bison.c"
+ break;
+
+ case 805: /* set_elem_option: "timeout" time_spec */
+#line 4552 "parser_bison.y"
+ {
+ (yyvsp[-2].expr)->timeout = (yyvsp[0].val);
+ }
+#line 13597 "parser_bison.c"
+ break;
+
+ case 806: /* set_elem_option: "expires" time_spec */
+#line 4556 "parser_bison.y"
+ {
+ (yyvsp[-2].expr)->expiration = (yyvsp[0].val);
+ }
+#line 13605 "parser_bison.c"
+ break;
+
+ case 807: /* set_elem_option: comment_spec */
+#line 4560 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].expr)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].expr)->comment = (yyvsp[0].string);
+ }
+#line 13617 "parser_bison.c"
+ break;
+
+ case 808: /* set_elem_expr_options: set_elem_expr_option */
+#line 4570 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[-1].expr);
+ }
+#line 13625 "parser_bison.c"
+ break;
+
+ case 810: /* set_elem_stmt_list: set_elem_stmt */
+#line 4577 "parser_bison.y"
+ {
+ (yyval.list) = xmalloc(sizeof(*(yyval.list)));
+ init_list_head((yyval.list));
+ list_add_tail(&(yyvsp[0].stmt)->list, (yyval.list));
+ }
+#line 13635 "parser_bison.c"
+ break;
+
+ case 811: /* set_elem_stmt_list: set_elem_stmt_list set_elem_stmt */
+#line 4583 "parser_bison.y"
+ {
+ (yyval.list) = (yyvsp[-1].list);
+ list_add_tail(&(yyvsp[0].stmt)->list, (yyvsp[-1].list));
+ }
+#line 13644 "parser_bison.c"
+ break;
+
+ case 812: /* set_elem_stmt: "counter" close_scope_counter */
+#line 4590 "parser_bison.y"
+ {
+ (yyval.stmt) = counter_stmt_alloc(&(yyloc));
+ }
+#line 13652 "parser_bison.c"
+ break;
+
+ case 813: /* set_elem_stmt: "counter" "packets" "number" "bytes" "number" close_scope_counter */
+#line 4594 "parser_bison.y"
+ {
+ (yyval.stmt) = counter_stmt_alloc(&(yyloc));
+ (yyval.stmt)->counter.packets = (yyvsp[-3].val);
+ (yyval.stmt)->counter.bytes = (yyvsp[-1].val);
+ }
+#line 13662 "parser_bison.c"
+ break;
+
+ case 814: /* set_elem_stmt: "limit" "rate" limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit */
+#line 4600 "parser_bison.y"
+ {
+ if ((yyvsp[-1].val) == 0) {
+ erec_queue(error(&(yylsp[-1]), "limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ (yyval.stmt) = limit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->limit.rate = (yyvsp[-2].limit_rate).rate;
+ (yyval.stmt)->limit.unit = (yyvsp[-2].limit_rate).unit;
+ (yyval.stmt)->limit.burst = (yyvsp[-1].val);
+ (yyval.stmt)->limit.type = NFT_LIMIT_PKTS;
+ (yyval.stmt)->limit.flags = (yyvsp[-3].val);
+ }
+#line 13680 "parser_bison.c"
+ break;
+
+ case 815: /* set_elem_stmt: "limit" "rate" limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit */
+#line 4614 "parser_bison.y"
+ {
+ if ((yyvsp[-1].val) == 0) {
+ erec_queue(error(&(yylsp[0]), "limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ (yyval.stmt) = limit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->limit.rate = (yyvsp[-2].limit_rate).rate;
+ (yyval.stmt)->limit.unit = (yyvsp[-2].limit_rate).unit;
+ (yyval.stmt)->limit.burst = (yyvsp[-1].val);
+ (yyval.stmt)->limit.type = NFT_LIMIT_PKT_BYTES;
+ (yyval.stmt)->limit.flags = (yyvsp[-3].val);
+ }
+#line 13698 "parser_bison.c"
+ break;
+
+ case 816: /* set_elem_stmt: "ct" "count" "number" close_scope_ct */
+#line 4628 "parser_bison.y"
+ {
+ (yyval.stmt) = connlimit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->connlimit.count = (yyvsp[-1].val);
+ }
+#line 13707 "parser_bison.c"
+ break;
+
+ case 817: /* set_elem_stmt: "ct" "count" "over" "number" close_scope_ct */
+#line 4633 "parser_bison.y"
+ {
+ (yyval.stmt) = connlimit_stmt_alloc(&(yyloc));
+ (yyval.stmt)->connlimit.count = (yyvsp[-1].val);
+ (yyval.stmt)->connlimit.flags = NFT_CONNLIMIT_F_INV;
+ }
+#line 13717 "parser_bison.c"
+ break;
+
+ case 818: /* set_elem_stmt: "quota" quota_mode "number" quota_unit quota_used close_scope_quota */
+#line 4639 "parser_bison.y"
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&(yyloc), (yyvsp[-2].string), &rate);
+ xfree((yyvsp[-2].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ (yyval.stmt) = quota_stmt_alloc(&(yyloc));
+ (yyval.stmt)->quota.bytes = (yyvsp[-3].val) * rate;
+ (yyval.stmt)->quota.used = (yyvsp[-1].val);
+ (yyval.stmt)->quota.flags = (yyvsp[-4].val);
+ }
+#line 13737 "parser_bison.c"
+ break;
+
+ case 819: /* set_elem_stmt: "last" "used" "never" close_scope_last */
+#line 4655 "parser_bison.y"
+ {
+ (yyval.stmt) = last_stmt_alloc(&(yyloc));
+ }
+#line 13745 "parser_bison.c"
+ break;
+
+ case 820: /* set_elem_stmt: "last" "used" time_spec close_scope_last */
+#line 4659 "parser_bison.y"
+ {
+ (yyval.stmt) = last_stmt_alloc(&(yyloc));
+ (yyval.stmt)->last.used = (yyvsp[-1].val);
+ (yyval.stmt)->last.set = true;
+ }
+#line 13755 "parser_bison.c"
+ break;
+
+ case 821: /* set_elem_expr_option: "timeout" time_spec */
+#line 4667 "parser_bison.y"
+ {
+ (yyvsp[-2].expr)->timeout = (yyvsp[0].val);
+ }
+#line 13763 "parser_bison.c"
+ break;
+
+ case 822: /* set_elem_expr_option: "expires" time_spec */
+#line 4671 "parser_bison.y"
+ {
+ (yyvsp[-2].expr)->expiration = (yyvsp[0].val);
+ }
+#line 13771 "parser_bison.c"
+ break;
+
+ case 823: /* set_elem_expr_option: comment_spec */
+#line 4675 "parser_bison.y"
+ {
+ if (already_set((yyvsp[-1].expr)->comment, &(yylsp[0]), state)) {
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ (yyvsp[-1].expr)->comment = (yyvsp[0].string);
+ }
+#line 13783 "parser_bison.c"
+ break;
+
+ case 829: /* initializer_expr: '{' '}' */
+#line 4693 "parser_bison.y"
+ { (yyval.expr) = compound_expr_alloc(&(yyloc), EXPR_SET); }
+#line 13789 "parser_bison.c"
+ break;
+
+ case 830: /* initializer_expr: "-" "number" */
+#line 4695 "parser_bison.y"
+ {
+ int32_t num = -(yyvsp[0].val);
+
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(num) * BITS_PER_BYTE,
+ &num);
+ }
+#line 13802 "parser_bison.c"
+ break;
+
+ case 831: /* counter_config: "packets" "number" "bytes" "number" */
+#line 4706 "parser_bison.y"
+ {
+ struct counter *counter;
+
+ counter = &(yyvsp[-4].obj)->counter;
+ counter->packets = (yyvsp[-2].val);
+ counter->bytes = (yyvsp[0].val);
+ }
+#line 13814 "parser_bison.c"
+ break;
+
+ case 832: /* counter_obj: %empty */
+#line 4716 "parser_bison.y"
+ {
+ (yyval.obj) = obj_alloc(&(yyloc));
+ (yyval.obj)->type = NFT_OBJECT_COUNTER;
+ }
+#line 13823 "parser_bison.c"
+ break;
+
+ case 833: /* quota_config: quota_mode "number" quota_unit quota_used */
+#line 4723 "parser_bison.y"
+ {
+ struct error_record *erec;
+ struct quota *quota;
+ uint64_t rate;
+
+ erec = data_unit_parse(&(yyloc), (yyvsp[-1].string), &rate);
+ xfree((yyvsp[-1].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ quota = &(yyvsp[-4].obj)->quota;
+ quota->bytes = (yyvsp[-2].val) * rate;
+ quota->used = (yyvsp[0].val);
+ quota->flags = (yyvsp[-3].val);
+ }
+#line 13845 "parser_bison.c"
+ break;
+
+ case 834: /* quota_obj: %empty */
+#line 4743 "parser_bison.y"
+ {
+ (yyval.obj) = obj_alloc(&(yyloc));
+ (yyval.obj)->type = NFT_OBJECT_QUOTA;
+ }
+#line 13854 "parser_bison.c"
+ break;
+
+ case 835: /* secmark_config: string */
+#line 4750 "parser_bison.y"
+ {
+ int ret;
+ struct secmark *secmark;
+
+ secmark = &(yyvsp[-1].obj)->secmark;
+ ret = snprintf(secmark->ctx, sizeof(secmark->ctx), "%s", (yyvsp[0].string));
+ if (ret <= 0 || ret >= (int)sizeof(secmark->ctx)) {
+ erec_queue(error(&(yylsp[0]), "invalid context '%s', max length is %u\n", (yyvsp[0].string), (int)sizeof(secmark->ctx)), state->msgs);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ xfree((yyvsp[0].string));
+ }
+#line 13872 "parser_bison.c"
+ break;
+
+ case 836: /* secmark_obj: %empty */
+#line 4766 "parser_bison.y"
+ {
+ (yyval.obj) = obj_alloc(&(yyloc));
+ (yyval.obj)->type = NFT_OBJECT_SECMARK;
+ }
+#line 13881 "parser_bison.c"
+ break;
+
+ case 837: /* ct_obj_type: "helper" */
+#line 4772 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_CT_HELPER; }
+#line 13887 "parser_bison.c"
+ break;
+
+ case 838: /* ct_obj_type: "timeout" */
+#line 4773 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_CT_TIMEOUT; }
+#line 13893 "parser_bison.c"
+ break;
+
+ case 839: /* ct_obj_type: "expectation" */
+#line 4774 "parser_bison.y"
+ { (yyval.val) = NFT_OBJECT_CT_EXPECT; }
+#line 13899 "parser_bison.c"
+ break;
+
+ case 840: /* ct_cmd_type: "helpers" */
+#line 4777 "parser_bison.y"
+ { (yyval.val) = CMD_OBJ_CT_HELPERS; }
+#line 13905 "parser_bison.c"
+ break;
+
+ case 841: /* ct_cmd_type: "timeout" */
+#line 4778 "parser_bison.y"
+ { (yyval.val) = CMD_OBJ_CT_TIMEOUTS; }
+#line 13911 "parser_bison.c"
+ break;
+
+ case 842: /* ct_cmd_type: "expectation" */
+#line 4779 "parser_bison.y"
+ { (yyval.val) = CMD_OBJ_CT_EXPECTATIONS; }
+#line 13917 "parser_bison.c"
+ break;
+
+ case 843: /* ct_l4protoname: "tcp" close_scope_tcp */
+#line 4782 "parser_bison.y"
+ { (yyval.val) = IPPROTO_TCP; }
+#line 13923 "parser_bison.c"
+ break;
+
+ case 844: /* ct_l4protoname: "udp" close_scope_udp */
+#line 4783 "parser_bison.y"
+ { (yyval.val) = IPPROTO_UDP; }
+#line 13929 "parser_bison.c"
+ break;
+
+ case 845: /* ct_helper_config: "type" "quoted string" "protocol" ct_l4protoname stmt_separator close_scope_type */
+#line 4787 "parser_bison.y"
+ {
+ struct ct_helper *ct;
+ int ret;
+
+ ct = &(yyvsp[-6].obj)->ct_helper;
+
+ ret = snprintf(ct->name, sizeof(ct->name), "%s", (yyvsp[-4].string));
+ if (ret <= 0 || ret >= (int)sizeof(ct->name)) {
+ erec_queue(error(&(yylsp[-4]), "invalid name '%s', max length is %u\n", (yyvsp[-4].string), (int)sizeof(ct->name)), state->msgs);
+ YYERROR;
+ }
+ xfree((yyvsp[-4].string));
+
+ ct->l4proto = (yyvsp[-2].val);
+ }
+#line 13949 "parser_bison.c"
+ break;
+
+ case 846: /* ct_helper_config: "l3proto" family_spec_explicit stmt_separator */
+#line 4803 "parser_bison.y"
+ {
+ (yyvsp[-3].obj)->ct_helper.l3proto = (yyvsp[-1].val);
+ }
+#line 13957 "parser_bison.c"
+ break;
+
+ case 847: /* timeout_states: timeout_state */
+#line 4809 "parser_bison.y"
+ {
+ (yyval.list) = xmalloc(sizeof(*(yyval.list)));
+ init_list_head((yyval.list));
+ list_add_tail((yyvsp[0].list), (yyval.list));
+ }
+#line 13967 "parser_bison.c"
+ break;
+
+ case 848: /* timeout_states: timeout_states "comma" timeout_state */
+#line 4815 "parser_bison.y"
+ {
+ list_add_tail((yyvsp[0].list), (yyvsp[-2].list));
+ (yyval.list) = (yyvsp[-2].list);
+ }
+#line 13976 "parser_bison.c"
+ break;
+
+ case 849: /* timeout_state: "string" "colon" time_spec_or_num_s */
+#line 4822 "parser_bison.y"
+ {
+ struct timeout_state *ts;
+
+ ts = xzalloc(sizeof(*ts));
+ ts->timeout_str = (yyvsp[-2].string);
+ ts->timeout_value = (yyvsp[0].val);
+ ts->location = (yylsp[-2]);
+ init_list_head(&ts->head);
+ (yyval.list) = &ts->head;
+ }
+#line 13991 "parser_bison.c"
+ break;
+
+ case 850: /* ct_timeout_config: "protocol" ct_l4protoname stmt_separator */
+#line 4835 "parser_bison.y"
+ {
+ struct ct_timeout *ct;
+ int l4proto = (yyvsp[-1].val);
+
+ ct = &(yyvsp[-3].obj)->ct_timeout;
+ ct->l4proto = l4proto;
+ }
+#line 14003 "parser_bison.c"
+ break;
+
+ case 851: /* ct_timeout_config: "policy" '=' '{' timeout_states '}' stmt_separator close_scope_policy */
+#line 4843 "parser_bison.y"
+ {
+ struct ct_timeout *ct;
+
+ ct = &(yyvsp[-7].obj)->ct_timeout;
+ list_splice_tail((yyvsp[-3].list), &ct->timeout_list);
+ xfree((yyvsp[-3].list));
+ }
+#line 14015 "parser_bison.c"
+ break;
+
+ case 852: /* ct_timeout_config: "l3proto" family_spec_explicit stmt_separator */
+#line 4851 "parser_bison.y"
+ {
+ (yyvsp[-3].obj)->ct_timeout.l3proto = (yyvsp[-1].val);
+ }
+#line 14023 "parser_bison.c"
+ break;
+
+ case 853: /* ct_expect_config: "protocol" ct_l4protoname stmt_separator */
+#line 4857 "parser_bison.y"
+ {
+ (yyvsp[-3].obj)->ct_expect.l4proto = (yyvsp[-1].val);
+ }
+#line 14031 "parser_bison.c"
+ break;
+
+ case 854: /* ct_expect_config: "dport" "number" stmt_separator */
+#line 4861 "parser_bison.y"
+ {
+ (yyvsp[-3].obj)->ct_expect.dport = (yyvsp[-1].val);
+ }
+#line 14039 "parser_bison.c"
+ break;
+
+ case 855: /* ct_expect_config: "timeout" time_spec stmt_separator */
+#line 4865 "parser_bison.y"
+ {
+ (yyvsp[-3].obj)->ct_expect.timeout = (yyvsp[-1].val);
+ }
+#line 14047 "parser_bison.c"
+ break;
+
+ case 856: /* ct_expect_config: "size" "number" stmt_separator */
+#line 4869 "parser_bison.y"
+ {
+ (yyvsp[-3].obj)->ct_expect.size = (yyvsp[-1].val);
+ }
+#line 14055 "parser_bison.c"
+ break;
+
+ case 857: /* ct_expect_config: "l3proto" family_spec_explicit stmt_separator */
+#line 4873 "parser_bison.y"
+ {
+ (yyvsp[-3].obj)->ct_expect.l3proto = (yyvsp[-1].val);
+ }
+#line 14063 "parser_bison.c"
+ break;
+
+ case 858: /* ct_obj_alloc: %empty */
+#line 4879 "parser_bison.y"
+ {
+ (yyval.obj) = obj_alloc(&(yyloc));
+ }
+#line 14071 "parser_bison.c"
+ break;
+
+ case 859: /* limit_config: "rate" limit_mode limit_rate_pkts limit_burst_pkts */
+#line 4885 "parser_bison.y"
+ {
+ struct limit *limit;
+
+ limit = &(yyvsp[-4].obj)->limit;
+ limit->rate = (yyvsp[-1].limit_rate).rate;
+ limit->unit = (yyvsp[-1].limit_rate).unit;
+ limit->burst = (yyvsp[0].val);
+ limit->type = NFT_LIMIT_PKTS;
+ limit->flags = (yyvsp[-2].val);
+ }
+#line 14086 "parser_bison.c"
+ break;
+
+ case 860: /* limit_config: "rate" limit_mode limit_rate_bytes limit_burst_bytes */
+#line 4896 "parser_bison.y"
+ {
+ struct limit *limit;
+
+ limit = &(yyvsp[-4].obj)->limit;
+ limit->rate = (yyvsp[-1].limit_rate).rate;
+ limit->unit = (yyvsp[-1].limit_rate).unit;
+ limit->burst = (yyvsp[0].val);
+ limit->type = NFT_LIMIT_PKT_BYTES;
+ limit->flags = (yyvsp[-2].val);
+ }
+#line 14101 "parser_bison.c"
+ break;
+
+ case 861: /* limit_obj: %empty */
+#line 4909 "parser_bison.y"
+ {
+ (yyval.obj) = obj_alloc(&(yyloc));
+ (yyval.obj)->type = NFT_OBJECT_LIMIT;
+ }
+#line 14110 "parser_bison.c"
+ break;
+
+ case 862: /* relational_expr: expr rhs_expr */
+#line 4916 "parser_bison.y"
+ {
+ (yyval.expr) = relational_expr_alloc(&(yyloc), OP_IMPLICIT, (yyvsp[-1].expr), (yyvsp[0].expr));
+ }
+#line 14118 "parser_bison.c"
+ break;
+
+ case 863: /* relational_expr: expr list_rhs_expr */
+#line 4920 "parser_bison.y"
+ {
+ (yyval.expr) = relational_expr_alloc(&(yyloc), OP_IMPLICIT, (yyvsp[-1].expr), (yyvsp[0].expr));
+ }
+#line 14126 "parser_bison.c"
+ break;
+
+ case 864: /* relational_expr: expr basic_rhs_expr "/" list_rhs_expr */
+#line 4924 "parser_bison.y"
+ {
+ (yyval.expr) = flagcmp_expr_alloc(&(yyloc), OP_EQ, (yyvsp[-3].expr), (yyvsp[0].expr), (yyvsp[-2].expr));
+ }
+#line 14134 "parser_bison.c"
+ break;
+
+ case 865: /* relational_expr: expr list_rhs_expr "/" list_rhs_expr */
+#line 4928 "parser_bison.y"
+ {
+ (yyval.expr) = flagcmp_expr_alloc(&(yyloc), OP_EQ, (yyvsp[-3].expr), (yyvsp[0].expr), (yyvsp[-2].expr));
+ }
+#line 14142 "parser_bison.c"
+ break;
+
+ case 866: /* relational_expr: expr relational_op basic_rhs_expr "/" list_rhs_expr */
+#line 4932 "parser_bison.y"
+ {
+ (yyval.expr) = flagcmp_expr_alloc(&(yyloc), (yyvsp[-3].val), (yyvsp[-4].expr), (yyvsp[0].expr), (yyvsp[-2].expr));
+ }
+#line 14150 "parser_bison.c"
+ break;
+
+ case 867: /* relational_expr: expr relational_op list_rhs_expr "/" list_rhs_expr */
+#line 4936 "parser_bison.y"
+ {
+ (yyval.expr) = flagcmp_expr_alloc(&(yyloc), (yyvsp[-3].val), (yyvsp[-4].expr), (yyvsp[0].expr), (yyvsp[-2].expr));
+ }
+#line 14158 "parser_bison.c"
+ break;
+
+ case 868: /* relational_expr: expr relational_op rhs_expr */
+#line 4940 "parser_bison.y"
+ {
+ (yyval.expr) = relational_expr_alloc(&(yylsp[-1]), (yyvsp[-1].val), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 14166 "parser_bison.c"
+ break;
+
+ case 869: /* relational_expr: expr relational_op list_rhs_expr */
+#line 4944 "parser_bison.y"
+ {
+ (yyval.expr) = relational_expr_alloc(&(yylsp[-1]), (yyvsp[-1].val), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 14174 "parser_bison.c"
+ break;
+
+ case 870: /* list_rhs_expr: basic_rhs_expr "comma" basic_rhs_expr */
+#line 4950 "parser_bison.y"
+ {
+ (yyval.expr) = list_expr_alloc(&(yyloc));
+ compound_expr_add((yyval.expr), (yyvsp[-2].expr));
+ compound_expr_add((yyval.expr), (yyvsp[0].expr));
+ }
+#line 14184 "parser_bison.c"
+ break;
+
+ case 871: /* list_rhs_expr: list_rhs_expr "comma" basic_rhs_expr */
+#line 4956 "parser_bison.y"
+ {
+ (yyvsp[-2].expr)->location = (yyloc);
+ compound_expr_add((yyvsp[-2].expr), (yyvsp[0].expr));
+ (yyval.expr) = (yyvsp[-2].expr);
+ }
+#line 14194 "parser_bison.c"
+ break;
+
+ case 872: /* rhs_expr: concat_rhs_expr */
+#line 4963 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 14200 "parser_bison.c"
+ break;
+
+ case 873: /* rhs_expr: set_expr */
+#line 4964 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 14206 "parser_bison.c"
+ break;
+
+ case 874: /* rhs_expr: set_ref_symbol_expr */
+#line 4965 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 14212 "parser_bison.c"
+ break;
+
+ case 876: /* shift_rhs_expr: shift_rhs_expr "<<" primary_rhs_expr */
+#line 4970 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_LSHIFT, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 14220 "parser_bison.c"
+ break;
+
+ case 877: /* shift_rhs_expr: shift_rhs_expr ">>" primary_rhs_expr */
+#line 4974 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_RSHIFT, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 14228 "parser_bison.c"
+ break;
+
+ case 879: /* and_rhs_expr: and_rhs_expr "&" shift_rhs_expr */
+#line 4981 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_AND, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 14236 "parser_bison.c"
+ break;
+
+ case 881: /* exclusive_or_rhs_expr: exclusive_or_rhs_expr "^" and_rhs_expr */
+#line 4988 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_XOR, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 14244 "parser_bison.c"
+ break;
+
+ case 883: /* inclusive_or_rhs_expr: inclusive_or_rhs_expr '|' exclusive_or_rhs_expr */
+#line 4995 "parser_bison.y"
+ {
+ (yyval.expr) = binop_expr_alloc(&(yyloc), OP_OR, (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 14252 "parser_bison.c"
+ break;
+
+ case 887: /* concat_rhs_expr: concat_rhs_expr "." multiton_rhs_expr */
+#line 5006 "parser_bison.y"
+ {
+ struct location rhs[] = {
+ [1] = (yylsp[-1]),
+ [2] = (yylsp[0]),
+ };
+
+ (yyval.expr) = handle_concat_expr(&(yyloc), (yyval.expr), (yyvsp[-2].expr), (yyvsp[0].expr), rhs);
+ }
+#line 14265 "parser_bison.c"
+ break;
+
+ case 888: /* concat_rhs_expr: concat_rhs_expr "." basic_rhs_expr */
+#line 5015 "parser_bison.y"
+ {
+ struct location rhs[] = {
+ [1] = (yylsp[-1]),
+ [2] = (yylsp[0]),
+ };
+
+ (yyval.expr) = handle_concat_expr(&(yyloc), (yyval.expr), (yyvsp[-2].expr), (yyvsp[0].expr), rhs);
+ }
+#line 14278 "parser_bison.c"
+ break;
+
+ case 889: /* boolean_keys: "exists" */
+#line 5025 "parser_bison.y"
+ { (yyval.val8) = true; }
+#line 14284 "parser_bison.c"
+ break;
+
+ case 890: /* boolean_keys: "missing" */
+#line 5026 "parser_bison.y"
+ { (yyval.val8) = false; }
+#line 14290 "parser_bison.c"
+ break;
+
+ case 891: /* boolean_expr: boolean_keys */
+#line 5030 "parser_bison.y"
+ {
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &boolean_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof((yyvsp[0].val8)) * BITS_PER_BYTE, &(yyvsp[0].val8));
+ }
+#line 14300 "parser_bison.c"
+ break;
+
+ case 892: /* keyword_expr: "ether" close_scope_eth */
+#line 5037 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "ether"); }
+#line 14306 "parser_bison.c"
+ break;
+
+ case 893: /* keyword_expr: "ip" close_scope_ip */
+#line 5038 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "ip"); }
+#line 14312 "parser_bison.c"
+ break;
+
+ case 894: /* keyword_expr: "ip6" close_scope_ip6 */
+#line 5039 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "ip6"); }
+#line 14318 "parser_bison.c"
+ break;
+
+ case 895: /* keyword_expr: "vlan" close_scope_vlan */
+#line 5040 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "vlan"); }
+#line 14324 "parser_bison.c"
+ break;
+
+ case 896: /* keyword_expr: "arp" close_scope_arp */
+#line 5041 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "arp"); }
+#line 14330 "parser_bison.c"
+ break;
+
+ case 897: /* keyword_expr: "dnat" close_scope_nat */
+#line 5042 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "dnat"); }
+#line 14336 "parser_bison.c"
+ break;
+
+ case 898: /* keyword_expr: "snat" close_scope_nat */
+#line 5043 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "snat"); }
+#line 14342 "parser_bison.c"
+ break;
+
+ case 899: /* keyword_expr: "ecn" */
+#line 5044 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "ecn"); }
+#line 14348 "parser_bison.c"
+ break;
+
+ case 900: /* keyword_expr: "reset" close_scope_reset */
+#line 5045 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "reset"); }
+#line 14354 "parser_bison.c"
+ break;
+
+ case 901: /* keyword_expr: "destroy" close_scope_destroy */
+#line 5046 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "destroy"); }
+#line 14360 "parser_bison.c"
+ break;
+
+ case 902: /* keyword_expr: "original" */
+#line 5047 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "original"); }
+#line 14366 "parser_bison.c"
+ break;
+
+ case 903: /* keyword_expr: "reply" */
+#line 5048 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "reply"); }
+#line 14372 "parser_bison.c"
+ break;
+
+ case 904: /* keyword_expr: "label" */
+#line 5049 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "label"); }
+#line 14378 "parser_bison.c"
+ break;
+
+ case 905: /* keyword_expr: "last" close_scope_last */
+#line 5050 "parser_bison.y"
+ { (yyval.expr) = symbol_value(&(yyloc), "last"); }
+#line 14384 "parser_bison.c"
+ break;
+
+ case 906: /* primary_rhs_expr: symbol_expr */
+#line 5053 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 14390 "parser_bison.c"
+ break;
+
+ case 907: /* primary_rhs_expr: integer_expr */
+#line 5054 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 14396 "parser_bison.c"
+ break;
+
+ case 908: /* primary_rhs_expr: boolean_expr */
+#line 5055 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 14402 "parser_bison.c"
+ break;
+
+ case 909: /* primary_rhs_expr: keyword_expr */
+#line 5056 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[0].expr); }
+#line 14408 "parser_bison.c"
+ break;
+
+ case 910: /* primary_rhs_expr: "tcp" close_scope_tcp */
+#line 5058 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_TCP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14419 "parser_bison.c"
+ break;
+
+ case 911: /* primary_rhs_expr: "udp" close_scope_udp */
+#line 5065 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_UDP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14430 "parser_bison.c"
+ break;
+
+ case 912: /* primary_rhs_expr: "udplite" close_scope_udplite */
+#line 5072 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_UDPLITE;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14441 "parser_bison.c"
+ break;
+
+ case 913: /* primary_rhs_expr: "esp" close_scope_esp */
+#line 5079 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_ESP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14452 "parser_bison.c"
+ break;
+
+ case 914: /* primary_rhs_expr: "ah" close_scope_ah */
+#line 5086 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_AH;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14463 "parser_bison.c"
+ break;
+
+ case 915: /* primary_rhs_expr: "icmp" close_scope_icmp */
+#line 5093 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_ICMP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14474 "parser_bison.c"
+ break;
+
+ case 916: /* primary_rhs_expr: "igmp" */
+#line 5100 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_IGMP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14485 "parser_bison.c"
+ break;
+
+ case 917: /* primary_rhs_expr: "icmpv6" close_scope_icmp */
+#line 5107 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_ICMPV6;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14496 "parser_bison.c"
+ break;
+
+ case 918: /* primary_rhs_expr: "gre" close_scope_gre */
+#line 5114 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_GRE;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14507 "parser_bison.c"
+ break;
+
+ case 919: /* primary_rhs_expr: "comp" close_scope_comp */
+#line 5121 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_COMP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14518 "parser_bison.c"
+ break;
+
+ case 920: /* primary_rhs_expr: "dccp" close_scope_dccp */
+#line 5128 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_DCCP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14529 "parser_bison.c"
+ break;
+
+ case 921: /* primary_rhs_expr: "sctp" close_scope_sctp */
+#line 5135 "parser_bison.y"
+ {
+ uint8_t data = IPPROTO_SCTP;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14540 "parser_bison.c"
+ break;
+
+ case 922: /* primary_rhs_expr: "redirect" close_scope_nat */
+#line 5142 "parser_bison.y"
+ {
+ uint8_t data = ICMP_REDIRECT;
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &icmp_type_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+#line 14551 "parser_bison.c"
+ break;
+
+ case 923: /* primary_rhs_expr: '(' basic_rhs_expr ')' */
+#line 5148 "parser_bison.y"
+ { (yyval.expr) = (yyvsp[-1].expr); }
+#line 14557 "parser_bison.c"
+ break;
+
+ case 924: /* relational_op: "==" */
+#line 5151 "parser_bison.y"
+ { (yyval.val) = OP_EQ; }
+#line 14563 "parser_bison.c"
+ break;
+
+ case 925: /* relational_op: "!=" */
+#line 5152 "parser_bison.y"
+ { (yyval.val) = OP_NEQ; }
+#line 14569 "parser_bison.c"
+ break;
+
+ case 926: /* relational_op: "<" */
+#line 5153 "parser_bison.y"
+ { (yyval.val) = OP_LT; }
+#line 14575 "parser_bison.c"
+ break;
+
+ case 927: /* relational_op: ">" */
+#line 5154 "parser_bison.y"
+ { (yyval.val) = OP_GT; }
+#line 14581 "parser_bison.c"
+ break;
+
+ case 928: /* relational_op: ">=" */
+#line 5155 "parser_bison.y"
+ { (yyval.val) = OP_GTE; }
+#line 14587 "parser_bison.c"
+ break;
+
+ case 929: /* relational_op: "<=" */
+#line 5156 "parser_bison.y"
+ { (yyval.val) = OP_LTE; }
+#line 14593 "parser_bison.c"
+ break;
+
+ case 930: /* relational_op: "!" */
+#line 5157 "parser_bison.y"
+ { (yyval.val) = OP_NEG; }
+#line 14599 "parser_bison.c"
+ break;
+
+ case 931: /* verdict_expr: "accept" */
+#line 5161 "parser_bison.y"
+ {
+ (yyval.expr) = verdict_expr_alloc(&(yyloc), NF_ACCEPT, NULL);
+ }
+#line 14607 "parser_bison.c"
+ break;
+
+ case 932: /* verdict_expr: "drop" */
+#line 5165 "parser_bison.y"
+ {
+ (yyval.expr) = verdict_expr_alloc(&(yyloc), NF_DROP, NULL);
+ }
+#line 14615 "parser_bison.c"
+ break;
+
+ case 933: /* verdict_expr: "continue" */
+#line 5169 "parser_bison.y"
+ {
+ (yyval.expr) = verdict_expr_alloc(&(yyloc), NFT_CONTINUE, NULL);
+ }
+#line 14623 "parser_bison.c"
+ break;
+
+ case 934: /* verdict_expr: "jump" chain_expr */
+#line 5173 "parser_bison.y"
+ {
+ (yyval.expr) = verdict_expr_alloc(&(yyloc), NFT_JUMP, (yyvsp[0].expr));
+ }
+#line 14631 "parser_bison.c"
+ break;
+
+ case 935: /* verdict_expr: "goto" chain_expr */
+#line 5177 "parser_bison.y"
+ {
+ (yyval.expr) = verdict_expr_alloc(&(yyloc), NFT_GOTO, (yyvsp[0].expr));
+ }
+#line 14639 "parser_bison.c"
+ break;
+
+ case 936: /* verdict_expr: "return" */
+#line 5181 "parser_bison.y"
+ {
+ (yyval.expr) = verdict_expr_alloc(&(yyloc), NFT_RETURN, NULL);
+ }
+#line 14647 "parser_bison.c"
+ break;
+
+ case 938: /* chain_expr: identifier */
+#line 5188 "parser_bison.y"
+ {
+ (yyval.expr) = constant_expr_alloc(&(yyloc), &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen((yyvsp[0].string)) * BITS_PER_BYTE,
+ (yyvsp[0].string));
+ xfree((yyvsp[0].string));
+ }
+#line 14659 "parser_bison.c"
+ break;
+
+ case 939: /* meta_expr: "meta" meta_key close_scope_meta */
+#line 5198 "parser_bison.y"
+ {
+ (yyval.expr) = meta_expr_alloc(&(yyloc), (yyvsp[-1].val));
+ }
+#line 14667 "parser_bison.c"
+ break;
+
+ case 940: /* meta_expr: meta_key_unqualified */
+#line 5202 "parser_bison.y"
+ {
+ (yyval.expr) = meta_expr_alloc(&(yyloc), (yyvsp[0].val));
+ }
+#line 14675 "parser_bison.c"
+ break;
+
+ case 941: /* meta_expr: "meta" "string" close_scope_meta */
+#line 5206 "parser_bison.y"
+ {
+ struct error_record *erec;
+ unsigned int key;
+
+ erec = meta_key_parse(&(yyloc), (yyvsp[-1].string), &key);
+ xfree((yyvsp[-1].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ (yyval.expr) = meta_expr_alloc(&(yyloc), key);
+ }
+#line 14693 "parser_bison.c"
+ break;
+
+ case 944: /* meta_key_qualified: "length" */
+#line 5225 "parser_bison.y"
+ { (yyval.val) = NFT_META_LEN; }
+#line 14699 "parser_bison.c"
+ break;
+
+ case 945: /* meta_key_qualified: "protocol" */
+#line 5226 "parser_bison.y"
+ { (yyval.val) = NFT_META_PROTOCOL; }
+#line 14705 "parser_bison.c"
+ break;
+
+ case 946: /* meta_key_qualified: "priority" */
+#line 5227 "parser_bison.y"
+ { (yyval.val) = NFT_META_PRIORITY; }
+#line 14711 "parser_bison.c"
+ break;
+
+ case 947: /* meta_key_qualified: "random" */
+#line 5228 "parser_bison.y"
+ { (yyval.val) = NFT_META_PRANDOM; }
+#line 14717 "parser_bison.c"
+ break;
+
+ case 948: /* meta_key_qualified: "secmark" close_scope_secmark */
+#line 5229 "parser_bison.y"
+ { (yyval.val) = NFT_META_SECMARK; }
+#line 14723 "parser_bison.c"
+ break;
+
+ case 949: /* meta_key_unqualified: "mark" */
+#line 5232 "parser_bison.y"
+ { (yyval.val) = NFT_META_MARK; }
+#line 14729 "parser_bison.c"
+ break;
+
+ case 950: /* meta_key_unqualified: "iif" */
+#line 5233 "parser_bison.y"
+ { (yyval.val) = NFT_META_IIF; }
+#line 14735 "parser_bison.c"
+ break;
+
+ case 951: /* meta_key_unqualified: "iifname" */
+#line 5234 "parser_bison.y"
+ { (yyval.val) = NFT_META_IIFNAME; }
+#line 14741 "parser_bison.c"
+ break;
+
+ case 952: /* meta_key_unqualified: "iiftype" */
+#line 5235 "parser_bison.y"
+ { (yyval.val) = NFT_META_IIFTYPE; }
+#line 14747 "parser_bison.c"
+ break;
+
+ case 953: /* meta_key_unqualified: "oif" */
+#line 5236 "parser_bison.y"
+ { (yyval.val) = NFT_META_OIF; }
+#line 14753 "parser_bison.c"
+ break;
+
+ case 954: /* meta_key_unqualified: "oifname" */
+#line 5237 "parser_bison.y"
+ { (yyval.val) = NFT_META_OIFNAME; }
+#line 14759 "parser_bison.c"
+ break;
+
+ case 955: /* meta_key_unqualified: "oiftype" */
+#line 5238 "parser_bison.y"
+ { (yyval.val) = NFT_META_OIFTYPE; }
+#line 14765 "parser_bison.c"
+ break;
+
+ case 956: /* meta_key_unqualified: "skuid" */
+#line 5239 "parser_bison.y"
+ { (yyval.val) = NFT_META_SKUID; }
+#line 14771 "parser_bison.c"
+ break;
+
+ case 957: /* meta_key_unqualified: "skgid" */
+#line 5240 "parser_bison.y"
+ { (yyval.val) = NFT_META_SKGID; }
+#line 14777 "parser_bison.c"
+ break;
+
+ case 958: /* meta_key_unqualified: "nftrace" */
+#line 5241 "parser_bison.y"
+ { (yyval.val) = NFT_META_NFTRACE; }
+#line 14783 "parser_bison.c"
+ break;
+
+ case 959: /* meta_key_unqualified: "rtclassid" */
+#line 5242 "parser_bison.y"
+ { (yyval.val) = NFT_META_RTCLASSID; }
+#line 14789 "parser_bison.c"
+ break;
+
+ case 960: /* meta_key_unqualified: "ibriport" */
+#line 5243 "parser_bison.y"
+ { (yyval.val) = NFT_META_BRI_IIFNAME; }
+#line 14795 "parser_bison.c"
+ break;
+
+ case 961: /* meta_key_unqualified: "obriport" */
+#line 5244 "parser_bison.y"
+ { (yyval.val) = NFT_META_BRI_OIFNAME; }
+#line 14801 "parser_bison.c"
+ break;
+
+ case 962: /* meta_key_unqualified: "ibrname" */
+#line 5245 "parser_bison.y"
+ { (yyval.val) = NFT_META_BRI_IIFNAME; }
+#line 14807 "parser_bison.c"
+ break;
+
+ case 963: /* meta_key_unqualified: "obrname" */
+#line 5246 "parser_bison.y"
+ { (yyval.val) = NFT_META_BRI_OIFNAME; }
+#line 14813 "parser_bison.c"
+ break;
+
+ case 964: /* meta_key_unqualified: "pkttype" */
+#line 5247 "parser_bison.y"
+ { (yyval.val) = NFT_META_PKTTYPE; }
+#line 14819 "parser_bison.c"
+ break;
+
+ case 965: /* meta_key_unqualified: "cpu" */
+#line 5248 "parser_bison.y"
+ { (yyval.val) = NFT_META_CPU; }
+#line 14825 "parser_bison.c"
+ break;
+
+ case 966: /* meta_key_unqualified: "iifgroup" */
+#line 5249 "parser_bison.y"
+ { (yyval.val) = NFT_META_IIFGROUP; }
+#line 14831 "parser_bison.c"
+ break;
+
+ case 967: /* meta_key_unqualified: "oifgroup" */
+#line 5250 "parser_bison.y"
+ { (yyval.val) = NFT_META_OIFGROUP; }
+#line 14837 "parser_bison.c"
+ break;
+
+ case 968: /* meta_key_unqualified: "cgroup" */
+#line 5251 "parser_bison.y"
+ { (yyval.val) = NFT_META_CGROUP; }
+#line 14843 "parser_bison.c"
+ break;
+
+ case 969: /* meta_key_unqualified: "ipsec" close_scope_ipsec */
+#line 5252 "parser_bison.y"
+ { (yyval.val) = NFT_META_SECPATH; }
+#line 14849 "parser_bison.c"
+ break;
+
+ case 970: /* meta_key_unqualified: "time" */
+#line 5253 "parser_bison.y"
+ { (yyval.val) = NFT_META_TIME_NS; }
+#line 14855 "parser_bison.c"
+ break;
+
+ case 971: /* meta_key_unqualified: "day" */
+#line 5254 "parser_bison.y"
+ { (yyval.val) = NFT_META_TIME_DAY; }
+#line 14861 "parser_bison.c"
+ break;
+
+ case 972: /* meta_key_unqualified: "hour" */
+#line 5255 "parser_bison.y"
+ { (yyval.val) = NFT_META_TIME_HOUR; }
+#line 14867 "parser_bison.c"
+ break;
+
+ case 973: /* meta_stmt: "meta" meta_key "set" stmt_expr close_scope_meta */
+#line 5259 "parser_bison.y"
+ {
+ switch ((yyvsp[-3].val)) {
+ case NFT_META_SECMARK:
+ switch ((yyvsp[-1].expr)->etype) {
+ case EXPR_CT:
+ (yyval.stmt) = meta_stmt_alloc(&(yyloc), (yyvsp[-3].val), (yyvsp[-1].expr));
+ break;
+ default:
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_SECMARK;
+ (yyval.stmt)->objref.expr = (yyvsp[-1].expr);
+ break;
+ }
+ break;
+ default:
+ (yyval.stmt) = meta_stmt_alloc(&(yyloc), (yyvsp[-3].val), (yyvsp[-1].expr));
+ break;
+ }
+ }
+#line 14891 "parser_bison.c"
+ break;
+
+ case 974: /* meta_stmt: meta_key_unqualified "set" stmt_expr */
+#line 5279 "parser_bison.y"
+ {
+ (yyval.stmt) = meta_stmt_alloc(&(yyloc), (yyvsp[-2].val), (yyvsp[0].expr));
+ }
+#line 14899 "parser_bison.c"
+ break;
+
+ case 975: /* meta_stmt: "meta" "string" "set" stmt_expr close_scope_meta */
+#line 5283 "parser_bison.y"
+ {
+ struct error_record *erec;
+ unsigned int key;
+
+ erec = meta_key_parse(&(yyloc), (yyvsp[-3].string), &key);
+ xfree((yyvsp[-3].string));
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ (yyval.stmt) = meta_stmt_alloc(&(yyloc), key, (yyvsp[-1].expr));
+ }
+#line 14917 "parser_bison.c"
+ break;
+
+ case 976: /* meta_stmt: "notrack" */
+#line 5297 "parser_bison.y"
+ {
+ (yyval.stmt) = notrack_stmt_alloc(&(yyloc));
+ }
+#line 14925 "parser_bison.c"
+ break;
+
+ case 977: /* meta_stmt: "flow" "offload" "@" string close_scope_at */
+#line 5301 "parser_bison.y"
+ {
+ (yyval.stmt) = flow_offload_stmt_alloc(&(yyloc), (yyvsp[-1].string));
+ }
+#line 14933 "parser_bison.c"
+ break;
+
+ case 978: /* meta_stmt: "flow" "add" "@" string close_scope_at */
+#line 5305 "parser_bison.y"
+ {
+ (yyval.stmt) = flow_offload_stmt_alloc(&(yyloc), (yyvsp[-1].string));
+ }
+#line 14941 "parser_bison.c"
+ break;
+
+ case 979: /* socket_expr: "socket" socket_key close_scope_socket */
+#line 5311 "parser_bison.y"
+ {
+ (yyval.expr) = socket_expr_alloc(&(yyloc), (yyvsp[-1].val), 0);
+ }
+#line 14949 "parser_bison.c"
+ break;
+
+ case 980: /* socket_expr: "socket" "cgroupv2" "level" "number" close_scope_socket */
+#line 5315 "parser_bison.y"
+ {
+ (yyval.expr) = socket_expr_alloc(&(yyloc), NFT_SOCKET_CGROUPV2, (yyvsp[-1].val));
+ }
+#line 14957 "parser_bison.c"
+ break;
+
+ case 981: /* socket_key: "transparent" */
+#line 5320 "parser_bison.y"
+ { (yyval.val) = NFT_SOCKET_TRANSPARENT; }
+#line 14963 "parser_bison.c"
+ break;
+
+ case 982: /* socket_key: "mark" */
+#line 5321 "parser_bison.y"
+ { (yyval.val) = NFT_SOCKET_MARK; }
+#line 14969 "parser_bison.c"
+ break;
+
+ case 983: /* socket_key: "wildcard" */
+#line 5322 "parser_bison.y"
+ { (yyval.val) = NFT_SOCKET_WILDCARD; }
+#line 14975 "parser_bison.c"
+ break;
+
+ case 984: /* offset_opt: %empty */
+#line 5325 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 14981 "parser_bison.c"
+ break;
+
+ case 985: /* offset_opt: "offset" "number" */
+#line 5326 "parser_bison.y"
+ { (yyval.val) = (yyvsp[0].val); }
+#line 14987 "parser_bison.c"
+ break;
+
+ case 986: /* numgen_type: "inc" */
+#line 5329 "parser_bison.y"
+ { (yyval.val) = NFT_NG_INCREMENTAL; }
+#line 14993 "parser_bison.c"
+ break;
+
+ case 987: /* numgen_type: "random" */
+#line 5330 "parser_bison.y"
+ { (yyval.val) = NFT_NG_RANDOM; }
+#line 14999 "parser_bison.c"
+ break;
+
+ case 988: /* numgen_expr: "numgen" numgen_type "mod" "number" offset_opt close_scope_numgen */
+#line 5334 "parser_bison.y"
+ {
+ (yyval.expr) = numgen_expr_alloc(&(yyloc), (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[-1].val));
+ }
+#line 15007 "parser_bison.c"
+ break;
+
+ case 989: /* xfrm_spnum: "spnum" "number" */
+#line 5339 "parser_bison.y"
+ { (yyval.val) = (yyvsp[0].val); }
+#line 15013 "parser_bison.c"
+ break;
+
+ case 990: /* xfrm_spnum: %empty */
+#line 5340 "parser_bison.y"
+ { (yyval.val) = 0; }
+#line 15019 "parser_bison.c"
+ break;
+
+ case 991: /* xfrm_dir: "in" */
+#line 5343 "parser_bison.y"
+ { (yyval.val) = XFRM_POLICY_IN; }
+#line 15025 "parser_bison.c"
+ break;
+
+ case 992: /* xfrm_dir: "out" */
+#line 5344 "parser_bison.y"
+ { (yyval.val) = XFRM_POLICY_OUT; }
+#line 15031 "parser_bison.c"
+ break;
+
+ case 993: /* xfrm_state_key: "spi" */
+#line 5347 "parser_bison.y"
+ { (yyval.val) = NFT_XFRM_KEY_SPI; }
+#line 15037 "parser_bison.c"
+ break;
+
+ case 994: /* xfrm_state_key: "reqid" */
+#line 5348 "parser_bison.y"
+ { (yyval.val) = NFT_XFRM_KEY_REQID; }
+#line 15043 "parser_bison.c"
+ break;
+
+ case 995: /* xfrm_state_proto_key: "daddr" */
+#line 5351 "parser_bison.y"
+ { (yyval.val) = NFT_XFRM_KEY_DADDR_IP4; }
+#line 15049 "parser_bison.c"
+ break;
+
+ case 996: /* xfrm_state_proto_key: "saddr" */
+#line 5352 "parser_bison.y"
+ { (yyval.val) = NFT_XFRM_KEY_SADDR_IP4; }
+#line 15055 "parser_bison.c"
+ break;
+
+ case 997: /* xfrm_expr: "ipsec" xfrm_dir xfrm_spnum xfrm_state_key close_scope_ipsec */
+#line 5356 "parser_bison.y"
+ {
+ if ((yyvsp[-2].val) > 255) {
+ erec_queue(error(&(yylsp[-2]), "value too large"), state->msgs);
+ YYERROR;
+ }
+ (yyval.expr) = xfrm_expr_alloc(&(yyloc), (yyvsp[-3].val), (yyvsp[-2].val), (yyvsp[-1].val));
+ }
+#line 15067 "parser_bison.c"
+ break;
+
+ case 998: /* xfrm_expr: "ipsec" xfrm_dir xfrm_spnum nf_key_proto xfrm_state_proto_key close_scope_ipsec */
+#line 5364 "parser_bison.y"
+ {
+ enum nft_xfrm_keys xfrmk = (yyvsp[-1].val);
+
+ switch ((yyvsp[-2].val)) {
+ case NFPROTO_IPV4:
+ break;
+ case NFPROTO_IPV6:
+ if ((yyvsp[-1].val) == NFT_XFRM_KEY_SADDR_IP4)
+ xfrmk = NFT_XFRM_KEY_SADDR_IP6;
+ else if ((yyvsp[-1].val) == NFT_XFRM_KEY_DADDR_IP4)
+ xfrmk = NFT_XFRM_KEY_DADDR_IP6;
+ break;
+ default:
+ YYERROR;
+ break;
+ }
+
+ if ((yyvsp[-3].val) > 255) {
+ erec_queue(error(&(yylsp[-3]), "value too large"), state->msgs);
+ YYERROR;
+ }
+
+ (yyval.expr) = xfrm_expr_alloc(&(yyloc), (yyvsp[-4].val), (yyvsp[-3].val), xfrmk);
+ }
+#line 15096 "parser_bison.c"
+ break;
+
+ case 999: /* hash_expr: "jhash" expr "mod" "number" "seed" "number" offset_opt close_scope_hash */
+#line 5391 "parser_bison.y"
+ {
+ (yyval.expr) = hash_expr_alloc(&(yyloc), (yyvsp[-4].val), true, (yyvsp[-2].val), (yyvsp[-1].val), NFT_HASH_JENKINS);
+ (yyval.expr)->hash.expr = (yyvsp[-6].expr);
+ }
+#line 15105 "parser_bison.c"
+ break;
+
+ case 1000: /* hash_expr: "jhash" expr "mod" "number" offset_opt close_scope_hash */
+#line 5396 "parser_bison.y"
+ {
+ (yyval.expr) = hash_expr_alloc(&(yyloc), (yyvsp[-2].val), false, 0, (yyvsp[-1].val), NFT_HASH_JENKINS);
+ (yyval.expr)->hash.expr = (yyvsp[-4].expr);
+ }
+#line 15114 "parser_bison.c"
+ break;
+
+ case 1001: /* hash_expr: "symhash" "mod" "number" offset_opt close_scope_hash */
+#line 5401 "parser_bison.y"
+ {
+ (yyval.expr) = hash_expr_alloc(&(yyloc), (yyvsp[-2].val), false, 0, (yyvsp[-1].val), NFT_HASH_SYM);
+ }
+#line 15122 "parser_bison.c"
+ break;
+
+ case 1002: /* nf_key_proto: "ip" close_scope_ip */
+#line 5406 "parser_bison.y"
+ { (yyval.val) = NFPROTO_IPV4; }
+#line 15128 "parser_bison.c"
+ break;
+
+ case 1003: /* nf_key_proto: "ip6" close_scope_ip6 */
+#line 5407 "parser_bison.y"
+ { (yyval.val) = NFPROTO_IPV6; }
+#line 15134 "parser_bison.c"
+ break;
+
+ case 1004: /* rt_expr: "rt" rt_key close_scope_rt */
+#line 5411 "parser_bison.y"
+ {
+ (yyval.expr) = rt_expr_alloc(&(yyloc), (yyvsp[-1].val), true);
+ }
+#line 15142 "parser_bison.c"
+ break;
+
+ case 1005: /* rt_expr: "rt" nf_key_proto rt_key close_scope_rt */
+#line 5415 "parser_bison.y"
+ {
+ enum nft_rt_keys rtk = (yyvsp[-1].val);
+
+ switch ((yyvsp[-2].val)) {
+ case NFPROTO_IPV4:
+ break;
+ case NFPROTO_IPV6:
+ if ((yyvsp[-1].val) == NFT_RT_NEXTHOP4)
+ rtk = NFT_RT_NEXTHOP6;
+ break;
+ default:
+ YYERROR;
+ break;
+ }
+
+ (yyval.expr) = rt_expr_alloc(&(yyloc), rtk, false);
+ }
+#line 15164 "parser_bison.c"
+ break;
+
+ case 1006: /* rt_key: "classid" */
+#line 5434 "parser_bison.y"
+ { (yyval.val) = NFT_RT_CLASSID; }
+#line 15170 "parser_bison.c"
+ break;
+
+ case 1007: /* rt_key: "nexthop" */
+#line 5435 "parser_bison.y"
+ { (yyval.val) = NFT_RT_NEXTHOP4; }
+#line 15176 "parser_bison.c"
+ break;
+
+ case 1008: /* rt_key: "mtu" */
+#line 5436 "parser_bison.y"
+ { (yyval.val) = NFT_RT_TCPMSS; }
+#line 15182 "parser_bison.c"
+ break;
+
+ case 1009: /* rt_key: "ipsec" close_scope_ipsec */
+#line 5437 "parser_bison.y"
+ { (yyval.val) = NFT_RT_XFRM; }
+#line 15188 "parser_bison.c"
+ break;
+
+ case 1010: /* ct_expr: "ct" ct_key close_scope_ct */
+#line 5441 "parser_bison.y"
+ {
+ (yyval.expr) = ct_expr_alloc(&(yyloc), (yyvsp[-1].val), -1);
+ }
+#line 15196 "parser_bison.c"
+ break;
+
+ case 1011: /* ct_expr: "ct" ct_dir ct_key_dir close_scope_ct */
+#line 5445 "parser_bison.y"
+ {
+ (yyval.expr) = ct_expr_alloc(&(yyloc), (yyvsp[-1].val), (yyvsp[-2].val));
+ }
+#line 15204 "parser_bison.c"
+ break;
+
+ case 1012: /* ct_expr: "ct" ct_dir ct_key_proto_field close_scope_ct */
+#line 5449 "parser_bison.y"
+ {
+ (yyval.expr) = ct_expr_alloc(&(yyloc), (yyvsp[-1].val), (yyvsp[-2].val));
+ }
+#line 15212 "parser_bison.c"
+ break;
+
+ case 1013: /* ct_dir: "original" */
+#line 5454 "parser_bison.y"
+ { (yyval.val) = IP_CT_DIR_ORIGINAL; }
+#line 15218 "parser_bison.c"
+ break;
+
+ case 1014: /* ct_dir: "reply" */
+#line 5455 "parser_bison.y"
+ { (yyval.val) = IP_CT_DIR_REPLY; }
+#line 15224 "parser_bison.c"
+ break;
+
+ case 1015: /* ct_key: "l3proto" */
+#line 5458 "parser_bison.y"
+ { (yyval.val) = NFT_CT_L3PROTOCOL; }
+#line 15230 "parser_bison.c"
+ break;
+
+ case 1016: /* ct_key: "protocol" */
+#line 5459 "parser_bison.y"
+ { (yyval.val) = NFT_CT_PROTOCOL; }
+#line 15236 "parser_bison.c"
+ break;
+
+ case 1017: /* ct_key: "mark" */
+#line 5460 "parser_bison.y"
+ { (yyval.val) = NFT_CT_MARK; }
+#line 15242 "parser_bison.c"
+ break;
+
+ case 1018: /* ct_key: "state" */
+#line 5461 "parser_bison.y"
+ { (yyval.val) = NFT_CT_STATE; }
+#line 15248 "parser_bison.c"
+ break;
+
+ case 1019: /* ct_key: "direction" */
+#line 5462 "parser_bison.y"
+ { (yyval.val) = NFT_CT_DIRECTION; }
+#line 15254 "parser_bison.c"
+ break;
+
+ case 1020: /* ct_key: "status" */
+#line 5463 "parser_bison.y"
+ { (yyval.val) = NFT_CT_STATUS; }
+#line 15260 "parser_bison.c"
+ break;
+
+ case 1021: /* ct_key: "expiration" */
+#line 5464 "parser_bison.y"
+ { (yyval.val) = NFT_CT_EXPIRATION; }
+#line 15266 "parser_bison.c"
+ break;
+
+ case 1022: /* ct_key: "helper" */
+#line 5465 "parser_bison.y"
+ { (yyval.val) = NFT_CT_HELPER; }
+#line 15272 "parser_bison.c"
+ break;
+
+ case 1023: /* ct_key: "saddr" */
+#line 5466 "parser_bison.y"
+ { (yyval.val) = NFT_CT_SRC; }
+#line 15278 "parser_bison.c"
+ break;
+
+ case 1024: /* ct_key: "daddr" */
+#line 5467 "parser_bison.y"
+ { (yyval.val) = NFT_CT_DST; }
+#line 15284 "parser_bison.c"
+ break;
+
+ case 1025: /* ct_key: "proto-src" */
+#line 5468 "parser_bison.y"
+ { (yyval.val) = NFT_CT_PROTO_SRC; }
+#line 15290 "parser_bison.c"
+ break;
+
+ case 1026: /* ct_key: "proto-dst" */
+#line 5469 "parser_bison.y"
+ { (yyval.val) = NFT_CT_PROTO_DST; }
+#line 15296 "parser_bison.c"
+ break;
+
+ case 1027: /* ct_key: "label" */
+#line 5470 "parser_bison.y"
+ { (yyval.val) = NFT_CT_LABELS; }
+#line 15302 "parser_bison.c"
+ break;
+
+ case 1028: /* ct_key: "event" */
+#line 5471 "parser_bison.y"
+ { (yyval.val) = NFT_CT_EVENTMASK; }
+#line 15308 "parser_bison.c"
+ break;
+
+ case 1029: /* ct_key: "secmark" close_scope_secmark */
+#line 5472 "parser_bison.y"
+ { (yyval.val) = NFT_CT_SECMARK; }
+#line 15314 "parser_bison.c"
+ break;
+
+ case 1030: /* ct_key: "id" */
+#line 5473 "parser_bison.y"
+ { (yyval.val) = NFT_CT_ID; }
+#line 15320 "parser_bison.c"
+ break;
+
+ case 1032: /* ct_key_dir: "saddr" */
+#line 5477 "parser_bison.y"
+ { (yyval.val) = NFT_CT_SRC; }
+#line 15326 "parser_bison.c"
+ break;
+
+ case 1033: /* ct_key_dir: "daddr" */
+#line 5478 "parser_bison.y"
+ { (yyval.val) = NFT_CT_DST; }
+#line 15332 "parser_bison.c"
+ break;
+
+ case 1034: /* ct_key_dir: "l3proto" */
+#line 5479 "parser_bison.y"
+ { (yyval.val) = NFT_CT_L3PROTOCOL; }
+#line 15338 "parser_bison.c"
+ break;
+
+ case 1035: /* ct_key_dir: "protocol" */
+#line 5480 "parser_bison.y"
+ { (yyval.val) = NFT_CT_PROTOCOL; }
+#line 15344 "parser_bison.c"
+ break;
+
+ case 1036: /* ct_key_dir: "proto-src" */
+#line 5481 "parser_bison.y"
+ { (yyval.val) = NFT_CT_PROTO_SRC; }
+#line 15350 "parser_bison.c"
+ break;
+
+ case 1037: /* ct_key_dir: "proto-dst" */
+#line 5482 "parser_bison.y"
+ { (yyval.val) = NFT_CT_PROTO_DST; }
+#line 15356 "parser_bison.c"
+ break;
+
+ case 1039: /* ct_key_proto_field: "ip" "saddr" close_scope_ip */
+#line 5486 "parser_bison.y"
+ { (yyval.val) = NFT_CT_SRC_IP; }
+#line 15362 "parser_bison.c"
+ break;
+
+ case 1040: /* ct_key_proto_field: "ip" "daddr" close_scope_ip */
+#line 5487 "parser_bison.y"
+ { (yyval.val) = NFT_CT_DST_IP; }
+#line 15368 "parser_bison.c"
+ break;
+
+ case 1041: /* ct_key_proto_field: "ip6" "saddr" close_scope_ip6 */
+#line 5488 "parser_bison.y"
+ { (yyval.val) = NFT_CT_SRC_IP6; }
+#line 15374 "parser_bison.c"
+ break;
+
+ case 1042: /* ct_key_proto_field: "ip6" "daddr" close_scope_ip6 */
+#line 5489 "parser_bison.y"
+ { (yyval.val) = NFT_CT_DST_IP6; }
+#line 15380 "parser_bison.c"
+ break;
+
+ case 1043: /* ct_key_dir_optional: "bytes" */
+#line 5492 "parser_bison.y"
+ { (yyval.val) = NFT_CT_BYTES; }
+#line 15386 "parser_bison.c"
+ break;
+
+ case 1044: /* ct_key_dir_optional: "packets" */
+#line 5493 "parser_bison.y"
+ { (yyval.val) = NFT_CT_PKTS; }
+#line 15392 "parser_bison.c"
+ break;
+
+ case 1045: /* ct_key_dir_optional: "avgpkt" */
+#line 5494 "parser_bison.y"
+ { (yyval.val) = NFT_CT_AVGPKT; }
+#line 15398 "parser_bison.c"
+ break;
+
+ case 1046: /* ct_key_dir_optional: "zone" */
+#line 5495 "parser_bison.y"
+ { (yyval.val) = NFT_CT_ZONE; }
+#line 15404 "parser_bison.c"
+ break;
+
+ case 1049: /* list_stmt_expr: symbol_stmt_expr "comma" symbol_stmt_expr */
+#line 5503 "parser_bison.y"
+ {
+ (yyval.expr) = list_expr_alloc(&(yyloc));
+ compound_expr_add((yyval.expr), (yyvsp[-2].expr));
+ compound_expr_add((yyval.expr), (yyvsp[0].expr));
+ }
+#line 15414 "parser_bison.c"
+ break;
+
+ case 1050: /* list_stmt_expr: list_stmt_expr "comma" symbol_stmt_expr */
+#line 5509 "parser_bison.y"
+ {
+ (yyvsp[-2].expr)->location = (yyloc);
+ compound_expr_add((yyvsp[-2].expr), (yyvsp[0].expr));
+ (yyval.expr) = (yyvsp[-2].expr);
+ }
+#line 15424 "parser_bison.c"
+ break;
+
+ case 1051: /* ct_stmt: "ct" ct_key "set" stmt_expr close_scope_ct */
+#line 5517 "parser_bison.y"
+ {
+ switch ((yyvsp[-3].val)) {
+ case NFT_CT_HELPER:
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_CT_HELPER;
+ (yyval.stmt)->objref.expr = (yyvsp[-1].expr);
+ break;
+ default:
+ (yyval.stmt) = ct_stmt_alloc(&(yyloc), (yyvsp[-3].val), -1, (yyvsp[-1].expr));
+ break;
+ }
+ }
+#line 15441 "parser_bison.c"
+ break;
+
+ case 1052: /* ct_stmt: "ct" "timeout" "set" stmt_expr close_scope_ct */
+#line 5530 "parser_bison.y"
+ {
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_CT_TIMEOUT;
+ (yyval.stmt)->objref.expr = (yyvsp[-1].expr);
+
+ }
+#line 15452 "parser_bison.c"
+ break;
+
+ case 1053: /* ct_stmt: "ct" "expectation" "set" stmt_expr close_scope_ct */
+#line 5537 "parser_bison.y"
+ {
+ (yyval.stmt) = objref_stmt_alloc(&(yyloc));
+ (yyval.stmt)->objref.type = NFT_OBJECT_CT_EXPECT;
+ (yyval.stmt)->objref.expr = (yyvsp[-1].expr);
+ }
+#line 15462 "parser_bison.c"
+ break;
+
+ case 1054: /* ct_stmt: "ct" ct_dir ct_key_dir_optional "set" stmt_expr close_scope_ct */
+#line 5543 "parser_bison.y"
+ {
+ (yyval.stmt) = ct_stmt_alloc(&(yyloc), (yyvsp[-3].val), (yyvsp[-4].val), (yyvsp[-1].expr));
+ }
+#line 15470 "parser_bison.c"
+ break;
+
+ case 1055: /* payload_stmt: payload_expr "set" stmt_expr */
+#line 5549 "parser_bison.y"
+ {
+ if ((yyvsp[-2].expr)->etype == EXPR_EXTHDR)
+ (yyval.stmt) = exthdr_stmt_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ else
+ (yyval.stmt) = payload_stmt_alloc(&(yyloc), (yyvsp[-2].expr), (yyvsp[0].expr));
+ }
+#line 15481 "parser_bison.c"
+ break;
+
+ case 1078: /* payload_raw_expr: "@" payload_base_spec "comma" "number" "comma" "number" close_scope_at */
+#line 5582 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), NULL, 0);
+ payload_init_raw((yyval.expr), (yyvsp[-5].val), (yyvsp[-3].val), (yyvsp[-1].val));
+ (yyval.expr)->byteorder = BYTEORDER_BIG_ENDIAN;
+ (yyval.expr)->payload.is_raw = true;
+ }
+#line 15492 "parser_bison.c"
+ break;
+
+ case 1079: /* payload_base_spec: "ll" */
+#line 5590 "parser_bison.y"
+ { (yyval.val) = PROTO_BASE_LL_HDR; }
+#line 15498 "parser_bison.c"
+ break;
+
+ case 1080: /* payload_base_spec: "nh" */
+#line 5591 "parser_bison.y"
+ { (yyval.val) = PROTO_BASE_NETWORK_HDR; }
+#line 15504 "parser_bison.c"
+ break;
+
+ case 1081: /* payload_base_spec: "th" close_scope_th */
+#line 5592 "parser_bison.y"
+ { (yyval.val) = PROTO_BASE_TRANSPORT_HDR; }
+#line 15510 "parser_bison.c"
+ break;
+
+ case 1082: /* payload_base_spec: "string" */
+#line 5594 "parser_bison.y"
+ {
+ if (!strcmp((yyvsp[0].string), "ih")) {
+ (yyval.val) = PROTO_BASE_INNER_HDR;
+ } else {
+ erec_queue(error(&(yylsp[0]), "unknown raw payload base"), state->msgs);
+ xfree((yyvsp[0].string));
+ YYERROR;
+ }
+ xfree((yyvsp[0].string));
+ }
+#line 15525 "parser_bison.c"
+ break;
+
+ case 1083: /* eth_hdr_expr: "ether" eth_hdr_field close_scope_eth */
+#line 5607 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_eth, (yyvsp[-1].val));
+ }
+#line 15533 "parser_bison.c"
+ break;
+
+ case 1084: /* eth_hdr_field: "saddr" */
+#line 5612 "parser_bison.y"
+ { (yyval.val) = ETHHDR_SADDR; }
+#line 15539 "parser_bison.c"
+ break;
+
+ case 1085: /* eth_hdr_field: "daddr" */
+#line 5613 "parser_bison.y"
+ { (yyval.val) = ETHHDR_DADDR; }
+#line 15545 "parser_bison.c"
+ break;
+
+ case 1086: /* eth_hdr_field: "type" close_scope_type */
+#line 5614 "parser_bison.y"
+ { (yyval.val) = ETHHDR_TYPE; }
+#line 15551 "parser_bison.c"
+ break;
+
+ case 1087: /* vlan_hdr_expr: "vlan" vlan_hdr_field close_scope_vlan */
+#line 5618 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_vlan, (yyvsp[-1].val));
+ }
+#line 15559 "parser_bison.c"
+ break;
+
+ case 1088: /* vlan_hdr_field: "id" */
+#line 5623 "parser_bison.y"
+ { (yyval.val) = VLANHDR_VID; }
+#line 15565 "parser_bison.c"
+ break;
+
+ case 1089: /* vlan_hdr_field: "cfi" */
+#line 5624 "parser_bison.y"
+ { (yyval.val) = VLANHDR_CFI; }
+#line 15571 "parser_bison.c"
+ break;
+
+ case 1090: /* vlan_hdr_field: "dei" */
+#line 5625 "parser_bison.y"
+ { (yyval.val) = VLANHDR_DEI; }
+#line 15577 "parser_bison.c"
+ break;
+
+ case 1091: /* vlan_hdr_field: "pcp" */
+#line 5626 "parser_bison.y"
+ { (yyval.val) = VLANHDR_PCP; }
+#line 15583 "parser_bison.c"
+ break;
+
+ case 1092: /* vlan_hdr_field: "type" close_scope_type */
+#line 5627 "parser_bison.y"
+ { (yyval.val) = VLANHDR_TYPE; }
+#line 15589 "parser_bison.c"
+ break;
+
+ case 1093: /* arp_hdr_expr: "arp" arp_hdr_field close_scope_arp */
+#line 5631 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_arp, (yyvsp[-1].val));
+ }
+#line 15597 "parser_bison.c"
+ break;
+
+ case 1094: /* arp_hdr_field: "htype" */
+#line 5636 "parser_bison.y"
+ { (yyval.val) = ARPHDR_HRD; }
+#line 15603 "parser_bison.c"
+ break;
+
+ case 1095: /* arp_hdr_field: "ptype" */
+#line 5637 "parser_bison.y"
+ { (yyval.val) = ARPHDR_PRO; }
+#line 15609 "parser_bison.c"
+ break;
+
+ case 1096: /* arp_hdr_field: "hlen" */
+#line 5638 "parser_bison.y"
+ { (yyval.val) = ARPHDR_HLN; }
+#line 15615 "parser_bison.c"
+ break;
+
+ case 1097: /* arp_hdr_field: "plen" */
+#line 5639 "parser_bison.y"
+ { (yyval.val) = ARPHDR_PLN; }
+#line 15621 "parser_bison.c"
+ break;
+
+ case 1098: /* arp_hdr_field: "operation" */
+#line 5640 "parser_bison.y"
+ { (yyval.val) = ARPHDR_OP; }
+#line 15627 "parser_bison.c"
+ break;
+
+ case 1099: /* arp_hdr_field: "saddr" "ether" close_scope_eth */
+#line 5641 "parser_bison.y"
+ { (yyval.val) = ARPHDR_SADDR_ETHER; }
+#line 15633 "parser_bison.c"
+ break;
+
+ case 1100: /* arp_hdr_field: "daddr" "ether" close_scope_eth */
+#line 5642 "parser_bison.y"
+ { (yyval.val) = ARPHDR_DADDR_ETHER; }
+#line 15639 "parser_bison.c"
+ break;
+
+ case 1101: /* arp_hdr_field: "saddr" "ip" close_scope_ip */
+#line 5643 "parser_bison.y"
+ { (yyval.val) = ARPHDR_SADDR_IP; }
+#line 15645 "parser_bison.c"
+ break;
+
+ case 1102: /* arp_hdr_field: "daddr" "ip" close_scope_ip */
+#line 5644 "parser_bison.y"
+ { (yyval.val) = ARPHDR_DADDR_IP; }
+#line 15651 "parser_bison.c"
+ break;
+
+ case 1103: /* ip_hdr_expr: "ip" ip_hdr_field close_scope_ip */
+#line 5648 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_ip, (yyvsp[-1].val));
+ }
+#line 15659 "parser_bison.c"
+ break;
+
+ case 1104: /* ip_hdr_expr: "ip" "option" ip_option_type ip_option_field close_scope_ip */
+#line 5652 "parser_bison.y"
+ {
+ (yyval.expr) = ipopt_expr_alloc(&(yyloc), (yyvsp[-2].val), (yyvsp[-1].val));
+ if (!(yyval.expr)) {
+ erec_queue(error(&(yylsp[-4]), "unknown ip option type/field"), state->msgs);
+ YYERROR;
+ }
+ }
+#line 15671 "parser_bison.c"
+ break;
+
+ case 1105: /* ip_hdr_expr: "ip" "option" ip_option_type close_scope_ip */
+#line 5660 "parser_bison.y"
+ {
+ (yyval.expr) = ipopt_expr_alloc(&(yyloc), (yyvsp[-1].val), IPOPT_FIELD_TYPE);
+ (yyval.expr)->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+#line 15680 "parser_bison.c"
+ break;
+
+ case 1106: /* ip_hdr_field: "version" */
+#line 5666 "parser_bison.y"
+ { (yyval.val) = IPHDR_VERSION; }
+#line 15686 "parser_bison.c"
+ break;
+
+ case 1107: /* ip_hdr_field: "hdrlength" */
+#line 5667 "parser_bison.y"
+ { (yyval.val) = IPHDR_HDRLENGTH; }
+#line 15692 "parser_bison.c"
+ break;
+
+ case 1108: /* ip_hdr_field: "dscp" */
+#line 5668 "parser_bison.y"
+ { (yyval.val) = IPHDR_DSCP; }
+#line 15698 "parser_bison.c"
+ break;
+
+ case 1109: /* ip_hdr_field: "ecn" */
+#line 5669 "parser_bison.y"
+ { (yyval.val) = IPHDR_ECN; }
+#line 15704 "parser_bison.c"
+ break;
+
+ case 1110: /* ip_hdr_field: "length" */
+#line 5670 "parser_bison.y"
+ { (yyval.val) = IPHDR_LENGTH; }
+#line 15710 "parser_bison.c"
+ break;
+
+ case 1111: /* ip_hdr_field: "id" */
+#line 5671 "parser_bison.y"
+ { (yyval.val) = IPHDR_ID; }
+#line 15716 "parser_bison.c"
+ break;
+
+ case 1112: /* ip_hdr_field: "frag-off" */
+#line 5672 "parser_bison.y"
+ { (yyval.val) = IPHDR_FRAG_OFF; }
+#line 15722 "parser_bison.c"
+ break;
+
+ case 1113: /* ip_hdr_field: "ttl" */
+#line 5673 "parser_bison.y"
+ { (yyval.val) = IPHDR_TTL; }
+#line 15728 "parser_bison.c"
+ break;
+
+ case 1114: /* ip_hdr_field: "protocol" */
+#line 5674 "parser_bison.y"
+ { (yyval.val) = IPHDR_PROTOCOL; }
+#line 15734 "parser_bison.c"
+ break;
+
+ case 1115: /* ip_hdr_field: "checksum" */
+#line 5675 "parser_bison.y"
+ { (yyval.val) = IPHDR_CHECKSUM; }
+#line 15740 "parser_bison.c"
+ break;
+
+ case 1116: /* ip_hdr_field: "saddr" */
+#line 5676 "parser_bison.y"
+ { (yyval.val) = IPHDR_SADDR; }
+#line 15746 "parser_bison.c"
+ break;
+
+ case 1117: /* ip_hdr_field: "daddr" */
+#line 5677 "parser_bison.y"
+ { (yyval.val) = IPHDR_DADDR; }
+#line 15752 "parser_bison.c"
+ break;
+
+ case 1118: /* ip_option_type: "lsrr" */
+#line 5680 "parser_bison.y"
+ { (yyval.val) = IPOPT_LSRR; }
+#line 15758 "parser_bison.c"
+ break;
+
+ case 1119: /* ip_option_type: "rr" */
+#line 5681 "parser_bison.y"
+ { (yyval.val) = IPOPT_RR; }
+#line 15764 "parser_bison.c"
+ break;
+
+ case 1120: /* ip_option_type: "ssrr" */
+#line 5682 "parser_bison.y"
+ { (yyval.val) = IPOPT_SSRR; }
+#line 15770 "parser_bison.c"
+ break;
+
+ case 1121: /* ip_option_type: "ra" */
+#line 5683 "parser_bison.y"
+ { (yyval.val) = IPOPT_RA; }
+#line 15776 "parser_bison.c"
+ break;
+
+ case 1122: /* ip_option_field: "type" close_scope_type */
+#line 5686 "parser_bison.y"
+ { (yyval.val) = IPOPT_FIELD_TYPE; }
+#line 15782 "parser_bison.c"
+ break;
+
+ case 1123: /* ip_option_field: "length" */
+#line 5687 "parser_bison.y"
+ { (yyval.val) = IPOPT_FIELD_LENGTH; }
+#line 15788 "parser_bison.c"
+ break;
+
+ case 1124: /* ip_option_field: "value" */
+#line 5688 "parser_bison.y"
+ { (yyval.val) = IPOPT_FIELD_VALUE; }
+#line 15794 "parser_bison.c"
+ break;
+
+ case 1125: /* ip_option_field: "ptr" */
+#line 5689 "parser_bison.y"
+ { (yyval.val) = IPOPT_FIELD_PTR; }
+#line 15800 "parser_bison.c"
+ break;
+
+ case 1126: /* ip_option_field: "addr" */
+#line 5690 "parser_bison.y"
+ { (yyval.val) = IPOPT_FIELD_ADDR_0; }
+#line 15806 "parser_bison.c"
+ break;
+
+ case 1127: /* icmp_hdr_expr: "icmp" icmp_hdr_field close_scope_icmp */
+#line 5694 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_icmp, (yyvsp[-1].val));
+ }
+#line 15814 "parser_bison.c"
+ break;
+
+ case 1128: /* icmp_hdr_field: "type" close_scope_type */
+#line 5699 "parser_bison.y"
+ { (yyval.val) = ICMPHDR_TYPE; }
+#line 15820 "parser_bison.c"
+ break;
+
+ case 1129: /* icmp_hdr_field: "code" */
+#line 5700 "parser_bison.y"
+ { (yyval.val) = ICMPHDR_CODE; }
+#line 15826 "parser_bison.c"
+ break;
+
+ case 1130: /* icmp_hdr_field: "checksum" */
+#line 5701 "parser_bison.y"
+ { (yyval.val) = ICMPHDR_CHECKSUM; }
+#line 15832 "parser_bison.c"
+ break;
+
+ case 1131: /* icmp_hdr_field: "id" */
+#line 5702 "parser_bison.y"
+ { (yyval.val) = ICMPHDR_ID; }
+#line 15838 "parser_bison.c"
+ break;
+
+ case 1132: /* icmp_hdr_field: "seq" */
+#line 5703 "parser_bison.y"
+ { (yyval.val) = ICMPHDR_SEQ; }
+#line 15844 "parser_bison.c"
+ break;
+
+ case 1133: /* icmp_hdr_field: "gateway" */
+#line 5704 "parser_bison.y"
+ { (yyval.val) = ICMPHDR_GATEWAY; }
+#line 15850 "parser_bison.c"
+ break;
+
+ case 1134: /* icmp_hdr_field: "mtu" */
+#line 5705 "parser_bison.y"
+ { (yyval.val) = ICMPHDR_MTU; }
+#line 15856 "parser_bison.c"
+ break;
+
+ case 1135: /* igmp_hdr_expr: "igmp" igmp_hdr_field close_scope_igmp */
+#line 5709 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_igmp, (yyvsp[-1].val));
+ }
+#line 15864 "parser_bison.c"
+ break;
+
+ case 1136: /* igmp_hdr_field: "type" close_scope_type */
+#line 5714 "parser_bison.y"
+ { (yyval.val) = IGMPHDR_TYPE; }
+#line 15870 "parser_bison.c"
+ break;
+
+ case 1137: /* igmp_hdr_field: "checksum" */
+#line 5715 "parser_bison.y"
+ { (yyval.val) = IGMPHDR_CHECKSUM; }
+#line 15876 "parser_bison.c"
+ break;
+
+ case 1138: /* igmp_hdr_field: "mrt" */
+#line 5716 "parser_bison.y"
+ { (yyval.val) = IGMPHDR_MRT; }
+#line 15882 "parser_bison.c"
+ break;
+
+ case 1139: /* igmp_hdr_field: "group" */
+#line 5717 "parser_bison.y"
+ { (yyval.val) = IGMPHDR_GROUP; }
+#line 15888 "parser_bison.c"
+ break;
+
+ case 1140: /* ip6_hdr_expr: "ip6" ip6_hdr_field close_scope_ip6 */
+#line 5721 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_ip6, (yyvsp[-1].val));
+ }
+#line 15896 "parser_bison.c"
+ break;
+
+ case 1141: /* ip6_hdr_field: "version" */
+#line 5726 "parser_bison.y"
+ { (yyval.val) = IP6HDR_VERSION; }
+#line 15902 "parser_bison.c"
+ break;
+
+ case 1142: /* ip6_hdr_field: "dscp" */
+#line 5727 "parser_bison.y"
+ { (yyval.val) = IP6HDR_DSCP; }
+#line 15908 "parser_bison.c"
+ break;
+
+ case 1143: /* ip6_hdr_field: "ecn" */
+#line 5728 "parser_bison.y"
+ { (yyval.val) = IP6HDR_ECN; }
+#line 15914 "parser_bison.c"
+ break;
+
+ case 1144: /* ip6_hdr_field: "flowlabel" */
+#line 5729 "parser_bison.y"
+ { (yyval.val) = IP6HDR_FLOWLABEL; }
+#line 15920 "parser_bison.c"
+ break;
+
+ case 1145: /* ip6_hdr_field: "length" */
+#line 5730 "parser_bison.y"
+ { (yyval.val) = IP6HDR_LENGTH; }
+#line 15926 "parser_bison.c"
+ break;
+
+ case 1146: /* ip6_hdr_field: "nexthdr" */
+#line 5731 "parser_bison.y"
+ { (yyval.val) = IP6HDR_NEXTHDR; }
+#line 15932 "parser_bison.c"
+ break;
+
+ case 1147: /* ip6_hdr_field: "hoplimit" */
+#line 5732 "parser_bison.y"
+ { (yyval.val) = IP6HDR_HOPLIMIT; }
+#line 15938 "parser_bison.c"
+ break;
+
+ case 1148: /* ip6_hdr_field: "saddr" */
+#line 5733 "parser_bison.y"
+ { (yyval.val) = IP6HDR_SADDR; }
+#line 15944 "parser_bison.c"
+ break;
+
+ case 1149: /* ip6_hdr_field: "daddr" */
+#line 5734 "parser_bison.y"
+ { (yyval.val) = IP6HDR_DADDR; }
+#line 15950 "parser_bison.c"
+ break;
+
+ case 1150: /* icmp6_hdr_expr: "icmpv6" icmp6_hdr_field close_scope_icmp */
+#line 5737 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_icmp6, (yyvsp[-1].val));
+ }
+#line 15958 "parser_bison.c"
+ break;
+
+ case 1151: /* icmp6_hdr_field: "type" close_scope_type */
+#line 5742 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_TYPE; }
+#line 15964 "parser_bison.c"
+ break;
+
+ case 1152: /* icmp6_hdr_field: "code" */
+#line 5743 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_CODE; }
+#line 15970 "parser_bison.c"
+ break;
+
+ case 1153: /* icmp6_hdr_field: "checksum" */
+#line 5744 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_CHECKSUM; }
+#line 15976 "parser_bison.c"
+ break;
+
+ case 1154: /* icmp6_hdr_field: "param-problem" */
+#line 5745 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_PPTR; }
+#line 15982 "parser_bison.c"
+ break;
+
+ case 1155: /* icmp6_hdr_field: "mtu" */
+#line 5746 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_MTU; }
+#line 15988 "parser_bison.c"
+ break;
+
+ case 1156: /* icmp6_hdr_field: "id" */
+#line 5747 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_ID; }
+#line 15994 "parser_bison.c"
+ break;
+
+ case 1157: /* icmp6_hdr_field: "seq" */
+#line 5748 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_SEQ; }
+#line 16000 "parser_bison.c"
+ break;
+
+ case 1158: /* icmp6_hdr_field: "max-delay" */
+#line 5749 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_MAXDELAY; }
+#line 16006 "parser_bison.c"
+ break;
+
+ case 1159: /* icmp6_hdr_field: "taddr" */
+#line 5750 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_TADDR; }
+#line 16012 "parser_bison.c"
+ break;
+
+ case 1160: /* icmp6_hdr_field: "daddr" */
+#line 5751 "parser_bison.y"
+ { (yyval.val) = ICMP6HDR_DADDR; }
+#line 16018 "parser_bison.c"
+ break;
+
+ case 1161: /* auth_hdr_expr: "ah" auth_hdr_field close_scope_ah */
+#line 5755 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_ah, (yyvsp[-1].val));
+ }
+#line 16026 "parser_bison.c"
+ break;
+
+ case 1162: /* auth_hdr_field: "nexthdr" */
+#line 5760 "parser_bison.y"
+ { (yyval.val) = AHHDR_NEXTHDR; }
+#line 16032 "parser_bison.c"
+ break;
+
+ case 1163: /* auth_hdr_field: "hdrlength" */
+#line 5761 "parser_bison.y"
+ { (yyval.val) = AHHDR_HDRLENGTH; }
+#line 16038 "parser_bison.c"
+ break;
+
+ case 1164: /* auth_hdr_field: "reserved" */
+#line 5762 "parser_bison.y"
+ { (yyval.val) = AHHDR_RESERVED; }
+#line 16044 "parser_bison.c"
+ break;
+
+ case 1165: /* auth_hdr_field: "spi" */
+#line 5763 "parser_bison.y"
+ { (yyval.val) = AHHDR_SPI; }
+#line 16050 "parser_bison.c"
+ break;
+
+ case 1166: /* auth_hdr_field: "seq" */
+#line 5764 "parser_bison.y"
+ { (yyval.val) = AHHDR_SEQUENCE; }
+#line 16056 "parser_bison.c"
+ break;
+
+ case 1167: /* esp_hdr_expr: "esp" esp_hdr_field close_scope_esp */
+#line 5768 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_esp, (yyvsp[-1].val));
+ }
+#line 16064 "parser_bison.c"
+ break;
+
+ case 1168: /* esp_hdr_field: "spi" */
+#line 5773 "parser_bison.y"
+ { (yyval.val) = ESPHDR_SPI; }
+#line 16070 "parser_bison.c"
+ break;
+
+ case 1169: /* esp_hdr_field: "seq" */
+#line 5774 "parser_bison.y"
+ { (yyval.val) = ESPHDR_SEQUENCE; }
+#line 16076 "parser_bison.c"
+ break;
+
+ case 1170: /* comp_hdr_expr: "comp" comp_hdr_field close_scope_comp */
+#line 5778 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_comp, (yyvsp[-1].val));
+ }
+#line 16084 "parser_bison.c"
+ break;
+
+ case 1171: /* comp_hdr_field: "nexthdr" */
+#line 5783 "parser_bison.y"
+ { (yyval.val) = COMPHDR_NEXTHDR; }
+#line 16090 "parser_bison.c"
+ break;
+
+ case 1172: /* comp_hdr_field: "flags" */
+#line 5784 "parser_bison.y"
+ { (yyval.val) = COMPHDR_FLAGS; }
+#line 16096 "parser_bison.c"
+ break;
+
+ case 1173: /* comp_hdr_field: "cpi" */
+#line 5785 "parser_bison.y"
+ { (yyval.val) = COMPHDR_CPI; }
+#line 16102 "parser_bison.c"
+ break;
+
+ case 1174: /* udp_hdr_expr: "udp" udp_hdr_field close_scope_udp */
+#line 5789 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_udp, (yyvsp[-1].val));
+ }
+#line 16110 "parser_bison.c"
+ break;
+
+ case 1175: /* udp_hdr_field: "sport" */
+#line 5794 "parser_bison.y"
+ { (yyval.val) = UDPHDR_SPORT; }
+#line 16116 "parser_bison.c"
+ break;
+
+ case 1176: /* udp_hdr_field: "dport" */
+#line 5795 "parser_bison.y"
+ { (yyval.val) = UDPHDR_DPORT; }
+#line 16122 "parser_bison.c"
+ break;
+
+ case 1177: /* udp_hdr_field: "length" */
+#line 5796 "parser_bison.y"
+ { (yyval.val) = UDPHDR_LENGTH; }
+#line 16128 "parser_bison.c"
+ break;
+
+ case 1178: /* udp_hdr_field: "checksum" */
+#line 5797 "parser_bison.y"
+ { (yyval.val) = UDPHDR_CHECKSUM; }
+#line 16134 "parser_bison.c"
+ break;
+
+ case 1179: /* udplite_hdr_expr: "udplite" udplite_hdr_field close_scope_udplite */
+#line 5801 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_udplite, (yyvsp[-1].val));
+ }
+#line 16142 "parser_bison.c"
+ break;
+
+ case 1180: /* udplite_hdr_field: "sport" */
+#line 5806 "parser_bison.y"
+ { (yyval.val) = UDPHDR_SPORT; }
+#line 16148 "parser_bison.c"
+ break;
+
+ case 1181: /* udplite_hdr_field: "dport" */
+#line 5807 "parser_bison.y"
+ { (yyval.val) = UDPHDR_DPORT; }
+#line 16154 "parser_bison.c"
+ break;
+
+ case 1182: /* udplite_hdr_field: "csumcov" */
+#line 5808 "parser_bison.y"
+ { (yyval.val) = UDPHDR_LENGTH; }
+#line 16160 "parser_bison.c"
+ break;
+
+ case 1183: /* udplite_hdr_field: "checksum" */
+#line 5809 "parser_bison.y"
+ { (yyval.val) = UDPHDR_CHECKSUM; }
+#line 16166 "parser_bison.c"
+ break;
+
+ case 1184: /* tcp_hdr_expr: "tcp" tcp_hdr_field */
+#line 5813 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_tcp, (yyvsp[0].val));
+ }
+#line 16174 "parser_bison.c"
+ break;
+
+ case 1185: /* tcp_hdr_expr: "tcp" "option" tcp_hdr_option_type */
+#line 5817 "parser_bison.y"
+ {
+ (yyval.expr) = tcpopt_expr_alloc(&(yyloc), (yyvsp[0].val), TCPOPT_COMMON_KIND);
+ (yyval.expr)->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+#line 16183 "parser_bison.c"
+ break;
+
+ case 1186: /* tcp_hdr_expr: "tcp" "option" tcp_hdr_option_kind_and_field */
+#line 5822 "parser_bison.y"
+ {
+ (yyval.expr) = tcpopt_expr_alloc(&(yyloc), (yyvsp[0].tcp_kind_field).kind, (yyvsp[0].tcp_kind_field).field);
+ }
+#line 16191 "parser_bison.c"
+ break;
+
+ case 1187: /* tcp_hdr_expr: "tcp" "option" "@" close_scope_at tcp_hdr_option_type "comma" "number" "comma" "number" */
+#line 5826 "parser_bison.y"
+ {
+ (yyval.expr) = tcpopt_expr_alloc(&(yyloc), (yyvsp[-4].val), 0);
+ tcpopt_init_raw((yyval.expr), (yyvsp[-4].val), (yyvsp[-2].val), (yyvsp[0].val), 0);
+ }
+#line 16200 "parser_bison.c"
+ break;
+
+ case 1207: /* vxlan_hdr_expr: "vxlan" vxlan_hdr_field */
+#line 5858 "parser_bison.y"
+ {
+ struct expr *expr;
+
+ expr = payload_expr_alloc(&(yyloc), &proto_vxlan, (yyvsp[0].val));
+ expr->payload.inner_desc = &proto_vxlan;
+ (yyval.expr) = expr;
+ }
+#line 16212 "parser_bison.c"
+ break;
+
+ case 1208: /* vxlan_hdr_expr: "vxlan" inner_expr */
+#line 5866 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[0].expr);
+ (yyval.expr)->location = (yyloc);
+ (yyval.expr)->payload.inner_desc = &proto_vxlan;
+ }
+#line 16222 "parser_bison.c"
+ break;
+
+ case 1209: /* vxlan_hdr_field: "vni" */
+#line 5873 "parser_bison.y"
+ { (yyval.val) = VXLANHDR_VNI; }
+#line 16228 "parser_bison.c"
+ break;
+
+ case 1210: /* vxlan_hdr_field: "flags" */
+#line 5874 "parser_bison.y"
+ { (yyval.val) = VXLANHDR_FLAGS; }
+#line 16234 "parser_bison.c"
+ break;
+
+ case 1211: /* geneve_hdr_expr: "geneve" geneve_hdr_field */
+#line 5878 "parser_bison.y"
+ {
+ struct expr *expr;
+
+ expr = payload_expr_alloc(&(yyloc), &proto_geneve, (yyvsp[0].val));
+ expr->payload.inner_desc = &proto_geneve;
+ (yyval.expr) = expr;
+ }
+#line 16246 "parser_bison.c"
+ break;
+
+ case 1212: /* geneve_hdr_expr: "geneve" inner_expr */
+#line 5886 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[0].expr);
+ (yyval.expr)->location = (yyloc);
+ (yyval.expr)->payload.inner_desc = &proto_geneve;
+ }
+#line 16256 "parser_bison.c"
+ break;
+
+ case 1213: /* geneve_hdr_field: "vni" */
+#line 5893 "parser_bison.y"
+ { (yyval.val) = GNVHDR_VNI; }
+#line 16262 "parser_bison.c"
+ break;
+
+ case 1214: /* geneve_hdr_field: "type" */
+#line 5894 "parser_bison.y"
+ { (yyval.val) = GNVHDR_TYPE; }
+#line 16268 "parser_bison.c"
+ break;
+
+ case 1215: /* gre_hdr_expr: "gre" gre_hdr_field close_scope_gre */
+#line 5898 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_gre, (yyvsp[-1].val));
+ }
+#line 16276 "parser_bison.c"
+ break;
+
+ case 1216: /* gre_hdr_expr: "gre" close_scope_gre inner_inet_expr */
+#line 5902 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[0].expr);
+ (yyval.expr)->payload.inner_desc = &proto_gre;
+ }
+#line 16285 "parser_bison.c"
+ break;
+
+ case 1217: /* gre_hdr_field: "version" */
+#line 5908 "parser_bison.y"
+ { (yyval.val) = GREHDR_VERSION; }
+#line 16291 "parser_bison.c"
+ break;
+
+ case 1218: /* gre_hdr_field: "flags" */
+#line 5909 "parser_bison.y"
+ { (yyval.val) = GREHDR_FLAGS; }
+#line 16297 "parser_bison.c"
+ break;
+
+ case 1219: /* gre_hdr_field: "protocol" */
+#line 5910 "parser_bison.y"
+ { (yyval.val) = GREHDR_PROTOCOL; }
+#line 16303 "parser_bison.c"
+ break;
+
+ case 1220: /* gretap_hdr_expr: "gretap" close_scope_gre inner_expr */
+#line 5914 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[0].expr);
+ (yyval.expr)->payload.inner_desc = &proto_gretap;
+ }
+#line 16312 "parser_bison.c"
+ break;
+
+ case 1221: /* optstrip_stmt: "reset" "tcp" "option" tcp_hdr_option_type close_scope_tcp */
+#line 5921 "parser_bison.y"
+ {
+ (yyval.stmt) = optstrip_stmt_alloc(&(yyloc), tcpopt_expr_alloc(&(yyloc),
+ (yyvsp[-1].val), TCPOPT_COMMON_KIND));
+ }
+#line 16321 "parser_bison.c"
+ break;
+
+ case 1222: /* tcp_hdr_field: "sport" */
+#line 5927 "parser_bison.y"
+ { (yyval.val) = TCPHDR_SPORT; }
+#line 16327 "parser_bison.c"
+ break;
+
+ case 1223: /* tcp_hdr_field: "dport" */
+#line 5928 "parser_bison.y"
+ { (yyval.val) = TCPHDR_DPORT; }
+#line 16333 "parser_bison.c"
+ break;
+
+ case 1224: /* tcp_hdr_field: "seq" */
+#line 5929 "parser_bison.y"
+ { (yyval.val) = TCPHDR_SEQ; }
+#line 16339 "parser_bison.c"
+ break;
+
+ case 1225: /* tcp_hdr_field: "ackseq" */
+#line 5930 "parser_bison.y"
+ { (yyval.val) = TCPHDR_ACKSEQ; }
+#line 16345 "parser_bison.c"
+ break;
+
+ case 1226: /* tcp_hdr_field: "doff" */
+#line 5931 "parser_bison.y"
+ { (yyval.val) = TCPHDR_DOFF; }
+#line 16351 "parser_bison.c"
+ break;
+
+ case 1227: /* tcp_hdr_field: "reserved" */
+#line 5932 "parser_bison.y"
+ { (yyval.val) = TCPHDR_RESERVED; }
+#line 16357 "parser_bison.c"
+ break;
+
+ case 1228: /* tcp_hdr_field: "flags" */
+#line 5933 "parser_bison.y"
+ { (yyval.val) = TCPHDR_FLAGS; }
+#line 16363 "parser_bison.c"
+ break;
+
+ case 1229: /* tcp_hdr_field: "window" */
+#line 5934 "parser_bison.y"
+ { (yyval.val) = TCPHDR_WINDOW; }
+#line 16369 "parser_bison.c"
+ break;
+
+ case 1230: /* tcp_hdr_field: "checksum" */
+#line 5935 "parser_bison.y"
+ { (yyval.val) = TCPHDR_CHECKSUM; }
+#line 16375 "parser_bison.c"
+ break;
+
+ case 1231: /* tcp_hdr_field: "urgptr" */
+#line 5936 "parser_bison.y"
+ { (yyval.val) = TCPHDR_URGPTR; }
+#line 16381 "parser_bison.c"
+ break;
+
+ case 1232: /* tcp_hdr_option_kind_and_field: "mss" tcpopt_field_maxseg */
+#line 5940 "parser_bison.y"
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MAXSEG, .field = (yyvsp[0].val) };
+ (yyval.tcp_kind_field) = kind_field;
+ }
+#line 16390 "parser_bison.c"
+ break;
+
+ case 1233: /* tcp_hdr_option_kind_and_field: tcp_hdr_option_sack tcpopt_field_sack */
+#line 5945 "parser_bison.y"
+ {
+ struct tcp_kind_field kind_field = { .kind = (yyvsp[-1].val), .field = (yyvsp[0].val) };
+ (yyval.tcp_kind_field) = kind_field;
+ }
+#line 16399 "parser_bison.c"
+ break;
+
+ case 1234: /* tcp_hdr_option_kind_and_field: "window" tcpopt_field_window */
+#line 5950 "parser_bison.y"
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_WINDOW, .field = (yyvsp[0].val) };
+ (yyval.tcp_kind_field) = kind_field;
+ }
+#line 16408 "parser_bison.c"
+ break;
+
+ case 1235: /* tcp_hdr_option_kind_and_field: "timestamp" tcpopt_field_tsopt */
+#line 5955 "parser_bison.y"
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_TIMESTAMP, .field = (yyvsp[0].val) };
+ (yyval.tcp_kind_field) = kind_field;
+ }
+#line 16417 "parser_bison.c"
+ break;
+
+ case 1236: /* tcp_hdr_option_kind_and_field: tcp_hdr_option_type "length" */
+#line 5960 "parser_bison.y"
+ {
+ struct tcp_kind_field kind_field = { .kind = (yyvsp[-1].val), .field = TCPOPT_COMMON_LENGTH };
+ (yyval.tcp_kind_field) = kind_field;
+ }
+#line 16426 "parser_bison.c"
+ break;
+
+ case 1237: /* tcp_hdr_option_kind_and_field: "mptcp" tcpopt_field_mptcp */
+#line 5965 "parser_bison.y"
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MPTCP, .field = (yyvsp[0].val) };
+ (yyval.tcp_kind_field) = kind_field;
+ }
+#line 16435 "parser_bison.c"
+ break;
+
+ case 1238: /* tcp_hdr_option_sack: "sack" */
+#line 5971 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_SACK; }
+#line 16441 "parser_bison.c"
+ break;
+
+ case 1239: /* tcp_hdr_option_sack: "sack0" */
+#line 5972 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_SACK; }
+#line 16447 "parser_bison.c"
+ break;
+
+ case 1240: /* tcp_hdr_option_sack: "sack1" */
+#line 5973 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_SACK1; }
+#line 16453 "parser_bison.c"
+ break;
+
+ case 1241: /* tcp_hdr_option_sack: "sack2" */
+#line 5974 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_SACK2; }
+#line 16459 "parser_bison.c"
+ break;
+
+ case 1242: /* tcp_hdr_option_sack: "sack3" */
+#line 5975 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_SACK3; }
+#line 16465 "parser_bison.c"
+ break;
+
+ case 1243: /* tcp_hdr_option_type: "echo" */
+#line 5978 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_ECHO; }
+#line 16471 "parser_bison.c"
+ break;
+
+ case 1244: /* tcp_hdr_option_type: "eol" */
+#line 5979 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_EOL; }
+#line 16477 "parser_bison.c"
+ break;
+
+ case 1245: /* tcp_hdr_option_type: "fastopen" */
+#line 5980 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_FASTOPEN; }
+#line 16483 "parser_bison.c"
+ break;
+
+ case 1246: /* tcp_hdr_option_type: "md5sig" */
+#line 5981 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_MD5SIG; }
+#line 16489 "parser_bison.c"
+ break;
+
+ case 1247: /* tcp_hdr_option_type: "mptcp" */
+#line 5982 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_MPTCP; }
+#line 16495 "parser_bison.c"
+ break;
+
+ case 1248: /* tcp_hdr_option_type: "mss" */
+#line 5983 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_MAXSEG; }
+#line 16501 "parser_bison.c"
+ break;
+
+ case 1249: /* tcp_hdr_option_type: "nop" */
+#line 5984 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_NOP; }
+#line 16507 "parser_bison.c"
+ break;
+
+ case 1250: /* tcp_hdr_option_type: "sack-permitted" */
+#line 5985 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_SACK_PERMITTED; }
+#line 16513 "parser_bison.c"
+ break;
+
+ case 1251: /* tcp_hdr_option_type: "timestamp" */
+#line 5986 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_TIMESTAMP; }
+#line 16519 "parser_bison.c"
+ break;
+
+ case 1252: /* tcp_hdr_option_type: "window" */
+#line 5987 "parser_bison.y"
+ { (yyval.val) = TCPOPT_KIND_WINDOW; }
+#line 16525 "parser_bison.c"
+ break;
+
+ case 1253: /* tcp_hdr_option_type: tcp_hdr_option_sack */
+#line 5988 "parser_bison.y"
+ { (yyval.val) = (yyvsp[0].val); }
+#line 16531 "parser_bison.c"
+ break;
+
+ case 1254: /* tcp_hdr_option_type: "number" */
+#line 5989 "parser_bison.y"
+ {
+ if ((yyvsp[0].val) > 255) {
+ erec_queue(error(&(yylsp[0]), "value too large"), state->msgs);
+ YYERROR;
+ }
+ (yyval.val) = (yyvsp[0].val);
+ }
+#line 16543 "parser_bison.c"
+ break;
+
+ case 1255: /* tcpopt_field_sack: "left" */
+#line 5998 "parser_bison.y"
+ { (yyval.val) = TCPOPT_SACK_LEFT; }
+#line 16549 "parser_bison.c"
+ break;
+
+ case 1256: /* tcpopt_field_sack: "right" */
+#line 5999 "parser_bison.y"
+ { (yyval.val) = TCPOPT_SACK_RIGHT; }
+#line 16555 "parser_bison.c"
+ break;
+
+ case 1257: /* tcpopt_field_window: "count" */
+#line 6002 "parser_bison.y"
+ { (yyval.val) = TCPOPT_WINDOW_COUNT; }
+#line 16561 "parser_bison.c"
+ break;
+
+ case 1258: /* tcpopt_field_tsopt: "tsval" */
+#line 6005 "parser_bison.y"
+ { (yyval.val) = TCPOPT_TS_TSVAL; }
+#line 16567 "parser_bison.c"
+ break;
+
+ case 1259: /* tcpopt_field_tsopt: "tsecr" */
+#line 6006 "parser_bison.y"
+ { (yyval.val) = TCPOPT_TS_TSECR; }
+#line 16573 "parser_bison.c"
+ break;
+
+ case 1260: /* tcpopt_field_maxseg: "size" */
+#line 6009 "parser_bison.y"
+ { (yyval.val) = TCPOPT_MAXSEG_SIZE; }
+#line 16579 "parser_bison.c"
+ break;
+
+ case 1261: /* tcpopt_field_mptcp: "subtype" */
+#line 6012 "parser_bison.y"
+ { (yyval.val) = TCPOPT_MPTCP_SUBTYPE; }
+#line 16585 "parser_bison.c"
+ break;
+
+ case 1262: /* dccp_hdr_expr: "dccp" dccp_hdr_field close_scope_dccp */
+#line 6016 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_dccp, (yyvsp[-1].val));
+ }
+#line 16593 "parser_bison.c"
+ break;
+
+ case 1263: /* dccp_hdr_expr: "dccp" "option" "number" close_scope_dccp */
+#line 6020 "parser_bison.y"
+ {
+ if ((yyvsp[-1].val) > DCCPOPT_TYPE_MAX) {
+ erec_queue(error(&(yylsp[-3]), "value too large"),
+ state->msgs);
+ YYERROR;
+ }
+ (yyval.expr) = dccpopt_expr_alloc(&(yyloc), (yyvsp[-1].val));
+ }
+#line 16606 "parser_bison.c"
+ break;
+
+ case 1264: /* dccp_hdr_field: "sport" */
+#line 6030 "parser_bison.y"
+ { (yyval.val) = DCCPHDR_SPORT; }
+#line 16612 "parser_bison.c"
+ break;
+
+ case 1265: /* dccp_hdr_field: "dport" */
+#line 6031 "parser_bison.y"
+ { (yyval.val) = DCCPHDR_DPORT; }
+#line 16618 "parser_bison.c"
+ break;
+
+ case 1266: /* dccp_hdr_field: "type" close_scope_type */
+#line 6032 "parser_bison.y"
+ { (yyval.val) = DCCPHDR_TYPE; }
+#line 16624 "parser_bison.c"
+ break;
+
+ case 1267: /* sctp_chunk_type: "data" */
+#line 6035 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_DATA; }
+#line 16630 "parser_bison.c"
+ break;
+
+ case 1268: /* sctp_chunk_type: "init" */
+#line 6036 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_INIT; }
+#line 16636 "parser_bison.c"
+ break;
+
+ case 1269: /* sctp_chunk_type: "init-ack" */
+#line 6037 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_INIT_ACK; }
+#line 16642 "parser_bison.c"
+ break;
+
+ case 1270: /* sctp_chunk_type: "sack" */
+#line 6038 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_SACK; }
+#line 16648 "parser_bison.c"
+ break;
+
+ case 1271: /* sctp_chunk_type: "heartbeat" */
+#line 6039 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_HEARTBEAT; }
+#line 16654 "parser_bison.c"
+ break;
+
+ case 1272: /* sctp_chunk_type: "heartbeat-ack" */
+#line 6040 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_HEARTBEAT_ACK; }
+#line 16660 "parser_bison.c"
+ break;
+
+ case 1273: /* sctp_chunk_type: "abort" */
+#line 6041 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_ABORT; }
+#line 16666 "parser_bison.c"
+ break;
+
+ case 1274: /* sctp_chunk_type: "shutdown" */
+#line 6042 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_SHUTDOWN; }
+#line 16672 "parser_bison.c"
+ break;
+
+ case 1275: /* sctp_chunk_type: "shutdown-ack" */
+#line 6043 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_SHUTDOWN_ACK; }
+#line 16678 "parser_bison.c"
+ break;
+
+ case 1276: /* sctp_chunk_type: "error" */
+#line 6044 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_ERROR; }
+#line 16684 "parser_bison.c"
+ break;
+
+ case 1277: /* sctp_chunk_type: "cookie-echo" */
+#line 6045 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_COOKIE_ECHO; }
+#line 16690 "parser_bison.c"
+ break;
+
+ case 1278: /* sctp_chunk_type: "cookie-ack" */
+#line 6046 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_COOKIE_ACK; }
+#line 16696 "parser_bison.c"
+ break;
+
+ case 1279: /* sctp_chunk_type: "ecne" */
+#line 6047 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_ECNE; }
+#line 16702 "parser_bison.c"
+ break;
+
+ case 1280: /* sctp_chunk_type: "cwr" */
+#line 6048 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_CWR; }
+#line 16708 "parser_bison.c"
+ break;
+
+ case 1281: /* sctp_chunk_type: "shutdown-complete" */
+#line 6049 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE; }
+#line 16714 "parser_bison.c"
+ break;
+
+ case 1282: /* sctp_chunk_type: "asconf-ack" */
+#line 6050 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_ASCONF_ACK; }
+#line 16720 "parser_bison.c"
+ break;
+
+ case 1283: /* sctp_chunk_type: "forward-tsn" */
+#line 6051 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_FORWARD_TSN; }
+#line 16726 "parser_bison.c"
+ break;
+
+ case 1284: /* sctp_chunk_type: "asconf" */
+#line 6052 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_TYPE_ASCONF; }
+#line 16732 "parser_bison.c"
+ break;
+
+ case 1285: /* sctp_chunk_common_field: "type" close_scope_type */
+#line 6055 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_COMMON_TYPE; }
+#line 16738 "parser_bison.c"
+ break;
+
+ case 1286: /* sctp_chunk_common_field: "flags" */
+#line 6056 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_COMMON_FLAGS; }
+#line 16744 "parser_bison.c"
+ break;
+
+ case 1287: /* sctp_chunk_common_field: "length" */
+#line 6057 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_COMMON_LENGTH; }
+#line 16750 "parser_bison.c"
+ break;
+
+ case 1288: /* sctp_chunk_data_field: "tsn" */
+#line 6060 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_DATA_TSN; }
+#line 16756 "parser_bison.c"
+ break;
+
+ case 1289: /* sctp_chunk_data_field: "stream" */
+#line 6061 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_DATA_STREAM; }
+#line 16762 "parser_bison.c"
+ break;
+
+ case 1290: /* sctp_chunk_data_field: "ssn" */
+#line 6062 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_DATA_SSN; }
+#line 16768 "parser_bison.c"
+ break;
+
+ case 1291: /* sctp_chunk_data_field: "ppid" */
+#line 6063 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_DATA_PPID; }
+#line 16774 "parser_bison.c"
+ break;
+
+ case 1292: /* sctp_chunk_init_field: "init-tag" */
+#line 6066 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_INIT_TAG; }
+#line 16780 "parser_bison.c"
+ break;
+
+ case 1293: /* sctp_chunk_init_field: "a-rwnd" */
+#line 6067 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_INIT_RWND; }
+#line 16786 "parser_bison.c"
+ break;
+
+ case 1294: /* sctp_chunk_init_field: "num-outbound-streams" */
+#line 6068 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_INIT_OSTREAMS; }
+#line 16792 "parser_bison.c"
+ break;
+
+ case 1295: /* sctp_chunk_init_field: "num-inbound-streams" */
+#line 6069 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_INIT_ISTREAMS; }
+#line 16798 "parser_bison.c"
+ break;
+
+ case 1296: /* sctp_chunk_init_field: "initial-tsn" */
+#line 6070 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_INIT_TSN; }
+#line 16804 "parser_bison.c"
+ break;
+
+ case 1297: /* sctp_chunk_sack_field: "cum-tsn-ack" */
+#line 6073 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_SACK_CTSN_ACK; }
+#line 16810 "parser_bison.c"
+ break;
+
+ case 1298: /* sctp_chunk_sack_field: "a-rwnd" */
+#line 6074 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_SACK_RWND; }
+#line 16816 "parser_bison.c"
+ break;
+
+ case 1299: /* sctp_chunk_sack_field: "num-gap-ack-blocks" */
+#line 6075 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_SACK_GACK_BLOCKS; }
+#line 16822 "parser_bison.c"
+ break;
+
+ case 1300: /* sctp_chunk_sack_field: "num-dup-tsns" */
+#line 6076 "parser_bison.y"
+ { (yyval.val) = SCTP_CHUNK_SACK_DUP_TSNS; }
+#line 16828 "parser_bison.c"
+ break;
+
+ case 1301: /* sctp_chunk_alloc: sctp_chunk_type */
+#line 6080 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), (yyvsp[0].val), SCTP_CHUNK_COMMON_TYPE);
+ (yyval.expr)->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+#line 16837 "parser_bison.c"
+ break;
+
+ case 1302: /* sctp_chunk_alloc: sctp_chunk_type sctp_chunk_common_field */
+#line 6085 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), (yyvsp[-1].val), (yyvsp[0].val));
+ }
+#line 16845 "parser_bison.c"
+ break;
+
+ case 1303: /* sctp_chunk_alloc: "data" sctp_chunk_data_field */
+#line 6089 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_DATA, (yyvsp[0].val));
+ }
+#line 16853 "parser_bison.c"
+ break;
+
+ case 1304: /* sctp_chunk_alloc: "init" sctp_chunk_init_field */
+#line 6093 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_INIT, (yyvsp[0].val));
+ }
+#line 16861 "parser_bison.c"
+ break;
+
+ case 1305: /* sctp_chunk_alloc: "init-ack" sctp_chunk_init_field */
+#line 6097 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_INIT_ACK, (yyvsp[0].val));
+ }
+#line 16869 "parser_bison.c"
+ break;
+
+ case 1306: /* sctp_chunk_alloc: "sack" sctp_chunk_sack_field */
+#line 6101 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_SACK, (yyvsp[0].val));
+ }
+#line 16877 "parser_bison.c"
+ break;
+
+ case 1307: /* sctp_chunk_alloc: "shutdown" "cum-tsn-ack" */
+#line 6105 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_SHUTDOWN,
+ SCTP_CHUNK_SHUTDOWN_CTSN_ACK);
+ }
+#line 16886 "parser_bison.c"
+ break;
+
+ case 1308: /* sctp_chunk_alloc: "ecne" "lowest-tsn" */
+#line 6110 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_ECNE,
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN);
+ }
+#line 16895 "parser_bison.c"
+ break;
+
+ case 1309: /* sctp_chunk_alloc: "cwr" "lowest-tsn" */
+#line 6115 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_CWR,
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN);
+ }
+#line 16904 "parser_bison.c"
+ break;
+
+ case 1310: /* sctp_chunk_alloc: "asconf-ack" "seqno" */
+#line 6120 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_ASCONF_ACK,
+ SCTP_CHUNK_ASCONF_SEQNO);
+ }
+#line 16913 "parser_bison.c"
+ break;
+
+ case 1311: /* sctp_chunk_alloc: "forward-tsn" "new-cum-tsn" */
+#line 6125 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_FORWARD_TSN,
+ SCTP_CHUNK_FORWARD_TSN_NCTSN);
+ }
+#line 16922 "parser_bison.c"
+ break;
+
+ case 1312: /* sctp_chunk_alloc: "asconf" "seqno" */
+#line 6130 "parser_bison.y"
+ {
+ (yyval.expr) = sctp_chunk_expr_alloc(&(yyloc), SCTP_CHUNK_TYPE_ASCONF,
+ SCTP_CHUNK_ASCONF_SEQNO);
+ }
+#line 16931 "parser_bison.c"
+ break;
+
+ case 1313: /* sctp_hdr_expr: "sctp" sctp_hdr_field close_scope_sctp */
+#line 6137 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_sctp, (yyvsp[-1].val));
+ }
+#line 16939 "parser_bison.c"
+ break;
+
+ case 1314: /* sctp_hdr_expr: "sctp" "chunk" sctp_chunk_alloc close_scope_sctp_chunk close_scope_sctp */
+#line 6141 "parser_bison.y"
+ {
+ (yyval.expr) = (yyvsp[-2].expr);
+ }
+#line 16947 "parser_bison.c"
+ break;
+
+ case 1315: /* sctp_hdr_field: "sport" */
+#line 6146 "parser_bison.y"
+ { (yyval.val) = SCTPHDR_SPORT; }
+#line 16953 "parser_bison.c"
+ break;
+
+ case 1316: /* sctp_hdr_field: "dport" */
+#line 6147 "parser_bison.y"
+ { (yyval.val) = SCTPHDR_DPORT; }
+#line 16959 "parser_bison.c"
+ break;
+
+ case 1317: /* sctp_hdr_field: "vtag" */
+#line 6148 "parser_bison.y"
+ { (yyval.val) = SCTPHDR_VTAG; }
+#line 16965 "parser_bison.c"
+ break;
+
+ case 1318: /* sctp_hdr_field: "checksum" */
+#line 6149 "parser_bison.y"
+ { (yyval.val) = SCTPHDR_CHECKSUM; }
+#line 16971 "parser_bison.c"
+ break;
+
+ case 1319: /* th_hdr_expr: "th" th_hdr_field close_scope_th */
+#line 6153 "parser_bison.y"
+ {
+ (yyval.expr) = payload_expr_alloc(&(yyloc), &proto_th, (yyvsp[-1].val));
+ if ((yyval.expr))
+ (yyval.expr)->payload.is_raw = true;
+ }
+#line 16981 "parser_bison.c"
+ break;
+
+ case 1320: /* th_hdr_field: "sport" */
+#line 6160 "parser_bison.y"
+ { (yyval.val) = THDR_SPORT; }
+#line 16987 "parser_bison.c"
+ break;
+
+ case 1321: /* th_hdr_field: "dport" */
+#line 6161 "parser_bison.y"
+ { (yyval.val) = THDR_DPORT; }
+#line 16993 "parser_bison.c"
+ break;
+
+ case 1330: /* hbh_hdr_expr: "hbh" hbh_hdr_field close_scope_hbh */
+#line 6175 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_hbh, (yyvsp[-1].val));
+ }
+#line 17001 "parser_bison.c"
+ break;
+
+ case 1331: /* hbh_hdr_field: "nexthdr" */
+#line 6180 "parser_bison.y"
+ { (yyval.val) = HBHHDR_NEXTHDR; }
+#line 17007 "parser_bison.c"
+ break;
+
+ case 1332: /* hbh_hdr_field: "hdrlength" */
+#line 6181 "parser_bison.y"
+ { (yyval.val) = HBHHDR_HDRLENGTH; }
+#line 17013 "parser_bison.c"
+ break;
+
+ case 1333: /* rt_hdr_expr: "rt" rt_hdr_field close_scope_rt */
+#line 6185 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_rt, (yyvsp[-1].val));
+ }
+#line 17021 "parser_bison.c"
+ break;
+
+ case 1334: /* rt_hdr_field: "nexthdr" */
+#line 6190 "parser_bison.y"
+ { (yyval.val) = RTHDR_NEXTHDR; }
+#line 17027 "parser_bison.c"
+ break;
+
+ case 1335: /* rt_hdr_field: "hdrlength" */
+#line 6191 "parser_bison.y"
+ { (yyval.val) = RTHDR_HDRLENGTH; }
+#line 17033 "parser_bison.c"
+ break;
+
+ case 1336: /* rt_hdr_field: "type" close_scope_type */
+#line 6192 "parser_bison.y"
+ { (yyval.val) = RTHDR_TYPE; }
+#line 17039 "parser_bison.c"
+ break;
+
+ case 1337: /* rt_hdr_field: "seg-left" */
+#line 6193 "parser_bison.y"
+ { (yyval.val) = RTHDR_SEG_LEFT; }
+#line 17045 "parser_bison.c"
+ break;
+
+ case 1338: /* rt0_hdr_expr: "rt0" rt0_hdr_field close_scope_rt */
+#line 6197 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_rt0, (yyvsp[-1].val));
+ }
+#line 17053 "parser_bison.c"
+ break;
+
+ case 1339: /* rt0_hdr_field: "addr" '[' "number" ']' */
+#line 6203 "parser_bison.y"
+ {
+ (yyval.val) = RT0HDR_ADDR_1 + (yyvsp[-1].val) - 1;
+ }
+#line 17061 "parser_bison.c"
+ break;
+
+ case 1340: /* rt2_hdr_expr: "rt2" rt2_hdr_field close_scope_rt */
+#line 6209 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_rt2, (yyvsp[-1].val));
+ }
+#line 17069 "parser_bison.c"
+ break;
+
+ case 1341: /* rt2_hdr_field: "addr" */
+#line 6214 "parser_bison.y"
+ { (yyval.val) = RT2HDR_ADDR; }
+#line 17075 "parser_bison.c"
+ break;
+
+ case 1342: /* rt4_hdr_expr: "srh" rt4_hdr_field close_scope_rt */
+#line 6218 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_rt4, (yyvsp[-1].val));
+ }
+#line 17083 "parser_bison.c"
+ break;
+
+ case 1343: /* rt4_hdr_field: "last-entry" */
+#line 6223 "parser_bison.y"
+ { (yyval.val) = RT4HDR_LASTENT; }
+#line 17089 "parser_bison.c"
+ break;
+
+ case 1344: /* rt4_hdr_field: "flags" */
+#line 6224 "parser_bison.y"
+ { (yyval.val) = RT4HDR_FLAGS; }
+#line 17095 "parser_bison.c"
+ break;
+
+ case 1345: /* rt4_hdr_field: "tag" */
+#line 6225 "parser_bison.y"
+ { (yyval.val) = RT4HDR_TAG; }
+#line 17101 "parser_bison.c"
+ break;
+
+ case 1346: /* rt4_hdr_field: "sid" '[' "number" ']' */
+#line 6227 "parser_bison.y"
+ {
+ (yyval.val) = RT4HDR_SID_1 + (yyvsp[-1].val) - 1;
+ }
+#line 17109 "parser_bison.c"
+ break;
+
+ case 1347: /* frag_hdr_expr: "frag" frag_hdr_field close_scope_frag */
+#line 6233 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_frag, (yyvsp[-1].val));
+ }
+#line 17117 "parser_bison.c"
+ break;
+
+ case 1348: /* frag_hdr_field: "nexthdr" */
+#line 6238 "parser_bison.y"
+ { (yyval.val) = FRAGHDR_NEXTHDR; }
+#line 17123 "parser_bison.c"
+ break;
+
+ case 1349: /* frag_hdr_field: "reserved" */
+#line 6239 "parser_bison.y"
+ { (yyval.val) = FRAGHDR_RESERVED; }
+#line 17129 "parser_bison.c"
+ break;
+
+ case 1350: /* frag_hdr_field: "frag-off" */
+#line 6240 "parser_bison.y"
+ { (yyval.val) = FRAGHDR_FRAG_OFF; }
+#line 17135 "parser_bison.c"
+ break;
+
+ case 1351: /* frag_hdr_field: "reserved2" */
+#line 6241 "parser_bison.y"
+ { (yyval.val) = FRAGHDR_RESERVED2; }
+#line 17141 "parser_bison.c"
+ break;
+
+ case 1352: /* frag_hdr_field: "more-fragments" */
+#line 6242 "parser_bison.y"
+ { (yyval.val) = FRAGHDR_MFRAGS; }
+#line 17147 "parser_bison.c"
+ break;
+
+ case 1353: /* frag_hdr_field: "id" */
+#line 6243 "parser_bison.y"
+ { (yyval.val) = FRAGHDR_ID; }
+#line 17153 "parser_bison.c"
+ break;
+
+ case 1354: /* dst_hdr_expr: "dst" dst_hdr_field close_scope_dst */
+#line 6247 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_dst, (yyvsp[-1].val));
+ }
+#line 17161 "parser_bison.c"
+ break;
+
+ case 1355: /* dst_hdr_field: "nexthdr" */
+#line 6252 "parser_bison.y"
+ { (yyval.val) = DSTHDR_NEXTHDR; }
+#line 17167 "parser_bison.c"
+ break;
+
+ case 1356: /* dst_hdr_field: "hdrlength" */
+#line 6253 "parser_bison.y"
+ { (yyval.val) = DSTHDR_HDRLENGTH; }
+#line 17173 "parser_bison.c"
+ break;
+
+ case 1357: /* mh_hdr_expr: "mh" mh_hdr_field close_scope_mh */
+#line 6257 "parser_bison.y"
+ {
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), &exthdr_mh, (yyvsp[-1].val));
+ }
+#line 17181 "parser_bison.c"
+ break;
+
+ case 1358: /* mh_hdr_field: "nexthdr" */
+#line 6262 "parser_bison.y"
+ { (yyval.val) = MHHDR_NEXTHDR; }
+#line 17187 "parser_bison.c"
+ break;
+
+ case 1359: /* mh_hdr_field: "hdrlength" */
+#line 6263 "parser_bison.y"
+ { (yyval.val) = MHHDR_HDRLENGTH; }
+#line 17193 "parser_bison.c"
+ break;
+
+ case 1360: /* mh_hdr_field: "type" close_scope_type */
+#line 6264 "parser_bison.y"
+ { (yyval.val) = MHHDR_TYPE; }
+#line 17199 "parser_bison.c"
+ break;
+
+ case 1361: /* mh_hdr_field: "reserved" */
+#line 6265 "parser_bison.y"
+ { (yyval.val) = MHHDR_RESERVED; }
+#line 17205 "parser_bison.c"
+ break;
+
+ case 1362: /* mh_hdr_field: "checksum" */
+#line 6266 "parser_bison.y"
+ { (yyval.val) = MHHDR_CHECKSUM; }
+#line 17211 "parser_bison.c"
+ break;
+
+ case 1363: /* exthdr_exists_expr: "exthdr" exthdr_key */
+#line 6270 "parser_bison.y"
+ {
+ const struct exthdr_desc *desc;
+
+ desc = exthdr_find_proto((yyvsp[0].val));
+
+ /* Assume that NEXTHDR template is always
+ * the first one in list of templates.
+ */
+ (yyval.expr) = exthdr_expr_alloc(&(yyloc), desc, 1);
+ (yyval.expr)->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+#line 17227 "parser_bison.c"
+ break;
+
+ case 1364: /* exthdr_key: "hbh" close_scope_hbh */
+#line 6283 "parser_bison.y"
+ { (yyval.val) = IPPROTO_HOPOPTS; }
+#line 17233 "parser_bison.c"
+ break;
+
+ case 1365: /* exthdr_key: "rt" close_scope_rt */
+#line 6284 "parser_bison.y"
+ { (yyval.val) = IPPROTO_ROUTING; }
+#line 17239 "parser_bison.c"
+ break;
+
+ case 1366: /* exthdr_key: "frag" close_scope_frag */
+#line 6285 "parser_bison.y"
+ { (yyval.val) = IPPROTO_FRAGMENT; }
+#line 17245 "parser_bison.c"
+ break;
+
+ case 1367: /* exthdr_key: "dst" close_scope_dst */
+#line 6286 "parser_bison.y"
+ { (yyval.val) = IPPROTO_DSTOPTS; }
+#line 17251 "parser_bison.c"
+ break;
+
+ case 1368: /* exthdr_key: "mh" close_scope_mh */
+#line 6287 "parser_bison.y"
+ { (yyval.val) = IPPROTO_MH; }
+#line 17257 "parser_bison.c"
+ break;
+
+
+#line 17261 "parser_bison.c"
+
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+
+ *++yyvsp = yyval;
+ *++yylsp = yyloc;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+ {
+ const int yylhs = yyr1[yyn] - YYNTOKENS;
+ const int yyi = yypgoto[yylhs] + *yyssp;
+ yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp
+ ? yytable[yyi]
+ : yydefgoto[yylhs]);
+ }
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar);
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+ {
+ yypcontext_t yyctx
+ = {yyssp, yytoken, &yylloc};
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == -1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = YY_CAST (char *,
+ YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc)));
+ if (yymsg)
+ {
+ yysyntax_error_status
+ = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx);
+ yymsgp = yymsg;
+ }
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = YYENOMEM;
+ }
+ }
+ yyerror (&yylloc, nft, scanner, state, yymsgp);
+ if (yysyntax_error_status == YYENOMEM)
+ goto yyexhaustedlab;
+ }
+ }
+
+ yyerror_range[1] = yylloc;
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= TOKEN_EOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == TOKEN_EOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, &yylloc, nft, scanner, state);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+ /* Pacify compilers when the user code never invokes YYERROR and the
+ label yyerrorlab therefore never appears in user code. */
+ if (0)
+ YYERROR;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ /* Pop stack until we find a state that shifts the error token. */
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYSYMBOL_YYerror;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+ yyerror_range[1] = *yylsp;
+ yydestruct ("Error: popping",
+ YY_ACCESSING_SYMBOL (yystate), yyvsp, yylsp, nft, scanner, state);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ yyerror_range[2] = yylloc;
+ ++yylsp;
+ YYLLOC_DEFAULT (*yylsp, yyerror_range, 2);
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+
+#if 1
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (&yylloc, nft, scanner, state, YY_("memory exhausted"));
+ yyresult = 2;
+ goto yyreturn;
+#endif
+
+
+/*-------------------------------------------------------.
+| yyreturn -- parsing is finished, clean up and return. |
+`-------------------------------------------------------*/
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, &yylloc, nft, scanner, state);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yylsp, nft, scanner, state);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ return yyresult;
+}
+
+#line 6290 "parser_bison.y"
+
diff --git a/src/parser_bison.h b/src/parser_bison.h
new file mode 100644
index 0000000..9e754a2
--- /dev/null
+++ b/src/parser_bison.h
@@ -0,0 +1,845 @@
+/* A Bison parser, made by GNU Bison 3.7.5. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
+ Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+ especially those whose name start with YY_ or yy_. They are
+ private implementation details that can be changed or removed. */
+
+#ifndef YY_NFT_PARSER_BISON_H_INCLUDED
+# define YY_NFT_PARSER_BISON_H_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int nft_debug;
+#endif
+
+/* Token kinds. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ YYEMPTY = -2,
+ TOKEN_EOF = 0, /* "end of file" */
+ YYerror = 256, /* error */
+ YYUNDEF = 257, /* "invalid token" */
+ JUNK = 258, /* "junk" */
+ NEWLINE = 259, /* "newline" */
+ COLON = 260, /* "colon" */
+ SEMICOLON = 261, /* "semicolon" */
+ COMMA = 262, /* "comma" */
+ DOT = 263, /* "." */
+ EQ = 264, /* "==" */
+ NEQ = 265, /* "!=" */
+ LT = 266, /* "<" */
+ GT = 267, /* ">" */
+ GTE = 268, /* ">=" */
+ LTE = 269, /* "<=" */
+ LSHIFT = 270, /* "<<" */
+ RSHIFT = 271, /* ">>" */
+ AMPERSAND = 272, /* "&" */
+ CARET = 273, /* "^" */
+ NOT = 274, /* "!" */
+ SLASH = 275, /* "/" */
+ ASTERISK = 276, /* "*" */
+ DASH = 277, /* "-" */
+ AT = 278, /* "@" */
+ VMAP = 279, /* "vmap" */
+ PLUS = 280, /* "+" */
+ INCLUDE = 281, /* "include" */
+ DEFINE = 282, /* "define" */
+ REDEFINE = 283, /* "redefine" */
+ UNDEFINE = 284, /* "undefine" */
+ FIB = 285, /* "fib" */
+ SOCKET = 286, /* "socket" */
+ TRANSPARENT = 287, /* "transparent" */
+ WILDCARD = 288, /* "wildcard" */
+ CGROUPV2 = 289, /* "cgroupv2" */
+ TPROXY = 290, /* "tproxy" */
+ OSF = 291, /* "osf" */
+ SYNPROXY = 292, /* "synproxy" */
+ MSS = 293, /* "mss" */
+ WSCALE = 294, /* "wscale" */
+ TYPEOF = 295, /* "typeof" */
+ HOOK = 296, /* "hook" */
+ HOOKS = 297, /* "hooks" */
+ DEVICE = 298, /* "device" */
+ DEVICES = 299, /* "devices" */
+ TABLE = 300, /* "table" */
+ TABLES = 301, /* "tables" */
+ CHAIN = 302, /* "chain" */
+ CHAINS = 303, /* "chains" */
+ RULE = 304, /* "rule" */
+ RULES = 305, /* "rules" */
+ SETS = 306, /* "sets" */
+ SET = 307, /* "set" */
+ ELEMENT = 308, /* "element" */
+ MAP = 309, /* "map" */
+ MAPS = 310, /* "maps" */
+ FLOWTABLE = 311, /* "flowtable" */
+ HANDLE = 312, /* "handle" */
+ RULESET = 313, /* "ruleset" */
+ TRACE = 314, /* "trace" */
+ INET = 315, /* "inet" */
+ NETDEV = 316, /* "netdev" */
+ ADD = 317, /* "add" */
+ UPDATE = 318, /* "update" */
+ REPLACE = 319, /* "replace" */
+ CREATE = 320, /* "create" */
+ INSERT = 321, /* "insert" */
+ DELETE = 322, /* "delete" */
+ GET = 323, /* "get" */
+ LIST = 324, /* "list" */
+ RESET = 325, /* "reset" */
+ FLUSH = 326, /* "flush" */
+ RENAME = 327, /* "rename" */
+ DESCRIBE = 328, /* "describe" */
+ IMPORT = 329, /* "import" */
+ EXPORT = 330, /* "export" */
+ DESTROY = 331, /* "destroy" */
+ MONITOR = 332, /* "monitor" */
+ ALL = 333, /* "all" */
+ ACCEPT = 334, /* "accept" */
+ DROP = 335, /* "drop" */
+ CONTINUE = 336, /* "continue" */
+ JUMP = 337, /* "jump" */
+ GOTO = 338, /* "goto" */
+ RETURN = 339, /* "return" */
+ TO = 340, /* "to" */
+ CONSTANT = 341, /* "constant" */
+ INTERVAL = 342, /* "interval" */
+ DYNAMIC = 343, /* "dynamic" */
+ AUTOMERGE = 344, /* "auto-merge" */
+ TIMEOUT = 345, /* "timeout" */
+ GC_INTERVAL = 346, /* "gc-interval" */
+ ELEMENTS = 347, /* "elements" */
+ EXPIRES = 348, /* "expires" */
+ POLICY = 349, /* "policy" */
+ MEMORY = 350, /* "memory" */
+ PERFORMANCE = 351, /* "performance" */
+ SIZE = 352, /* "size" */
+ FLOW = 353, /* "flow" */
+ OFFLOAD = 354, /* "offload" */
+ METER = 355, /* "meter" */
+ METERS = 356, /* "meters" */
+ FLOWTABLES = 357, /* "flowtables" */
+ NUM = 358, /* "number" */
+ STRING = 359, /* "string" */
+ QUOTED_STRING = 360, /* "quoted string" */
+ ASTERISK_STRING = 361, /* "string with a trailing asterisk" */
+ LL_HDR = 362, /* "ll" */
+ NETWORK_HDR = 363, /* "nh" */
+ TRANSPORT_HDR = 364, /* "th" */
+ BRIDGE = 365, /* "bridge" */
+ ETHER = 366, /* "ether" */
+ SADDR = 367, /* "saddr" */
+ DADDR = 368, /* "daddr" */
+ TYPE = 369, /* "type" */
+ VLAN = 370, /* "vlan" */
+ ID = 371, /* "id" */
+ CFI = 372, /* "cfi" */
+ DEI = 373, /* "dei" */
+ PCP = 374, /* "pcp" */
+ ARP = 375, /* "arp" */
+ HTYPE = 376, /* "htype" */
+ PTYPE = 377, /* "ptype" */
+ HLEN = 378, /* "hlen" */
+ PLEN = 379, /* "plen" */
+ OPERATION = 380, /* "operation" */
+ IP = 381, /* "ip" */
+ HDRVERSION = 382, /* "version" */
+ HDRLENGTH = 383, /* "hdrlength" */
+ DSCP = 384, /* "dscp" */
+ ECN = 385, /* "ecn" */
+ LENGTH = 386, /* "length" */
+ FRAG_OFF = 387, /* "frag-off" */
+ TTL = 388, /* "ttl" */
+ PROTOCOL = 389, /* "protocol" */
+ CHECKSUM = 390, /* "checksum" */
+ PTR = 391, /* "ptr" */
+ VALUE = 392, /* "value" */
+ LSRR = 393, /* "lsrr" */
+ RR = 394, /* "rr" */
+ SSRR = 395, /* "ssrr" */
+ RA = 396, /* "ra" */
+ ICMP = 397, /* "icmp" */
+ CODE = 398, /* "code" */
+ SEQUENCE = 399, /* "seq" */
+ GATEWAY = 400, /* "gateway" */
+ MTU = 401, /* "mtu" */
+ IGMP = 402, /* "igmp" */
+ MRT = 403, /* "mrt" */
+ OPTIONS = 404, /* "options" */
+ IP6 = 405, /* "ip6" */
+ PRIORITY = 406, /* "priority" */
+ FLOWLABEL = 407, /* "flowlabel" */
+ NEXTHDR = 408, /* "nexthdr" */
+ HOPLIMIT = 409, /* "hoplimit" */
+ ICMP6 = 410, /* "icmpv6" */
+ PPTR = 411, /* "param-problem" */
+ MAXDELAY = 412, /* "max-delay" */
+ TADDR = 413, /* "taddr" */
+ AH = 414, /* "ah" */
+ RESERVED = 415, /* "reserved" */
+ SPI = 416, /* "spi" */
+ ESP = 417, /* "esp" */
+ COMP = 418, /* "comp" */
+ FLAGS = 419, /* "flags" */
+ CPI = 420, /* "cpi" */
+ PORT = 421, /* "port" */
+ UDP = 422, /* "udp" */
+ SPORT = 423, /* "sport" */
+ DPORT = 424, /* "dport" */
+ UDPLITE = 425, /* "udplite" */
+ CSUMCOV = 426, /* "csumcov" */
+ TCP = 427, /* "tcp" */
+ ACKSEQ = 428, /* "ackseq" */
+ DOFF = 429, /* "doff" */
+ WINDOW = 430, /* "window" */
+ URGPTR = 431, /* "urgptr" */
+ OPTION = 432, /* "option" */
+ ECHO = 433, /* "echo" */
+ EOL = 434, /* "eol" */
+ MPTCP = 435, /* "mptcp" */
+ NOP = 436, /* "nop" */
+ SACK = 437, /* "sack" */
+ SACK0 = 438, /* "sack0" */
+ SACK1 = 439, /* "sack1" */
+ SACK2 = 440, /* "sack2" */
+ SACK3 = 441, /* "sack3" */
+ SACK_PERM = 442, /* "sack-permitted" */
+ FASTOPEN = 443, /* "fastopen" */
+ MD5SIG = 444, /* "md5sig" */
+ TIMESTAMP = 445, /* "timestamp" */
+ COUNT = 446, /* "count" */
+ LEFT = 447, /* "left" */
+ RIGHT = 448, /* "right" */
+ TSVAL = 449, /* "tsval" */
+ TSECR = 450, /* "tsecr" */
+ SUBTYPE = 451, /* "subtype" */
+ DCCP = 452, /* "dccp" */
+ VXLAN = 453, /* "vxlan" */
+ VNI = 454, /* "vni" */
+ GRE = 455, /* "gre" */
+ GRETAP = 456, /* "gretap" */
+ GENEVE = 457, /* "geneve" */
+ SCTP = 458, /* "sctp" */
+ CHUNK = 459, /* "chunk" */
+ DATA = 460, /* "data" */
+ INIT = 461, /* "init" */
+ INIT_ACK = 462, /* "init-ack" */
+ HEARTBEAT = 463, /* "heartbeat" */
+ HEARTBEAT_ACK = 464, /* "heartbeat-ack" */
+ ABORT = 465, /* "abort" */
+ SHUTDOWN = 466, /* "shutdown" */
+ SHUTDOWN_ACK = 467, /* "shutdown-ack" */
+ ERROR = 468, /* "error" */
+ COOKIE_ECHO = 469, /* "cookie-echo" */
+ COOKIE_ACK = 470, /* "cookie-ack" */
+ ECNE = 471, /* "ecne" */
+ CWR = 472, /* "cwr" */
+ SHUTDOWN_COMPLETE = 473, /* "shutdown-complete" */
+ ASCONF_ACK = 474, /* "asconf-ack" */
+ FORWARD_TSN = 475, /* "forward-tsn" */
+ ASCONF = 476, /* "asconf" */
+ TSN = 477, /* "tsn" */
+ STREAM = 478, /* "stream" */
+ SSN = 479, /* "ssn" */
+ PPID = 480, /* "ppid" */
+ INIT_TAG = 481, /* "init-tag" */
+ A_RWND = 482, /* "a-rwnd" */
+ NUM_OSTREAMS = 483, /* "num-outbound-streams" */
+ NUM_ISTREAMS = 484, /* "num-inbound-streams" */
+ INIT_TSN = 485, /* "initial-tsn" */
+ CUM_TSN_ACK = 486, /* "cum-tsn-ack" */
+ NUM_GACK_BLOCKS = 487, /* "num-gap-ack-blocks" */
+ NUM_DUP_TSNS = 488, /* "num-dup-tsns" */
+ LOWEST_TSN = 489, /* "lowest-tsn" */
+ SEQNO = 490, /* "seqno" */
+ NEW_CUM_TSN = 491, /* "new-cum-tsn" */
+ VTAG = 492, /* "vtag" */
+ RT = 493, /* "rt" */
+ RT0 = 494, /* "rt0" */
+ RT2 = 495, /* "rt2" */
+ RT4 = 496, /* "srh" */
+ SEG_LEFT = 497, /* "seg-left" */
+ ADDR = 498, /* "addr" */
+ LAST_ENT = 499, /* "last-entry" */
+ TAG = 500, /* "tag" */
+ SID = 501, /* "sid" */
+ HBH = 502, /* "hbh" */
+ FRAG = 503, /* "frag" */
+ RESERVED2 = 504, /* "reserved2" */
+ MORE_FRAGMENTS = 505, /* "more-fragments" */
+ DST = 506, /* "dst" */
+ MH = 507, /* "mh" */
+ META = 508, /* "meta" */
+ MARK = 509, /* "mark" */
+ IIF = 510, /* "iif" */
+ IIFNAME = 511, /* "iifname" */
+ IIFTYPE = 512, /* "iiftype" */
+ OIF = 513, /* "oif" */
+ OIFNAME = 514, /* "oifname" */
+ OIFTYPE = 515, /* "oiftype" */
+ SKUID = 516, /* "skuid" */
+ SKGID = 517, /* "skgid" */
+ NFTRACE = 518, /* "nftrace" */
+ RTCLASSID = 519, /* "rtclassid" */
+ IBRIPORT = 520, /* "ibriport" */
+ OBRIPORT = 521, /* "obriport" */
+ IBRIDGENAME = 522, /* "ibrname" */
+ OBRIDGENAME = 523, /* "obrname" */
+ PKTTYPE = 524, /* "pkttype" */
+ CPU = 525, /* "cpu" */
+ IIFGROUP = 526, /* "iifgroup" */
+ OIFGROUP = 527, /* "oifgroup" */
+ CGROUP = 528, /* "cgroup" */
+ TIME = 529, /* "time" */
+ CLASSID = 530, /* "classid" */
+ NEXTHOP = 531, /* "nexthop" */
+ CT = 532, /* "ct" */
+ L3PROTOCOL = 533, /* "l3proto" */
+ PROTO_SRC = 534, /* "proto-src" */
+ PROTO_DST = 535, /* "proto-dst" */
+ ZONE = 536, /* "zone" */
+ DIRECTION = 537, /* "direction" */
+ EVENT = 538, /* "event" */
+ EXPECTATION = 539, /* "expectation" */
+ EXPIRATION = 540, /* "expiration" */
+ HELPER = 541, /* "helper" */
+ LABEL = 542, /* "label" */
+ STATE = 543, /* "state" */
+ STATUS = 544, /* "status" */
+ ORIGINAL = 545, /* "original" */
+ REPLY = 546, /* "reply" */
+ COUNTER = 547, /* "counter" */
+ NAME = 548, /* "name" */
+ PACKETS = 549, /* "packets" */
+ BYTES = 550, /* "bytes" */
+ AVGPKT = 551, /* "avgpkt" */
+ LAST = 552, /* "last" */
+ NEVER = 553, /* "never" */
+ COUNTERS = 554, /* "counters" */
+ QUOTAS = 555, /* "quotas" */
+ LIMITS = 556, /* "limits" */
+ SYNPROXYS = 557, /* "synproxys" */
+ HELPERS = 558, /* "helpers" */
+ LOG = 559, /* "log" */
+ PREFIX = 560, /* "prefix" */
+ GROUP = 561, /* "group" */
+ SNAPLEN = 562, /* "snaplen" */
+ QUEUE_THRESHOLD = 563, /* "queue-threshold" */
+ LEVEL = 564, /* "level" */
+ LIMIT = 565, /* "limit" */
+ RATE = 566, /* "rate" */
+ BURST = 567, /* "burst" */
+ OVER = 568, /* "over" */
+ UNTIL = 569, /* "until" */
+ QUOTA = 570, /* "quota" */
+ USED = 571, /* "used" */
+ SECMARK = 572, /* "secmark" */
+ SECMARKS = 573, /* "secmarks" */
+ SECOND = 574, /* "second" */
+ MINUTE = 575, /* "minute" */
+ HOUR = 576, /* "hour" */
+ DAY = 577, /* "day" */
+ WEEK = 578, /* "week" */
+ _REJECT = 579, /* "reject" */
+ WITH = 580, /* "with" */
+ ICMPX = 581, /* "icmpx" */
+ SNAT = 582, /* "snat" */
+ DNAT = 583, /* "dnat" */
+ MASQUERADE = 584, /* "masquerade" */
+ REDIRECT = 585, /* "redirect" */
+ RANDOM = 586, /* "random" */
+ FULLY_RANDOM = 587, /* "fully-random" */
+ PERSISTENT = 588, /* "persistent" */
+ QUEUE = 589, /* "queue" */
+ QUEUENUM = 590, /* "num" */
+ BYPASS = 591, /* "bypass" */
+ FANOUT = 592, /* "fanout" */
+ DUP = 593, /* "dup" */
+ FWD = 594, /* "fwd" */
+ NUMGEN = 595, /* "numgen" */
+ INC = 596, /* "inc" */
+ MOD = 597, /* "mod" */
+ OFFSET = 598, /* "offset" */
+ JHASH = 599, /* "jhash" */
+ SYMHASH = 600, /* "symhash" */
+ SEED = 601, /* "seed" */
+ POSITION = 602, /* "position" */
+ INDEX = 603, /* "index" */
+ COMMENT = 604, /* "comment" */
+ XML = 605, /* "xml" */
+ JSON = 606, /* "json" */
+ VM = 607, /* "vm" */
+ NOTRACK = 608, /* "notrack" */
+ EXISTS = 609, /* "exists" */
+ MISSING = 610, /* "missing" */
+ EXTHDR = 611, /* "exthdr" */
+ IPSEC = 612, /* "ipsec" */
+ REQID = 613, /* "reqid" */
+ SPNUM = 614, /* "spnum" */
+ IN = 615, /* "in" */
+ OUT = 616, /* "out" */
+ XT = 617 /* "xt" */
+ };
+ typedef enum yytokentype yytoken_kind_t;
+#endif
+/* Token kinds. */
+#define YYEMPTY -2
+#define TOKEN_EOF 0
+#define YYerror 256
+#define YYUNDEF 257
+#define JUNK 258
+#define NEWLINE 259
+#define COLON 260
+#define SEMICOLON 261
+#define COMMA 262
+#define DOT 263
+#define EQ 264
+#define NEQ 265
+#define LT 266
+#define GT 267
+#define GTE 268
+#define LTE 269
+#define LSHIFT 270
+#define RSHIFT 271
+#define AMPERSAND 272
+#define CARET 273
+#define NOT 274
+#define SLASH 275
+#define ASTERISK 276
+#define DASH 277
+#define AT 278
+#define VMAP 279
+#define PLUS 280
+#define INCLUDE 281
+#define DEFINE 282
+#define REDEFINE 283
+#define UNDEFINE 284
+#define FIB 285
+#define SOCKET 286
+#define TRANSPARENT 287
+#define WILDCARD 288
+#define CGROUPV2 289
+#define TPROXY 290
+#define OSF 291
+#define SYNPROXY 292
+#define MSS 293
+#define WSCALE 294
+#define TYPEOF 295
+#define HOOK 296
+#define HOOKS 297
+#define DEVICE 298
+#define DEVICES 299
+#define TABLE 300
+#define TABLES 301
+#define CHAIN 302
+#define CHAINS 303
+#define RULE 304
+#define RULES 305
+#define SETS 306
+#define SET 307
+#define ELEMENT 308
+#define MAP 309
+#define MAPS 310
+#define FLOWTABLE 311
+#define HANDLE 312
+#define RULESET 313
+#define TRACE 314
+#define INET 315
+#define NETDEV 316
+#define ADD 317
+#define UPDATE 318
+#define REPLACE 319
+#define CREATE 320
+#define INSERT 321
+#define DELETE 322
+#define GET 323
+#define LIST 324
+#define RESET 325
+#define FLUSH 326
+#define RENAME 327
+#define DESCRIBE 328
+#define IMPORT 329
+#define EXPORT 330
+#define DESTROY 331
+#define MONITOR 332
+#define ALL 333
+#define ACCEPT 334
+#define DROP 335
+#define CONTINUE 336
+#define JUMP 337
+#define GOTO 338
+#define RETURN 339
+#define TO 340
+#define CONSTANT 341
+#define INTERVAL 342
+#define DYNAMIC 343
+#define AUTOMERGE 344
+#define TIMEOUT 345
+#define GC_INTERVAL 346
+#define ELEMENTS 347
+#define EXPIRES 348
+#define POLICY 349
+#define MEMORY 350
+#define PERFORMANCE 351
+#define SIZE 352
+#define FLOW 353
+#define OFFLOAD 354
+#define METER 355
+#define METERS 356
+#define FLOWTABLES 357
+#define NUM 358
+#define STRING 359
+#define QUOTED_STRING 360
+#define ASTERISK_STRING 361
+#define LL_HDR 362
+#define NETWORK_HDR 363
+#define TRANSPORT_HDR 364
+#define BRIDGE 365
+#define ETHER 366
+#define SADDR 367
+#define DADDR 368
+#define TYPE 369
+#define VLAN 370
+#define ID 371
+#define CFI 372
+#define DEI 373
+#define PCP 374
+#define ARP 375
+#define HTYPE 376
+#define PTYPE 377
+#define HLEN 378
+#define PLEN 379
+#define OPERATION 380
+#define IP 381
+#define HDRVERSION 382
+#define HDRLENGTH 383
+#define DSCP 384
+#define ECN 385
+#define LENGTH 386
+#define FRAG_OFF 387
+#define TTL 388
+#define PROTOCOL 389
+#define CHECKSUM 390
+#define PTR 391
+#define VALUE 392
+#define LSRR 393
+#define RR 394
+#define SSRR 395
+#define RA 396
+#define ICMP 397
+#define CODE 398
+#define SEQUENCE 399
+#define GATEWAY 400
+#define MTU 401
+#define IGMP 402
+#define MRT 403
+#define OPTIONS 404
+#define IP6 405
+#define PRIORITY 406
+#define FLOWLABEL 407
+#define NEXTHDR 408
+#define HOPLIMIT 409
+#define ICMP6 410
+#define PPTR 411
+#define MAXDELAY 412
+#define TADDR 413
+#define AH 414
+#define RESERVED 415
+#define SPI 416
+#define ESP 417
+#define COMP 418
+#define FLAGS 419
+#define CPI 420
+#define PORT 421
+#define UDP 422
+#define SPORT 423
+#define DPORT 424
+#define UDPLITE 425
+#define CSUMCOV 426
+#define TCP 427
+#define ACKSEQ 428
+#define DOFF 429
+#define WINDOW 430
+#define URGPTR 431
+#define OPTION 432
+#define ECHO 433
+#define EOL 434
+#define MPTCP 435
+#define NOP 436
+#define SACK 437
+#define SACK0 438
+#define SACK1 439
+#define SACK2 440
+#define SACK3 441
+#define SACK_PERM 442
+#define FASTOPEN 443
+#define MD5SIG 444
+#define TIMESTAMP 445
+#define COUNT 446
+#define LEFT 447
+#define RIGHT 448
+#define TSVAL 449
+#define TSECR 450
+#define SUBTYPE 451
+#define DCCP 452
+#define VXLAN 453
+#define VNI 454
+#define GRE 455
+#define GRETAP 456
+#define GENEVE 457
+#define SCTP 458
+#define CHUNK 459
+#define DATA 460
+#define INIT 461
+#define INIT_ACK 462
+#define HEARTBEAT 463
+#define HEARTBEAT_ACK 464
+#define ABORT 465
+#define SHUTDOWN 466
+#define SHUTDOWN_ACK 467
+#define ERROR 468
+#define COOKIE_ECHO 469
+#define COOKIE_ACK 470
+#define ECNE 471
+#define CWR 472
+#define SHUTDOWN_COMPLETE 473
+#define ASCONF_ACK 474
+#define FORWARD_TSN 475
+#define ASCONF 476
+#define TSN 477
+#define STREAM 478
+#define SSN 479
+#define PPID 480
+#define INIT_TAG 481
+#define A_RWND 482
+#define NUM_OSTREAMS 483
+#define NUM_ISTREAMS 484
+#define INIT_TSN 485
+#define CUM_TSN_ACK 486
+#define NUM_GACK_BLOCKS 487
+#define NUM_DUP_TSNS 488
+#define LOWEST_TSN 489
+#define SEQNO 490
+#define NEW_CUM_TSN 491
+#define VTAG 492
+#define RT 493
+#define RT0 494
+#define RT2 495
+#define RT4 496
+#define SEG_LEFT 497
+#define ADDR 498
+#define LAST_ENT 499
+#define TAG 500
+#define SID 501
+#define HBH 502
+#define FRAG 503
+#define RESERVED2 504
+#define MORE_FRAGMENTS 505
+#define DST 506
+#define MH 507
+#define META 508
+#define MARK 509
+#define IIF 510
+#define IIFNAME 511
+#define IIFTYPE 512
+#define OIF 513
+#define OIFNAME 514
+#define OIFTYPE 515
+#define SKUID 516
+#define SKGID 517
+#define NFTRACE 518
+#define RTCLASSID 519
+#define IBRIPORT 520
+#define OBRIPORT 521
+#define IBRIDGENAME 522
+#define OBRIDGENAME 523
+#define PKTTYPE 524
+#define CPU 525
+#define IIFGROUP 526
+#define OIFGROUP 527
+#define CGROUP 528
+#define TIME 529
+#define CLASSID 530
+#define NEXTHOP 531
+#define CT 532
+#define L3PROTOCOL 533
+#define PROTO_SRC 534
+#define PROTO_DST 535
+#define ZONE 536
+#define DIRECTION 537
+#define EVENT 538
+#define EXPECTATION 539
+#define EXPIRATION 540
+#define HELPER 541
+#define LABEL 542
+#define STATE 543
+#define STATUS 544
+#define ORIGINAL 545
+#define REPLY 546
+#define COUNTER 547
+#define NAME 548
+#define PACKETS 549
+#define BYTES 550
+#define AVGPKT 551
+#define LAST 552
+#define NEVER 553
+#define COUNTERS 554
+#define QUOTAS 555
+#define LIMITS 556
+#define SYNPROXYS 557
+#define HELPERS 558
+#define LOG 559
+#define PREFIX 560
+#define GROUP 561
+#define SNAPLEN 562
+#define QUEUE_THRESHOLD 563
+#define LEVEL 564
+#define LIMIT 565
+#define RATE 566
+#define BURST 567
+#define OVER 568
+#define UNTIL 569
+#define QUOTA 570
+#define USED 571
+#define SECMARK 572
+#define SECMARKS 573
+#define SECOND 574
+#define MINUTE 575
+#define HOUR 576
+#define DAY 577
+#define WEEK 578
+#define _REJECT 579
+#define WITH 580
+#define ICMPX 581
+#define SNAT 582
+#define DNAT 583
+#define MASQUERADE 584
+#define REDIRECT 585
+#define RANDOM 586
+#define FULLY_RANDOM 587
+#define PERSISTENT 588
+#define QUEUE 589
+#define QUEUENUM 590
+#define BYPASS 591
+#define FANOUT 592
+#define DUP 593
+#define FWD 594
+#define NUMGEN 595
+#define INC 596
+#define MOD 597
+#define OFFSET 598
+#define JHASH 599
+#define SYMHASH 600
+#define SEED 601
+#define POSITION 602
+#define INDEX 603
+#define COMMENT 604
+#define XML 605
+#define JSON 606
+#define VM 607
+#define NOTRACK 608
+#define EXISTS 609
+#define MISSING 610
+#define EXTHDR 611
+#define IPSEC 612
+#define REQID 613
+#define SPNUM 614
+#define IN 615
+#define OUT 616
+#define XT 617
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+union YYSTYPE
+{
+#line 205 "parser_bison.y"
+
+ uint64_t val;
+ uint32_t val32;
+ uint8_t val8;
+ const char * string;
+
+ struct list_head *list;
+ struct cmd *cmd;
+ struct handle handle;
+ struct table *table;
+ struct chain *chain;
+ struct rule *rule;
+ struct stmt *stmt;
+ struct expr *expr;
+ struct set *set;
+ struct obj *obj;
+ struct flowtable *flowtable;
+ struct ct *ct;
+ const struct datatype *datatype;
+ struct handle_spec handle_spec;
+ struct position_spec position_spec;
+ struct prio_spec prio_spec;
+ struct limit_rate limit_rate;
+ struct tcp_kind_field {
+ uint16_t kind; /* must allow > 255 for SACK1, 2.. hack */
+ uint8_t field;
+ } tcp_kind_field;
+
+#line 820 "parser_bison.h"
+
+};
+typedef union YYSTYPE YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+/* Location type. */
+#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
+typedef struct YYLTYPE YYLTYPE;
+struct YYLTYPE
+{
+ int first_line;
+ int first_column;
+ int last_line;
+ int last_column;
+};
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+int nft_parse (struct nft_ctx *nft, void *scanner, struct parser_state *state);
+
+#endif /* !YY_NFT_PARSER_BISON_H_INCLUDED */
diff --git a/src/parser_bison.y b/src/parser_bison.y
new file mode 100644
index 0000000..c517dc3
--- /dev/null
+++ b/src/parser_bison.y
@@ -0,0 +1,6290 @@
+/*
+ * Copyright (c) 2007-2012 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+%{
+#include <nft.h>
+
+#include <ctype.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <syslog.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/if_ether.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/nfnetlink_osf.h>
+#include <linux/netfilter/nf_synproxy.h>
+#include <linux/xfrm.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <libnftnl/common.h>
+#include <libnftnl/set.h>
+#include <libnftnl/udata.h>
+
+#include <rule.h>
+#include <statement.h>
+#include <expression.h>
+#include <headers.h>
+#include <utils.h>
+#include <parser.h>
+#include <erec.h>
+#include <sctp_chunk.h>
+
+#include "parser_bison.h"
+
+void parser_init(struct nft_ctx *nft, struct parser_state *state,
+ struct list_head *msgs, struct list_head *cmds,
+ struct scope *top_scope)
+{
+ memset(state, 0, sizeof(*state));
+ state->msgs = msgs;
+ state->cmds = cmds;
+ state->scopes[0] = scope_init(top_scope, NULL);
+ init_list_head(&state->indesc_list);
+}
+
+static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner,
+ struct parser_state *state, const char *s)
+{
+ erec_queue(error(loc, "%s", s), state->msgs);
+}
+
+static struct scope *current_scope(const struct parser_state *state)
+{
+ return state->scopes[state->scope];
+}
+
+static int open_scope(struct parser_state *state, struct scope *scope)
+{
+ 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)
+{
+ if (state->scope_err || state->scope == 0) {
+ state->scope_err = false;
+ return;
+ }
+
+ state->scope--;
+}
+
+static void location_init(void *scanner, struct parser_state *state,
+ struct location *loc)
+{
+ memset(loc, 0, sizeof(*loc));
+ loc->indesc = state->indesc;
+}
+
+static void location_update(struct location *loc, struct location *rhs, int n)
+{
+ if (n) {
+ loc->indesc = rhs[n].indesc;
+ loc->token_offset = rhs[1].token_offset;
+ loc->line_offset = rhs[1].line_offset;
+ loc->first_line = rhs[1].first_line;
+ loc->first_column = rhs[1].first_column;
+ loc->last_line = rhs[n].last_line;
+ loc->last_column = rhs[n].last_column;
+ } else {
+ loc->indesc = rhs[0].indesc;
+ loc->token_offset = rhs[0].token_offset;
+ loc->line_offset = rhs[0].line_offset;
+ loc->first_line = loc->last_line = rhs[0].last_line;
+ loc->first_column = loc->last_column = rhs[0].last_column;
+ }
+}
+
+static struct expr *handle_concat_expr(const struct location *loc,
+ struct expr *expr,
+ struct expr *expr_l, struct expr *expr_r,
+ struct location loc_rhs[3])
+{
+ if (expr->etype != EXPR_CONCAT) {
+ expr = concat_expr_alloc(loc);
+ compound_expr_add(expr, expr_l);
+ } else {
+ location_update(&expr_r->location, loc_rhs, 2);
+
+ expr = expr_l;
+ expr->location = *loc;
+ }
+
+ compound_expr_add(expr, expr_r);
+ return expr;
+}
+
+static bool already_set(const void *attr, const struct location *loc,
+ struct parser_state *state)
+{
+ if (!attr)
+ return false;
+
+ erec_queue(error(loc, "You can only specify this once. This statement is duplicated."),
+ state->msgs);
+ return true;
+}
+
+static struct expr *ifname_expr_alloc(const struct location *location,
+ struct list_head *queue,
+ const char *name)
+{
+ unsigned int length = strlen(name);
+ struct expr *expr;
+
+ if (length == 0) {
+ xfree(name);
+ erec_queue(error(location, "empty interface name"), queue);
+ return NULL;
+ }
+
+ if (length > 16) {
+ xfree(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);
+
+ xfree(name);
+
+ return expr;
+}
+
+#define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N)
+
+#define symbol_value(loc, str) \
+ symbol_expr_alloc(loc, SYMBOL_VALUE, current_scope(state), str)
+
+/* Declare those here to avoid compiler warnings */
+void nft_set_debug(int, void *);
+int nft_lex(void *, void *, void *);
+%}
+
+/* Declaration section */
+
+%name-prefix "nft_"
+%debug
+%define api.pure
+%parse-param { struct nft_ctx *nft }
+%parse-param { void *scanner }
+%parse-param { struct parser_state *state }
+%lex-param { scanner }
+%define parse.error verbose
+%locations
+
+%initial-action {
+ location_init(scanner, state, &yylloc);
+ if (nft->debug_mask & NFT_DEBUG_SCANNER)
+ nft_set_debug(1, scanner);
+ if (nft->debug_mask & NFT_DEBUG_PARSER)
+ yydebug = 1;
+}
+
+%union {
+ uint64_t val;
+ uint32_t val32;
+ uint8_t val8;
+ const char * string;
+
+ struct list_head *list;
+ struct cmd *cmd;
+ struct handle handle;
+ struct table *table;
+ struct chain *chain;
+ struct rule *rule;
+ struct stmt *stmt;
+ struct expr *expr;
+ struct set *set;
+ struct obj *obj;
+ struct flowtable *flowtable;
+ struct ct *ct;
+ const struct datatype *datatype;
+ struct handle_spec handle_spec;
+ struct position_spec position_spec;
+ struct prio_spec prio_spec;
+ struct limit_rate limit_rate;
+ struct tcp_kind_field {
+ uint16_t kind; /* must allow > 255 for SACK1, 2.. hack */
+ uint8_t field;
+ } tcp_kind_field;
+}
+
+%token TOKEN_EOF 0 "end of file"
+%token JUNK "junk"
+
+%token NEWLINE "newline"
+%token COLON "colon"
+%token SEMICOLON "semicolon"
+%token COMMA "comma"
+%token DOT "."
+
+%token EQ "=="
+%token NEQ "!="
+%token LT "<"
+%token GT ">"
+%token GTE ">="
+%token LTE "<="
+%token LSHIFT "<<"
+%token RSHIFT ">>"
+%token AMPERSAND "&"
+%token CARET "^"
+%token NOT "!"
+%token SLASH "/"
+%token ASTERISK "*"
+%token DASH "-"
+%token AT "@"
+%token VMAP "vmap"
+
+%token PLUS "+"
+
+%token INCLUDE "include"
+%token DEFINE "define"
+%token REDEFINE "redefine"
+%token UNDEFINE "undefine"
+
+%token FIB "fib"
+
+%token SOCKET "socket"
+%token TRANSPARENT "transparent"
+%token WILDCARD "wildcard"
+%token CGROUPV2 "cgroupv2"
+
+%token TPROXY "tproxy"
+
+%token OSF "osf"
+
+%token SYNPROXY "synproxy"
+%token MSS "mss"
+%token WSCALE "wscale"
+
+%token TYPEOF "typeof"
+
+%token HOOK "hook"
+%token HOOKS "hooks"
+%token DEVICE "device"
+%token DEVICES "devices"
+%token TABLE "table"
+%token TABLES "tables"
+%token CHAIN "chain"
+%token CHAINS "chains"
+%token RULE "rule"
+%token RULES "rules"
+%token SETS "sets"
+%token SET "set"
+%token ELEMENT "element"
+%token MAP "map"
+%token MAPS "maps"
+%token FLOWTABLE "flowtable"
+%token HANDLE "handle"
+%token RULESET "ruleset"
+%token TRACE "trace"
+
+%token INET "inet"
+%token NETDEV "netdev"
+
+%token ADD "add"
+%token UPDATE "update"
+%token REPLACE "replace"
+%token CREATE "create"
+%token INSERT "insert"
+%token DELETE "delete"
+%token GET "get"
+%token LIST "list"
+%token RESET "reset"
+%token FLUSH "flush"
+%token RENAME "rename"
+%token DESCRIBE "describe"
+%token IMPORT "import"
+%token EXPORT "export"
+%token DESTROY "destroy"
+
+%token MONITOR "monitor"
+
+%token ALL "all"
+
+%token ACCEPT "accept"
+%token DROP "drop"
+%token CONTINUE "continue"
+%token JUMP "jump"
+%token GOTO "goto"
+%token RETURN "return"
+%token TO "to"
+
+%token CONSTANT "constant"
+%token INTERVAL "interval"
+%token DYNAMIC "dynamic"
+%token AUTOMERGE "auto-merge"
+%token TIMEOUT "timeout"
+%token GC_INTERVAL "gc-interval"
+%token ELEMENTS "elements"
+%token EXPIRES "expires"
+
+%token POLICY "policy"
+%token MEMORY "memory"
+%token PERFORMANCE "performance"
+%token SIZE "size"
+
+%token FLOW "flow"
+%token OFFLOAD "offload"
+%token METER "meter"
+%token METERS "meters"
+
+%token FLOWTABLES "flowtables"
+
+%token <val> NUM "number"
+%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
+
+%token LL_HDR "ll"
+%token NETWORK_HDR "nh"
+%token TRANSPORT_HDR "th"
+
+%token BRIDGE "bridge"
+
+%token ETHER "ether"
+%token SADDR "saddr"
+%token DADDR "daddr"
+%token TYPE "type"
+
+%token VLAN "vlan"
+%token ID "id"
+%token CFI "cfi"
+%token DEI "dei"
+%token PCP "pcp"
+
+%token ARP "arp"
+%token HTYPE "htype"
+%token PTYPE "ptype"
+%token HLEN "hlen"
+%token PLEN "plen"
+%token OPERATION "operation"
+
+%token IP "ip"
+%token HDRVERSION "version"
+%token HDRLENGTH "hdrlength"
+%token DSCP "dscp"
+%token ECN "ecn"
+%token LENGTH "length"
+%token FRAG_OFF "frag-off"
+%token TTL "ttl"
+%token PROTOCOL "protocol"
+%token CHECKSUM "checksum"
+
+%token PTR "ptr"
+%token VALUE "value"
+
+%token LSRR "lsrr"
+%token RR "rr"
+%token SSRR "ssrr"
+%token RA "ra"
+
+%token ICMP "icmp"
+%token CODE "code"
+%token SEQUENCE "seq"
+%token GATEWAY "gateway"
+%token MTU "mtu"
+
+%token IGMP "igmp"
+%token MRT "mrt"
+
+%token OPTIONS "options"
+
+%token IP6 "ip6"
+%token PRIORITY "priority"
+%token FLOWLABEL "flowlabel"
+%token NEXTHDR "nexthdr"
+%token HOPLIMIT "hoplimit"
+
+%token ICMP6 "icmpv6"
+%token PPTR "param-problem"
+%token MAXDELAY "max-delay"
+%token TADDR "taddr"
+
+%token AH "ah"
+%token RESERVED "reserved"
+%token SPI "spi"
+
+%token ESP "esp"
+
+%token COMP "comp"
+%token FLAGS "flags"
+%token CPI "cpi"
+
+%token PORT "port"
+%token UDP "udp"
+%token SPORT "sport"
+%token DPORT "dport"
+%token UDPLITE "udplite"
+%token CSUMCOV "csumcov"
+
+%token TCP "tcp"
+%token ACKSEQ "ackseq"
+%token DOFF "doff"
+%token WINDOW "window"
+%token URGPTR "urgptr"
+%token OPTION "option"
+%token ECHO "echo"
+%token EOL "eol"
+%token MPTCP "mptcp"
+%token NOP "nop"
+%token SACK "sack"
+%token SACK0 "sack0"
+%token SACK1 "sack1"
+%token SACK2 "sack2"
+%token SACK3 "sack3"
+%token SACK_PERM "sack-permitted"
+%token FASTOPEN "fastopen"
+%token MD5SIG "md5sig"
+%token TIMESTAMP "timestamp"
+%token COUNT "count"
+%token LEFT "left"
+%token RIGHT "right"
+%token TSVAL "tsval"
+%token TSECR "tsecr"
+%token SUBTYPE "subtype"
+
+%token DCCP "dccp"
+
+%token VXLAN "vxlan"
+%token VNI "vni"
+
+%token GRE "gre"
+%token GRETAP "gretap"
+
+%token GENEVE "geneve"
+
+%token SCTP "sctp"
+%token CHUNK "chunk"
+%token DATA "data"
+%token INIT "init"
+%token INIT_ACK "init-ack"
+%token HEARTBEAT "heartbeat"
+%token HEARTBEAT_ACK "heartbeat-ack"
+%token ABORT "abort"
+%token SHUTDOWN "shutdown"
+%token SHUTDOWN_ACK "shutdown-ack"
+%token ERROR "error"
+%token COOKIE_ECHO "cookie-echo"
+%token COOKIE_ACK "cookie-ack"
+%token ECNE "ecne"
+%token CWR "cwr"
+%token SHUTDOWN_COMPLETE "shutdown-complete"
+%token ASCONF_ACK "asconf-ack"
+%token FORWARD_TSN "forward-tsn"
+%token ASCONF "asconf"
+%token TSN "tsn"
+%token STREAM "stream"
+%token SSN "ssn"
+%token PPID "ppid"
+%token INIT_TAG "init-tag"
+%token A_RWND "a-rwnd"
+%token NUM_OSTREAMS "num-outbound-streams"
+%token NUM_ISTREAMS "num-inbound-streams"
+%token INIT_TSN "initial-tsn"
+%token CUM_TSN_ACK "cum-tsn-ack"
+%token NUM_GACK_BLOCKS "num-gap-ack-blocks"
+%token NUM_DUP_TSNS "num-dup-tsns"
+%token LOWEST_TSN "lowest-tsn"
+%token SEQNO "seqno"
+%token NEW_CUM_TSN "new-cum-tsn"
+
+%token VTAG "vtag"
+
+%token RT "rt"
+%token RT0 "rt0"
+%token RT2 "rt2"
+%token RT4 "srh"
+%token SEG_LEFT "seg-left"
+%token ADDR "addr"
+%token LAST_ENT "last-entry"
+%token TAG "tag"
+%token SID "sid"
+
+%token HBH "hbh"
+
+%token FRAG "frag"
+%token RESERVED2 "reserved2"
+%token MORE_FRAGMENTS "more-fragments"
+
+%token DST "dst"
+
+%token MH "mh"
+
+%token META "meta"
+%token MARK "mark"
+%token IIF "iif"
+%token IIFNAME "iifname"
+%token IIFTYPE "iiftype"
+%token OIF "oif"
+%token OIFNAME "oifname"
+%token OIFTYPE "oiftype"
+%token SKUID "skuid"
+%token SKGID "skgid"
+%token NFTRACE "nftrace"
+%token RTCLASSID "rtclassid"
+%token IBRIPORT "ibriport"
+%token OBRIPORT "obriport"
+%token IBRIDGENAME "ibrname"
+%token OBRIDGENAME "obrname"
+%token PKTTYPE "pkttype"
+%token CPU "cpu"
+%token IIFGROUP "iifgroup"
+%token OIFGROUP "oifgroup"
+%token CGROUP "cgroup"
+%token TIME "time"
+
+%token CLASSID "classid"
+%token NEXTHOP "nexthop"
+
+%token CT "ct"
+%token L3PROTOCOL "l3proto"
+%token PROTO_SRC "proto-src"
+%token PROTO_DST "proto-dst"
+%token ZONE "zone"
+%token DIRECTION "direction"
+%token EVENT "event"
+%token EXPECTATION "expectation"
+%token EXPIRATION "expiration"
+%token HELPER "helper"
+%token LABEL "label"
+%token STATE "state"
+%token STATUS "status"
+%token ORIGINAL "original"
+%token REPLY "reply"
+
+%token COUNTER "counter"
+%token NAME "name"
+%token PACKETS "packets"
+%token BYTES "bytes"
+%token AVGPKT "avgpkt"
+
+%token LAST "last"
+%token NEVER "never"
+
+%token COUNTERS "counters"
+%token QUOTAS "quotas"
+%token LIMITS "limits"
+%token SYNPROXYS "synproxys"
+%token HELPERS "helpers"
+
+%token LOG "log"
+%token PREFIX "prefix"
+%token GROUP "group"
+%token SNAPLEN "snaplen"
+%token QUEUE_THRESHOLD "queue-threshold"
+%token LEVEL "level"
+
+%token LIMIT "limit"
+%token RATE "rate"
+%token BURST "burst"
+%token OVER "over"
+%token UNTIL "until"
+
+%token QUOTA "quota"
+%token USED "used"
+
+%token SECMARK "secmark"
+%token SECMARKS "secmarks"
+
+%token SECOND "second"
+%token MINUTE "minute"
+%token HOUR "hour"
+%token DAY "day"
+%token WEEK "week"
+
+%token _REJECT "reject"
+%token WITH "with"
+%token ICMPX "icmpx"
+
+%token SNAT "snat"
+%token DNAT "dnat"
+%token MASQUERADE "masquerade"
+%token REDIRECT "redirect"
+%token RANDOM "random"
+%token FULLY_RANDOM "fully-random"
+%token PERSISTENT "persistent"
+
+%token QUEUE "queue"
+%token QUEUENUM "num"
+%token BYPASS "bypass"
+%token FANOUT "fanout"
+
+%token DUP "dup"
+%token FWD "fwd"
+
+%token NUMGEN "numgen"
+%token INC "inc"
+%token MOD "mod"
+%token OFFSET "offset"
+
+%token JHASH "jhash"
+%token SYMHASH "symhash"
+%token SEED "seed"
+
+%token POSITION "position"
+%token INDEX "index"
+%token COMMENT "comment"
+
+%token XML "xml"
+%token JSON "json"
+%token VM "vm"
+
+%token NOTRACK "notrack"
+
+%token EXISTS "exists"
+%token MISSING "missing"
+
+%token EXTHDR "exthdr"
+
+%token IPSEC "ipsec"
+%token REQID "reqid"
+%token SPNUM "spnum"
+
+%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
+
+%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
+
+%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 destroy_cmd
+%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd destroy_cmd
+
+%type <handle> table_spec tableid_spec table_or_id_spec
+%destructor { handle_free(&$$); } table_spec tableid_spec table_or_id_spec
+%type <handle> chain_spec chainid_spec chain_or_id_spec
+%destructor { handle_free(&$$); } chain_spec chainid_spec chain_or_id_spec
+
+%type <handle> flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
+%destructor { handle_free(&$$); } flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
+%type <handle> set_spec setid_spec set_or_id_spec
+%destructor { handle_free(&$$); } set_spec setid_spec set_or_id_spec
+%type <handle> obj_spec objid_spec obj_or_id_spec
+%destructor { handle_free(&$$); } obj_spec objid_spec obj_or_id_spec
+
+%type <handle> set_identifier flowtableid_spec flowtable_identifier obj_identifier
+%destructor { handle_free(&$$); } set_identifier flowtableid_spec obj_identifier
+
+%type <handle> basehook_spec
+%destructor { handle_free(&$$); } basehook_spec
+
+%type <val> family_spec family_spec_explicit
+%type <val32> int_num chain_policy
+%type <prio_spec> extended_prio_spec prio_spec
+%type <string> extended_prio_name quota_unit basehook_device_name
+%destructor { xfree($$); } extended_prio_name quota_unit basehook_device_name
+
+%type <expr> dev_spec
+%destructor { xfree($$); } dev_spec
+
+%type <table> table_block_alloc table_block
+%destructor { close_scope(state); table_free($$); } table_block_alloc
+%type <chain> chain_block_alloc chain_block subchain_block
+%destructor { close_scope(state); chain_free($$); } chain_block_alloc
+%type <rule> rule rule_alloc
+%destructor { rule_free($$); } rule
+
+%type <val> set_flag_list set_flag
+
+%type <val> set_policy_spec
+
+%type <set> set_block_alloc set_block
+%destructor { set_free($$); } set_block_alloc
+
+%type <set> map_block_alloc map_block
+%destructor { set_free($$); } map_block_alloc
+%type <val> map_block_obj_type map_block_data_interval
+
+%type <flowtable> flowtable_block_alloc flowtable_block
+%destructor { flowtable_free($$); } flowtable_block_alloc
+
+%type <obj> obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block synproxy_block
+%destructor { obj_free($$); } obj_block_alloc
+
+%type <list> stmt_list stateful_stmt_list set_elem_stmt_list
+%destructor { stmt_list_free($$); xfree($$); } stmt_list stateful_stmt_list set_elem_stmt_list
+%type <stmt> stmt match_stmt verdict_stmt set_elem_stmt
+%destructor { stmt_free($$); } stmt match_stmt verdict_stmt set_elem_stmt
+%type <stmt> counter_stmt counter_stmt_alloc stateful_stmt last_stmt
+%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt last_stmt
+%type <stmt> payload_stmt
+%destructor { stmt_free($$); } payload_stmt
+%type <stmt> ct_stmt
+%destructor { stmt_free($$); } ct_stmt
+%type <stmt> meta_stmt
+%destructor { stmt_free($$); } meta_stmt
+%type <stmt> log_stmt log_stmt_alloc
+%destructor { stmt_free($$); } log_stmt log_stmt_alloc
+%type <val> level_type log_flags log_flags_tcp log_flag_tcp
+%type <stmt> limit_stmt quota_stmt connlimit_stmt
+%destructor { stmt_free($$); } limit_stmt quota_stmt connlimit_stmt
+%type <val> limit_burst_pkts limit_burst_bytes limit_mode limit_bytes time_unit quota_mode
+%type <stmt> reject_stmt reject_stmt_alloc
+%destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
+%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
+%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
+%type <val> nf_nat_flags nf_nat_flag offset_opt
+%type <stmt> tproxy_stmt
+%destructor { stmt_free($$); } tproxy_stmt
+%type <stmt> synproxy_stmt synproxy_stmt_alloc
+%destructor { stmt_free($$); } synproxy_stmt synproxy_stmt_alloc
+%type <stmt> chain_stmt
+%destructor { stmt_free($$); } chain_stmt
+%type <val> chain_stmt_type
+
+%type <stmt> queue_stmt queue_stmt_alloc queue_stmt_compat
+%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc queue_stmt_compat
+%type <expr> queue_stmt_expr_simple queue_stmt_expr queue_expr reject_with_expr
+%destructor { expr_free($$); } queue_stmt_expr_simple queue_stmt_expr queue_expr reject_with_expr
+%type <val> queue_stmt_flags queue_stmt_flag
+%type <stmt> dup_stmt
+%destructor { stmt_free($$); } dup_stmt
+%type <stmt> fwd_stmt
+%destructor { stmt_free($$); } fwd_stmt
+%type <stmt> set_stmt
+%destructor { stmt_free($$); } set_stmt
+%type <val> set_stmt_op
+%type <stmt> map_stmt
+%destructor { stmt_free($$); } map_stmt
+%type <stmt> meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc
+%destructor { stmt_free($$); } meter_stmt meter_stmt_alloc flow_stmt_legacy_alloc
+
+%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> exclusive_or_expr inclusive_or_expr
+%destructor { expr_free($$); } exclusive_or_expr inclusive_or_expr
+%type <expr> basic_expr
+%destructor { expr_free($$); } basic_expr
+%type <expr> set_ref_expr set_ref_symbol_expr
+%destructor { expr_free($$); } set_ref_expr set_ref_symbol_expr
+
+%type <expr> multiton_rhs_expr
+%destructor { expr_free($$); } multiton_rhs_expr
+%type <expr> prefix_rhs_expr range_rhs_expr
+%destructor { expr_free($$); } prefix_rhs_expr range_rhs_expr
+
+%type <expr> stmt_expr concat_stmt_expr map_stmt_expr map_stmt_expr_set
+%destructor { expr_free($$); } stmt_expr concat_stmt_expr map_stmt_expr map_stmt_expr_set
+
+%type <expr> multiton_stmt_expr
+%destructor { expr_free($$); } multiton_stmt_expr
+%type <expr> prefix_stmt_expr range_stmt_expr
+%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr
+
+%type <expr> primary_stmt_expr basic_stmt_expr
+%destructor { expr_free($$); } primary_stmt_expr basic_stmt_expr
+%type <expr> list_stmt_expr shift_stmt_expr
+%destructor { expr_free($$); } list_stmt_expr shift_stmt_expr
+%type <expr> and_stmt_expr exclusive_or_stmt_expr inclusive_or_stmt_expr
+%destructor { expr_free($$); } and_stmt_expr exclusive_or_stmt_expr inclusive_or_stmt_expr
+
+%type <expr> concat_expr
+%destructor { expr_free($$); } concat_expr
+
+%type <expr> map_expr
+%destructor { expr_free($$); } map_expr
+
+%type <expr> verdict_map_stmt
+%destructor { expr_free($$); } verdict_map_stmt
+
+%type <expr> verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr
+%destructor { expr_free($$); } verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr
+
+%type <expr> set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member
+%destructor { expr_free($$); } set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member
+%type <expr> set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
+%destructor { expr_free($$); } set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
+%type <expr> set_elem_expr_stmt set_elem_expr_stmt_alloc
+%destructor { expr_free($$); } set_elem_expr_stmt set_elem_expr_stmt_alloc
+
+%type <expr> meter_key_expr meter_key_expr_alloc
+%destructor { expr_free($$); } meter_key_expr meter_key_expr_alloc
+
+%type <expr> expr initializer_expr keyword_expr
+%destructor { expr_free($$); } expr initializer_expr keyword_expr
+
+%type <expr> rhs_expr concat_rhs_expr basic_rhs_expr
+%destructor { expr_free($$); } rhs_expr concat_rhs_expr basic_rhs_expr
+%type <expr> primary_rhs_expr list_rhs_expr shift_rhs_expr symbol_stmt_expr
+%destructor { expr_free($$); } primary_rhs_expr list_rhs_expr shift_rhs_expr symbol_stmt_expr
+%type <expr> and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
+%destructor { expr_free($$); } and_rhs_expr exclusive_or_rhs_expr inclusive_or_rhs_expr
+
+%type <obj> counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj
+%destructor { obj_free($$); } counter_obj quota_obj ct_obj_alloc limit_obj secmark_obj synproxy_obj
+
+%type <expr> relational_expr
+%destructor { expr_free($$); } relational_expr
+%type <val> relational_op
+
+%type <expr> payload_expr payload_raw_expr
+%destructor { expr_free($$); } payload_expr payload_raw_expr
+%type <val> payload_base_spec
+%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
+%type <expr> arp_hdr_expr
+%destructor { expr_free($$); } arp_hdr_expr
+%type <val> arp_hdr_field
+%type <expr> ip_hdr_expr icmp_hdr_expr igmp_hdr_expr numgen_expr hash_expr
+%destructor { expr_free($$); } ip_hdr_expr icmp_hdr_expr igmp_hdr_expr numgen_expr hash_expr
+%type <val> ip_hdr_field icmp_hdr_field igmp_hdr_field
+%type <val> ip_option_type ip_option_field
+%type <expr> ip6_hdr_expr icmp6_hdr_expr
+%destructor { expr_free($$); } ip6_hdr_expr icmp6_hdr_expr
+%type <val> ip6_hdr_field icmp6_hdr_field
+%type <expr> auth_hdr_expr esp_hdr_expr comp_hdr_expr
+%destructor { expr_free($$); } auth_hdr_expr esp_hdr_expr comp_hdr_expr
+%type <val> auth_hdr_field esp_hdr_field comp_hdr_field
+%type <expr> udp_hdr_expr udplite_hdr_expr
+%destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr
+%type <val> udp_hdr_field udplite_hdr_field
+%type <expr> dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc
+%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc
+%type <val> dccp_hdr_field sctp_hdr_field
+%type <val> sctp_chunk_type sctp_chunk_common_field
+%type <val> sctp_chunk_data_field sctp_chunk_init_field
+%type <val> sctp_chunk_sack_field
+%type <expr> th_hdr_expr
+%destructor { expr_free($$); } th_hdr_expr
+%type <val> th_hdr_field
+
+%type <expr> exthdr_expr
+%destructor { expr_free($$); } exthdr_expr
+%type <expr> hbh_hdr_expr frag_hdr_expr dst_hdr_expr
+%destructor { expr_free($$); } hbh_hdr_expr frag_hdr_expr dst_hdr_expr
+%type <val> hbh_hdr_field frag_hdr_field dst_hdr_field
+%type <expr> rt_hdr_expr rt0_hdr_expr rt2_hdr_expr rt4_hdr_expr
+%destructor { expr_free($$); } rt_hdr_expr rt0_hdr_expr rt2_hdr_expr rt4_hdr_expr
+%type <val> rt_hdr_field rt0_hdr_field rt2_hdr_field rt4_hdr_field
+%type <expr> mh_hdr_expr
+%destructor { expr_free($$); } mh_hdr_expr
+%type <val> mh_hdr_field
+
+%type <expr> meta_expr
+%destructor { expr_free($$); } meta_expr
+%type <val> meta_key meta_key_qualified meta_key_unqualified numgen_type
+
+%type <expr> socket_expr
+%destructor { expr_free($$); } socket_expr
+%type<val> socket_key
+
+%type <val> nf_key_proto
+
+%type <expr> rt_expr
+%destructor { expr_free($$); } rt_expr
+%type <val> rt_key
+
+%type <expr> ct_expr
+%destructor { expr_free($$); } ct_expr
+%type <val> ct_key ct_dir ct_key_dir_optional ct_key_dir ct_key_proto_field
+
+%type <expr> fib_expr
+%destructor { expr_free($$); } fib_expr
+%type <val> fib_tuple fib_result fib_flag
+
+%type <expr> osf_expr
+%type <val> osf_ttl
+%destructor { expr_free($$); } osf_expr
+
+%type <val> markup_format
+%type <string> monitor_event
+%destructor { xfree($$); } monitor_event
+%type <val> monitor_object monitor_format
+
+%type <val> synproxy_ts synproxy_sack
+
+%type <expr> tcp_hdr_expr
+%destructor { expr_free($$); } tcp_hdr_expr
+%type <val> tcp_hdr_field
+%type <val> tcp_hdr_option_type
+%type <val> tcp_hdr_option_sack
+%type <val> tcpopt_field_maxseg tcpopt_field_mptcp tcpopt_field_sack tcpopt_field_tsopt tcpopt_field_window
+%type <tcp_kind_field> tcp_hdr_option_kind_and_field
+
+%type <expr> inner_eth_expr inner_inet_expr inner_expr
+%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr
+
+%type <expr> vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr
+%destructor { expr_free($$); } vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr
+%type <val> vxlan_hdr_field geneve_hdr_field gre_hdr_field
+
+%type <stmt> optstrip_stmt
+%destructor { stmt_free($$); } optstrip_stmt
+
+%type <stmt> xt_stmt
+%destructor { stmt_free($$); } xt_stmt
+
+%type <expr> boolean_expr
+%destructor { expr_free($$); } boolean_expr
+%type <val8> boolean_keys
+
+%type <expr> exthdr_exists_expr
+%destructor { expr_free($$); } exthdr_exists_expr
+%type <val> exthdr_key
+
+%type <val> ct_l4protoname ct_obj_type ct_cmd_type
+
+%type <list> timeout_states timeout_state
+%destructor { xfree($$); } timeout_states timeout_state
+
+%type <val> xfrm_state_key xfrm_state_proto_key xfrm_dir xfrm_spnum
+%type <expr> xfrm_expr
+%destructor { expr_free($$); } xfrm_expr
+
+%type <expr> set_elem_key_expr
+%destructor { expr_free($$); } set_elem_key_expr
+
+%%
+
+input : /* empty */
+ | input line
+ {
+ if ($2 != NULL) {
+ $2->location = @2;
+ list_add_tail(&$2->list, state->cmds);
+ }
+ }
+ ;
+
+stmt_separator : NEWLINE
+ | SEMICOLON
+ ;
+
+opt_newline : NEWLINE
+ | /* empty */
+ ;
+
+close_scope_ah : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_AH); };
+close_scope_arp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ARP); };
+close_scope_at : { scanner_pop_start_cond(nft->scanner, PARSER_SC_AT); };
+close_scope_comp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_COMP); };
+close_scope_ct : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CT); };
+close_scope_counter : { scanner_pop_start_cond(nft->scanner, PARSER_SC_COUNTER); };
+close_scope_last : { scanner_pop_start_cond(nft->scanner, PARSER_SC_LAST); };
+close_scope_dccp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DCCP); };
+close_scope_destroy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_DESTROY); };
+close_scope_dst : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DST); };
+close_scope_dup : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_DUP); };
+close_scope_esp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_ESP); };
+close_scope_eth : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ETH); };
+close_scope_export : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_EXPORT); };
+close_scope_fib : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FIB); };
+close_scope_frag : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FRAG); };
+close_scope_fwd : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_FWD); };
+close_scope_gre : { scanner_pop_start_cond(nft->scanner, PARSER_SC_GRE); };
+close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); };
+close_scope_hbh : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HBH); };
+close_scope_ip : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP); };
+close_scope_ip6 : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP6); };
+close_scope_vlan : { scanner_pop_start_cond(nft->scanner, PARSER_SC_VLAN); };
+close_scope_icmp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ICMP); };
+close_scope_igmp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IGMP); };
+close_scope_import : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_IMPORT); };
+close_scope_ipsec : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_IPSEC); };
+close_scope_list : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_LIST); };
+close_scope_limit : { scanner_pop_start_cond(nft->scanner, PARSER_SC_LIMIT); };
+close_scope_meta : { scanner_pop_start_cond(nft->scanner, PARSER_SC_META); };
+close_scope_mh : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_MH); };
+close_scope_monitor : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_MONITOR); };
+close_scope_nat : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_NAT); };
+close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); };
+close_scope_osf : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_OSF); };
+close_scope_policy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_POLICY); };
+close_scope_quota : { scanner_pop_start_cond(nft->scanner, PARSER_SC_QUOTA); };
+close_scope_queue : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_QUEUE); };
+close_scope_reject : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_REJECT); };
+close_scope_reset : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_RESET); };
+close_scope_rt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_RT); };
+close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); };
+close_scope_sctp_chunk : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SCTP_CHUNK); };
+close_scope_secmark : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SECMARK); };
+close_scope_socket : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SOCKET); }
+close_scope_tcp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_TCP); };
+close_scope_tproxy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_TPROXY); };
+close_scope_type : { scanner_pop_start_cond(nft->scanner, PARSER_SC_TYPE); };
+close_scope_th : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_TH); };
+close_scope_udp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDP); };
+close_scope_udplite : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDPLITE); };
+
+close_scope_log : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_LOG); }
+close_scope_synproxy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_SYNPROXY); }
+close_scope_xt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_XT); }
+
+common_block : INCLUDE QUOTED_STRING stmt_separator
+ {
+ if (scanner_include_file(nft, scanner, $2, &@$) < 0) {
+ xfree($2);
+ YYERROR;
+ }
+ xfree($2);
+ }
+ | DEFINE identifier '=' initializer_expr stmt_separator
+ {
+ struct scope *scope = current_scope(state);
+
+ if (symbol_lookup(scope, $2) != NULL) {
+ erec_queue(error(&@2, "redefinition of symbol '%s'", $2),
+ state->msgs);
+ expr_free($4);
+ xfree($2);
+ YYERROR;
+ }
+
+ symbol_bind(scope, $2, $4);
+ xfree($2);
+ }
+ | REDEFINE identifier '=' initializer_expr stmt_separator
+ {
+ struct scope *scope = current_scope(state);
+
+ symbol_bind(scope, $2, $4);
+ xfree($2);
+ }
+ | UNDEFINE identifier stmt_separator
+ {
+ struct scope *scope = current_scope(state);
+
+ if (symbol_unbind(scope, $2) < 0) {
+ erec_queue(error(&@2, "undefined symbol '%s'", $2),
+ state->msgs);
+ xfree($2);
+ YYERROR;
+ }
+ xfree($2);
+ }
+ | error stmt_separator
+ {
+ if (++state->nerrs == nft->parser_max_errors)
+ YYABORT;
+ yyerrok;
+ }
+ ;
+
+line : common_block { $$ = NULL; }
+ | stmt_separator { $$ = NULL; }
+ | base_cmd stmt_separator { $$ = $1; }
+ | base_cmd TOKEN_EOF
+ {
+ /*
+ * Very hackish workaround for bison >= 2.4: previous versions
+ * terminated parsing after EOF, 2.4+ tries to get further input
+ * in 'input' and calls the scanner again, causing a crash when
+ * the final input buffer has been popped. Terminate manually to
+ * avoid this. The correct fix should be to adjust the grammar
+ * to accept EOF in input, but for unknown reasons it does not
+ * work.
+ */
+ if ($1 != NULL) {
+ $1->location = @1;
+ list_add_tail(&$1->list, state->cmds);
+ }
+ $$ = NULL;
+ YYACCEPT;
+ }
+ ;
+
+base_cmd : /* empty */ add_cmd { $$ = $1; }
+ | ADD add_cmd { $$ = $2; }
+ | REPLACE replace_cmd { $$ = $2; }
+ | CREATE create_cmd { $$ = $2; }
+ | INSERT insert_cmd { $$ = $2; }
+ | DELETE delete_cmd { $$ = $2; }
+ | GET get_cmd { $$ = $2; }
+ | LIST list_cmd close_scope_list { $$ = $2; }
+ | RESET reset_cmd close_scope_reset { $$ = $2; }
+ | FLUSH flush_cmd { $$ = $2; }
+ | RENAME rename_cmd { $$ = $2; }
+ | IMPORT import_cmd close_scope_import { $$ = $2; }
+ | EXPORT export_cmd close_scope_export { $$ = $2; }
+ | MONITOR monitor_cmd close_scope_monitor { $$ = $2; }
+ | DESCRIBE describe_cmd { $$ = $2; }
+ | DESTROY destroy_cmd close_scope_destroy { $$ = $2; }
+ ;
+
+add_cmd : TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &$2, &@$, NULL);
+ }
+ | TABLE table_spec table_block_alloc
+ '{' table_block '}'
+ {
+ handle_merge(&$3->handle, &$2);
+ close_scope(state);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &$2, &@$, $5);
+ }
+ | CHAIN chain_spec
+ {
+ $$ = cmd_alloc(CMD_ADD, 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_ADD, CMD_OBJ_CHAIN, &$2, &@$, $5);
+ }
+ | RULE rule_position rule
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$2, &@$, $3);
+ }
+ | /* empty */ rule_position rule
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &$1, &@$, $2);
+ }
+ | SET set_spec set_block_alloc
+ '{' set_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, &@$, $5);
+ }
+ | MAP set_spec map_block_alloc
+ '{' map_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &$2, &@$, $5);
+ }
+ | ELEMENT set_spec set_block_expr
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
+ }
+ | FLOWTABLE flowtable_spec flowtable_block_alloc
+ '{' flowtable_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
+ }
+ | COUNTER obj_spec close_scope_counter
+ {
+ struct obj *obj;
+
+ obj = obj_alloc(&@$);
+ obj->type = NFT_OBJECT_COUNTER;
+ handle_merge(&obj->handle, &$2);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, obj);
+ }
+ | COUNTER obj_spec counter_obj counter_config close_scope_counter
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | COUNTER obj_spec counter_obj '{' counter_block '}' close_scope_counter
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj quota_config close_scope_quota
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj '{' quota_block '}' close_scope_quota
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
+ | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
+ }
+ | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
+ }
+ | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4);
+ }
+ | LIMIT obj_spec limit_obj limit_config close_scope_limit
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3);
+ }
+ | LIMIT obj_spec limit_obj '{' limit_block '}' close_scope_limit
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3);
+ }
+ | SECMARK obj_spec secmark_obj secmark_config close_scope_secmark
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3);
+ }
+ | SECMARK obj_spec secmark_obj '{' secmark_block '}' close_scope_secmark
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3);
+ }
+ | SYNPROXY obj_spec synproxy_obj synproxy_config close_scope_synproxy
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
+ }
+ | SYNPROXY obj_spec synproxy_obj '{' synproxy_block '}' close_scope_synproxy
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
+ }
+ ;
+
+replace_cmd : RULE ruleid_spec rule
+ {
+ $$ = cmd_alloc(CMD_REPLACE, CMD_OBJ_RULE, &$2, &@$, $3);
+ }
+ ;
+
+create_cmd : TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_TABLE, &$2, &@$, NULL);
+ }
+ | TABLE table_spec table_block_alloc
+ '{' table_block '}'
+ {
+ handle_merge(&$3->handle, &$2);
+ close_scope(state);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_TABLE, &$2, &@$, $5);
+ }
+ | CHAIN chain_spec
+ {
+ $$ = cmd_alloc(CMD_CREATE, 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_CREATE, CMD_OBJ_CHAIN, &$2, &@$, $5);
+ }
+ | SET set_spec set_block_alloc
+ '{' set_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SET, &$2, &@$, $5);
+ }
+ | MAP set_spec map_block_alloc
+ '{' map_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SET, &$2, &@$, $5);
+ }
+ | ELEMENT set_spec set_block_expr
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
+ }
+ | FLOWTABLE flowtable_spec flowtable_block_alloc
+ '{' flowtable_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
+ }
+ | COUNTER obj_spec close_scope_counter
+ {
+ struct obj *obj;
+
+ obj = obj_alloc(&@$);
+ obj->type = NFT_OBJECT_COUNTER;
+ handle_merge(&obj->handle, &$2);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, obj);
+ }
+ | COUNTER obj_spec counter_obj counter_config close_scope_counter
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj quota_config close_scope_quota
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
+ | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
+ }
+ | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
+ }
+ | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4);
+ }
+ | LIMIT obj_spec limit_obj limit_config close_scope_limit
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2, &@$, $3);
+ }
+ | SECMARK obj_spec secmark_obj secmark_config close_scope_secmark
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SECMARK, &$2, &@$, $3);
+ }
+ | SYNPROXY obj_spec synproxy_obj synproxy_config close_scope_synproxy
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
+ }
+ ;
+
+insert_cmd : RULE rule_position rule
+ {
+ $$ = cmd_alloc(CMD_INSERT, CMD_OBJ_RULE, &$2, &@$, $3);
+ }
+ ;
+
+table_or_id_spec : table_spec
+ | tableid_spec
+ ;
+
+chain_or_id_spec : chain_spec
+ | chainid_spec
+ ;
+
+set_or_id_spec : set_spec
+ | setid_spec
+ ;
+
+obj_or_id_spec : obj_spec
+ | objid_spec
+ ;
+
+delete_cmd : TABLE table_or_id_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, &@$, NULL);
+ }
+ | CHAIN chain_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);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, $5);
+ }
+ | RULE ruleid_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2, &@$, NULL);
+ }
+ | SET set_or_id_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL);
+ }
+ | MAP set_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL);
+ }
+ | ELEMENT set_spec set_block_expr
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
+ }
+ | FLOWTABLE flowtable_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
+ }
+ | FLOWTABLE flowtableid_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
+ }
+ | FLOWTABLE flowtable_spec flowtable_block_alloc
+ '{' flowtable_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
+ }
+ | COUNTER obj_or_id_spec close_scope_counter
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ }
+ | QUOTA obj_or_id_spec close_scope_quota
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+ }
+ | CT ct_obj_type obj_spec ct_obj_alloc close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_DELETE, $2, &$3, &@$, $4);
+ if ($2 == NFT_OBJECT_CT_TIMEOUT)
+ init_list_head(&$4->ct_timeout.timeout_list);
+ }
+ | LIMIT obj_or_id_spec close_scope_limit
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL);
+ }
+ | SECMARK obj_or_id_spec close_scope_secmark
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL);
+ }
+ | SYNPROXY obj_or_id_spec close_scope_synproxy
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
+ }
+ ;
+
+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);
+ }
+ ;
+
+list_cmd : TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &$2, &@$, NULL);
+ }
+ | TABLES ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_TABLE, &$2, &@$, NULL);
+ }
+ | CHAIN chain_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAIN, &$2, &@$, NULL);
+ }
+ | CHAINS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CHAINS, &$2, &@$, NULL);
+ }
+ | SETS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &$2, &@$, NULL);
+ }
+ | SETS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SETS, &$3, &@$, NULL);
+ }
+ | SET set_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SET, &$2, &@$, NULL);
+ }
+ | COUNTERS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &$2, &@$, NULL);
+ }
+ | COUNTERS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &$3, &@$, NULL);
+ }
+ | COUNTER obj_spec close_scope_counter
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ }
+ | QUOTAS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &$2, &@$, NULL);
+ }
+ | QUOTAS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &$3, &@$, NULL);
+ }
+ | QUOTA obj_spec close_scope_quota
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+ }
+ | LIMITS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &$2, &@$, NULL);
+ }
+ | LIMITS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &$3, &@$, NULL);
+ }
+ | LIMIT obj_spec close_scope_limit
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMIT, &$2, &@$, NULL);
+ }
+ | SECMARKS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &$2, &@$, NULL);
+ }
+ | SECMARKS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &$3, &@$, NULL);
+ }
+ | SECMARK obj_spec close_scope_secmark
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARK, &$2, &@$, NULL);
+ }
+ | SYNPROXYS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &$2, &@$, NULL);
+ }
+ | SYNPROXYS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &$3, &@$, NULL);
+ }
+ | SYNPROXY obj_spec close_scope_synproxy
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
+ }
+ | RULESET ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_RULESET, &$2, &@$, NULL);
+ }
+ | FLOW TABLES ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METERS, &$3, &@$, NULL);
+ }
+ | FLOW TABLE set_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &$3, &@$, NULL);
+ }
+ | METERS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METERS, &$2, &@$, NULL);
+ }
+ | METER set_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &$2, &@$, NULL);
+ }
+ | FLOWTABLES ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLES, &$2, &@$, NULL);
+ }
+ | FLOWTABLE flowtable_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
+ }
+ | MAPS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAPS, &$2, &@$, NULL);
+ }
+ | MAP set_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAP, &$2, &@$, NULL);
+ }
+ | CT ct_obj_type obj_spec close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_LIST, $2, &$3, &@$, NULL);
+ }
+ | CT ct_cmd_type TABLE table_spec close_scope_ct
+ {
+ $$ = cmd_alloc(CMD_LIST, $2, &$4, &@$, NULL);
+ }
+ | HOOKS basehook_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_HOOKS, &$2, &@$, NULL);
+ }
+ ;
+
+basehook_device_name : DEVICE STRING
+ {
+ $$ = $2;
+ }
+ ;
+
+basehook_spec : ruleset_spec
+ {
+ $$ = $1;
+ }
+ | ruleset_spec basehook_device_name
+ {
+ if ($2) {
+ $1.obj.name = $2;
+ $1.obj.location = @2;
+ }
+ $$ = $1;
+ }
+ ;
+
+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
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTER, &$2,&@$, NULL);
+ }
+ | QUOTAS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$2, &@$, NULL);
+ }
+ | QUOTAS TABLE table_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
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_TABLE, &$2, &@$, NULL);
+ }
+ | CHAIN chain_spec
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_CHAIN, &$2, &@$, NULL);
+ }
+ | SET set_spec
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_SET, &$2, &@$, NULL);
+ }
+ | MAP set_spec
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_MAP, &$2, &@$, NULL);
+ }
+ | FLOW TABLE set_spec
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_METER, &$3, &@$, NULL);
+ }
+ | METER set_spec
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_METER, &$2, &@$, NULL);
+ }
+ | RULESET ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_RULESET, &$2, &@$, NULL);
+ }
+ ;
+
+rename_cmd : CHAIN chain_spec identifier
+ {
+ $$ = cmd_alloc(CMD_RENAME, CMD_OBJ_CHAIN, &$2, &@$, NULL);
+ $$->arg = $3;
+ }
+ ;
+
+import_cmd : RULESET markup_format
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc($2);
+ $$ = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
+ }
+ | markup_format
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc($1);
+ $$ = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
+ }
+ ;
+
+export_cmd : RULESET markup_format
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc($2);
+ $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
+ }
+ | markup_format
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc($1);
+ $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
+ }
+ ;
+
+monitor_cmd : monitor_event monitor_object monitor_format
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct monitor *m = monitor_alloc($3, $2, $1);
+ m->location = @1;
+ $$ = cmd_alloc(CMD_MONITOR, CMD_OBJ_MONITOR, &h, &@$, m);
+ }
+ ;
+
+monitor_event : /* empty */ { $$ = NULL; }
+ | STRING { $$ = $1; }
+ ;
+
+monitor_object : /* empty */ { $$ = CMD_MONITOR_OBJ_ANY; }
+ | TABLES { $$ = CMD_MONITOR_OBJ_TABLES; }
+ | CHAINS { $$ = CMD_MONITOR_OBJ_CHAINS; }
+ | SETS { $$ = CMD_MONITOR_OBJ_SETS; }
+ | RULES { $$ = CMD_MONITOR_OBJ_RULES; }
+ | ELEMENTS { $$ = CMD_MONITOR_OBJ_ELEMS; }
+ | RULESET { $$ = CMD_MONITOR_OBJ_RULESET; }
+ | TRACE { $$ = CMD_MONITOR_OBJ_TRACE; }
+ ;
+
+monitor_format : /* empty */ { $$ = NFTNL_OUTPUT_DEFAULT; }
+ | markup_format
+ ;
+
+markup_format : XML { $$ = __NFT_OUTPUT_NOTSUPP; }
+ | JSON { $$ = NFTNL_OUTPUT_JSON; }
+ | VM JSON { $$ = NFTNL_OUTPUT_JSON; }
+ ;
+
+describe_cmd : primary_expr
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ $$ = cmd_alloc(CMD_DESCRIBE, CMD_OBJ_EXPR, &h, &@$, NULL);
+ $$->expr = $1;
+ }
+ ;
+
+table_block_alloc : /* empty */
+ {
+ $$ = table_alloc();
+ if (open_scope(state, &$$->scope) < 0) {
+ erec_queue(error(&@$, "too many levels of nesting"),
+ state->msgs);
+ state->nerrs++;
+ }
+ }
+ ;
+
+table_options : FLAGS STRING
+ {
+ if (strcmp($2, "dormant") == 0) {
+ $<table>0->flags |= TABLE_F_DORMANT;
+ xfree($2);
+ } else if (strcmp($2, "owner") == 0) {
+ $<table>0->flags |= TABLE_F_OWNER;
+ xfree($2);
+ } else {
+ erec_queue(error(&@2, "unknown table option %s", $2),
+ state->msgs);
+ xfree($2);
+ YYERROR;
+ }
+ }
+ | comment_spec
+ {
+ if (already_set($<table>0->comment, &@$, state)) {
+ xfree($1);
+ YYERROR;
+ }
+ $<table>0->comment = $1;
+ }
+ ;
+
+table_block : /* empty */ { $$ = $<table>-1; }
+ | table_block common_block
+ | table_block stmt_separator
+ | table_block table_options stmt_separator
+ | table_block CHAIN chain_identifier
+ chain_block_alloc '{' chain_block '}'
+ stmt_separator
+ {
+ $4->location = @3;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ close_scope(state);
+ list_add_tail(&$4->list, &$1->chains);
+ $$ = $1;
+ }
+ | table_block SET set_identifier
+ set_block_alloc '{' set_block '}'
+ stmt_separator
+ {
+ $4->location = @3;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->sets);
+ $$ = $1;
+ }
+ | table_block MAP set_identifier
+ map_block_alloc '{' map_block '}'
+ stmt_separator
+ {
+ $4->location = @3;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->sets);
+ $$ = $1;
+ }
+
+ | table_block FLOWTABLE flowtable_identifier
+ flowtable_block_alloc '{' flowtable_block '}'
+ stmt_separator
+ {
+ $4->location = @3;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->flowtables);
+ $$ = $1;
+ }
+ | table_block COUNTER obj_identifier
+ obj_block_alloc '{' counter_block '}'
+ stmt_separator close_scope_counter
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_COUNTER;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
+ | table_block QUOTA obj_identifier
+ obj_block_alloc '{' quota_block '}'
+ stmt_separator close_scope_quota
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_QUOTA;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ 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
+ {
+ $5->location = @4;
+ $5->type = NFT_OBJECT_CT_HELPER;
+ handle_merge(&$5->handle, &$4);
+ handle_free(&$4);
+ 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
+ {
+ $5->location = @4;
+ $5->type = NFT_OBJECT_CT_TIMEOUT;
+ handle_merge(&$5->handle, &$4);
+ handle_free(&$4);
+ 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
+ {
+ $5->location = @4;
+ $5->type = NFT_OBJECT_CT_EXPECT;
+ handle_merge(&$5->handle, &$4);
+ handle_free(&$4);
+ list_add_tail(&$5->list, &$1->objs);
+ $$ = $1;
+ }
+ | table_block LIMIT obj_identifier
+ obj_block_alloc '{' limit_block '}'
+ stmt_separator close_scope_limit
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_LIMIT;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
+ | table_block SECMARK obj_identifier
+ obj_block_alloc '{' secmark_block '}'
+ stmt_separator close_scope_secmark
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_SECMARK;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
+ | table_block SYNPROXY obj_identifier
+ obj_block_alloc '{' synproxy_block '}'
+ stmt_separator close_scope_synproxy
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_SYNPROXY;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
+ ;
+
+chain_block_alloc : /* empty */
+ {
+ $$ = chain_alloc();
+ if (open_scope(state, &$$->scope) < 0) {
+ erec_queue(error(&@$, "too many levels of nesting"),
+ state->msgs);
+ state->nerrs++;
+ }
+ }
+ ;
+
+chain_block : /* empty */ { $$ = $<chain>-1; }
+ | chain_block common_block
+ | chain_block stmt_separator
+ | chain_block hook_spec stmt_separator
+ | chain_block policy_spec stmt_separator
+ | chain_block flags_spec stmt_separator
+ | chain_block rule stmt_separator
+ {
+ list_add_tail(&$2->list, &$1->rules);
+ $$ = $1;
+ }
+ | chain_block DEVICES '=' flowtable_expr stmt_separator
+ {
+ if ($$->dev_expr) {
+ list_splice_init(&$4->expressions, &$$->dev_expr->expressions);
+ expr_free($4);
+ break;
+ }
+ $$->dev_expr = $4;
+ }
+ | chain_block comment_spec stmt_separator
+ {
+ if (already_set($1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $1->comment = $2;
+ }
+ ;
+
+subchain_block : /* empty */ { $$ = $<chain>-1; }
+ | subchain_block stmt_separator
+ | subchain_block rule stmt_separator
+ {
+ list_add_tail(&$2->list, &$1->rules);
+ $$ = $1;
+ }
+ ;
+
+typeof_data_expr : primary_expr
+ {
+ struct expr *e = $1;
+
+ if (e->etype == EXPR_SYMBOL &&
+ strcmp("verdict", e->identifier) == 0) {
+ struct expr *v = verdict_expr_alloc(&@1, NF_ACCEPT, NULL);
+
+ expr_free(e);
+ v->flags &= ~EXPR_F_CONSTANT;
+ e = v;
+ }
+
+ if (expr_ops(e)->build_udata == NULL) {
+ erec_queue(error(&@1, "map data type '%s' lacks typeof serialization", expr_ops(e)->name),
+ state->msgs);
+ expr_free(e);
+ YYERROR;
+ }
+ $$ = e;
+ }
+ | typeof_expr DOT primary_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+typeof_expr : primary_expr
+ {
+ if (expr_ops($1)->build_udata == NULL) {
+ erec_queue(error(&@1, "primary expression type '%s' lacks typeof serialization", expr_ops($1)->name),
+ state->msgs);
+ expr_free($1);
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ | typeof_expr DOT primary_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+
+set_block_alloc : /* empty */
+ {
+ $$ = set_alloc(&internal_location);
+ }
+ ;
+
+set_block : /* empty */ { $$ = $<set>-1; }
+ | set_block common_block
+ | set_block stmt_separator
+ | set_block TYPE data_type_expr stmt_separator close_scope_type
+ {
+ $1->key = $3;
+ $$ = $1;
+ }
+ | set_block TYPEOF typeof_expr stmt_separator
+ {
+ $1->key = $3;
+ datatype_set($1->key, $3->dtype);
+ $$ = $1;
+ }
+ | set_block FLAGS set_flag_list stmt_separator
+ {
+ $1->flags = $3;
+ $$ = $1;
+ }
+ | set_block TIMEOUT time_spec stmt_separator
+ {
+ $1->timeout = $3;
+ $$ = $1;
+ }
+ | set_block GC_INTERVAL time_spec stmt_separator
+ {
+ $1->gc_int = $3;
+ $$ = $1;
+ }
+ | set_block stateful_stmt_list stmt_separator
+ {
+ list_splice_tail($2, &$1->stmt_list);
+ $$ = $1;
+ free($2);
+ }
+ | set_block ELEMENTS '=' set_block_expr
+ {
+ $1->init = $4;
+ $$ = $1;
+ }
+ | set_block AUTOMERGE
+ {
+ $1->automerge = true;
+ $$ = $1;
+ }
+ | set_block set_mechanism stmt_separator
+ | set_block comment_spec stmt_separator
+ {
+ if (already_set($1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $1->comment = $2;
+ $$ = $1;
+ }
+ ;
+
+set_block_expr : set_expr
+ | variable_expr
+ ;
+
+set_flag_list : set_flag_list COMMA set_flag
+ {
+ $$ = $1 | $3;
+ }
+ | set_flag
+ ;
+
+set_flag : CONSTANT { $$ = NFT_SET_CONSTANT; }
+ | INTERVAL { $$ = NFT_SET_INTERVAL; }
+ | TIMEOUT { $$ = NFT_SET_TIMEOUT; }
+ | DYNAMIC { $$ = NFT_SET_EVAL; }
+ ;
+
+map_block_alloc : /* empty */
+ {
+ $$ = set_alloc(&internal_location);
+ }
+ ;
+
+map_block_obj_type : COUNTER close_scope_counter { $$ = NFT_OBJECT_COUNTER; }
+ | QUOTA close_scope_quota { $$ = NFT_OBJECT_QUOTA; }
+ | LIMIT close_scope_limit { $$ = NFT_OBJECT_LIMIT; }
+ | SECMARK close_scope_secmark { $$ = NFT_OBJECT_SECMARK; }
+ | SYNPROXY close_scope_synproxy { $$ = NFT_OBJECT_SYNPROXY; }
+ ;
+
+map_block_data_interval : INTERVAL { $$ = EXPR_F_INTERVAL; }
+ | { $$ = 0; }
+ ;
+
+map_block : /* empty */ { $$ = $<set>-1; }
+ | map_block common_block
+ | map_block stmt_separator
+ | map_block TIMEOUT time_spec stmt_separator
+ {
+ $1->timeout = $3;
+ $$ = $1;
+ }
+ | map_block GC_INTERVAL time_spec stmt_separator
+ {
+ $1->gc_int = $3;
+ $$ = $1;
+ }
+ | map_block TYPE
+ data_type_expr COLON map_block_data_interval data_type_expr
+ stmt_separator close_scope_type
+ {
+ $1->key = $3;
+ $1->data = $6;
+ $1->data->flags |= $5;
+
+ $1->flags |= NFT_SET_MAP;
+ $$ = $1;
+ }
+ | map_block TYPEOF
+ typeof_expr COLON typeof_data_expr
+ stmt_separator
+ {
+ $1->key = $3;
+ datatype_set($1->key, $3->dtype);
+ $1->data = $5;
+
+ $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;
+ $$ = $1;
+ }
+ | map_block TYPE
+ data_type_expr COLON map_block_obj_type
+ stmt_separator close_scope_type
+ {
+ $1->key = $3;
+ $1->objtype = $5;
+ $1->flags |= NFT_SET_OBJECT;
+ $$ = $1;
+ }
+ | map_block FLAGS set_flag_list stmt_separator
+ {
+ $1->flags |= $3;
+ $$ = $1;
+ }
+ | map_block stateful_stmt_list stmt_separator
+ {
+ list_splice_tail($2, &$1->stmt_list);
+ $$ = $1;
+ free($2);
+ }
+ | map_block ELEMENTS '=' set_block_expr
+ {
+ $1->init = $4;
+ $$ = $1;
+ }
+ | map_block comment_spec stmt_separator
+ {
+ if (already_set($1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $1->comment = $2;
+ $$ = $1;
+ }
+ | map_block set_mechanism stmt_separator
+ ;
+
+set_mechanism : POLICY set_policy_spec close_scope_policy
+ {
+ $<set>0->policy = $2;
+ }
+ | SIZE NUM
+ {
+ $<set>0->desc.size = $2;
+ }
+ ;
+
+set_policy_spec : PERFORMANCE { $$ = NFT_SET_POL_PERFORMANCE; }
+ | MEMORY { $$ = NFT_SET_POL_MEMORY; }
+ ;
+
+flowtable_block_alloc : /* empty */
+ {
+ $$ = flowtable_alloc(&internal_location);
+ }
+ ;
+
+flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
+ | flowtable_block common_block
+ | flowtable_block stmt_separator
+ | flowtable_block HOOK STRING prio_spec stmt_separator
+ {
+ $$->hook.loc = @3;
+ $$->hook.name = chain_hookname_lookup($3);
+ if ($$->hook.name == NULL) {
+ erec_queue(error(&@3, "unknown chain hook"),
+ state->msgs);
+ xfree($3);
+ YYERROR;
+ }
+ xfree($3);
+
+ $$->priority = $4;
+ }
+ | flowtable_block DEVICES '=' flowtable_expr stmt_separator
+ {
+ $$->dev_expr = $4;
+ }
+ | flowtable_block COUNTER close_scope_counter
+ {
+ $$->flags |= NFT_FLOWTABLE_COUNTER;
+ }
+ | flowtable_block FLAGS OFFLOAD stmt_separator
+ {
+ $$->flags |= FLOWTABLE_F_HW_OFFLOAD;
+ }
+ ;
+
+flowtable_expr : '{' flowtable_list_expr '}'
+ {
+ $2->location = @$;
+ $$ = $2;
+ }
+ | variable_expr
+ {
+ $1->location = @$;
+ $$ = $1;
+ }
+ ;
+
+flowtable_list_expr : flowtable_expr_member
+ {
+ $$ = compound_expr_alloc(&@$, EXPR_LIST);
+ compound_expr_add($$, $1);
+ }
+ | flowtable_list_expr COMMA flowtable_expr_member
+ {
+ compound_expr_add($1, $3);
+ $$ = $1;
+ }
+ | flowtable_list_expr COMMA opt_newline
+ ;
+
+flowtable_expr_member : QUOTED_STRING
+ {
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = expr;
+ }
+ | STRING
+ {
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = expr;
+ }
+ | variable_expr
+ {
+ datatype_set($1->sym->expr, &ifname_type);
+ $$ = $1;
+ }
+ ;
+
+data_type_atom_expr : type_identifier
+ {
+ const struct datatype *dtype = datatype_lookup_byname($1);
+ if (dtype == NULL) {
+ erec_queue(error(&@1, "unknown datatype %s", $1),
+ state->msgs);
+ xfree($1);
+ YYERROR;
+ }
+ $$ = constant_expr_alloc(&@1, dtype, dtype->byteorder,
+ dtype->size, NULL);
+ xfree($1);
+ }
+ | TIME
+ {
+ $$ = constant_expr_alloc(&@1, &time_type, time_type.byteorder,
+ time_type.size, NULL);
+ }
+ ;
+
+data_type_expr : data_type_atom_expr
+ | data_type_expr DOT data_type_atom_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+obj_block_alloc : /* empty */
+ {
+ $$ = obj_alloc(&internal_location);
+ }
+ ;
+
+counter_block : /* empty */ { $$ = $<obj>-1; }
+ | counter_block common_block
+ | counter_block stmt_separator
+ | counter_block counter_config
+ {
+ $$ = $1;
+ }
+ | counter_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+quota_block : /* empty */ { $$ = $<obj>-1; }
+ | quota_block common_block
+ | quota_block stmt_separator
+ | quota_block quota_config
+ {
+ $$ = $1;
+ }
+ | quota_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+ct_helper_block : /* empty */ { $$ = $<obj>-1; }
+ | ct_helper_block common_block
+ | ct_helper_block stmt_separator
+ | ct_helper_block ct_helper_config
+ {
+ $$ = $1;
+ }
+ | ct_helper_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+ct_timeout_block : /*empty */
+ {
+ $$ = $<obj>-1;
+ init_list_head(&$$->ct_timeout.timeout_list);
+ }
+ | ct_timeout_block common_block
+ | ct_timeout_block stmt_separator
+ | ct_timeout_block ct_timeout_config
+ {
+ $$ = $1;
+ }
+ | ct_timeout_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+ct_expect_block : /*empty */ { $$ = $<obj>-1; }
+ | ct_expect_block common_block
+ | ct_expect_block stmt_separator
+ | ct_expect_block ct_expect_config
+ {
+ $$ = $1;
+ }
+ | ct_expect_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+limit_block : /* empty */ { $$ = $<obj>-1; }
+ | limit_block common_block
+ | limit_block stmt_separator
+ | limit_block limit_config
+ {
+ $$ = $1;
+ }
+ | limit_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+secmark_block : /* empty */ { $$ = $<obj>-1; }
+ | secmark_block common_block
+ | secmark_block stmt_separator
+ | secmark_block secmark_config
+ {
+ $$ = $1;
+ }
+ | secmark_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+synproxy_block : /* empty */ { $$ = $<obj>-1; }
+ | synproxy_block common_block
+ | synproxy_block stmt_separator
+ | synproxy_block synproxy_config
+ {
+ $$ = $1;
+ }
+ | synproxy_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ xfree($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
+ ;
+
+type_identifier : STRING { $$ = $1; }
+ | MARK { $$ = xstrdup("mark"); }
+ | DSCP { $$ = xstrdup("dscp"); }
+ | ECN { $$ = xstrdup("ecn"); }
+ | CLASSID { $$ = xstrdup("classid"); }
+ ;
+
+hook_spec : TYPE close_scope_type STRING HOOK STRING dev_spec prio_spec
+ {
+ const char *chain_type = chain_type_name_lookup($3);
+
+ if (chain_type == NULL) {
+ erec_queue(error(&@3, "unknown chain type"),
+ state->msgs);
+ xfree($3);
+ YYERROR;
+ }
+ $<chain>0->type.loc = @3;
+ $<chain>0->type.str = xstrdup(chain_type);
+ xfree($3);
+
+ $<chain>0->loc = @$;
+ $<chain>0->hook.loc = @5;
+ $<chain>0->hook.name = chain_hookname_lookup($5);
+ if ($<chain>0->hook.name == NULL) {
+ erec_queue(error(&@5, "unknown chain hook"),
+ state->msgs);
+ xfree($5);
+ YYERROR;
+ }
+ xfree($5);
+
+ $<chain>0->dev_expr = $6;
+ $<chain>0->priority = $7;
+ $<chain>0->flags |= CHAIN_F_BASECHAIN;
+ }
+ ;
+
+prio_spec : PRIORITY extended_prio_spec
+ {
+ $$ = $2;
+ $$.loc = @$;
+ }
+ ;
+
+extended_prio_name : OUT
+ {
+ $$ = strdup("out");
+ }
+ | STRING
+ ;
+
+extended_prio_spec : int_num
+ {
+ struct prio_spec spec = {0};
+
+ spec.expr = constant_expr_alloc(&@$, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) *
+ BITS_PER_BYTE, &$1);
+ $$ = spec;
+ }
+ | variable_expr
+ {
+ struct prio_spec spec = {0};
+
+ spec.expr = $1;
+ $$ = spec;
+ }
+ | extended_prio_name
+ {
+ struct prio_spec spec = {0};
+
+ spec.expr = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen($1) * BITS_PER_BYTE,
+ $1);
+ xfree($1);
+ $$ = spec;
+ }
+ | extended_prio_name PLUS NUM
+ {
+ struct prio_spec spec = {0};
+
+ char str[NFT_NAME_MAXLEN];
+ snprintf(str, sizeof(str), "%s + %" PRIu64, $1, $3);
+ spec.expr = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(str) * BITS_PER_BYTE,
+ str);
+ xfree($1);
+ $$ = spec;
+ }
+ | extended_prio_name DASH NUM
+ {
+ struct prio_spec spec = {0};
+ char str[NFT_NAME_MAXLEN];
+
+ snprintf(str, sizeof(str), "%s - %" PRIu64, $1, $3);
+ spec.expr = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(str) * BITS_PER_BYTE,
+ str);
+ xfree($1);
+ $$ = spec;
+ }
+ ;
+
+int_num : NUM { $$ = $1; }
+ | DASH NUM { $$ = -$2; }
+ ;
+
+dev_spec : DEVICE string
+ {
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $2);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = compound_expr_alloc(&@$, EXPR_LIST);
+ compound_expr_add($$, expr);
+
+ }
+ | DEVICE variable_expr
+ {
+ datatype_set($2->sym->expr, &ifname_type);
+ $$ = compound_expr_alloc(&@$, EXPR_LIST);
+ compound_expr_add($$, $2);
+ }
+ | DEVICES '=' flowtable_expr
+ {
+ $$ = $3;
+ }
+ | /* empty */ { $$ = NULL; }
+ ;
+
+flags_spec : FLAGS OFFLOAD
+ {
+ $<chain>0->flags |= CHAIN_F_HW_OFFLOAD;
+ }
+ ;
+
+policy_spec : POLICY policy_expr close_scope_policy
+ {
+ if ($<chain>0->policy) {
+ erec_queue(error(&@$, "you cannot set chain policy twice"),
+ state->msgs);
+ expr_free($2);
+ YYERROR;
+ }
+ $<chain>0->policy = $2;
+ $<chain>0->policy->location = @$;
+ }
+ ;
+
+policy_expr : variable_expr
+ {
+ datatype_set($1->sym->expr, &policy_type);
+ $$ = $1;
+ }
+ | chain_policy
+ {
+ $$ = constant_expr_alloc(&@$, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) *
+ BITS_PER_BYTE, &$1);
+ }
+ ;
+
+chain_policy : ACCEPT { $$ = NF_ACCEPT; }
+ | DROP { $$ = NF_DROP; }
+ ;
+
+identifier : STRING
+ | LAST { $$ = xstrdup("last"); }
+ ;
+
+string : STRING
+ | QUOTED_STRING
+ | ASTERISK_STRING
+ ;
+
+time_spec : STRING
+ {
+ struct error_record *erec;
+ uint64_t res;
+
+ erec = time_parse(&@1, $1, &res);
+ xfree($1);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = res;
+ }
+ ;
+
+/* compatibility kludge to allow either 60, 60s, 1m, ... */
+time_spec_or_num_s : NUM
+ | time_spec { $$ = $1 / 1000u; }
+ ;
+
+family_spec : /* empty */ { $$ = NFPROTO_IPV4; }
+ | family_spec_explicit
+ ;
+
+family_spec_explicit : IP close_scope_ip { $$ = NFPROTO_IPV4; }
+ | IP6 close_scope_ip6 { $$ = NFPROTO_IPV6; }
+ | INET { $$ = NFPROTO_INET; }
+ | ARP close_scope_arp { $$ = NFPROTO_ARP; }
+ | BRIDGE { $$ = NFPROTO_BRIDGE; }
+ | NETDEV { $$ = NFPROTO_NETDEV; }
+ ;
+
+table_spec : family_spec identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.family = $1;
+ $$.table.location = @2;
+ $$.table.name = $2;
+ }
+ ;
+
+tableid_spec : family_spec HANDLE NUM
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.family = $1;
+ $$.handle.id = $3;
+ $$.handle.location = @3;
+ }
+ ;
+
+chain_spec : table_spec identifier
+ {
+ $$ = $1;
+ $$.chain.name = $2;
+ $$.chain.location = @2;
+ }
+ ;
+
+chainid_spec : table_spec HANDLE NUM
+ {
+ $$ = $1;
+ $$.handle.location = @3;
+ $$.handle.id = $3;
+ }
+ ;
+
+chain_identifier : identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.chain.name = $1;
+ $$.chain.location = @1;
+ }
+ ;
+
+set_spec : table_spec identifier
+ {
+ $$ = $1;
+ $$.set.name = $2;
+ $$.set.location = @2;
+ }
+ ;
+
+setid_spec : table_spec HANDLE NUM
+ {
+ $$ = $1;
+ $$.handle.location = @3;
+ $$.handle.id = $3;
+ }
+ ;
+
+set_identifier : identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.set.name = $1;
+ $$.set.location = @1;
+ }
+ ;
+
+flowtable_spec : table_spec identifier
+ {
+ $$ = $1;
+ $$.flowtable.name = $2;
+ $$.flowtable.location = @2;
+ }
+ ;
+
+flowtableid_spec : table_spec HANDLE NUM
+ {
+ $$ = $1;
+ $$.handle.location = @3;
+ $$.handle.id = $3;
+ }
+ ;
+
+flowtable_identifier : identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.flowtable.name = $1;
+ $$.flowtable.location = @1;
+ }
+ ;
+
+obj_spec : table_spec identifier
+ {
+ $$ = $1;
+ $$.obj.name = $2;
+ $$.obj.location = @2;
+ }
+ ;
+
+objid_spec : table_spec HANDLE NUM
+ {
+ $$ = $1;
+ $$.handle.location = @3;
+ $$.handle.id = $3;
+ }
+ ;
+
+obj_identifier : identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.obj.name = $1;
+ $$.obj.location = @1;
+ }
+ ;
+
+handle_spec : HANDLE NUM
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.handle.location = @2;
+ $$.handle.id = $2;
+ }
+ ;
+
+position_spec : POSITION NUM
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.position.location = @$;
+ $$.position.id = $2;
+ }
+ ;
+
+index_spec : INDEX NUM
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.index.location = @$;
+ $$.index.id = $2 + 1;
+ }
+ ;
+
+rule_position : chain_spec
+ {
+ $$ = $1;
+ }
+ | chain_spec position_spec
+ {
+ handle_merge(&$1, &$2);
+ $$ = $1;
+ }
+ | chain_spec handle_spec
+ {
+ $2.position.location = $2.handle.location;
+ $2.position.id = $2.handle.id;
+ $2.handle.id = 0;
+ handle_merge(&$1, &$2);
+ $$ = $1;
+ }
+ | chain_spec index_spec
+ {
+ handle_merge(&$1, &$2);
+ $$ = $1;
+ }
+ ;
+
+ruleid_spec : chain_spec handle_spec
+ {
+ handle_merge(&$1, &$2);
+ $$ = $1;
+ }
+ ;
+
+comment_spec : COMMENT string
+ {
+ if (strlen($2) > NFTNL_UDATA_COMMENT_MAXLEN) {
+ erec_queue(error(&@2, "comment too long, %d characters maximum allowed",
+ NFTNL_UDATA_COMMENT_MAXLEN),
+ state->msgs);
+ xfree($2);
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ ;
+
+ruleset_spec : /* empty */
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.family = NFPROTO_UNSPEC;
+ }
+ | family_spec_explicit
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.family = $1;
+ }
+ ;
+
+rule : rule_alloc
+ {
+ $$->comment = NULL;
+ }
+ | rule_alloc comment_spec
+ {
+ $$->comment = $2;
+ }
+ ;
+
+rule_alloc : stmt_list
+ {
+ struct stmt *i;
+
+ $$ = rule_alloc(&@$, NULL);
+ list_for_each_entry(i, $1, list)
+ $$->num_stmts++;
+ list_splice_tail($1, &$$->stmts);
+ xfree($1);
+ }
+ ;
+
+stmt_list : stmt
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail(&$1->list, $$);
+ }
+ | stmt_list stmt
+ {
+ $$ = $1;
+ list_add_tail(&$2->list, $1);
+ }
+ ;
+
+stateful_stmt_list : stateful_stmt
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail(&$1->list, $$);
+ }
+ | stateful_stmt_list stateful_stmt
+ {
+ $$ = $1;
+ list_add_tail(&$2->list, $1);
+ }
+ ;
+
+stateful_stmt : counter_stmt close_scope_counter
+ | limit_stmt
+ | quota_stmt
+ | connlimit_stmt
+ | last_stmt close_scope_last
+ ;
+
+stmt : verdict_stmt
+ | match_stmt
+ | meter_stmt
+ | payload_stmt
+ | stateful_stmt
+ | meta_stmt
+ | log_stmt close_scope_log
+ | reject_stmt close_scope_reject
+ | nat_stmt close_scope_nat
+ | tproxy_stmt close_scope_tproxy
+ | queue_stmt
+ | ct_stmt
+ | masq_stmt close_scope_nat
+ | redir_stmt close_scope_nat
+ | dup_stmt close_scope_dup
+ | fwd_stmt close_scope_fwd
+ | set_stmt
+ | map_stmt
+ | synproxy_stmt close_scope_synproxy
+ | chain_stmt
+ | optstrip_stmt
+ | xt_stmt close_scope_xt
+ ;
+
+xt_stmt : XT STRING string
+ {
+ $$ = NULL;
+ xfree($2);
+ xfree($3);
+ erec_queue(error(&@$, "unsupported xtables compat expression, use iptables-nft with this ruleset"),
+ state->msgs);
+ YYERROR;
+ }
+ ;
+
+chain_stmt_type : JUMP { $$ = NFT_JUMP; }
+ | GOTO { $$ = NFT_GOTO; }
+ ;
+
+chain_stmt : chain_stmt_type chain_block_alloc '{' subchain_block '}'
+ {
+ $2->location = @2;
+ close_scope(state);
+ $4->location = @4;
+ $$ = chain_stmt_alloc(&@$, $4, $1);
+ }
+ ;
+
+verdict_stmt : verdict_expr
+ {
+ $$ = verdict_stmt_alloc(&@$, $1);
+ }
+ | verdict_map_stmt
+ {
+ $$ = verdict_stmt_alloc(&@$, $1);
+ }
+ ;
+
+verdict_map_stmt : concat_expr VMAP verdict_map_expr
+ {
+ $$ = map_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+verdict_map_expr : '{' verdict_map_list_expr '}'
+ {
+ $2->location = @$;
+ $$ = $2;
+ }
+ | set_ref_expr
+ ;
+
+verdict_map_list_expr : verdict_map_list_member_expr
+ {
+ $$ = set_expr_alloc(&@$, NULL);
+ compound_expr_add($$, $1);
+ }
+ | verdict_map_list_expr COMMA verdict_map_list_member_expr
+ {
+ compound_expr_add($1, $3);
+ $$ = $1;
+ }
+ | verdict_map_list_expr COMMA opt_newline
+ ;
+
+verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline
+ {
+ $$ = mapping_expr_alloc(&@2, $2, $4);
+ }
+ ;
+
+connlimit_stmt : CT COUNT NUM close_scope_ct
+ {
+ $$ = connlimit_stmt_alloc(&@$);
+ $$->connlimit.count = $3;
+ }
+ | CT COUNT OVER NUM close_scope_ct
+ {
+ $$ = connlimit_stmt_alloc(&@$);
+ $$->connlimit.count = $4;
+ $$->connlimit.flags = NFT_CONNLIMIT_F_INV;
+ }
+ ;
+
+counter_stmt : counter_stmt_alloc
+ | counter_stmt_alloc counter_args
+
+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
+ {
+ $<stmt>$ = $<stmt>0;
+ }
+ | counter_args counter_arg
+ ;
+
+counter_arg : PACKETS NUM
+ {
+ $<stmt>0->counter.packets = $2;
+ }
+ | BYTES NUM
+ {
+ $<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
+ ;
+
+log_stmt_alloc : LOG
+ {
+ $$ = log_stmt_alloc(&@$);
+ }
+ ;
+
+log_args : log_arg
+ {
+ $<stmt>$ = $<stmt>0;
+ }
+ | log_args log_arg
+ ;
+
+log_arg : PREFIX string
+ {
+ struct scope *scope = current_scope(state);
+ bool done = false, another_var = false;
+ char *start, *end, scratch = '\0';
+ struct expr *expr, *item;
+ struct symbol *sym;
+ enum {
+ PARSE_TEXT,
+ PARSE_VAR,
+ } prefix_state;
+
+ /* No variables in log prefix, skip. */
+ if (!strchr($2, '$')) {
+ expr = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen($2) + 1) * BITS_PER_BYTE, $2);
+ xfree($2);
+ $<stmt>0->log.prefix = expr;
+ $<stmt>0->log.flags |= STMT_LOG_PREFIX;
+ break;
+ }
+
+ /* Parse variables in log prefix string using a
+ * state machine parser with two states. This
+ * parser creates list of expressions composed
+ * of constant and variable expressions.
+ */
+ expr = compound_expr_alloc(&@$, EXPR_LIST);
+
+ start = (char *)$2;
+
+ if (*start != '$') {
+ prefix_state = PARSE_TEXT;
+ } else {
+ prefix_state = PARSE_VAR;
+ start++;
+ }
+ end = start;
+
+ /* Not nice, but works. */
+ while (!done) {
+ switch (prefix_state) {
+ case PARSE_TEXT:
+ while (*end != '\0' && *end != '$')
+ end++;
+
+ if (*end == '\0')
+ done = true;
+
+ *end = '\0';
+ item = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(start) + 1) * BITS_PER_BYTE,
+ start);
+ compound_expr_add(expr, item);
+
+ if (done)
+ break;
+
+ start = end + 1;
+ end = start;
+
+ /* fall through */
+ case PARSE_VAR:
+ while (isalnum(*end) || *end == '_')
+ end++;
+
+ if (*end == '\0')
+ done = true;
+ else if (*end == '$')
+ another_var = true;
+ else
+ scratch = *end;
+
+ *end = '\0';
+
+ sym = symbol_get(scope, start);
+ if (!sym) {
+ sym = symbol_lookup_fuzzy(scope, start);
+ if (sym) {
+ erec_queue(error(&@2, "unknown identifier '%s'; "
+ "did you mean identifier ‘%s’?",
+ start, sym->identifier),
+ state->msgs);
+ } else {
+ erec_queue(error(&@2, "unknown identifier '%s'",
+ start),
+ state->msgs);
+ }
+ expr_free(expr);
+ xfree($2);
+ YYERROR;
+ }
+ item = variable_expr_alloc(&@$, scope, sym);
+ compound_expr_add(expr, item);
+
+ if (done)
+ break;
+
+ /* Restore original byte after
+ * symbol lookup.
+ */
+ if (scratch) {
+ *end = scratch;
+ scratch = '\0';
+ }
+
+ start = end;
+ if (another_var) {
+ another_var = false;
+ start++;
+ prefix_state = PARSE_VAR;
+ } else {
+ prefix_state = PARSE_TEXT;
+ }
+ end = start;
+ break;
+ }
+ }
+
+ xfree($2);
+ $<stmt>0->log.prefix = expr;
+ $<stmt>0->log.flags |= STMT_LOG_PREFIX;
+ }
+ | GROUP NUM
+ {
+ $<stmt>0->log.group = $2;
+ $<stmt>0->log.flags |= STMT_LOG_GROUP;
+ }
+ | SNAPLEN NUM
+ {
+ $<stmt>0->log.snaplen = $2;
+ $<stmt>0->log.flags |= STMT_LOG_SNAPLEN;
+ }
+ | QUEUE_THRESHOLD NUM
+ {
+ $<stmt>0->log.qthreshold = $2;
+ $<stmt>0->log.flags |= STMT_LOG_QTHRESHOLD;
+ }
+ | LEVEL level_type
+ {
+ $<stmt>0->log.level = $2;
+ $<stmt>0->log.flags |= STMT_LOG_LEVEL;
+ }
+ | FLAGS log_flags
+ {
+ $<stmt>0->log.logflags |= $2;
+ }
+ ;
+
+level_type : string
+ {
+ if (!strcmp("emerg", $1))
+ $$ = NFT_LOGLEVEL_EMERG;
+ else if (!strcmp("alert", $1))
+ $$ = NFT_LOGLEVEL_ALERT;
+ else if (!strcmp("crit", $1))
+ $$ = NFT_LOGLEVEL_CRIT;
+ else if (!strcmp("err", $1))
+ $$ = NFT_LOGLEVEL_ERR;
+ else if (!strcmp("warn", $1))
+ $$ = NFT_LOGLEVEL_WARNING;
+ else if (!strcmp("notice", $1))
+ $$ = NFT_LOGLEVEL_NOTICE;
+ else if (!strcmp("info", $1))
+ $$ = NFT_LOGLEVEL_INFO;
+ else if (!strcmp("debug", $1))
+ $$ = NFT_LOGLEVEL_DEBUG;
+ else if (!strcmp("audit", $1))
+ $$ = NFT_LOGLEVEL_AUDIT;
+ else {
+ erec_queue(error(&@1, "invalid log level"),
+ state->msgs);
+ xfree($1);
+ YYERROR;
+ }
+ xfree($1);
+ }
+ ;
+
+log_flags : TCP log_flags_tcp close_scope_tcp
+ {
+ $$ = $2;
+ }
+ | IP OPTIONS close_scope_ip
+ {
+ $$ = NF_LOG_IPOPT;
+ }
+ | SKUID
+ {
+ $$ = NF_LOG_UID;
+ }
+ | ETHER close_scope_eth
+ {
+ $$ = NF_LOG_MACDECODE;
+ }
+ | ALL
+ {
+ $$ = NF_LOG_MASK;
+ }
+ ;
+
+log_flags_tcp : log_flags_tcp COMMA log_flag_tcp
+ {
+ $$ = $1 | $3;
+ }
+ | log_flag_tcp
+ ;
+
+log_flag_tcp : SEQUENCE
+ {
+ $$ = NF_LOG_TCPSEQ;
+ }
+ | OPTIONS
+ {
+ $$ = NF_LOG_TCPOPT;
+ }
+ ;
+
+limit_stmt : LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit
+ {
+ if ($5 == 0) {
+ erec_queue(error(&@5, "packet limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = limit_stmt_alloc(&@$);
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
+ $$->limit.type = NFT_LIMIT_PKTS;
+ $$->limit.flags = $3;
+ }
+ | LIMIT RATE limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit
+ {
+ $$ = limit_stmt_alloc(&@$);
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
+ $$->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; }
+ | UNTIL { $$ = 0; }
+ | /* empty */ { $$ = 0; }
+ ;
+
+quota_unit : BYTES { $$ = xstrdup("bytes"); }
+ | STRING { $$ = $1; }
+ ;
+
+quota_used : /* empty */ { $$ = 0; }
+ | USED NUM quota_unit
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $3, &rate);
+ xfree($3);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = $2 * rate;
+ }
+ ;
+
+quota_stmt : QUOTA quota_mode NUM quota_unit quota_used close_scope_quota
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $4, &rate);
+ xfree($4);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = quota_stmt_alloc(&@$);
+ $$->quota.bytes = $3 * rate;
+ $$->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; }
+ | UNTIL { $$ = 0; }
+ | /* empty */ { $$ = 0; }
+ ;
+
+limit_burst_pkts : /* empty */ { $$ = 5; }
+ | BURST NUM PACKETS { $$ = $2; }
+ ;
+
+limit_rate_pkts : NUM SLASH time_unit
+ {
+ $$.rate = $1;
+ $$.unit = $3;
+ }
+ ;
+
+limit_burst_bytes : /* empty */ { $$ = 0; }
+ | BURST limit_bytes { $$ = $2; }
+ ;
+
+limit_rate_bytes : NUM STRING
+ {
+ struct error_record *erec;
+ uint64_t rate, unit;
+
+ erec = rate_parse(&@$, $2, &rate, &unit);
+ xfree($2);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$.rate = rate * $1;
+ $$.unit = unit;
+ }
+ | limit_bytes SLASH time_unit
+ {
+ $$.rate = $1;
+ $$.unit = $3;
+ }
+ ;
+
+limit_bytes : NUM BYTES { $$ = $1; }
+ | NUM STRING
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $2, &rate);
+ xfree($2);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = $1 * rate;
+ }
+ ;
+
+time_unit : SECOND { $$ = 1ULL; }
+ | MINUTE { $$ = 1ULL * 60; }
+ | HOUR { $$ = 1ULL * 60 * 60; }
+ | DAY { $$ = 1ULL * 60 * 60 * 24; }
+ | WEEK { $$ = 1ULL * 60 * 60 * 24 * 7; }
+ ;
+
+reject_stmt : reject_stmt_alloc reject_opts
+ ;
+
+reject_stmt_alloc : _REJECT
+ {
+ $$ = reject_stmt_alloc(&@$);
+ }
+ ;
+
+reject_with_expr : STRING
+ {
+ $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+ current_scope(state), $1);
+ xfree($1);
+ }
+ | integer_expr { $$ = $1; }
+ ;
+
+reject_opts : /* empty */
+ {
+ $<stmt>0->reject.type = -1;
+ $<stmt>0->reject.icmp_code = -1;
+ }
+ | WITH ICMP TYPE reject_with_expr close_scope_type close_scope_icmp
+ {
+ $<stmt>0->reject.family = NFPROTO_IPV4;
+ $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
+ $<stmt>0->reject.expr = $4;
+ datatype_set($<stmt>0->reject.expr, &icmp_code_type);
+ }
+ | WITH ICMP reject_with_expr
+ {
+ $<stmt>0->reject.family = NFPROTO_IPV4;
+ $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
+ $<stmt>0->reject.expr = $3;
+ datatype_set($<stmt>0->reject.expr, &icmp_code_type);
+ }
+ | WITH ICMP6 TYPE reject_with_expr close_scope_type close_scope_icmp
+ {
+ $<stmt>0->reject.family = NFPROTO_IPV6;
+ $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
+ $<stmt>0->reject.expr = $4;
+ datatype_set($<stmt>0->reject.expr, &icmpv6_code_type);
+ }
+ | WITH ICMP6 reject_with_expr
+ {
+ $<stmt>0->reject.family = NFPROTO_IPV6;
+ $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
+ $<stmt>0->reject.expr = $3;
+ datatype_set($<stmt>0->reject.expr, &icmpv6_code_type);
+ }
+ | WITH ICMPX TYPE reject_with_expr close_scope_type
+ {
+ $<stmt>0->reject.type = NFT_REJECT_ICMPX_UNREACH;
+ $<stmt>0->reject.expr = $4;
+ datatype_set($<stmt>0->reject.expr, &icmpx_code_type);
+ }
+ | WITH ICMPX reject_with_expr
+ {
+ $<stmt>0->reject.type = NFT_REJECT_ICMPX_UNREACH;
+ $<stmt>0->reject.expr = $3;
+ datatype_set($<stmt>0->reject.expr, &icmpx_code_type);
+ }
+ | WITH TCP close_scope_tcp RESET close_scope_reset
+ {
+ $<stmt>0->reject.type = NFT_REJECT_TCP_RST;
+ }
+ ;
+
+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); }
+ ;
+
+tproxy_stmt : TPROXY TO stmt_expr
+ {
+ $$ = tproxy_stmt_alloc(&@$);
+ $$->tproxy.family = NFPROTO_UNSPEC;
+ $$->tproxy.addr = $3;
+ }
+ | TPROXY nf_key_proto TO stmt_expr
+ {
+ $$ = tproxy_stmt_alloc(&@$);
+ $$->tproxy.family = $2;
+ $$->tproxy.addr = $4;
+ }
+ | TPROXY TO COLON stmt_expr
+ {
+ $$ = tproxy_stmt_alloc(&@$);
+ $$->tproxy.family = NFPROTO_UNSPEC;
+ $$->tproxy.port = $4;
+ }
+ | TPROXY TO stmt_expr COLON stmt_expr
+ {
+ $$ = tproxy_stmt_alloc(&@$);
+ $$->tproxy.family = NFPROTO_UNSPEC;
+ $$->tproxy.addr = $3;
+ $$->tproxy.port = $5;
+ }
+ | TPROXY nf_key_proto TO stmt_expr COLON stmt_expr
+ {
+ $$ = tproxy_stmt_alloc(&@$);
+ $$->tproxy.family = $2;
+ $$->tproxy.addr = $4;
+ $$->tproxy.port = $6;
+ }
+ | TPROXY nf_key_proto TO COLON stmt_expr
+ {
+ $$ = tproxy_stmt_alloc(&@$);
+ $$->tproxy.family = $2;
+ $$->tproxy.port = $5;
+ }
+ ;
+
+synproxy_stmt : synproxy_stmt_alloc
+ | synproxy_stmt_alloc synproxy_args
+ ;
+
+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
+ {
+ $<stmt>$ = $<stmt>0;
+ }
+ | synproxy_args synproxy_arg
+ ;
+
+synproxy_arg : MSS NUM
+ {
+ $<stmt>0->synproxy.mss = $2;
+ $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
+ }
+ | WSCALE NUM
+ {
+ $<stmt>0->synproxy.wscale = $2;
+ $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
+ }
+ | TIMESTAMP
+ {
+ $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP;
+ }
+ | SACK_PERM
+ {
+ $<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM;
+ }
+ ;
+
+synproxy_config : MSS NUM WSCALE NUM synproxy_ts synproxy_sack
+ {
+ struct synproxy *synproxy;
+ uint32_t flags = 0;
+
+ synproxy = &$<obj>0->synproxy;
+ synproxy->mss = $2;
+ flags |= NF_SYNPROXY_OPT_MSS;
+ synproxy->wscale = $4;
+ flags |= NF_SYNPROXY_OPT_WSCALE;
+ if ($5)
+ flags |= $5;
+ if ($6)
+ flags |= $6;
+ synproxy->flags = flags;
+ }
+ | MSS NUM stmt_separator WSCALE NUM stmt_separator synproxy_ts synproxy_sack
+ {
+ struct synproxy *synproxy;
+ uint32_t flags = 0;
+
+ synproxy = &$<obj>0->synproxy;
+ synproxy->mss = $2;
+ flags |= NF_SYNPROXY_OPT_MSS;
+ synproxy->wscale = $5;
+ flags |= NF_SYNPROXY_OPT_WSCALE;
+ if ($7)
+ flags |= $7;
+ if ($8)
+ flags |= $8;
+ synproxy->flags = flags;
+ }
+ ;
+
+synproxy_obj : /* empty */
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_SYNPROXY;
+ }
+ ;
+
+synproxy_ts : /* empty */ { $$ = 0; }
+ | TIMESTAMP
+ {
+ $$ = NF_SYNPROXY_OPT_TIMESTAMP;
+ }
+ ;
+
+synproxy_sack : /* empty */ { $$ = 0; }
+ | SACK_PERM
+ {
+ $$ = NF_SYNPROXY_OPT_SACK_PERM;
+ }
+ ;
+
+primary_stmt_expr : symbol_expr { $$ = $1; }
+ | integer_expr { $$ = $1; }
+ | boolean_expr { $$ = $1; }
+ | meta_expr { $$ = $1; }
+ | rt_expr { $$ = $1; }
+ | ct_expr { $$ = $1; }
+ | numgen_expr { $$ = $1; }
+ | hash_expr { $$ = $1; }
+ | payload_expr { $$ = $1; }
+ | keyword_expr { $$ = $1; }
+ | socket_expr { $$ = $1; }
+ | osf_expr { $$ = $1; }
+ | '(' basic_stmt_expr ')' { $$ = $2; }
+ ;
+
+shift_stmt_expr : primary_stmt_expr
+ | shift_stmt_expr LSHIFT primary_stmt_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3);
+ }
+ | shift_stmt_expr RSHIFT primary_stmt_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3);
+ }
+ ;
+
+and_stmt_expr : shift_stmt_expr
+ | and_stmt_expr AMPERSAND shift_stmt_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_AND, $1, $3);
+ }
+ ;
+
+exclusive_or_stmt_expr : and_stmt_expr
+ | exclusive_or_stmt_expr CARET and_stmt_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3);
+ }
+ ;
+
+inclusive_or_stmt_expr : exclusive_or_stmt_expr
+ | inclusive_or_stmt_expr '|' exclusive_or_stmt_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_OR, $1, $3);
+ }
+ ;
+
+basic_stmt_expr : inclusive_or_stmt_expr
+ ;
+
+concat_stmt_expr : basic_stmt_expr
+ | concat_stmt_expr DOT primary_stmt_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+map_stmt_expr_set : set_expr
+ | set_ref_expr
+ ;
+
+map_stmt_expr : concat_stmt_expr MAP map_stmt_expr_set
+ {
+ $$ = map_expr_alloc(&@$, $1, $3);
+ }
+ | concat_stmt_expr { $$ = $1; }
+ ;
+
+prefix_stmt_expr : basic_stmt_expr SLASH NUM
+ {
+ $$ = prefix_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+range_stmt_expr : basic_stmt_expr DASH basic_stmt_expr
+ {
+ $$ = range_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+multiton_stmt_expr : prefix_stmt_expr
+ | range_stmt_expr
+ ;
+
+stmt_expr : map_stmt_expr
+ | multiton_stmt_expr
+ | list_stmt_expr
+ ;
+
+nat_stmt_args : stmt_expr
+ {
+ $<stmt>0->nat.addr = $1;
+ }
+ | TO stmt_expr
+ {
+ $<stmt>0->nat.addr = $2;
+ }
+ | nf_key_proto TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $3;
+ }
+ | stmt_expr COLON stmt_expr
+ {
+ $<stmt>0->nat.addr = $1;
+ $<stmt>0->nat.proto = $3;
+ }
+ | TO stmt_expr COLON stmt_expr
+ {
+ $<stmt>0->nat.addr = $2;
+ $<stmt>0->nat.proto = $4;
+ }
+ | nf_key_proto TO stmt_expr COLON stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $3;
+ $<stmt>0->nat.proto = $5;
+ }
+ | COLON stmt_expr
+ {
+ $<stmt>0->nat.proto = $2;
+ }
+ | TO COLON stmt_expr
+ {
+ $<stmt>0->nat.proto = $3;
+ }
+ | nat_stmt_args nf_nat_flags
+ {
+ $<stmt>0->nat.flags = $2;
+ }
+ | nf_key_proto ADDR DOT PORT TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $6;
+ $<stmt>0->nat.type_flags = STMT_NAT_F_CONCAT;
+ }
+ | nf_key_proto INTERVAL TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $4;
+ }
+ | INTERVAL TO stmt_expr
+ {
+ $<stmt>0->nat.addr = $3;
+ }
+ | nf_key_proto PREFIX TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $4;
+ $<stmt>0->nat.type_flags =
+ STMT_NAT_F_PREFIX;
+ $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
+ | PREFIX TO stmt_expr
+ {
+ $<stmt>0->nat.addr = $3;
+ $<stmt>0->nat.type_flags =
+ STMT_NAT_F_PREFIX;
+ $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
+ ;
+
+masq_stmt : masq_stmt_alloc masq_stmt_args
+ | masq_stmt_alloc
+ ;
+
+masq_stmt_alloc : MASQUERADE { $$ = nat_stmt_alloc(&@$, NFT_NAT_MASQ); }
+ ;
+
+masq_stmt_args : TO COLON stmt_expr
+ {
+ $<stmt>0->nat.proto = $3;
+ }
+ | TO COLON stmt_expr nf_nat_flags
+ {
+ $<stmt>0->nat.proto = $3;
+ $<stmt>0->nat.flags = $4;
+ }
+ | nf_nat_flags
+ {
+ $<stmt>0->nat.flags = $1;
+ }
+ ;
+
+redir_stmt : redir_stmt_alloc redir_stmt_arg
+ | redir_stmt_alloc
+ ;
+
+redir_stmt_alloc : REDIRECT { $$ = nat_stmt_alloc(&@$, NFT_NAT_REDIR); }
+ ;
+
+redir_stmt_arg : TO stmt_expr
+ {
+ $<stmt>0->nat.proto = $2;
+ }
+ | TO COLON stmt_expr
+ {
+ $<stmt>0->nat.proto = $3;
+ }
+ | nf_nat_flags
+ {
+ $<stmt>0->nat.flags = $1;
+ }
+ | TO stmt_expr nf_nat_flags
+ {
+ $<stmt>0->nat.proto = $2;
+ $<stmt>0->nat.flags = $3;
+ }
+ | TO COLON stmt_expr nf_nat_flags
+ {
+ $<stmt>0->nat.proto = $3;
+ $<stmt>0->nat.flags = $4;
+ }
+ ;
+
+dup_stmt : DUP TO stmt_expr
+ {
+ $$ = dup_stmt_alloc(&@$);
+ $$->dup.to = $3;
+ }
+ | DUP TO stmt_expr DEVICE stmt_expr
+ {
+ $$ = dup_stmt_alloc(&@$);
+ $$->dup.to = $3;
+ $$->dup.dev = $5;
+ }
+ ;
+
+fwd_stmt : FWD TO stmt_expr
+ {
+ $$ = fwd_stmt_alloc(&@$);
+ $$->fwd.dev = $3;
+ }
+ | FWD nf_key_proto TO stmt_expr DEVICE stmt_expr
+ {
+ $$ = fwd_stmt_alloc(&@$);
+ $$->fwd.family = $2;
+ $$->fwd.addr = $4;
+ $$->fwd.dev = $6;
+ }
+ ;
+
+nf_nat_flags : nf_nat_flag
+ | nf_nat_flags COMMA nf_nat_flag
+ {
+ $$ = $1 | $3;
+ }
+ ;
+
+nf_nat_flag : RANDOM { $$ = NF_NAT_RANGE_PROTO_RANDOM; }
+ | FULLY_RANDOM { $$ = NF_NAT_RANGE_PROTO_RANDOM_FULLY; }
+ | PERSISTENT { $$ = NF_NAT_RANGE_PERSISTENT; }
+ ;
+
+queue_stmt : queue_stmt_compat close_scope_queue
+ | QUEUE TO queue_stmt_expr close_scope_queue
+ {
+ $$ = queue_stmt_alloc(&@$, $3, 0);
+ }
+ | QUEUE FLAGS queue_stmt_flags TO queue_stmt_expr close_scope_queue
+ {
+ $$ = queue_stmt_alloc(&@$, $5, $3);
+ }
+ | QUEUE FLAGS queue_stmt_flags QUEUENUM queue_stmt_expr_simple close_scope_queue
+ {
+ $$ = queue_stmt_alloc(&@$, $5, $3);
+ }
+ ;
+
+queue_stmt_compat : queue_stmt_alloc
+ | queue_stmt_alloc queue_stmt_args
+ ;
+
+queue_stmt_alloc : QUEUE
+ {
+ $$ = queue_stmt_alloc(&@$, NULL, 0);
+ }
+ ;
+
+queue_stmt_args : queue_stmt_arg
+ {
+ $<stmt>$ = $<stmt>0;
+ }
+ | queue_stmt_args queue_stmt_arg
+ ;
+
+queue_stmt_arg : QUEUENUM queue_stmt_expr_simple
+ {
+ $<stmt>0->queue.queue = $2;
+ $<stmt>0->queue.queue->location = @$;
+ }
+ | queue_stmt_flags
+ {
+ $<stmt>0->queue.flags |= $1;
+ }
+ ;
+
+queue_expr : variable_expr
+ | integer_expr
+ ;
+
+queue_stmt_expr_simple : integer_expr
+ | variable_expr
+ | queue_expr DASH queue_expr
+ {
+ $$ = range_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+queue_stmt_expr : numgen_expr
+ | hash_expr
+ | map_expr
+ | queue_stmt_expr_simple
+ ;
+
+queue_stmt_flags : queue_stmt_flag
+ | queue_stmt_flags COMMA queue_stmt_flag
+ {
+ $$ = $1 | $3;
+ }
+ ;
+
+queue_stmt_flag : BYPASS { $$ = NFT_QUEUE_FLAG_BYPASS; }
+ | FANOUT { $$ = NFT_QUEUE_FLAG_CPU_FANOUT; }
+ ;
+
+set_elem_expr_stmt : set_elem_expr_stmt_alloc
+ | set_elem_expr_stmt_alloc set_elem_options
+ ;
+
+set_elem_expr_stmt_alloc: concat_expr
+ {
+ $$ = set_elem_expr_alloc(&@1, $1);
+ }
+ ;
+
+set_stmt : SET set_stmt_op set_elem_expr_stmt set_ref_expr
+ {
+ $$ = set_stmt_alloc(&@$);
+ $$->set.op = $2;
+ $$->set.key = $3;
+ $$->set.set = $4;
+ }
+ | set_stmt_op set_ref_expr '{' set_elem_expr_stmt '}'
+ {
+ $$ = set_stmt_alloc(&@$);
+ $$->set.op = $1;
+ $$->set.key = $4;
+ $$->set.set = $2;
+ }
+ | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list '}'
+ {
+ $$ = set_stmt_alloc(&@$);
+ $$->set.op = $1;
+ $$->set.key = $4;
+ $$->set.set = $2;
+ list_splice_tail($5, &$$->set.stmt_list);
+ free($5);
+ }
+ ;
+
+set_stmt_op : ADD { $$ = NFT_DYNSET_OP_ADD; }
+ | UPDATE { $$ = NFT_DYNSET_OP_UPDATE; }
+ | DELETE { $$ = NFT_DYNSET_OP_DELETE; }
+ ;
+
+map_stmt : set_stmt_op set_ref_expr '{' set_elem_expr_stmt COLON set_elem_expr_stmt '}'
+ {
+ $$ = map_stmt_alloc(&@$);
+ $$->map.op = $1;
+ $$->map.key = $4;
+ $$->map.data = $6;
+ $$->map.set = $2;
+ }
+ | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list COLON set_elem_expr_stmt '}'
+ {
+ $$ = map_stmt_alloc(&@$);
+ $$->map.op = $1;
+ $$->map.key = $4;
+ $$->map.data = $7;
+ $$->map.set = $2;
+ list_splice_tail($5, &$$->map.stmt_list);
+ free($5);
+ }
+ ;
+
+meter_stmt : flow_stmt_legacy_alloc flow_stmt_opts '{' meter_key_expr stmt '}'
+ {
+ $1->meter.key = $4;
+ $1->meter.stmt = $5;
+ $$->location = @$;
+ $$ = $1;
+ }
+ | meter_stmt_alloc { $$ = $1; }
+ ;
+
+flow_stmt_legacy_alloc : FLOW
+ {
+ $$ = meter_stmt_alloc(&@$);
+ }
+ ;
+
+flow_stmt_opts : flow_stmt_opt
+ {
+ $<stmt>$ = $<stmt>0;
+ }
+ | flow_stmt_opts flow_stmt_opt
+ ;
+
+flow_stmt_opt : TABLE identifier
+ {
+ $<stmt>0->meter.name = $2;
+ }
+ ;
+
+meter_stmt_alloc : METER identifier '{' meter_key_expr stmt '}'
+ {
+ $$ = meter_stmt_alloc(&@$);
+ $$->meter.name = $2;
+ $$->meter.size = 0;
+ $$->meter.key = $4;
+ $$->meter.stmt = $5;
+ $$->location = @$;
+ }
+ | METER identifier SIZE NUM '{' meter_key_expr stmt '}'
+ {
+ $$ = meter_stmt_alloc(&@$);
+ $$->meter.name = $2;
+ $$->meter.size = $4;
+ $$->meter.key = $6;
+ $$->meter.stmt = $7;
+ $$->location = @$;
+ }
+ ;
+
+match_stmt : relational_expr
+ {
+ $$ = expr_stmt_alloc(&@$, $1);
+ }
+ ;
+
+variable_expr : '$' identifier
+ {
+ struct scope *scope = current_scope(state);
+ struct symbol *sym;
+
+ sym = symbol_get(scope, $2);
+ if (!sym) {
+ sym = symbol_lookup_fuzzy(scope, $2);
+ if (sym) {
+ erec_queue(error(&@2, "unknown identifier '%s'; "
+ "did you mean identifier ‘%s’?",
+ $2, sym->identifier),
+ state->msgs);
+ } else {
+ erec_queue(error(&@2, "unknown identifier '%s'", $2),
+ state->msgs);
+ }
+ xfree($2);
+ YYERROR;
+ }
+
+ $$ = variable_expr_alloc(&@$, scope, sym);
+ xfree($2);
+ }
+ ;
+
+symbol_expr : variable_expr
+ | string
+ {
+ $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+ current_scope(state),
+ $1);
+ xfree($1);
+ }
+ ;
+
+set_ref_expr : set_ref_symbol_expr
+ | variable_expr
+ ;
+
+set_ref_symbol_expr : AT identifier close_scope_at
+ {
+ $$ = symbol_expr_alloc(&@$, SYMBOL_SET,
+ current_scope(state),
+ $2);
+ xfree($2);
+ }
+ ;
+
+integer_expr : NUM
+ {
+ char str[64];
+
+ snprintf(str, sizeof(str), "%" PRIu64, $1);
+ $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+ current_scope(state),
+ str);
+ }
+ ;
+
+primary_expr : symbol_expr { $$ = $1; }
+ | integer_expr { $$ = $1; }
+ | payload_expr { $$ = $1; }
+ | exthdr_expr { $$ = $1; }
+ | exthdr_exists_expr { $$ = $1; }
+ | meta_expr { $$ = $1; }
+ | socket_expr { $$ = $1; }
+ | rt_expr { $$ = $1; }
+ | ct_expr { $$ = $1; }
+ | numgen_expr { $$ = $1; }
+ | hash_expr { $$ = $1; }
+ | fib_expr { $$ = $1; }
+ | osf_expr { $$ = $1; }
+ | xfrm_expr { $$ = $1; }
+ | '(' basic_expr ')' { $$ = $2; }
+ ;
+
+fib_expr : FIB fib_tuple fib_result close_scope_fib
+ {
+ if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) {
+ erec_queue(error(&@2, "fib: need either saddr or daddr"), state->msgs);
+ YYERROR;
+ }
+
+ if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) ==
+ (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) {
+ erec_queue(error(&@2, "fib: saddr and daddr are mutually exclusive"), state->msgs);
+ YYERROR;
+ }
+
+ if (($2 & (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) ==
+ (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) {
+ erec_queue(error(&@2, "fib: iif and oif are mutually exclusive"), state->msgs);
+ YYERROR;
+ }
+
+ $$ = fib_expr_alloc(&@$, $2, $3);
+ }
+ ;
+
+fib_result : OIF { $$ =NFT_FIB_RESULT_OIF; }
+ | OIFNAME { $$ =NFT_FIB_RESULT_OIFNAME; }
+ | TYPE close_scope_type { $$ =NFT_FIB_RESULT_ADDRTYPE; }
+ ;
+
+fib_flag : SADDR { $$ = NFTA_FIB_F_SADDR; }
+ | DADDR { $$ = NFTA_FIB_F_DADDR; }
+ | MARK { $$ = NFTA_FIB_F_MARK; }
+ | IIF { $$ = NFTA_FIB_F_IIF; }
+ | OIF { $$ = NFTA_FIB_F_OIF; }
+ ;
+
+fib_tuple : fib_flag DOT fib_tuple
+ {
+ $$ = $1 | $3;
+ }
+ | fib_flag
+ ;
+
+osf_expr : OSF osf_ttl HDRVERSION close_scope_osf
+ {
+ $$ = osf_expr_alloc(&@$, $2, NFT_OSF_F_VERSION);
+ }
+ | OSF osf_ttl NAME close_scope_osf
+ {
+ $$ = osf_expr_alloc(&@$, $2, 0);
+ }
+ ;
+
+osf_ttl : /* empty */
+ {
+ $$ = NF_OSF_TTL_TRUE;
+ }
+ | TTL STRING
+ {
+ if (!strcmp($2, "loose"))
+ $$ = NF_OSF_TTL_LESS;
+ else if (!strcmp($2, "skip"))
+ $$ = NF_OSF_TTL_NOCHECK;
+ else {
+ erec_queue(error(&@2, "invalid ttl option"),
+ state->msgs);
+ xfree($2);
+ YYERROR;
+ }
+ xfree($2);
+ }
+ ;
+
+shift_expr : primary_expr
+ | shift_expr LSHIFT primary_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3);
+ }
+ | shift_expr RSHIFT primary_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3);
+ }
+ ;
+
+and_expr : shift_expr
+ | and_expr AMPERSAND shift_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_AND, $1, $3);
+ }
+ ;
+
+exclusive_or_expr : and_expr
+ | exclusive_or_expr CARET and_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3);
+ }
+ ;
+
+inclusive_or_expr : exclusive_or_expr
+ | inclusive_or_expr '|' exclusive_or_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_OR, $1, $3);
+ }
+ ;
+
+basic_expr : inclusive_or_expr
+ ;
+
+concat_expr : basic_expr
+ | concat_expr DOT basic_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+prefix_rhs_expr : basic_rhs_expr SLASH NUM
+ {
+ $$ = prefix_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+range_rhs_expr : basic_rhs_expr DASH basic_rhs_expr
+ {
+ $$ = range_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+multiton_rhs_expr : prefix_rhs_expr
+ | range_rhs_expr
+ ;
+
+map_expr : concat_expr MAP rhs_expr
+ {
+ $$ = map_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+expr : concat_expr
+ | set_expr
+ | map_expr
+ ;
+
+set_expr : '{' set_list_expr '}'
+ {
+ $2->location = @$;
+ $$ = $2;
+ }
+ ;
+
+set_list_expr : set_list_member_expr
+ {
+ $$ = set_expr_alloc(&@$, NULL);
+ compound_expr_add($$, $1);
+ }
+ | set_list_expr COMMA set_list_member_expr
+ {
+ compound_expr_add($1, $3);
+ $$ = $1;
+ }
+ | set_list_expr COMMA opt_newline
+ ;
+
+set_list_member_expr : opt_newline set_expr opt_newline
+ {
+ $$ = $2;
+ }
+ | opt_newline set_elem_expr opt_newline
+ {
+ $$ = $2;
+ }
+ | opt_newline set_elem_expr COLON set_rhs_expr opt_newline
+ {
+ $$ = mapping_expr_alloc(&@2, $2, $4);
+ }
+ ;
+
+meter_key_expr : meter_key_expr_alloc
+ | meter_key_expr_alloc set_elem_options
+ {
+ $$->location = @$;
+ $$ = $1;
+ }
+ ;
+
+meter_key_expr_alloc : concat_expr
+ {
+ $$ = set_elem_expr_alloc(&@1, $1);
+ }
+ ;
+
+set_elem_expr : set_elem_expr_alloc
+ | set_elem_expr_alloc set_elem_expr_options
+ ;
+
+set_elem_key_expr : set_lhs_expr { $$ = $1; }
+ | ASTERISK { $$ = set_elem_catchall_expr_alloc(&@1); }
+ ;
+
+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);
+ }
+ | set_elem_key_expr
+ {
+ $$ = set_elem_expr_alloc(&@1, $1);
+ }
+ ;
+
+set_elem_options : set_elem_option
+ {
+ $<expr>$ = $<expr>0;
+ }
+ | set_elem_options set_elem_option
+ ;
+
+set_elem_option : TIMEOUT time_spec
+ {
+ $<expr>0->timeout = $2;
+ }
+ | EXPIRES time_spec
+ {
+ $<expr>0->expiration = $2;
+ }
+ | comment_spec
+ {
+ if (already_set($<expr>0->comment, &@1, state)) {
+ xfree($1);
+ YYERROR;
+ }
+ $<expr>0->comment = $1;
+ }
+ ;
+
+set_elem_expr_options : set_elem_expr_option
+ {
+ $<expr>$ = $<expr>0;
+ }
+ | set_elem_expr_options set_elem_expr_option
+ ;
+
+set_elem_stmt_list : set_elem_stmt
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail(&$1->list, $$);
+ }
+ | set_elem_stmt_list set_elem_stmt
+ {
+ $$ = $1;
+ list_add_tail(&$2->list, $1);
+ }
+ ;
+
+set_elem_stmt : COUNTER close_scope_counter
+ {
+ $$ = counter_stmt_alloc(&@$);
+ }
+ | COUNTER PACKETS NUM BYTES NUM close_scope_counter
+ {
+ $$ = counter_stmt_alloc(&@$);
+ $$->counter.packets = $3;
+ $$->counter.bytes = $5;
+ }
+ | LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit
+ {
+ if ($5 == 0) {
+ erec_queue(error(&@5, "limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = limit_stmt_alloc(&@$);
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
+ $$->limit.type = NFT_LIMIT_PKTS;
+ $$->limit.flags = $3;
+ }
+ | LIMIT RATE limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit
+ {
+ if ($5 == 0) {
+ erec_queue(error(&@6, "limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = limit_stmt_alloc(&@$);
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
+ $$->limit.type = NFT_LIMIT_PKT_BYTES;
+ $$->limit.flags = $3;
+ }
+ | CT COUNT NUM close_scope_ct
+ {
+ $$ = connlimit_stmt_alloc(&@$);
+ $$->connlimit.count = $3;
+ }
+ | CT COUNT OVER NUM close_scope_ct
+ {
+ $$ = connlimit_stmt_alloc(&@$);
+ $$->connlimit.count = $4;
+ $$->connlimit.flags = NFT_CONNLIMIT_F_INV;
+ }
+ | QUOTA quota_mode NUM quota_unit quota_used close_scope_quota
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $4, &rate);
+ xfree($4);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = quota_stmt_alloc(&@$);
+ $$->quota.bytes = $3 * rate;
+ $$->quota.used = $5;
+ $$->quota.flags = $2;
+ }
+ | LAST USED NEVER close_scope_last
+ {
+ $$ = last_stmt_alloc(&@$);
+ }
+ | LAST USED time_spec close_scope_last
+ {
+ $$ = last_stmt_alloc(&@$);
+ $$->last.used = $3;
+ $$->last.set = true;
+ }
+ ;
+
+set_elem_expr_option : TIMEOUT time_spec
+ {
+ $<expr>0->timeout = $2;
+ }
+ | EXPIRES time_spec
+ {
+ $<expr>0->expiration = $2;
+ }
+ | comment_spec
+ {
+ if (already_set($<expr>0->comment, &@1, state)) {
+ xfree($1);
+ YYERROR;
+ }
+ $<expr>0->comment = $1;
+ }
+ ;
+
+set_lhs_expr : concat_rhs_expr
+ ;
+
+set_rhs_expr : concat_rhs_expr
+ | verdict_expr
+ ;
+
+initializer_expr : rhs_expr
+ | list_rhs_expr
+ | '{' '}' { $$ = compound_expr_alloc(&@$, EXPR_SET); }
+ | DASH NUM
+ {
+ int32_t num = -$2;
+
+ $$ = constant_expr_alloc(&@$, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(num) * BITS_PER_BYTE,
+ &num);
+ }
+ ;
+
+counter_config : PACKETS NUM BYTES NUM
+ {
+ struct counter *counter;
+
+ counter = &$<obj>0->counter;
+ counter->packets = $2;
+ counter->bytes = $4;
+ }
+ ;
+
+counter_obj : /* empty */
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_COUNTER;
+ }
+ ;
+
+quota_config : quota_mode NUM quota_unit quota_used
+ {
+ struct error_record *erec;
+ struct quota *quota;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $3, &rate);
+ xfree($3);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ quota = &$<obj>0->quota;
+ quota->bytes = $2 * rate;
+ quota->used = $4;
+ quota->flags = $1;
+ }
+ ;
+
+quota_obj : /* empty */
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_QUOTA;
+ }
+ ;
+
+secmark_config : string
+ {
+ int ret;
+ struct secmark *secmark;
+
+ secmark = &$<obj>0->secmark;
+ 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);
+ YYERROR;
+ }
+ xfree($1);
+ }
+ ;
+
+secmark_obj : /* empty */
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_SECMARK;
+ }
+ ;
+
+ct_obj_type : HELPER { $$ = NFT_OBJECT_CT_HELPER; }
+ | TIMEOUT { $$ = NFT_OBJECT_CT_TIMEOUT; }
+ | EXPECTATION { $$ = NFT_OBJECT_CT_EXPECT; }
+ ;
+
+ct_cmd_type : HELPERS { $$ = CMD_OBJ_CT_HELPERS; }
+ | TIMEOUT { $$ = CMD_OBJ_CT_TIMEOUTS; }
+ | EXPECTATION { $$ = CMD_OBJ_CT_EXPECTATIONS; }
+ ;
+
+ct_l4protoname : TCP close_scope_tcp { $$ = IPPROTO_TCP; }
+ | UDP close_scope_udp { $$ = IPPROTO_UDP; }
+ ;
+
+ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator close_scope_type
+ {
+ struct ct_helper *ct;
+ int ret;
+
+ ct = &$<obj>0->ct_helper;
+
+ 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);
+ YYERROR;
+ }
+ xfree($2);
+
+ ct->l4proto = $4;
+ }
+ | L3PROTOCOL family_spec_explicit stmt_separator
+ {
+ $<obj>0->ct_helper.l3proto = $2;
+ }
+ ;
+
+timeout_states : timeout_state
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail($1, $$);
+ }
+ | timeout_states COMMA timeout_state
+ {
+ list_add_tail($3, $1);
+ $$ = $1;
+ }
+ ;
+
+timeout_state : STRING COLON time_spec_or_num_s
+ {
+ struct timeout_state *ts;
+
+ ts = xzalloc(sizeof(*ts));
+ ts->timeout_str = $1;
+ ts->timeout_value = $3;
+ ts->location = @1;
+ init_list_head(&ts->head);
+ $$ = &ts->head;
+ }
+ ;
+
+ct_timeout_config : PROTOCOL ct_l4protoname stmt_separator
+ {
+ struct ct_timeout *ct;
+ int l4proto = $2;
+
+ ct = &$<obj>0->ct_timeout;
+ ct->l4proto = l4proto;
+ }
+ | POLICY '=' '{' timeout_states '}' stmt_separator close_scope_policy
+ {
+ struct ct_timeout *ct;
+
+ ct = &$<obj>0->ct_timeout;
+ list_splice_tail($4, &ct->timeout_list);
+ xfree($4);
+ }
+ | L3PROTOCOL family_spec_explicit stmt_separator
+ {
+ $<obj>0->ct_timeout.l3proto = $2;
+ }
+ ;
+
+ct_expect_config : PROTOCOL ct_l4protoname stmt_separator
+ {
+ $<obj>0->ct_expect.l4proto = $2;
+ }
+ | DPORT NUM stmt_separator
+ {
+ $<obj>0->ct_expect.dport = $2;
+ }
+ | TIMEOUT time_spec stmt_separator
+ {
+ $<obj>0->ct_expect.timeout = $2;
+ }
+ | SIZE NUM stmt_separator
+ {
+ $<obj>0->ct_expect.size = $2;
+ }
+ | L3PROTOCOL family_spec_explicit stmt_separator
+ {
+ $<obj>0->ct_expect.l3proto = $2;
+ }
+ ;
+
+ct_obj_alloc : /* empty */
+ {
+ $$ = obj_alloc(&@$);
+ }
+ ;
+
+limit_config : RATE limit_mode limit_rate_pkts limit_burst_pkts
+ {
+ struct limit *limit;
+
+ limit = &$<obj>0->limit;
+ limit->rate = $3.rate;
+ limit->unit = $3.unit;
+ limit->burst = $4;
+ limit->type = NFT_LIMIT_PKTS;
+ limit->flags = $2;
+ }
+ | RATE limit_mode limit_rate_bytes limit_burst_bytes
+ {
+ struct limit *limit;
+
+ limit = &$<obj>0->limit;
+ limit->rate = $3.rate;
+ limit->unit = $3.unit;
+ limit->burst = $4;
+ limit->type = NFT_LIMIT_PKT_BYTES;
+ limit->flags = $2;
+ }
+ ;
+
+limit_obj : /* empty */
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_LIMIT;
+ }
+ ;
+
+relational_expr : expr /* implicit */ rhs_expr
+ {
+ $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
+ }
+ | expr /* implicit */ list_rhs_expr
+ {
+ $$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
+ }
+ | expr /* implicit */ basic_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2);
+ }
+ | expr /* implicit */ list_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2);
+ }
+ | expr relational_op basic_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3);
+ }
+ | expr relational_op list_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3);
+ }
+ | expr relational_op rhs_expr
+ {
+ $$ = relational_expr_alloc(&@2, $2, $1, $3);
+ }
+ | expr relational_op list_rhs_expr
+ {
+ $$ = relational_expr_alloc(&@2, $2, $1, $3);
+ }
+ ;
+
+list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr
+ {
+ $$ = list_expr_alloc(&@$);
+ compound_expr_add($$, $1);
+ compound_expr_add($$, $3);
+ }
+ | list_rhs_expr COMMA basic_rhs_expr
+ {
+ $1->location = @$;
+ compound_expr_add($1, $3);
+ $$ = $1;
+ }
+ ;
+
+rhs_expr : concat_rhs_expr { $$ = $1; }
+ | set_expr { $$ = $1; }
+ | set_ref_symbol_expr { $$ = $1; }
+ ;
+
+shift_rhs_expr : primary_rhs_expr
+ | shift_rhs_expr LSHIFT primary_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3);
+ }
+ | shift_rhs_expr RSHIFT primary_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3);
+ }
+ ;
+
+and_rhs_expr : shift_rhs_expr
+ | and_rhs_expr AMPERSAND shift_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_AND, $1, $3);
+ }
+ ;
+
+exclusive_or_rhs_expr : and_rhs_expr
+ | exclusive_or_rhs_expr CARET and_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_XOR, $1, $3);
+ }
+ ;
+
+inclusive_or_rhs_expr : exclusive_or_rhs_expr
+ | inclusive_or_rhs_expr '|' exclusive_or_rhs_expr
+ {
+ $$ = binop_expr_alloc(&@$, OP_OR, $1, $3);
+ }
+ ;
+
+basic_rhs_expr : inclusive_or_rhs_expr
+ ;
+
+concat_rhs_expr : basic_rhs_expr
+ | multiton_rhs_expr
+ | concat_rhs_expr DOT multiton_rhs_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ | concat_rhs_expr DOT basic_rhs_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+boolean_keys : EXISTS { $$ = true; }
+ | MISSING { $$ = false; }
+ ;
+
+boolean_expr : boolean_keys
+ {
+ $$ = constant_expr_alloc(&@$, &boolean_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof($1) * BITS_PER_BYTE, &$1);
+ }
+ ;
+
+keyword_expr : ETHER close_scope_eth { $$ = symbol_value(&@$, "ether"); }
+ | IP close_scope_ip { $$ = symbol_value(&@$, "ip"); }
+ | IP6 close_scope_ip6 { $$ = symbol_value(&@$, "ip6"); }
+ | VLAN close_scope_vlan { $$ = symbol_value(&@$, "vlan"); }
+ | ARP close_scope_arp { $$ = symbol_value(&@$, "arp"); }
+ | DNAT close_scope_nat { $$ = symbol_value(&@$, "dnat"); }
+ | SNAT close_scope_nat { $$ = symbol_value(&@$, "snat"); }
+ | ECN { $$ = symbol_value(&@$, "ecn"); }
+ | RESET close_scope_reset { $$ = symbol_value(&@$, "reset"); }
+ | DESTROY close_scope_destroy { $$ = symbol_value(&@$, "destroy"); }
+ | ORIGINAL { $$ = symbol_value(&@$, "original"); }
+ | REPLY { $$ = symbol_value(&@$, "reply"); }
+ | LABEL { $$ = symbol_value(&@$, "label"); }
+ | LAST close_scope_last { $$ = symbol_value(&@$, "last"); }
+ ;
+
+primary_rhs_expr : symbol_expr { $$ = $1; }
+ | integer_expr { $$ = $1; }
+ | boolean_expr { $$ = $1; }
+ | keyword_expr { $$ = $1; }
+ | TCP close_scope_tcp
+ {
+ uint8_t data = IPPROTO_TCP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | UDP close_scope_udp
+ {
+ uint8_t data = IPPROTO_UDP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | UDPLITE close_scope_udplite
+ {
+ uint8_t data = IPPROTO_UDPLITE;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | ESP close_scope_esp
+ {
+ uint8_t data = IPPROTO_ESP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | AH close_scope_ah
+ {
+ uint8_t data = IPPROTO_AH;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | ICMP close_scope_icmp
+ {
+ uint8_t data = IPPROTO_ICMP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | IGMP
+ {
+ uint8_t data = IPPROTO_IGMP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | ICMP6 close_scope_icmp
+ {
+ uint8_t data = IPPROTO_ICMPV6;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ 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;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | DCCP close_scope_dccp
+ {
+ uint8_t data = IPPROTO_DCCP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | SCTP close_scope_sctp
+ {
+ uint8_t data = IPPROTO_SCTP;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | REDIRECT close_scope_nat
+ {
+ uint8_t data = ICMP_REDIRECT;
+ $$ = constant_expr_alloc(&@$, &icmp_type_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | '(' basic_rhs_expr ')' { $$ = $2; }
+ ;
+
+relational_op : EQ { $$ = OP_EQ; }
+ | NEQ { $$ = OP_NEQ; }
+ | LT { $$ = OP_LT; }
+ | GT { $$ = OP_GT; }
+ | GTE { $$ = OP_GTE; }
+ | LTE { $$ = OP_LTE; }
+ | NOT { $$ = OP_NEG; }
+ ;
+
+verdict_expr : ACCEPT
+ {
+ $$ = verdict_expr_alloc(&@$, NF_ACCEPT, NULL);
+ }
+ | DROP
+ {
+ $$ = verdict_expr_alloc(&@$, NF_DROP, NULL);
+ }
+ | CONTINUE
+ {
+ $$ = verdict_expr_alloc(&@$, NFT_CONTINUE, NULL);
+ }
+ | JUMP chain_expr
+ {
+ $$ = verdict_expr_alloc(&@$, NFT_JUMP, $2);
+ }
+ | GOTO chain_expr
+ {
+ $$ = verdict_expr_alloc(&@$, NFT_GOTO, $2);
+ }
+ | RETURN
+ {
+ $$ = verdict_expr_alloc(&@$, NFT_RETURN, NULL);
+ }
+ ;
+
+chain_expr : variable_expr
+ | identifier
+ {
+ $$ = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen($1) * BITS_PER_BYTE,
+ $1);
+ xfree($1);
+ }
+ ;
+
+meta_expr : META meta_key close_scope_meta
+ {
+ $$ = meta_expr_alloc(&@$, $2);
+ }
+ | meta_key_unqualified
+ {
+ $$ = meta_expr_alloc(&@$, $1);
+ }
+ | META STRING close_scope_meta
+ {
+ struct error_record *erec;
+ unsigned int key;
+
+ erec = meta_key_parse(&@$, $2, &key);
+ xfree($2);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ $$ = meta_expr_alloc(&@$, key);
+ }
+ ;
+
+meta_key : meta_key_qualified
+ | meta_key_unqualified
+ ;
+
+meta_key_qualified : LENGTH { $$ = NFT_META_LEN; }
+ | PROTOCOL { $$ = NFT_META_PROTOCOL; }
+ | PRIORITY { $$ = NFT_META_PRIORITY; }
+ | RANDOM { $$ = NFT_META_PRANDOM; }
+ | SECMARK close_scope_secmark { $$ = NFT_META_SECMARK; }
+ ;
+
+meta_key_unqualified : MARK { $$ = NFT_META_MARK; }
+ | IIF { $$ = NFT_META_IIF; }
+ | IIFNAME { $$ = NFT_META_IIFNAME; }
+ | IIFTYPE { $$ = NFT_META_IIFTYPE; }
+ | OIF { $$ = NFT_META_OIF; }
+ | OIFNAME { $$ = NFT_META_OIFNAME; }
+ | OIFTYPE { $$ = NFT_META_OIFTYPE; }
+ | SKUID { $$ = NFT_META_SKUID; }
+ | SKGID { $$ = NFT_META_SKGID; }
+ | NFTRACE { $$ = NFT_META_NFTRACE; }
+ | RTCLASSID { $$ = NFT_META_RTCLASSID; }
+ | IBRIPORT { $$ = NFT_META_BRI_IIFNAME; }
+ | OBRIPORT { $$ = NFT_META_BRI_OIFNAME; }
+ | IBRIDGENAME { $$ = NFT_META_BRI_IIFNAME; }
+ | OBRIDGENAME { $$ = NFT_META_BRI_OIFNAME; }
+ | PKTTYPE { $$ = NFT_META_PKTTYPE; }
+ | CPU { $$ = NFT_META_CPU; }
+ | IIFGROUP { $$ = NFT_META_IIFGROUP; }
+ | OIFGROUP { $$ = NFT_META_OIFGROUP; }
+ | CGROUP { $$ = NFT_META_CGROUP; }
+ | IPSEC close_scope_ipsec { $$ = NFT_META_SECPATH; }
+ | TIME { $$ = NFT_META_TIME_NS; }
+ | DAY { $$ = NFT_META_TIME_DAY; }
+ | HOUR { $$ = NFT_META_TIME_HOUR; }
+ ;
+
+meta_stmt : META meta_key SET stmt_expr close_scope_meta
+ {
+ switch ($2) {
+ case NFT_META_SECMARK:
+ switch ($4->etype) {
+ case EXPR_CT:
+ $$ = meta_stmt_alloc(&@$, $2, $4);
+ break;
+ default:
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_SECMARK;
+ $$->objref.expr = $4;
+ break;
+ }
+ break;
+ default:
+ $$ = meta_stmt_alloc(&@$, $2, $4);
+ break;
+ }
+ }
+ | meta_key_unqualified SET stmt_expr
+ {
+ $$ = meta_stmt_alloc(&@$, $1, $3);
+ }
+ | META STRING SET stmt_expr close_scope_meta
+ {
+ struct error_record *erec;
+ unsigned int key;
+
+ erec = meta_key_parse(&@$, $2, &key);
+ xfree($2);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ $$ = meta_stmt_alloc(&@$, key, $4);
+ }
+ | NOTRACK
+ {
+ $$ = notrack_stmt_alloc(&@$);
+ }
+ | FLOW OFFLOAD AT string close_scope_at
+ {
+ $$ = flow_offload_stmt_alloc(&@$, $4);
+ }
+ | FLOW ADD AT string close_scope_at
+ {
+ $$ = flow_offload_stmt_alloc(&@$, $4);
+ }
+ ;
+
+socket_expr : SOCKET socket_key close_scope_socket
+ {
+ $$ = socket_expr_alloc(&@$, $2, 0);
+ }
+ | SOCKET CGROUPV2 LEVEL NUM close_scope_socket
+ {
+ $$ = socket_expr_alloc(&@$, NFT_SOCKET_CGROUPV2, $4);
+ }
+ ;
+
+socket_key : TRANSPARENT { $$ = NFT_SOCKET_TRANSPARENT; }
+ | MARK { $$ = NFT_SOCKET_MARK; }
+ | WILDCARD { $$ = NFT_SOCKET_WILDCARD; }
+ ;
+
+offset_opt : /* empty */ { $$ = 0; }
+ | OFFSET NUM { $$ = $2; }
+ ;
+
+numgen_type : INC { $$ = NFT_NG_INCREMENTAL; }
+ | RANDOM { $$ = NFT_NG_RANDOM; }
+ ;
+
+numgen_expr : NUMGEN numgen_type MOD NUM offset_opt close_scope_numgen
+ {
+ $$ = numgen_expr_alloc(&@$, $2, $4, $5);
+ }
+ ;
+
+xfrm_spnum : SPNUM NUM { $$ = $2; }
+ | { $$ = 0; }
+ ;
+
+xfrm_dir : IN { $$ = XFRM_POLICY_IN; }
+ | OUT { $$ = XFRM_POLICY_OUT; }
+ ;
+
+xfrm_state_key : SPI { $$ = NFT_XFRM_KEY_SPI; }
+ | REQID { $$ = NFT_XFRM_KEY_REQID; }
+ ;
+
+xfrm_state_proto_key : DADDR { $$ = NFT_XFRM_KEY_DADDR_IP4; }
+ | SADDR { $$ = NFT_XFRM_KEY_SADDR_IP4; }
+ ;
+
+xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key close_scope_ipsec
+ {
+ if ($3 > 255) {
+ erec_queue(error(&@3, "value too large"), state->msgs);
+ YYERROR;
+ }
+ $$ = xfrm_expr_alloc(&@$, $2, $3, $4);
+ }
+ | IPSEC xfrm_dir xfrm_spnum nf_key_proto xfrm_state_proto_key close_scope_ipsec
+ {
+ enum nft_xfrm_keys xfrmk = $5;
+
+ switch ($4) {
+ case NFPROTO_IPV4:
+ break;
+ case NFPROTO_IPV6:
+ if ($5 == NFT_XFRM_KEY_SADDR_IP4)
+ xfrmk = NFT_XFRM_KEY_SADDR_IP6;
+ else if ($5 == NFT_XFRM_KEY_DADDR_IP4)
+ xfrmk = NFT_XFRM_KEY_DADDR_IP6;
+ break;
+ default:
+ YYERROR;
+ break;
+ }
+
+ if ($3 > 255) {
+ erec_queue(error(&@3, "value too large"), state->msgs);
+ YYERROR;
+ }
+
+ $$ = xfrm_expr_alloc(&@$, $2, $3, xfrmk);
+ }
+ ;
+
+hash_expr : JHASH expr MOD NUM SEED NUM offset_opt close_scope_hash
+ {
+ $$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS);
+ $$->hash.expr = $2;
+ }
+ | JHASH expr MOD NUM offset_opt close_scope_hash
+ {
+ $$ = hash_expr_alloc(&@$, $4, false, 0, $5, NFT_HASH_JENKINS);
+ $$->hash.expr = $2;
+ }
+ | SYMHASH MOD NUM offset_opt close_scope_hash
+ {
+ $$ = hash_expr_alloc(&@$, $3, false, 0, $4, NFT_HASH_SYM);
+ }
+ ;
+
+nf_key_proto : IP close_scope_ip { $$ = NFPROTO_IPV4; }
+ | IP6 close_scope_ip6 { $$ = NFPROTO_IPV6; }
+ ;
+
+rt_expr : RT rt_key close_scope_rt
+ {
+ $$ = rt_expr_alloc(&@$, $2, true);
+ }
+ | RT nf_key_proto rt_key close_scope_rt
+ {
+ enum nft_rt_keys rtk = $3;
+
+ switch ($2) {
+ case NFPROTO_IPV4:
+ break;
+ case NFPROTO_IPV6:
+ if ($3 == NFT_RT_NEXTHOP4)
+ rtk = NFT_RT_NEXTHOP6;
+ break;
+ default:
+ YYERROR;
+ break;
+ }
+
+ $$ = rt_expr_alloc(&@$, rtk, false);
+ }
+ ;
+
+rt_key : CLASSID { $$ = NFT_RT_CLASSID; }
+ | NEXTHOP { $$ = NFT_RT_NEXTHOP4; }
+ | MTU { $$ = NFT_RT_TCPMSS; }
+ | IPSEC close_scope_ipsec { $$ = NFT_RT_XFRM; }
+ ;
+
+ct_expr : CT ct_key close_scope_ct
+ {
+ $$ = ct_expr_alloc(&@$, $2, -1);
+ }
+ | CT ct_dir ct_key_dir close_scope_ct
+ {
+ $$ = ct_expr_alloc(&@$, $3, $2);
+ }
+ | CT ct_dir ct_key_proto_field close_scope_ct
+ {
+ $$ = ct_expr_alloc(&@$, $3, $2);
+ }
+ ;
+
+ct_dir : ORIGINAL { $$ = IP_CT_DIR_ORIGINAL; }
+ | REPLY { $$ = IP_CT_DIR_REPLY; }
+ ;
+
+ct_key : L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; }
+ | PROTOCOL { $$ = NFT_CT_PROTOCOL; }
+ | MARK { $$ = NFT_CT_MARK; }
+ | STATE { $$ = NFT_CT_STATE; }
+ | DIRECTION { $$ = NFT_CT_DIRECTION; }
+ | STATUS { $$ = NFT_CT_STATUS; }
+ | EXPIRATION { $$ = NFT_CT_EXPIRATION; }
+ | HELPER { $$ = NFT_CT_HELPER; }
+ | SADDR { $$ = NFT_CT_SRC; }
+ | DADDR { $$ = NFT_CT_DST; }
+ | PROTO_SRC { $$ = NFT_CT_PROTO_SRC; }
+ | PROTO_DST { $$ = NFT_CT_PROTO_DST; }
+ | LABEL { $$ = NFT_CT_LABELS; }
+ | EVENT { $$ = NFT_CT_EVENTMASK; }
+ | SECMARK close_scope_secmark { $$ = NFT_CT_SECMARK; }
+ | ID { $$ = NFT_CT_ID; }
+ | ct_key_dir_optional
+ ;
+
+ct_key_dir : SADDR { $$ = NFT_CT_SRC; }
+ | DADDR { $$ = NFT_CT_DST; }
+ | L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; }
+ | PROTOCOL { $$ = NFT_CT_PROTOCOL; }
+ | PROTO_SRC { $$ = NFT_CT_PROTO_SRC; }
+ | PROTO_DST { $$ = NFT_CT_PROTO_DST; }
+ | ct_key_dir_optional
+ ;
+
+ct_key_proto_field : IP SADDR close_scope_ip { $$ = NFT_CT_SRC_IP; }
+ | IP DADDR close_scope_ip { $$ = NFT_CT_DST_IP; }
+ | IP6 SADDR close_scope_ip6 { $$ = NFT_CT_SRC_IP6; }
+ | IP6 DADDR close_scope_ip6 { $$ = NFT_CT_DST_IP6; }
+ ;
+
+ct_key_dir_optional : BYTES { $$ = NFT_CT_BYTES; }
+ | PACKETS { $$ = NFT_CT_PKTS; }
+ | AVGPKT { $$ = NFT_CT_AVGPKT; }
+ | ZONE { $$ = NFT_CT_ZONE; }
+ ;
+
+symbol_stmt_expr : symbol_expr
+ | keyword_expr
+ ;
+
+list_stmt_expr : symbol_stmt_expr COMMA symbol_stmt_expr
+ {
+ $$ = list_expr_alloc(&@$);
+ compound_expr_add($$, $1);
+ compound_expr_add($$, $3);
+ }
+ | list_stmt_expr COMMA symbol_stmt_expr
+ {
+ $1->location = @$;
+ compound_expr_add($1, $3);
+ $$ = $1;
+ }
+ ;
+
+ct_stmt : CT ct_key SET stmt_expr close_scope_ct
+ {
+ switch ($2) {
+ case NFT_CT_HELPER:
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_CT_HELPER;
+ $$->objref.expr = $4;
+ break;
+ default:
+ $$ = ct_stmt_alloc(&@$, $2, -1, $4);
+ 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);
+ }
+ ;
+
+payload_stmt : payload_expr SET stmt_expr
+ {
+ if ($1->etype == EXPR_EXTHDR)
+ $$ = exthdr_stmt_alloc(&@$, $1, $3);
+ else
+ $$ = payload_stmt_alloc(&@$, $1, $3);
+ }
+ ;
+
+payload_expr : payload_raw_expr
+ | eth_hdr_expr
+ | vlan_hdr_expr
+ | arp_hdr_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
+ | 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_expr_alloc(&@$, NULL, 0);
+ payload_init_raw($$, $2, $4, $6);
+ $$->byteorder = BYTEORDER_BIG_ENDIAN;
+ $$->payload.is_raw = true;
+ }
+ ;
+
+payload_base_spec : LL_HDR { $$ = PROTO_BASE_LL_HDR; }
+ | NETWORK_HDR { $$ = PROTO_BASE_NETWORK_HDR; }
+ | TRANSPORT_HDR close_scope_th { $$ = PROTO_BASE_TRANSPORT_HDR; }
+ | STRING
+ {
+ if (!strcmp($1, "ih")) {
+ $$ = PROTO_BASE_INNER_HDR;
+ } else {
+ erec_queue(error(&@1, "unknown raw payload base"), state->msgs);
+ xfree($1);
+ YYERROR;
+ }
+ xfree($1);
+ }
+ ;
+
+eth_hdr_expr : ETHER eth_hdr_field close_scope_eth
+ {
+ $$ = payload_expr_alloc(&@$, &proto_eth, $2);
+ }
+ ;
+
+eth_hdr_field : SADDR { $$ = ETHHDR_SADDR; }
+ | DADDR { $$ = ETHHDR_DADDR; }
+ | TYPE close_scope_type { $$ = ETHHDR_TYPE; }
+ ;
+
+vlan_hdr_expr : VLAN vlan_hdr_field close_scope_vlan
+ {
+ $$ = payload_expr_alloc(&@$, &proto_vlan, $2);
+ }
+ ;
+
+vlan_hdr_field : ID { $$ = VLANHDR_VID; }
+ | CFI { $$ = VLANHDR_CFI; }
+ | DEI { $$ = VLANHDR_DEI; }
+ | PCP { $$ = VLANHDR_PCP; }
+ | TYPE close_scope_type { $$ = VLANHDR_TYPE; }
+ ;
+
+arp_hdr_expr : ARP arp_hdr_field close_scope_arp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_arp, $2);
+ }
+ ;
+
+arp_hdr_field : HTYPE { $$ = ARPHDR_HRD; }
+ | PTYPE { $$ = ARPHDR_PRO; }
+ | HLEN { $$ = ARPHDR_HLN; }
+ | PLEN { $$ = ARPHDR_PLN; }
+ | OPERATION { $$ = ARPHDR_OP; }
+ | SADDR ETHER close_scope_eth { $$ = ARPHDR_SADDR_ETHER; }
+ | DADDR ETHER close_scope_eth { $$ = ARPHDR_DADDR_ETHER; }
+ | SADDR IP close_scope_ip { $$ = ARPHDR_SADDR_IP; }
+ | DADDR IP close_scope_ip { $$ = ARPHDR_DADDR_IP; }
+ ;
+
+ip_hdr_expr : IP ip_hdr_field close_scope_ip
+ {
+ $$ = payload_expr_alloc(&@$, &proto_ip, $2);
+ }
+ | IP OPTION ip_option_type ip_option_field close_scope_ip
+ {
+ $$ = ipopt_expr_alloc(&@$, $3, $4);
+ if (!$$) {
+ erec_queue(error(&@1, "unknown ip option type/field"), state->msgs);
+ YYERROR;
+ }
+ }
+ | IP OPTION ip_option_type close_scope_ip
+ {
+ $$ = ipopt_expr_alloc(&@$, $3, IPOPT_FIELD_TYPE);
+ $$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+ ;
+
+ip_hdr_field : HDRVERSION { $$ = IPHDR_VERSION; }
+ | HDRLENGTH { $$ = IPHDR_HDRLENGTH; }
+ | DSCP { $$ = IPHDR_DSCP; }
+ | ECN { $$ = IPHDR_ECN; }
+ | LENGTH { $$ = IPHDR_LENGTH; }
+ | ID { $$ = IPHDR_ID; }
+ | FRAG_OFF { $$ = IPHDR_FRAG_OFF; }
+ | TTL { $$ = IPHDR_TTL; }
+ | PROTOCOL { $$ = IPHDR_PROTOCOL; }
+ | CHECKSUM { $$ = IPHDR_CHECKSUM; }
+ | SADDR { $$ = IPHDR_SADDR; }
+ | DADDR { $$ = IPHDR_DADDR; }
+ ;
+
+ip_option_type : LSRR { $$ = IPOPT_LSRR; }
+ | RR { $$ = IPOPT_RR; }
+ | SSRR { $$ = IPOPT_SSRR; }
+ | RA { $$ = IPOPT_RA; }
+ ;
+
+ip_option_field : TYPE close_scope_type { $$ = IPOPT_FIELD_TYPE; }
+ | LENGTH { $$ = IPOPT_FIELD_LENGTH; }
+ | VALUE { $$ = IPOPT_FIELD_VALUE; }
+ | PTR { $$ = IPOPT_FIELD_PTR; }
+ | ADDR { $$ = IPOPT_FIELD_ADDR_0; }
+ ;
+
+icmp_hdr_expr : ICMP icmp_hdr_field close_scope_icmp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_icmp, $2);
+ }
+ ;
+
+icmp_hdr_field : TYPE close_scope_type { $$ = ICMPHDR_TYPE; }
+ | CODE { $$ = ICMPHDR_CODE; }
+ | CHECKSUM { $$ = ICMPHDR_CHECKSUM; }
+ | ID { $$ = ICMPHDR_ID; }
+ | SEQUENCE { $$ = ICMPHDR_SEQ; }
+ | GATEWAY { $$ = ICMPHDR_GATEWAY; }
+ | MTU { $$ = ICMPHDR_MTU; }
+ ;
+
+igmp_hdr_expr : IGMP igmp_hdr_field close_scope_igmp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_igmp, $2);
+ }
+ ;
+
+igmp_hdr_field : TYPE close_scope_type { $$ = IGMPHDR_TYPE; }
+ | CHECKSUM { $$ = IGMPHDR_CHECKSUM; }
+ | MRT { $$ = IGMPHDR_MRT; }
+ | GROUP { $$ = IGMPHDR_GROUP; }
+ ;
+
+ip6_hdr_expr : IP6 ip6_hdr_field close_scope_ip6
+ {
+ $$ = payload_expr_alloc(&@$, &proto_ip6, $2);
+ }
+ ;
+
+ip6_hdr_field : HDRVERSION { $$ = IP6HDR_VERSION; }
+ | DSCP { $$ = IP6HDR_DSCP; }
+ | ECN { $$ = IP6HDR_ECN; }
+ | FLOWLABEL { $$ = IP6HDR_FLOWLABEL; }
+ | LENGTH { $$ = IP6HDR_LENGTH; }
+ | NEXTHDR { $$ = IP6HDR_NEXTHDR; }
+ | HOPLIMIT { $$ = IP6HDR_HOPLIMIT; }
+ | SADDR { $$ = IP6HDR_SADDR; }
+ | DADDR { $$ = IP6HDR_DADDR; }
+ ;
+icmp6_hdr_expr : ICMP6 icmp6_hdr_field close_scope_icmp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_icmp6, $2);
+ }
+ ;
+
+icmp6_hdr_field : TYPE close_scope_type { $$ = ICMP6HDR_TYPE; }
+ | CODE { $$ = ICMP6HDR_CODE; }
+ | CHECKSUM { $$ = ICMP6HDR_CHECKSUM; }
+ | PPTR { $$ = ICMP6HDR_PPTR; }
+ | MTU { $$ = ICMP6HDR_MTU; }
+ | 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
+ {
+ $$ = payload_expr_alloc(&@$, &proto_ah, $2);
+ }
+ ;
+
+auth_hdr_field : NEXTHDR { $$ = AHHDR_NEXTHDR; }
+ | HDRLENGTH { $$ = AHHDR_HDRLENGTH; }
+ | RESERVED { $$ = AHHDR_RESERVED; }
+ | SPI { $$ = AHHDR_SPI; }
+ | SEQUENCE { $$ = AHHDR_SEQUENCE; }
+ ;
+
+esp_hdr_expr : ESP esp_hdr_field close_scope_esp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_esp, $2);
+ }
+ ;
+
+esp_hdr_field : SPI { $$ = ESPHDR_SPI; }
+ | SEQUENCE { $$ = ESPHDR_SEQUENCE; }
+ ;
+
+comp_hdr_expr : COMP comp_hdr_field close_scope_comp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_comp, $2);
+ }
+ ;
+
+comp_hdr_field : NEXTHDR { $$ = COMPHDR_NEXTHDR; }
+ | FLAGS { $$ = COMPHDR_FLAGS; }
+ | CPI { $$ = COMPHDR_CPI; }
+ ;
+
+udp_hdr_expr : UDP udp_hdr_field close_scope_udp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_udp, $2);
+ }
+ ;
+
+udp_hdr_field : SPORT { $$ = UDPHDR_SPORT; }
+ | DPORT { $$ = UDPHDR_DPORT; }
+ | LENGTH { $$ = UDPHDR_LENGTH; }
+ | CHECKSUM { $$ = UDPHDR_CHECKSUM; }
+ ;
+
+udplite_hdr_expr : UDPLITE udplite_hdr_field close_scope_udplite
+ {
+ $$ = payload_expr_alloc(&@$, &proto_udplite, $2);
+ }
+ ;
+
+udplite_hdr_field : SPORT { $$ = UDPHDR_SPORT; }
+ | DPORT { $$ = UDPHDR_DPORT; }
+ | CSUMCOV { $$ = UDPHDR_LENGTH; }
+ | CHECKSUM { $$ = UDPHDR_CHECKSUM; }
+ ;
+
+tcp_hdr_expr : TCP tcp_hdr_field
+ {
+ $$ = payload_expr_alloc(&@$, &proto_tcp, $2);
+ }
+ | TCP OPTION tcp_hdr_option_type
+ {
+ $$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND);
+ $$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+ | TCP OPTION tcp_hdr_option_kind_and_field
+ {
+ $$ = tcpopt_expr_alloc(&@$, $3.kind, $3.field);
+ }
+ | TCP OPTION AT close_scope_at tcp_hdr_option_type COMMA NUM COMMA NUM
+ {
+ $$ = tcpopt_expr_alloc(&@$, $5, 0);
+ tcpopt_init_raw($$, $5, $7, $9, 0);
+ }
+ ;
+
+inner_inet_expr : ip_hdr_expr
+ | icmp_hdr_expr
+ | igmp_hdr_expr
+ | ip6_hdr_expr
+ | icmp6_hdr_expr
+ | auth_hdr_expr
+ | esp_hdr_expr
+ | comp_hdr_expr
+ | udp_hdr_expr
+ | udplite_hdr_expr
+ | tcp_hdr_expr close_scope_tcp
+ | dccp_hdr_expr
+ | sctp_hdr_expr
+ | th_hdr_expr
+ ;
+
+inner_eth_expr : eth_hdr_expr
+ | vlan_hdr_expr
+ | arp_hdr_expr
+ ;
+
+inner_expr : inner_eth_expr
+ | inner_inet_expr
+ ;
+
+vxlan_hdr_expr : VXLAN vxlan_hdr_field
+ {
+ struct expr *expr;
+
+ expr = payload_expr_alloc(&@$, &proto_vxlan, $2);
+ expr->payload.inner_desc = &proto_vxlan;
+ $$ = expr;
+ }
+ | VXLAN inner_expr
+ {
+ $$ = $2;
+ $$->location = @$;
+ $$->payload.inner_desc = &proto_vxlan;
+ }
+ ;
+
+vxlan_hdr_field : VNI { $$ = VXLANHDR_VNI; }
+ | FLAGS { $$ = VXLANHDR_FLAGS; }
+ ;
+
+geneve_hdr_expr : GENEVE geneve_hdr_field
+ {
+ struct expr *expr;
+
+ expr = payload_expr_alloc(&@$, &proto_geneve, $2);
+ expr->payload.inner_desc = &proto_geneve;
+ $$ = expr;
+ }
+ | GENEVE inner_expr
+ {
+ $$ = $2;
+ $$->location = @$;
+ $$->payload.inner_desc = &proto_geneve;
+ }
+ ;
+
+geneve_hdr_field : VNI { $$ = GNVHDR_VNI; }
+ | TYPE { $$ = GNVHDR_TYPE; }
+ ;
+
+gre_hdr_expr : GRE gre_hdr_field close_scope_gre
+ {
+ $$ = payload_expr_alloc(&@$, &proto_gre, $2);
+ }
+ | GRE close_scope_gre inner_inet_expr
+ {
+ $$ = $3;
+ $$->payload.inner_desc = &proto_gre;
+ }
+ ;
+
+gre_hdr_field : HDRVERSION { $$ = GREHDR_VERSION; }
+ | FLAGS { $$ = GREHDR_FLAGS; }
+ | PROTOCOL { $$ = GREHDR_PROTOCOL; }
+ ;
+
+gretap_hdr_expr : GRETAP close_scope_gre inner_expr
+ {
+ $$ = $3;
+ $$->payload.inner_desc = &proto_gretap;
+ }
+ ;
+
+optstrip_stmt : RESET TCP OPTION tcp_hdr_option_type close_scope_tcp
+ {
+ $$ = optstrip_stmt_alloc(&@$, tcpopt_expr_alloc(&@$,
+ $4, TCPOPT_COMMON_KIND));
+ }
+ ;
+
+tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
+ | DPORT { $$ = TCPHDR_DPORT; }
+ | SEQUENCE { $$ = TCPHDR_SEQ; }
+ | ACKSEQ { $$ = TCPHDR_ACKSEQ; }
+ | DOFF { $$ = TCPHDR_DOFF; }
+ | RESERVED { $$ = TCPHDR_RESERVED; }
+ | FLAGS { $$ = TCPHDR_FLAGS; }
+ | WINDOW { $$ = TCPHDR_WINDOW; }
+ | CHECKSUM { $$ = TCPHDR_CHECKSUM; }
+ | URGPTR { $$ = TCPHDR_URGPTR; }
+ ;
+
+tcp_hdr_option_kind_and_field : MSS tcpopt_field_maxseg
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MAXSEG, .field = $2 };
+ $$ = kind_field;
+ }
+ | tcp_hdr_option_sack tcpopt_field_sack
+ {
+ struct tcp_kind_field kind_field = { .kind = $1, .field = $2 };
+ $$ = kind_field;
+ }
+ | WINDOW tcpopt_field_window
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_WINDOW, .field = $2 };
+ $$ = kind_field;
+ }
+ | TIMESTAMP tcpopt_field_tsopt
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_TIMESTAMP, .field = $2 };
+ $$ = kind_field;
+ }
+ | tcp_hdr_option_type LENGTH
+ {
+ struct tcp_kind_field kind_field = { .kind = $1, .field = TCPOPT_COMMON_LENGTH };
+ $$ = kind_field;
+ }
+ | MPTCP tcpopt_field_mptcp
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MPTCP, .field = $2 };
+ $$ = kind_field;
+ }
+ ;
+
+tcp_hdr_option_sack : SACK { $$ = TCPOPT_KIND_SACK; }
+ | SACK0 { $$ = TCPOPT_KIND_SACK; }
+ | SACK1 { $$ = TCPOPT_KIND_SACK1; }
+ | SACK2 { $$ = TCPOPT_KIND_SACK2; }
+ | SACK3 { $$ = TCPOPT_KIND_SACK3; }
+ ;
+
+tcp_hdr_option_type : ECHO { $$ = TCPOPT_KIND_ECHO; }
+ | EOL { $$ = TCPOPT_KIND_EOL; }
+ | FASTOPEN { $$ = TCPOPT_KIND_FASTOPEN; }
+ | MD5SIG { $$ = TCPOPT_KIND_MD5SIG; }
+ | MPTCP { $$ = TCPOPT_KIND_MPTCP; }
+ | MSS { $$ = TCPOPT_KIND_MAXSEG; }
+ | NOP { $$ = TCPOPT_KIND_NOP; }
+ | SACK_PERM { $$ = TCPOPT_KIND_SACK_PERMITTED; }
+ | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; }
+ | WINDOW { $$ = TCPOPT_KIND_WINDOW; }
+ | tcp_hdr_option_sack { $$ = $1; }
+ | NUM {
+ if ($1 > 255) {
+ erec_queue(error(&@1, "value too large"), state->msgs);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+tcpopt_field_sack : LEFT { $$ = TCPOPT_SACK_LEFT; }
+ | RIGHT { $$ = TCPOPT_SACK_RIGHT; }
+ ;
+
+tcpopt_field_window : COUNT { $$ = TCPOPT_WINDOW_COUNT; }
+ ;
+
+tcpopt_field_tsopt : TSVAL { $$ = TCPOPT_TS_TSVAL; }
+ | TSECR { $$ = TCPOPT_TS_TSECR; }
+ ;
+
+tcpopt_field_maxseg : SIZE { $$ = TCPOPT_MAXSEG_SIZE; }
+ ;
+
+tcpopt_field_mptcp : SUBTYPE { $$ = TCPOPT_MPTCP_SUBTYPE; }
+ ;
+
+dccp_hdr_expr : DCCP dccp_hdr_field close_scope_dccp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_dccp, $2);
+ }
+ | DCCP OPTION NUM close_scope_dccp
+ {
+ if ($3 > DCCPOPT_TYPE_MAX) {
+ erec_queue(error(&@1, "value too large"),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = dccpopt_expr_alloc(&@$, $3);
+ }
+ ;
+
+dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; }
+ | DPORT { $$ = DCCPHDR_DPORT; }
+ | TYPE close_scope_type { $$ = DCCPHDR_TYPE; }
+ ;
+
+sctp_chunk_type : DATA { $$ = SCTP_CHUNK_TYPE_DATA; }
+ | INIT { $$ = SCTP_CHUNK_TYPE_INIT; }
+ | INIT_ACK { $$ = SCTP_CHUNK_TYPE_INIT_ACK; }
+ | SACK { $$ = SCTP_CHUNK_TYPE_SACK; }
+ | HEARTBEAT { $$ = SCTP_CHUNK_TYPE_HEARTBEAT; }
+ | HEARTBEAT_ACK { $$ = SCTP_CHUNK_TYPE_HEARTBEAT_ACK; }
+ | ABORT { $$ = SCTP_CHUNK_TYPE_ABORT; }
+ | SHUTDOWN { $$ = SCTP_CHUNK_TYPE_SHUTDOWN; }
+ | SHUTDOWN_ACK { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_ACK; }
+ | ERROR { $$ = SCTP_CHUNK_TYPE_ERROR; }
+ | COOKIE_ECHO { $$ = SCTP_CHUNK_TYPE_COOKIE_ECHO; }
+ | COOKIE_ACK { $$ = SCTP_CHUNK_TYPE_COOKIE_ACK; }
+ | ECNE { $$ = SCTP_CHUNK_TYPE_ECNE; }
+ | CWR { $$ = SCTP_CHUNK_TYPE_CWR; }
+ | SHUTDOWN_COMPLETE { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE; }
+ | ASCONF_ACK { $$ = SCTP_CHUNK_TYPE_ASCONF_ACK; }
+ | FORWARD_TSN { $$ = SCTP_CHUNK_TYPE_FORWARD_TSN; }
+ | ASCONF { $$ = SCTP_CHUNK_TYPE_ASCONF; }
+ ;
+
+sctp_chunk_common_field : TYPE close_scope_type { $$ = SCTP_CHUNK_COMMON_TYPE; }
+ | FLAGS { $$ = SCTP_CHUNK_COMMON_FLAGS; }
+ | LENGTH { $$ = SCTP_CHUNK_COMMON_LENGTH; }
+ ;
+
+sctp_chunk_data_field : TSN { $$ = SCTP_CHUNK_DATA_TSN; }
+ | STREAM { $$ = SCTP_CHUNK_DATA_STREAM; }
+ | SSN { $$ = SCTP_CHUNK_DATA_SSN; }
+ | PPID { $$ = SCTP_CHUNK_DATA_PPID; }
+ ;
+
+sctp_chunk_init_field : INIT_TAG { $$ = SCTP_CHUNK_INIT_TAG; }
+ | A_RWND { $$ = SCTP_CHUNK_INIT_RWND; }
+ | NUM_OSTREAMS { $$ = SCTP_CHUNK_INIT_OSTREAMS; }
+ | NUM_ISTREAMS { $$ = SCTP_CHUNK_INIT_ISTREAMS; }
+ | INIT_TSN { $$ = SCTP_CHUNK_INIT_TSN; }
+ ;
+
+sctp_chunk_sack_field : CUM_TSN_ACK { $$ = SCTP_CHUNK_SACK_CTSN_ACK; }
+ | A_RWND { $$ = SCTP_CHUNK_SACK_RWND; }
+ | NUM_GACK_BLOCKS { $$ = SCTP_CHUNK_SACK_GACK_BLOCKS; }
+ | NUM_DUP_TSNS { $$ = SCTP_CHUNK_SACK_DUP_TSNS; }
+ ;
+
+sctp_chunk_alloc : sctp_chunk_type
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, $1, SCTP_CHUNK_COMMON_TYPE);
+ $$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+ | sctp_chunk_type sctp_chunk_common_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, $1, $2);
+ }
+ | DATA sctp_chunk_data_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_DATA, $2);
+ }
+ | INIT sctp_chunk_init_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT, $2);
+ }
+ | INIT_ACK sctp_chunk_init_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT_ACK, $2);
+ }
+ | SACK sctp_chunk_sack_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SACK, $2);
+ }
+ | SHUTDOWN CUM_TSN_ACK
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SHUTDOWN,
+ SCTP_CHUNK_SHUTDOWN_CTSN_ACK);
+ }
+ | ECNE LOWEST_TSN
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ECNE,
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN);
+ }
+ | CWR LOWEST_TSN
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_CWR,
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN);
+ }
+ | ASCONF_ACK SEQNO
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF_ACK,
+ SCTP_CHUNK_ASCONF_SEQNO);
+ }
+ | FORWARD_TSN NEW_CUM_TSN
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_FORWARD_TSN,
+ SCTP_CHUNK_FORWARD_TSN_NCTSN);
+ }
+ | ASCONF SEQNO
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF,
+ SCTP_CHUNK_ASCONF_SEQNO);
+ }
+ ;
+
+sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp
+ {
+ $$ = payload_expr_alloc(&@$, &proto_sctp, $2);
+ }
+ | SCTP CHUNK sctp_chunk_alloc close_scope_sctp_chunk close_scope_sctp
+ {
+ $$ = $3;
+ }
+ ;
+
+sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; }
+ | DPORT { $$ = SCTPHDR_DPORT; }
+ | VTAG { $$ = SCTPHDR_VTAG; }
+ | CHECKSUM { $$ = SCTPHDR_CHECKSUM; }
+ ;
+
+th_hdr_expr : TRANSPORT_HDR th_hdr_field close_scope_th
+ {
+ $$ = payload_expr_alloc(&@$, &proto_th, $2);
+ if ($$)
+ $$->payload.is_raw = true;
+ }
+ ;
+
+th_hdr_field : SPORT { $$ = THDR_SPORT; }
+ | DPORT { $$ = THDR_DPORT; }
+ ;
+
+exthdr_expr : hbh_hdr_expr
+ | rt_hdr_expr
+ | rt0_hdr_expr
+ | rt2_hdr_expr
+ | rt4_hdr_expr
+ | frag_hdr_expr
+ | dst_hdr_expr
+ | mh_hdr_expr
+ ;
+
+hbh_hdr_expr : HBH hbh_hdr_field close_scope_hbh
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_hbh, $2);
+ }
+ ;
+
+hbh_hdr_field : NEXTHDR { $$ = HBHHDR_NEXTHDR; }
+ | HDRLENGTH { $$ = HBHHDR_HDRLENGTH; }
+ ;
+
+rt_hdr_expr : RT rt_hdr_field close_scope_rt
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_rt, $2);
+ }
+ ;
+
+rt_hdr_field : NEXTHDR { $$ = RTHDR_NEXTHDR; }
+ | HDRLENGTH { $$ = RTHDR_HDRLENGTH; }
+ | TYPE close_scope_type { $$ = RTHDR_TYPE; }
+ | SEG_LEFT { $$ = RTHDR_SEG_LEFT; }
+ ;
+
+rt0_hdr_expr : RT0 rt0_hdr_field close_scope_rt
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_rt0, $2);
+ }
+ ;
+
+rt0_hdr_field : ADDR '[' NUM ']'
+ {
+ $$ = RT0HDR_ADDR_1 + $3 - 1;
+ }
+ ;
+
+rt2_hdr_expr : RT2 rt2_hdr_field close_scope_rt
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_rt2, $2);
+ }
+ ;
+
+rt2_hdr_field : ADDR { $$ = RT2HDR_ADDR; }
+ ;
+
+rt4_hdr_expr : RT4 rt4_hdr_field close_scope_rt
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_rt4, $2);
+ }
+ ;
+
+rt4_hdr_field : LAST_ENT { $$ = RT4HDR_LASTENT; }
+ | FLAGS { $$ = RT4HDR_FLAGS; }
+ | TAG { $$ = RT4HDR_TAG; }
+ | SID '[' NUM ']'
+ {
+ $$ = RT4HDR_SID_1 + $3 - 1;
+ }
+ ;
+
+frag_hdr_expr : FRAG frag_hdr_field close_scope_frag
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_frag, $2);
+ }
+ ;
+
+frag_hdr_field : NEXTHDR { $$ = FRAGHDR_NEXTHDR; }
+ | RESERVED { $$ = FRAGHDR_RESERVED; }
+ | FRAG_OFF { $$ = FRAGHDR_FRAG_OFF; }
+ | RESERVED2 { $$ = FRAGHDR_RESERVED2; }
+ | MORE_FRAGMENTS { $$ = FRAGHDR_MFRAGS; }
+ | ID { $$ = FRAGHDR_ID; }
+ ;
+
+dst_hdr_expr : DST dst_hdr_field close_scope_dst
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_dst, $2);
+ }
+ ;
+
+dst_hdr_field : NEXTHDR { $$ = DSTHDR_NEXTHDR; }
+ | HDRLENGTH { $$ = DSTHDR_HDRLENGTH; }
+ ;
+
+mh_hdr_expr : MH mh_hdr_field close_scope_mh
+ {
+ $$ = exthdr_expr_alloc(&@$, &exthdr_mh, $2);
+ }
+ ;
+
+mh_hdr_field : NEXTHDR { $$ = MHHDR_NEXTHDR; }
+ | HDRLENGTH { $$ = MHHDR_HDRLENGTH; }
+ | TYPE close_scope_type { $$ = MHHDR_TYPE; }
+ | RESERVED { $$ = MHHDR_RESERVED; }
+ | CHECKSUM { $$ = MHHDR_CHECKSUM; }
+ ;
+
+exthdr_exists_expr : EXTHDR exthdr_key
+ {
+ const struct exthdr_desc *desc;
+
+ desc = exthdr_find_proto($2);
+
+ /* Assume that NEXTHDR template is always
+ * the first one in list of templates.
+ */
+ $$ = exthdr_expr_alloc(&@$, desc, 1);
+ $$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+ ;
+
+exthdr_key : HBH close_scope_hbh { $$ = IPPROTO_HOPOPTS; }
+ | RT close_scope_rt { $$ = IPPROTO_ROUTING; }
+ | FRAG close_scope_frag { $$ = IPPROTO_FRAGMENT; }
+ | DST close_scope_dst { $$ = IPPROTO_DSTOPTS; }
+ | MH close_scope_mh { $$ = IPPROTO_MH; }
+ ;
+
+%%
diff --git a/src/parser_json.c b/src/parser_json.c
new file mode 100644
index 0000000..199241a
--- /dev/null
+++ b/src/parser_json.c
@@ -0,0 +1,4415 @@
+/*
+ * 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 <syslog.h>
+
+#include <erec.h>
+#include <expression.h>
+#include <tcpopt.h>
+#include <list.h>
+#include <netlink.h>
+#include <parser.h>
+#include <rule.h>
+#include <sctp_chunk.h>
+#include <socket.h>
+
+#include <netdb.h>
+#include <netinet/icmp6.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <net/if.h>
+#include <linux/xfrm.h>
+
+#include <linux/netfilter.h>
+#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 <jansson.h>
+
+#include <mnl.h>
+#include <libnftnl/rule.h>
+#include <linux/netfilter/nfnetlink.h>
+
+#define CTX_F_RHS (1 << 0)
+#define CTX_F_STMT (1 << 1)
+#define CTX_F_PRIMARY (1 << 2)
+#define CTX_F_DTYPE (1 << 3)
+#define CTX_F_SET_RHS (1 << 4)
+#define CTX_F_MANGLE (1 << 5)
+#define CTX_F_SES (1 << 6) /* set_elem_expr_stmt */
+#define CTX_F_MAP (1 << 7) /* LHS of map_expr */
+#define CTX_F_CONCAT (1 << 8) /* inside concat_expr */
+
+struct json_ctx {
+ struct nft_ctx *nft;
+ struct list_head *msgs;
+ struct list_head *cmds;
+ uint32_t flags;
+};
+
+#define is_RHS(ctx) (ctx->flags & CTX_F_RHS)
+#define is_STMT(ctx) (ctx->flags & CTX_F_STMT)
+#define is_PRIMARY(ctx) (ctx->flags & CTX_F_PRIMARY)
+#define is_DTYPE(ctx) (ctx->flags & CTX_F_DTYPE)
+#define is_SET_RHS(ctx) (ctx->flags & CTX_F_SET_RHS)
+
+static char *ctx_flags_to_string(struct json_ctx *ctx)
+{
+ static char buf[1024];
+ const char *sep = "";
+
+ buf[0] = '\0';
+
+ if (is_RHS(ctx)) {
+ strcat(buf, sep);
+ strcat(buf, "RHS");
+ sep = ", ";
+ }
+ if (is_STMT(ctx)) {
+ strcat(buf, sep);
+ strcat(buf, "STMT");
+ sep = ", ";
+ }
+ if (is_PRIMARY(ctx)) {
+ strcat(buf, sep);
+ strcat(buf, "PRIMARY");
+ sep = ", ";
+ }
+ if (is_DTYPE(ctx)) {
+ strcat(buf, sep);
+ strcat(buf, "DTYPE");
+ sep = ", ";
+ }
+ if (is_SET_RHS(ctx)) {
+ strcat(buf, sep);
+ strcat(buf, "SET_RHS");
+ sep = ", ";
+ }
+ return buf;
+}
+
+/* common parser entry points */
+
+static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_rhs_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_stmt_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_primary_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_set_rhs_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_set_elem_expr_stmt(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root);
+static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root);
+
+/* parsing helpers */
+
+const struct location *int_loc = &internal_location;
+static struct input_descriptor json_indesc;
+
+static void json_lib_error(struct json_ctx *ctx, json_error_t *err)
+{
+ struct location loc = {
+ .indesc = &json_indesc,
+ .line_offset = err->position - err->column,
+ .first_line = err->line,
+ .last_line = err->line,
+ .first_column = err->column,
+ /* no information where problematic part ends :( */
+ .last_column = err->column,
+ };
+
+ erec_queue(error(&loc, err->text), ctx->msgs);
+}
+
+__attribute__((format(printf, 2, 3)))
+static void json_error(struct json_ctx *ctx, const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, int_loc, fmt, ap);
+ va_end(ap);
+ erec_queue(erec, ctx->msgs);
+}
+
+static const char *json_typename(const json_t *val)
+{
+ const char *type_name[] = {
+ [JSON_OBJECT] = "object",
+ [JSON_ARRAY] = "array",
+ [JSON_STRING] = "string",
+ [JSON_INTEGER] = "integer",
+ [JSON_REAL] = "real",
+ [JSON_TRUE] = "true",
+ [JSON_FALSE] = "false",
+ [JSON_NULL] = "null"
+ };
+
+ return type_name[json_typeof(val)];
+}
+
+static int json_unpack_err(struct json_ctx *ctx,
+ json_t *root, const char *fmt, ...)
+{
+ json_error_t err;
+ va_list ap;
+ int rc;
+
+ va_start(ap, fmt);
+ rc = json_vunpack_ex(root, &err, 0, fmt, ap);
+ va_end(ap);
+
+ if (rc)
+ json_lib_error(ctx, &err);
+ return rc;
+}
+
+static int json_unpack_stmt(struct json_ctx *ctx, json_t *root,
+ const char **key, json_t **value)
+{
+ assert(key);
+ assert(value);
+
+ if (json_object_size(root) != 1) {
+ json_error(ctx, "Malformed object (too many properties): '%s'.",
+ json_dumps(root, 0));
+ return 1;
+ }
+
+ json_object_foreach(root, *key, *value)
+ return 0;
+
+ /* not reached */
+ return 1;
+}
+
+static int parse_family(const char *name, uint32_t *family)
+{
+ unsigned int i;
+ struct {
+ const char *name;
+ int val;
+ } family_tbl[] = {
+ { "ip", NFPROTO_IPV4 },
+ { "ip6", NFPROTO_IPV6 },
+ { "inet", NFPROTO_INET },
+ { "arp", NFPROTO_ARP },
+ { "bridge", NFPROTO_BRIDGE },
+ { "netdev", NFPROTO_NETDEV }
+ };
+
+ assert(family);
+
+ for (i = 0; i < array_size(family_tbl); i++) {
+ if (strcmp(name, family_tbl[i].name))
+ continue;
+
+ *family = family_tbl[i].val;
+ return 0;
+ }
+ return -1;
+}
+
+static int json_parse_family(struct json_ctx *ctx, json_t *root)
+{
+ const char *family;
+
+ if (!json_unpack(root, "{s:s}", "family", &family)) {
+ uint32_t familyval;
+
+ if (parse_family(family, &familyval) ||
+ (familyval != NFPROTO_IPV6 &&
+ familyval != NFPROTO_IPV4)) {
+ json_error(ctx, "Invalid family '%s'.", family);
+ return -1;
+ }
+ return familyval;
+ }
+
+ return NFPROTO_UNSPEC;
+}
+
+static bool is_keyword(const char *keyword)
+{
+ const char *keywords[] = {
+ "ether",
+ "ip",
+ "ip6",
+ "vlan",
+ "arp",
+ "dnat",
+ "snat",
+ "ecn",
+ "reset",
+ "original",
+ "reply",
+ "label",
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(keywords); i++) {
+ if (!strcmp(keyword, keywords[i]))
+ return true;
+ }
+ return false;
+}
+
+static bool is_constant(const char *keyword)
+{
+ const char *constants[] = {
+ "tcp",
+ "udp",
+ "udplite",
+ "esp",
+ "ah",
+ "icmp",
+ "icmpv6",
+ "comp",
+ "dccp",
+ "sctp",
+ "redirect",
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(constants); i++) {
+ if (!strcmp(keyword, constants[i]))
+ return true;
+ }
+ return false;
+}
+
+static struct expr *json_parse_constant(struct json_ctx *ctx, const char *name)
+{
+ const struct {
+ const char *name;
+ uint8_t data;
+ const struct datatype *dtype;
+ } constant_tbl[] = {
+ { "tcp", IPPROTO_TCP, &inet_protocol_type },
+ { "udp", IPPROTO_UDP, &inet_protocol_type },
+ { "udplite", IPPROTO_UDPLITE, &inet_protocol_type },
+ { "esp", IPPROTO_ESP, &inet_protocol_type },
+ { "ah", IPPROTO_AH, &inet_protocol_type },
+ { "icmp", IPPROTO_ICMP, &inet_protocol_type },
+ { "icmpv6", IPPROTO_ICMPV6, &inet_protocol_type },
+ { "comp", IPPROTO_COMP, &inet_protocol_type },
+ { "dccp", IPPROTO_DCCP, &inet_protocol_type },
+ { "sctp", IPPROTO_SCTP, &inet_protocol_type },
+ { "redirect", ICMP_REDIRECT, &icmp_type_type },
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(constant_tbl); i++) {
+ if (strcmp(name, constant_tbl[i].name))
+ continue;
+ return constant_expr_alloc(int_loc,
+ constant_tbl[i].dtype,
+ BYTEORDER_HOST_ENDIAN,
+ BITS_PER_BYTE,
+ &constant_tbl[i].data);
+ }
+ json_error(ctx, "Unknown constant '%s'.", name);
+ return NULL;
+}
+
+/* this is a combination of symbol_expr, integer_expr, boolean_expr ... */
+static struct expr *json_parse_immediate(struct json_ctx *ctx, json_t *root)
+{
+ enum symbol_types symtype = SYMBOL_VALUE;
+ const char *str;
+ char buf[64] = {};
+
+ switch (json_typeof(root)) {
+ case JSON_STRING:
+ str = json_string_value(root);
+ if (str[0] == '@') {
+ symtype = SYMBOL_SET;
+ str++;
+ } else if (str[0] == '*' && str[1] == '\0') {
+ return set_elem_catchall_expr_alloc(int_loc);
+ } else if (is_keyword(str)) {
+ return symbol_expr_alloc(int_loc,
+ SYMBOL_VALUE, NULL, str);
+ } else if (is_constant(str)) {
+ return json_parse_constant(ctx, str);
+ }
+ break;
+ case JSON_INTEGER:
+ snprintf(buf, sizeof(buf),
+ "%" JSON_INTEGER_FORMAT, json_integer_value(root));
+ str = buf;
+ break;
+ case JSON_TRUE:
+ case JSON_FALSE:
+ buf[0] = json_is_true(root);
+ return constant_expr_alloc(int_loc, &boolean_type,
+ BYTEORDER_HOST_ENDIAN,
+ BITS_PER_BYTE, buf);
+ default:
+ json_error(ctx, "Unexpected JSON type %s for immediate value.",
+ json_typename(root));
+ return NULL;
+ }
+
+ return symbol_expr_alloc(int_loc, symtype, NULL, str);
+}
+
+static struct expr *json_parse_meta_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ struct error_record *erec;
+ unsigned int key;
+ const char *name;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "key", &name))
+ return NULL;
+ erec = meta_key_parse(int_loc, name, &key);
+ if (erec) {
+ erec_queue(erec, ctx->msgs);
+ return NULL;
+ }
+ return meta_expr_alloc(int_loc, key);
+}
+
+static struct expr *json_parse_osf_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const char *key, *ttl;
+ uint32_t flagval = 0;
+ uint8_t ttlval = 0;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "key", &key))
+ return NULL;
+
+ if (!json_unpack(root, "{s:s}", "ttl", &ttl)) {
+ if (!strcmp(ttl, "loose")) {
+ ttlval = 1;
+ } else if (!strcmp(ttl, "skip")) {
+ ttlval = 2;
+ } else {
+ json_error(ctx, "Invalid osf ttl option '%s'.", ttl);
+ return NULL;
+ }
+ }
+
+ if (!strcmp(key, "name")) {
+ return osf_expr_alloc(int_loc, ttlval, flagval);
+ } else if (!strcmp(key, "version")) {
+ flagval |= NFT_OSF_F_VERSION;
+ return osf_expr_alloc(int_loc, ttlval, flagval);
+ }
+
+ json_error(ctx, "Invalid osf key value.");
+ return NULL;
+}
+
+static struct expr *json_parse_socket_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const char *key;
+ int keyval = -1;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "key", &key))
+ return NULL;
+
+ if (!strcmp(key, "transparent"))
+ keyval = NFT_SOCKET_TRANSPARENT;
+ else if (!strcmp(key, "mark"))
+ keyval = NFT_SOCKET_MARK;
+ else if (!strcmp(key, "wildcard"))
+ keyval = NFT_SOCKET_WILDCARD;
+
+ if (keyval == -1) {
+ json_error(ctx, "Invalid socket key value.");
+ return NULL;
+ }
+
+ return socket_expr_alloc(int_loc, keyval, 0);
+}
+
+static int json_parse_payload_field(const struct proto_desc *desc,
+ const char *name, int *field)
+{
+ unsigned int i;
+
+ for (i = 0; i < PROTO_HDRS_MAX; i++) {
+ if (desc->templates[i].token &&
+ !strcmp(desc->templates[i].token, name)) {
+ if (field)
+ *field = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int json_parse_tcp_option_type(const char *name, int *val)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(tcpopt_protocols); i++) {
+ if (tcpopt_protocols[i] &&
+ !strcmp(tcpopt_protocols[i]->name, name)) {
+ if (val)
+ *val = i;
+ return 0;
+ }
+ }
+ /* special case for sack0 - sack3 */
+ if (sscanf(name, "sack%u", &i) == 1 && i < 4) {
+ if (val && i == 0)
+ *val = TCPOPT_KIND_SACK;
+ else if (val && i > 0)
+ *val = TCPOPT_KIND_SACK1 + i - 1;
+ return 0;
+ }
+ return 1;
+}
+
+static int json_parse_tcp_option_field(int type, const char *name, int *val)
+{
+ const struct exthdr_desc *desc;
+ unsigned int block = 0;
+ unsigned int i;
+
+ switch (type) {
+ case TCPOPT_KIND_SACK1:
+ type = TCPOPT_KIND_SACK;
+ block = 1;
+ break;
+ case TCPOPT_KIND_SACK2:
+ type = TCPOPT_KIND_SACK;
+ block = 2;
+ break;
+ case TCPOPT_KIND_SACK3:
+ type = TCPOPT_KIND_SACK;
+ block = 3;
+ break;
+ }
+
+ if (type < 0 || type >= (int)array_size(tcpopt_protocols))
+ return 1;
+
+ desc = tcpopt_protocols[type];
+ if (!desc)
+ return 1;
+
+ for (i = 0; i < array_size(desc->templates); i++) {
+ if (desc->templates[i].token &&
+ !strcmp(desc->templates[i].token, name)) {
+ if (block) {
+ block--;
+ continue;
+ }
+
+ if (val)
+ *val = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static const struct proto_desc *proto_lookup_byname(const char *name)
+{
+ const struct proto_desc *proto_tbl[] = {
+ &proto_eth,
+ &proto_vlan,
+ &proto_arp,
+ &proto_ip,
+ &proto_icmp,
+ &proto_igmp,
+ &proto_ip6,
+ &proto_icmp6,
+ &proto_ah,
+ &proto_esp,
+ &proto_comp,
+ &proto_udp,
+ &proto_udplite,
+ &proto_tcp,
+ &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;
+
+ for (i = 0; i < array_size(proto_tbl); i++) {
+ if (!strcmp(proto_tbl[i]->name, name))
+ return proto_tbl[i];
+ }
+ return NULL;
+}
+
+static struct expr *json_parse_payload_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const char *tunnel, *protocol, *field, *base;
+ int offset, len, val;
+ struct expr *expr;
+
+ if (!json_unpack(root, "{s:s, s:i, s:i}",
+ "base", &base, "offset", &offset, "len", &len)) {
+ if (!strcmp(base, "ll")) {
+ val = PROTO_BASE_LL_HDR;
+ } else if (!strcmp(base, "nh")) {
+ val = PROTO_BASE_NETWORK_HDR;
+ } else if (!strcmp(base, "th")) {
+ val = PROTO_BASE_TRANSPORT_HDR;
+ } else if (!strcmp(base, "ih")) {
+ val = PROTO_BASE_INNER_HDR;
+ } else {
+ json_error(ctx, "Invalid payload base '%s'.", base);
+ return NULL;
+ }
+ 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);
+
+ 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);
+
+ if (proto == &proto_th)
+ expr->payload.is_raw = true;
+
+ return expr;
+ }
+ json_error(ctx, "Invalid payload expression properties.");
+ return NULL;
+}
+
+static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ int fieldval, kind, offset, len;
+ const char *desc, *field;
+ struct expr *expr;
+
+ if (!json_unpack(root, "{s:i, s:i, s:i}",
+ "base", &kind, "offset", &offset, "len", &len)) {
+ uint32_t flag = 0;
+
+ if (kind < 0 || kind > 255)
+ return NULL;
+
+ expr = tcpopt_expr_alloc(int_loc, kind,
+ TCPOPT_COMMON_KIND);
+
+ if (offset == TCPOPT_COMMON_KIND && len == 8)
+ flag = NFT_EXTHDR_F_PRESENT;
+
+ tcpopt_init_raw(expr, kind, offset, len, flag);
+ return expr;
+ } else if (!json_unpack(root, "{s:s}", "name", &desc)) {
+ if (json_parse_tcp_option_type(desc, &kind)) {
+ json_error(ctx, "Unknown tcp option name '%s'.", desc);
+ return NULL;
+ }
+
+ if (json_unpack(root, "{s:s}", "field", &field)) {
+ expr = tcpopt_expr_alloc(int_loc, kind,
+ TCPOPT_COMMON_KIND);
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ return expr;
+ }
+
+ if (json_parse_tcp_option_field(kind, field, &fieldval)) {
+ json_error(ctx, "Unknown tcp option field '%s'.", field);
+ return NULL;
+ }
+
+ return tcpopt_expr_alloc(int_loc, kind, fieldval);
+ }
+
+ json_error(ctx, "Invalid tcp option expression properties.");
+ return NULL;
+}
+
+static int json_parse_ip_option_type(const char *name, int *val)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(ipopt_protocols); i++) {
+ if (ipopt_protocols[i] &&
+ !strcmp(ipopt_protocols[i]->name, name)) {
+ if (val)
+ *val = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int json_parse_ip_option_field(int type, const char *name, int *val)
+{
+ unsigned int i;
+ const struct exthdr_desc *desc = ipopt_protocols[type];
+
+ for (i = 0; i < array_size(desc->templates); i++) {
+ if (desc->templates[i].token &&
+ !strcmp(desc->templates[i].token, name)) {
+ if (val)
+ *val = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static struct expr *json_parse_ip_option_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const char *desc, *field;
+ int descval, fieldval;
+ struct expr *expr;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "name", &desc))
+ return NULL;
+
+ if (json_parse_ip_option_type(desc, &descval)) {
+ json_error(ctx, "Unknown ip option name '%s'.", desc);
+ return NULL;
+ }
+
+ if (json_unpack(root, "{s:s}", "field", &field)) {
+ expr = ipopt_expr_alloc(int_loc, descval,
+ IPOPT_FIELD_TYPE);
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+
+ return expr;
+ }
+ if (json_parse_ip_option_field(descval, field, &fieldval)) {
+ json_error(ctx, "Unknown ip option field '%s'.", field);
+ return NULL;
+ }
+ return ipopt_expr_alloc(int_loc, descval, fieldval);
+}
+
+static int json_parse_sctp_chunk_field(const struct exthdr_desc *desc,
+ const char *name, int *val)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(desc->templates); i++) {
+ if (desc->templates[i].token &&
+ !strcmp(desc->templates[i].token, name)) {
+ if (val)
+ *val = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static struct expr *json_parse_sctp_chunk_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const struct exthdr_desc *desc;
+ const char *name, *field;
+ struct expr *expr;
+ int fieldval;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "name", &name))
+ return NULL;
+
+ desc = sctp_chunk_protocol_find(name);
+ if (!desc) {
+ json_error(ctx, "Unknown sctp chunk name '%s'.", name);
+ return NULL;
+ }
+
+ if (json_unpack(root, "{s:s}", "field", &field)) {
+ expr = sctp_chunk_expr_alloc(int_loc, desc->type,
+ SCTP_CHUNK_COMMON_TYPE);
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+
+ return expr;
+ }
+ if (json_parse_sctp_chunk_field(desc, field, &fieldval)) {
+ json_error(ctx, "Unknown sctp chunk field '%s'.", field);
+ return NULL;
+ }
+ return sctp_chunk_expr_alloc(int_loc, desc->type, fieldval);
+}
+
+static struct expr *json_parse_dccp_option_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ int opt_type;
+
+ if (json_unpack_err(ctx, root, "{s:i}", "type", &opt_type))
+ return NULL;
+
+ if (opt_type < DCCPOPT_TYPE_MIN || opt_type > DCCPOPT_TYPE_MAX) {
+ json_error(ctx, "Unknown dccp option type '%d'.", opt_type);
+ return NULL;
+ }
+
+ return dccpopt_expr_alloc(int_loc, opt_type);
+}
+
+static const struct exthdr_desc *exthdr_lookup_byname(const char *name)
+{
+ const struct exthdr_desc *exthdr_tbl[] = {
+ &exthdr_hbh,
+ &exthdr_rt,
+ &exthdr_rt0,
+ &exthdr_rt2,
+ &exthdr_rt4,
+ &exthdr_frag,
+ &exthdr_dst,
+ &exthdr_mh,
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(exthdr_tbl); i++) {
+ if (!strcmp(exthdr_tbl[i]->name, name))
+ return exthdr_tbl[i];
+ }
+ return NULL;
+}
+
+static int json_parse_exthdr_field(const struct exthdr_desc *desc,
+ const char *name, int *field)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(desc->templates); i++) {
+ if (desc->templates[i].token &&
+ !strcmp(desc->templates[i].token, name)) {
+ if (field)
+ *field = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static struct expr *json_parse_exthdr_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const char *name, *field = NULL;
+ struct expr *expr;
+ int offset = 0, fieldval;
+ const struct exthdr_desc *desc;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "name", &name))
+ return NULL;
+
+ desc = exthdr_lookup_byname(name);
+ if (!desc) {
+ json_error(ctx, "Invalid exthdr protocol '%s'.", name);
+ return NULL;
+ }
+
+ if (json_unpack(root, "{s:s}", "field", &field)) {
+ expr = exthdr_expr_alloc(int_loc, desc, 1);
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ return expr;
+ }
+
+ if (json_parse_exthdr_field(desc, field, &fieldval)) {
+ json_error(ctx, "Unknown %s field %s.", desc->name, field);
+ return NULL;
+ }
+
+ /* special treatment for rt0 */
+ if (desc == &exthdr_rt0 &&
+ json_unpack_err(ctx, root, "{s:i}", "offset", &offset))
+ return NULL;
+
+ return exthdr_expr_alloc(int_loc, desc, fieldval + offset);
+}
+
+static struct expr *json_parse_rt_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const struct {
+ const char *name;
+ int val;
+ } rt_key_tbl[] = {
+ { "classid", NFT_RT_CLASSID },
+ { "nexthop", NFT_RT_NEXTHOP4 },
+ { "mtu", NFT_RT_TCPMSS },
+ { "ipsec", NFT_RT_XFRM },
+ };
+ const char *key;
+ unsigned int i;
+ int familyval;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "key", &key))
+ return NULL;
+ familyval = json_parse_family(ctx, root);
+ if (familyval < 0)
+ return NULL;
+
+ for (i = 0; i < array_size(rt_key_tbl); i++) {
+ int val = rt_key_tbl[i].val;
+ bool invalid = true;
+
+ if (strcmp(key, rt_key_tbl[i].name))
+ continue;
+
+ if (familyval) {
+ if (familyval == NFPROTO_IPV6 &&
+ val == NFT_RT_NEXTHOP4)
+ val = NFT_RT_NEXTHOP6;
+ invalid = false;
+ }
+ return rt_expr_alloc(int_loc, val, invalid);
+ }
+ json_error(ctx, "Unknown rt key '%s'.", key);
+ return NULL;
+}
+
+static bool ct_key_is_dir(enum nft_ct_keys key)
+{
+ const enum nft_ct_keys ct_dir_keys[] = {
+ NFT_CT_L3PROTOCOL,
+ NFT_CT_SRC,
+ NFT_CT_DST,
+ NFT_CT_PROTOCOL,
+ NFT_CT_PROTO_SRC,
+ NFT_CT_PROTO_DST,
+ NFT_CT_PKTS,
+ NFT_CT_BYTES,
+ NFT_CT_AVGPKT,
+ NFT_CT_ZONE,
+ NFT_CT_SRC_IP,
+ NFT_CT_DST_IP,
+ NFT_CT_SRC_IP6,
+ NFT_CT_DST_IP6,
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(ct_dir_keys); i++) {
+ if (key == ct_dir_keys[i])
+ return true;
+ }
+ return false;
+}
+
+static struct expr *json_parse_ct_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ int dirval = -1, keyval = -1;
+ const char *key, *dir;
+ unsigned int i;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "key", &key))
+ return NULL;
+
+ for (i = 0; i < array_size(ct_templates); i++) {
+ if (ct_templates[i].token &&
+ !strcmp(key, ct_templates[i].token)) {
+ keyval = i;
+ break;
+ }
+ }
+ if (keyval == -1) {
+ json_error(ctx, "Unknown ct key '%s'.", key);
+ return NULL;
+ }
+
+ if (!json_unpack(root, "{s:s}", "dir", &dir)) {
+ if (!strcmp(dir, "original")) {
+ dirval = IP_CT_DIR_ORIGINAL;
+ } else if (!strcmp(dir, "reply")) {
+ dirval = IP_CT_DIR_REPLY;
+ } else {
+ json_error(ctx, "Invalid direction '%s'.", dir);
+ return NULL;
+ }
+
+ if (!ct_key_is_dir(keyval)) {
+ json_error(ctx, "Direction not supported by CT key '%s'.", key);
+ return NULL;
+ }
+ }
+
+ return ct_expr_alloc(int_loc, keyval, dirval);
+}
+
+static struct expr *json_parse_numgen_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ int modeval, mod, offset = 0;
+ const char *mode;
+
+ if (json_unpack_err(ctx, root, "{s:s, s:i}",
+ "mode", &mode, "mod", &mod))
+ return NULL;
+ json_unpack(root, "{s:i}", "offset", &offset);
+
+ if (!strcmp(mode, "inc")) {
+ modeval = NFT_NG_INCREMENTAL;
+ } else if (!strcmp(mode, "random")) {
+ modeval = NFT_NG_RANDOM;
+ } else {
+ json_error(ctx, "Unknown numgen mode '%s'.", mode);
+ return NULL;
+ }
+
+ return numgen_expr_alloc(int_loc, modeval, mod, offset);
+}
+
+static struct expr *json_parse_hash_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ int mod, offset = 0, seed = 0;
+ struct expr *expr, *hash_expr;
+ bool have_seed;
+ json_t *jexpr;
+
+
+ if (json_unpack_err(ctx, root, "{s:i}", "mod", &mod))
+ return NULL;
+ json_unpack(root, "{s:i}", "offset", &offset);
+
+ if (!strcmp(type, "symhash")) {
+ return hash_expr_alloc(int_loc, mod, false, 0,
+ offset, NFT_HASH_SYM);
+ } else if (strcmp(type, "jhash")) {
+ json_error(ctx, "Unknown hash type '%s'.", type);
+ return NULL;
+ }
+
+ if (json_unpack_err(ctx, root, "{s:o}", "expr", &jexpr))
+ return NULL;
+ expr = json_parse_expr(ctx, jexpr);
+ if (!expr) {
+ json_error(ctx, "Invalid jhash expression.");
+ return NULL;
+ }
+ have_seed = !json_unpack(root, "{s:i}", "seed", &seed);
+
+ hash_expr = hash_expr_alloc(int_loc, mod, have_seed,
+ seed, offset, NFT_HASH_JENKINS);
+ hash_expr->hash.expr = expr;
+ return hash_expr;
+}
+
+static int fib_flag_parse(const char *name, int *flags)
+{
+ const char *fib_flags[] = {
+ "saddr",
+ "daddr",
+ "mark",
+ "iif",
+ "oif",
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(fib_flags); i++) {
+ if (!strcmp(name, fib_flags[i])) {
+ *flags |= (1 << i);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static struct expr *json_parse_fib_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const char *fib_result_tbl[] = {
+ [NFT_FIB_RESULT_UNSPEC] = NULL,
+ [NFT_FIB_RESULT_OIF] = "oif",
+ [NFT_FIB_RESULT_OIFNAME] = "oifname",
+ [NFT_FIB_RESULT_ADDRTYPE] = "type",
+ };
+ enum nft_fib_result resultval = NFT_FIB_RESULT_UNSPEC;
+ json_t *flags, *value;
+ const char *result;
+ unsigned int i;
+ size_t index;
+ int flagval = 0;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "result", &result))
+ return NULL;
+
+ for (i = 1; i < array_size(fib_result_tbl); i++) {
+ if (!strcmp(result, fib_result_tbl[i])) {
+ resultval = i;
+ break;
+ }
+ }
+ if (resultval == NFT_FIB_RESULT_UNSPEC) {
+ json_error(ctx, "Invalid fib result '%s'.", result);
+ return NULL;
+ }
+
+ if (!json_unpack(root, "{s:o}", "flags", &flags)) {
+ const char *flag;
+
+ if (json_is_string(flags)) {
+ flag = json_string_value(flags);
+
+ if (fib_flag_parse(flag, &flagval)) {
+ json_error(ctx, "Invalid fib flag '%s'.", flag);
+ return NULL;
+ }
+ } else if (!json_is_array(flags)) {
+ json_error(ctx, "Unexpected object type in fib tuple.");
+ return NULL;
+ }
+
+ json_array_foreach(flags, index, value) {
+ if (!json_is_string(value)) {
+ json_error(ctx, "Unexpected object type in fib flags array at index %zd.", index);
+ return NULL;
+ }
+ flag = json_string_value(value);
+
+ if (fib_flag_parse(flag, &flagval)) {
+ json_error(ctx, "Invalid fib flag '%s'.", flag);
+ return NULL;
+ }
+ }
+ }
+
+ /* sanity checks from fib_expr in parser_bison.y */
+
+ if ((flagval & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) {
+ json_error(ctx, "fib: need either saddr or daddr");
+ return NULL;
+ }
+
+ if ((flagval & (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)) {
+ json_error(ctx, "fib: iif and oif are mutually exclusive");
+ return NULL;
+ }
+
+ return fib_expr_alloc(int_loc, flagval, resultval);
+}
+
+static struct expr *json_parse_binop_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const struct {
+ const char *type;
+ enum ops op;
+ } op_tbl[] = {
+ { "|", OP_OR },
+ { "^", OP_XOR },
+ { "&", OP_AND },
+ { ">>", OP_RSHIFT },
+ { "<<", OP_LSHIFT },
+ };
+ enum ops thisop = OP_INVALID;
+ struct expr *left, *right;
+ json_t *jleft, *jright;
+ unsigned int i;
+
+ for (i = 0; i < array_size(op_tbl); i++) {
+ if (strcmp(type, op_tbl[i].type))
+ continue;
+
+ thisop = op_tbl[i].op;
+ break;
+ }
+ if (thisop == OP_INVALID) {
+ json_error(ctx, "Invalid binop type '%s'.", type);
+ return NULL;
+ }
+
+ if (json_unpack_err(ctx, root, "[o, o!]", &jleft, &jright))
+ return NULL;
+
+ left = json_parse_primary_expr(ctx, jleft);
+ if (!left) {
+ json_error(ctx, "Failed to parse LHS of binop expression.");
+ return NULL;
+ }
+ right = json_parse_rhs_expr(ctx, jright);
+ if (!right) {
+ json_error(ctx, "Failed to parse RHS of binop expression.");
+ expr_free(left);
+ return NULL;
+ }
+ return binop_expr_alloc(int_loc, thisop, left, right);
+}
+
+static struct expr *json_parse_concat_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ struct expr *expr = NULL, *tmp;
+ json_t *value;
+ size_t index;
+
+ if (!json_is_array(root)) {
+ json_error(ctx, "Unexpected concat object type %s.",
+ json_typename(root));
+ return NULL;
+ }
+
+ json_array_foreach(root, index, value) {
+ tmp = json_parse_concat_elem_expr(ctx, value);
+ if (!tmp) {
+ json_error(ctx, "Parsing expr at index %zd failed.", index);
+ expr_free(expr);
+ return NULL;
+ }
+ if (!expr) {
+ expr = tmp;
+ continue;
+ }
+ if (expr->etype != EXPR_CONCAT) {
+ struct expr *concat;
+
+ concat = concat_expr_alloc(int_loc);
+ compound_expr_add(concat, expr);
+ expr = concat;
+ }
+ compound_expr_add(expr, tmp);
+ }
+ return expr;
+}
+
+static struct expr *json_parse_prefix_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ struct expr *expr;
+ json_t *addr;
+ int len;
+
+ if (json_unpack_err(ctx, root, "{s:o, s:i}",
+ "addr", &addr, "len", &len))
+ return NULL;
+
+ expr = json_parse_primary_expr(ctx, addr);
+ if (!expr) {
+ json_error(ctx, "Invalid address in prefix expr.");
+ return NULL;
+ }
+ return prefix_expr_alloc(int_loc, expr, len);
+}
+
+static struct expr *json_parse_range_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ struct expr *expr_low, *expr_high;
+ json_t *low, *high;
+
+ if (json_unpack_err(ctx, root, "[o, o!]", &low, &high))
+ return NULL;
+
+ expr_low = json_parse_primary_expr(ctx, low);
+ if (!expr_low) {
+ json_error(ctx, "Invalid low value in range expression.");
+ return NULL;
+ }
+ expr_high = json_parse_primary_expr(ctx, high);
+ if (!expr_high) {
+ json_error(ctx, "Invalid high value in range expression.");
+ return NULL;
+ }
+ return range_expr_alloc(int_loc, expr_low, expr_high);
+}
+
+static struct expr *json_alloc_chain_expr(const char *chain)
+{
+ if (!chain)
+ return NULL;
+
+ return constant_expr_alloc(int_loc, &string_type, BYTEORDER_HOST_ENDIAN,
+ strlen(chain) * BITS_PER_BYTE, chain);
+}
+
+static struct expr *json_parse_verdict_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const struct {
+ int verdict;
+ const char *name;
+ bool need_chain;
+ } verdict_tbl[] = {
+ { NFT_CONTINUE, "continue", false },
+ { NFT_JUMP, "jump", true },
+ { NFT_GOTO, "goto", true },
+ { NFT_RETURN, "return", false },
+ { NF_ACCEPT, "accept", false },
+ { NF_DROP, "drop", false },
+ };
+ const char *chain = NULL;
+ unsigned int i;
+
+ for (i = 0; i < array_size(verdict_tbl); i++) {
+ if (strcmp(type, verdict_tbl[i].name))
+ continue;
+
+ if (verdict_tbl[i].need_chain &&
+ json_unpack_err(ctx, root, "{s:s}", "target", &chain))
+ return NULL;
+
+ return verdict_expr_alloc(int_loc, verdict_tbl[i].verdict,
+ json_alloc_chain_expr(chain));
+ }
+ json_error(ctx, "Unknown verdict '%s'.", type);
+ return NULL;
+}
+
+static struct expr *json_parse_set_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ struct expr *expr, *set_expr = NULL;
+ json_t *value;
+ size_t index;
+
+ if (!json_is_array(root)) {
+ expr = json_parse_immediate(ctx, root);
+ if (!expr)
+ return NULL;
+
+ if (expr->etype == EXPR_SYMBOL &&
+ expr->symtype == SYMBOL_SET)
+ return expr;
+
+ expr = set_elem_expr_alloc(int_loc, expr);
+ set_expr = set_expr_alloc(int_loc, NULL);
+ compound_expr_add(set_expr, expr);
+ return set_expr;
+ }
+
+ json_array_foreach(root, index, value) {
+ struct expr *expr;
+ json_t *jleft, *jright;
+
+ if (!json_unpack(value, "[o, o!]", &jleft, &jright)) {
+ struct expr *expr2;
+
+ expr = json_parse_rhs_expr(ctx, jleft);
+ if (!expr) {
+ json_error(ctx, "Invalid set elem at index %zu.", index);
+ expr_free(set_expr);
+ return NULL;
+ }
+ if (expr->etype != EXPR_SET_ELEM)
+ expr = set_elem_expr_alloc(int_loc, expr);
+
+ expr2 = json_parse_set_rhs_expr(ctx, jright);
+ if (!expr2) {
+ json_error(ctx, "Invalid set elem at index %zu.", index);
+ expr_free(expr);
+ expr_free(set_expr);
+ return NULL;
+ }
+ expr2 = mapping_expr_alloc(int_loc, expr, expr2);
+ expr = expr2;
+ } else {
+ expr = json_parse_rhs_expr(ctx, value);
+
+ if (!expr) {
+ json_error(ctx, "Invalid set elem at index %zu.", index);
+ expr_free(set_expr);
+ return NULL;
+ }
+
+ if (expr->etype != EXPR_SET_ELEM)
+ expr = set_elem_expr_alloc(int_loc, expr);
+ }
+
+ if (!set_expr)
+ set_expr = set_expr_alloc(int_loc, NULL);
+ compound_expr_add(set_expr, expr);
+ }
+ return set_expr;
+}
+
+static struct expr *json_parse_map_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ json_t *jkey, *jdata;
+ struct expr *key, *data;
+
+ if (json_unpack_err(ctx, root, "{s:o, s:o}",
+ "key", &jkey, "data", &jdata))
+ return NULL;
+
+ key = json_parse_map_lhs_expr(ctx, jkey);
+ if (!key) {
+ json_error(ctx, "Illegal map expression key.");
+ return NULL;
+ }
+
+ data = json_parse_rhs_expr(ctx, jdata);
+ if (!data) {
+ json_error(ctx, "Illegal map expression data.");
+ expr_free(key);
+ return NULL;
+ }
+
+ return map_expr_alloc(int_loc, key, data);
+}
+
+static struct expr *json_parse_set_elem_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ struct expr *expr;
+ json_t *tmp;
+ uint64_t i;
+
+ if (json_unpack_err(ctx, root, "{s:o}", "val", &tmp))
+ return NULL;
+
+ expr = json_parse_expr(ctx, tmp);
+ if (!expr)
+ return NULL;
+
+ expr = set_elem_expr_alloc(int_loc, expr);
+
+ if (!json_unpack(root, "{s:I}", "timeout", &i))
+ expr->timeout = i * 1000;
+ if (!json_unpack(root, "{s:I}", "expires", &i))
+ expr->expiration = i * 1000;
+ if (!json_unpack(root, "{s:s}", "comment", &expr->comment))
+ expr->comment = xstrdup(expr->comment);
+
+ return expr;
+}
+
+static struct expr *json_parse_xfrm_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const char *key, *dir;
+ unsigned int i, spnum;
+ int dirval = -1, familyval, keyval = -1;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "key", &key))
+ return NULL;
+
+ for (i = 1; i < array_size(xfrm_templates); i++) {
+ if (strcmp(key, xfrm_templates[i].token))
+ continue;
+ keyval = i;
+ break;
+ }
+
+ if (keyval == -1) {
+ json_error(ctx, "Unknown xfrm key '%s'.", key);
+ return NULL;
+ }
+
+ familyval = json_parse_family(ctx, root);
+ if (familyval < 0)
+ return NULL;
+
+ if (!json_unpack(root, "{s:s}", "dir", &dir)) {
+ if (!strcmp(dir, "in")) {
+ dirval = XFRM_POLICY_IN;
+ } else if (!strcmp(dir, "out")) {
+ dirval = XFRM_POLICY_OUT;
+ } else {
+ json_error(ctx, "Invalid direction '%s'.", dir);
+ return NULL;
+ }
+ }
+
+ spnum = 0;
+ if (!json_unpack(root, "{s:i}", "spnum", &spnum)) {
+ if (spnum > 255) {
+ json_error(ctx, "Invalid spnum'%d'.", spnum);
+ return NULL;
+ }
+ }
+
+ switch (keyval) {
+ case NFT_XFRM_KEY_SADDR_IP4:
+ if (familyval == NFPROTO_IPV6)
+ keyval = NFT_XFRM_KEY_SADDR_IP6;
+ break;
+ case NFT_XFRM_KEY_DADDR_IP4:
+ if (familyval == NFPROTO_IPV6)
+ keyval = NFT_XFRM_KEY_DADDR_IP6;
+ break;
+ default:
+ break;
+ }
+
+ return xfrm_expr_alloc(int_loc, dirval, spnum, keyval);
+}
+
+static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root)
+{
+ const struct {
+ const char *name;
+ struct expr *(*cb)(struct json_ctx *, const char *, json_t *);
+ uint32_t flags;
+ } cb_tbl[] = {
+ { "concat", json_parse_concat_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_DTYPE | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
+ { "set", json_parse_set_expr, CTX_F_RHS | CTX_F_STMT }, /* allow this as stmt expr because that allows set references */
+ { "map", json_parse_map_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS },
+ /* below three are multiton_rhs_expr */
+ { "prefix", json_parse_prefix_expr, CTX_F_RHS | CTX_F_SET_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "range", json_parse_range_expr, CTX_F_RHS | CTX_F_SET_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "payload", json_parse_payload_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "sctp chunk", json_parse_sctp_chunk_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "dccp option", json_parse_dccp_option_expr, CTX_F_PRIMARY },
+ { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "socket", json_parse_socket_expr, CTX_F_PRIMARY | CTX_F_CONCAT },
+ { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ /* below two are hash expr */
+ { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "fib", json_parse_fib_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "|", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "^", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "&", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { ">>", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "<<", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "accept", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
+ { "drop", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
+ { "continue", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
+ { "jump", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
+ { "goto", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
+ { "return", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
+ { "elem", json_parse_set_elem_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SES },
+ };
+ struct expr *list;
+ const char *type;
+ unsigned int i;
+ json_t *value;
+ size_t index;
+
+
+ switch (json_typeof(root)) {
+ case JSON_ARRAY:
+ if (!(ctx->flags & (CTX_F_RHS | CTX_F_STMT))) {
+ json_error(ctx, "List expression only allowed on RHS or in statement expression.");
+ return NULL;
+ }
+
+ if (is_PRIMARY(ctx)) {
+ json_error(ctx, "List expression not allowed as primary expression.");
+ return NULL;
+ }
+
+ list = list_expr_alloc(int_loc);
+ json_array_foreach(root, index, value) {
+ struct expr *expr = json_parse_expr(ctx, value);
+ if (!expr) {
+ json_error(ctx, "Parsing list expression item at index %zu failed.", index);
+ expr_free(list);
+ return NULL;
+ }
+ compound_expr_add(list, expr);
+ }
+ return list;
+ case JSON_TRUE:
+ case JSON_FALSE:
+ if (!is_RHS(ctx) && !is_PRIMARY(ctx)) {
+ json_error(ctx, "Boolean values not allowed in this context.");
+ return NULL;
+ }
+ /* fall through */
+ case JSON_STRING:
+ case JSON_INTEGER:
+ return json_parse_immediate(ctx, root);
+ default:
+ break;
+ }
+
+ if (json_unpack_stmt(ctx, root, &type, &value))
+ return NULL;
+
+ for (i = 0; i < array_size(cb_tbl); i++) {
+ if (strcmp(type, cb_tbl[i].name))
+ continue;
+
+ if ((cb_tbl[i].flags & ctx->flags) != ctx->flags) {
+ json_error(ctx, "Expression type %s not allowed in context (%s).",
+ type, ctx_flags_to_string(ctx));
+ return NULL;
+ }
+
+ return cb_tbl[i].cb(ctx, type, value);
+ }
+ json_error(ctx, "Unknown expression type '%s'.", type);
+ return NULL;
+}
+
+static struct expr *json_parse_flagged_expr(struct json_ctx *ctx,
+ uint32_t flags, json_t *root)
+{
+ uint32_t old_flags = ctx->flags;
+ struct expr *expr;
+
+ ctx->flags |= flags;
+ expr = json_parse_expr(ctx, root);
+ ctx->flags = old_flags;
+
+ return expr;
+}
+
+static struct expr *json_parse_rhs_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_RHS, root);
+}
+
+static struct expr *json_parse_stmt_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_STMT, root);
+}
+
+static struct expr *json_parse_primary_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_PRIMARY, root);
+}
+
+static struct expr *json_parse_set_rhs_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_SET_RHS, root);
+}
+
+static struct expr *json_parse_mangle_lhs_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_MANGLE, root);
+}
+
+static struct expr *json_parse_set_elem_expr_stmt(struct json_ctx *ctx, json_t *root)
+{
+ struct expr *expr = json_parse_flagged_expr(ctx, CTX_F_SES, root);
+
+ if (expr && expr->etype != EXPR_SET_ELEM)
+ expr = set_elem_expr_alloc(int_loc, expr);
+
+ return expr;
+}
+
+static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_MAP, root);
+}
+
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_CONCAT, root);
+}
+
+static struct expr *json_parse_dtype_expr(struct json_ctx *ctx, json_t *root)
+{
+ if (json_is_string(root)) {
+ const struct datatype *dtype;
+
+ dtype = datatype_lookup_byname(json_string_value(root));
+ if (!dtype) {
+ json_error(ctx, "Invalid datatype '%s'.",
+ json_string_value(root));
+ return NULL;
+ }
+ return constant_expr_alloc(int_loc, dtype,
+ dtype->byteorder, dtype->size, NULL);
+ } else if (json_is_array(root)) {
+ json_t *value;
+ size_t index;
+ struct expr *expr = concat_expr_alloc(int_loc);
+
+ json_array_foreach(root, index, value) {
+ struct expr *i = json_parse_dtype_expr(ctx, value);
+
+ if (!i) {
+ json_error(ctx, "Invalid datatype at index %zu.", index);
+ expr_free(expr);
+ return NULL;
+ }
+ compound_expr_add(expr, i);
+ }
+ return expr;
+ }
+ json_error(ctx, "Invalid set datatype.");
+ return NULL;
+}
+
+static struct stmt *json_parse_match_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct expr *left, *right, *rel_expr;
+ json_t *jleft, *jright;
+ const char *opstr = NULL;
+ enum ops op;
+
+ if (json_unpack_err(ctx, value, "{s:o, s:o, s:s}",
+ "left", &jleft,
+ "right", &jright,
+ "op", &opstr))
+ return NULL;
+
+ for (op = OP_INVALID; op < __OP_MAX; op++) {
+ if (expr_op_symbols[op] &&
+ !strcmp(opstr, expr_op_symbols[op]))
+ break;
+ }
+ switch (op) {
+ case OP_EQ ... OP_NEG:
+ break;
+ case __OP_MAX:
+ if (!strcmp(opstr, "in")) {
+ op = OP_IMPLICIT;
+ break;
+ }
+ /* fall through */
+ default:
+ json_error(ctx, "Invalid relational op '%s'.", opstr);
+ return NULL;
+ }
+
+ left = json_parse_expr(ctx, jleft);
+ if (!left) {
+ json_error(ctx, "Invalid LHS of relational.");
+ return NULL;
+ }
+ right = json_parse_rhs_expr(ctx, jright);
+ if (!right) {
+ expr_free(left);
+ json_error(ctx, "Invalid RHS of relational.");
+ return NULL;
+ }
+
+ rel_expr = relational_expr_alloc(int_loc, op, left, right);
+ return expr_stmt_alloc(int_loc, rel_expr);
+}
+
+static struct stmt *json_parse_counter_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ uint64_t packets, bytes;
+ struct stmt *stmt;
+
+ if (json_is_null(value))
+ return counter_stmt_alloc(int_loc);
+
+ if (!json_unpack(value, "{s:I, s:I}",
+ "packets", &packets,
+ "bytes", &bytes)) {
+ stmt = counter_stmt_alloc(int_loc);
+ stmt->counter.packets = packets;
+ stmt->counter.bytes = bytes;
+ return stmt;
+ }
+
+ stmt = objref_stmt_alloc(int_loc);
+ stmt->objref.type = NFT_OBJECT_COUNTER;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid counter reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ 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)
+{
+ struct expr *expr;
+
+ expr = json_parse_verdict_expr(ctx, key, value);
+ if (expr)
+ return verdict_stmt_alloc(int_loc, expr);
+
+ return NULL;
+}
+
+static struct stmt *json_parse_mangle_stmt(struct json_ctx *ctx,
+ 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))
+ return NULL;
+
+ key = json_parse_mangle_lhs_expr(ctx, jkey);
+ if (!key) {
+ json_error(ctx, "Invalid mangle statement key");
+ return NULL;
+ }
+ value = json_parse_stmt_expr(ctx, jvalue);
+ if (!value) {
+ json_error(ctx, "Invalid mangle statement value");
+ expr_free(key);
+ return NULL;
+ }
+
+ switch (key->etype) {
+ case EXPR_EXTHDR:
+ return exthdr_stmt_alloc(int_loc, key, value);
+ case EXPR_PAYLOAD:
+ return payload_stmt_alloc(int_loc, key, value);
+ case EXPR_META:
+ stmt = meta_stmt_alloc(int_loc, key->meta.key, value);
+ expr_free(key);
+ return stmt;
+ case EXPR_CT:
+ if (key->ct.key == NFT_CT_HELPER) {
+ stmt = objref_stmt_alloc(int_loc);
+ stmt->objref.type = NFT_OBJECT_CT_HELPER;
+ stmt->objref.expr = value;
+ } else {
+ stmt = ct_stmt_alloc(int_loc, key->ct.key,
+ key->ct.direction, value);
+ }
+ expr_free(key);
+ return stmt;
+ default:
+ json_error(ctx, "Invalid mangle statement key expression type.");
+ return NULL;
+ }
+}
+
+static uint64_t rate_to_bytes(uint64_t val, const char *unit)
+{
+ uint64_t bytes = val;
+
+ if (!strcmp(unit, "kbytes"))
+ return bytes * 1024;
+ if (!strcmp(unit, "mbytes"))
+ return bytes * 1024 * 1024;
+ return bytes;
+}
+
+static struct stmt *json_parse_quota_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt;
+ int inv = 0;
+ const char *val_unit = "bytes", *used_unit = "bytes";
+ uint64_t val, used = 0;
+
+ if (!json_unpack(value, "{s:I}", "val", &val)) {
+ json_unpack(value, "{s:b}", "inv", &inv);
+ json_unpack(value, "{s:s}", "val_unit", &val_unit);
+ json_unpack(value, "{s:I}", "used", &used);
+ json_unpack(value, "{s:s}", "used_unit", &used_unit);
+ stmt = quota_stmt_alloc(int_loc);
+ stmt->quota.bytes = rate_to_bytes(val, val_unit);
+ if (used)
+ stmt->quota.used = rate_to_bytes(used, used_unit);
+ stmt->quota.flags = (inv ? NFT_QUOTA_F_INV : 0);
+ return stmt;
+ }
+ stmt = objref_stmt_alloc(int_loc);
+ stmt->objref.type = NFT_OBJECT_QUOTA;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid quota reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ return stmt;
+}
+
+static uint64_t seconds_from_unit(const char *unit)
+{
+ if (!strcmp(unit, "week"))
+ return 60 * 60 * 24 * 7;
+ if (!strcmp(unit, "day"))
+ return 60 * 60 * 24;
+ if (!strcmp(unit, "hour"))
+ return 60 * 60;
+ if (!strcmp(unit, "minute"))
+ return 60;
+ return 1;
+}
+
+static struct stmt *json_parse_limit_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt;
+ uint64_t rate, burst = 0;
+ const char *rate_unit = "packets", *time, *burst_unit = "bytes";
+ int inv = 0;
+
+ if (!json_unpack(value, "{s:I, s:s}",
+ "rate", &rate, "per", &time)) {
+ json_unpack(value, "{s:s}", "rate_unit", &rate_unit);
+ json_unpack(value, "{s:b}", "inv", &inv);
+ json_unpack(value, "{s:I}", "burst", &burst);
+ json_unpack(value, "{s:s}", "burst_unit", &burst_unit);
+
+ 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;
+ } else {
+ stmt->limit.type = NFT_LIMIT_PKT_BYTES;
+ stmt->limit.rate = rate_to_bytes(rate, rate_unit);
+ stmt->limit.burst = rate_to_bytes(burst, burst_unit);
+ }
+ stmt->limit.unit = seconds_from_unit(time);
+ stmt->limit.flags = inv ? NFT_LIMIT_F_INV : 0;
+ return stmt;
+ }
+
+ stmt = objref_stmt_alloc(int_loc);
+ stmt->objref.type = NFT_OBJECT_LIMIT;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid limit reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ return stmt;
+}
+
+static struct stmt *json_parse_fwd_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ json_t *jaddr, *jdev;
+ struct stmt *stmt;
+ int familyval;
+
+ if (json_unpack_err(ctx, value, "{s:o}", "dev", &jdev))
+ return NULL;
+
+ stmt = fwd_stmt_alloc(int_loc);
+
+ stmt->fwd.dev = json_parse_stmt_expr(ctx, jdev);
+ if (!stmt->fwd.dev) {
+ json_error(ctx, "Invalid fwd dev value.");
+ goto out_err;
+ }
+
+ familyval = json_parse_family(ctx, value);
+ if (familyval < 0)
+ goto out_err;
+
+ if (familyval == NFPROTO_UNSPEC ||
+ json_unpack(value, "{s:o}", "addr", &jaddr))
+ return stmt;
+
+ stmt->fwd.family = familyval;
+ stmt->fwd.addr = json_parse_stmt_expr(ctx, jaddr);
+ if (!stmt->fwd.addr) {
+ json_error(ctx, "Invalid fwd addr value.");
+ goto out_err;
+ }
+
+ return stmt;
+out_err:
+ stmt_free(stmt);
+ return NULL;
+}
+
+static struct stmt *json_parse_flow_offload_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ const char *opstr, *flowtable;
+
+ if (json_unpack_err(ctx, value, "{s:s, s:s}",
+ "op", &opstr, "flowtable", &flowtable))
+ return NULL;
+
+ if (strcmp(opstr, "add")) {
+ json_error(ctx, "Unknown flow offload statement op '%s'.", opstr);
+ return NULL;
+ }
+
+ if (flowtable[0] != '@') {
+ json_error(ctx, "Illegal flowtable reference in flow offload statement.");
+ return NULL;
+ }
+
+ return flow_offload_stmt_alloc(int_loc, xstrdup(flowtable + 1));
+}
+
+static struct stmt *json_parse_notrack_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ return notrack_stmt_alloc(int_loc);
+}
+
+static struct stmt *json_parse_dup_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt;
+ struct expr *expr;
+ json_t *tmp;
+
+ if (json_unpack_err(ctx, value, "{s:o}", "addr", &tmp))
+ return NULL;
+
+ expr = json_parse_stmt_expr(ctx, tmp);
+ if (!expr) {
+ json_error(ctx, "Illegal dup addr arg.");
+ return NULL;
+ }
+
+ stmt = dup_stmt_alloc(int_loc);
+ stmt->dup.to = expr;
+
+ if (json_unpack(value, "{s:o}", "dev", &tmp))
+ return stmt;
+
+ expr = json_parse_stmt_expr(ctx, tmp);
+ if (!expr) {
+ json_error(ctx, "Illegal dup dev.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->dup.dev = expr;
+ 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)
+{
+ const struct {
+ const char *flag;
+ int val;
+ } flag_tbl[] = {
+ { "random", NF_NAT_RANGE_PROTO_RANDOM },
+ { "fully-random", NF_NAT_RANGE_PROTO_RANDOM_FULLY },
+ { "persistent", NF_NAT_RANGE_PERSISTENT },
+ { "netmap", NF_NAT_RANGE_NETMAP },
+ };
+ const char *flag;
+ unsigned int i;
+
+ assert(flags);
+
+ if (!json_is_string(root)) {
+ json_error(ctx, "Invalid nat flag type %s, expected string.",
+ json_typename(root));
+ return 1;
+ }
+ flag = json_string_value(root);
+ for (i = 0; i < array_size(flag_tbl); i++) {
+ if (!strcmp(flag, flag_tbl[i].flag)) {
+ *flags |= flag_tbl[i].val;
+ return 0;
+ }
+ }
+ json_error(ctx, "Unknown nat flag '%s'.", flag);
+ return 1;
+}
+
+static int json_parse_nat_flags(struct json_ctx *ctx, json_t *root)
+{
+ int flags = 0;
+ json_t *value;
+ size_t index;
+
+ if (json_is_string(root)) {
+ json_parse_nat_flag(ctx, root, &flags);
+ return flags;
+ } else if (!json_is_array(root)) {
+ json_error(ctx, "Invalid nat flags type %s.",
+ json_typename(root));
+ return -1;
+ }
+ json_array_foreach(root, index, value) {
+ if (json_parse_nat_flag(ctx, value, &flags))
+ json_error(ctx, "Parsing nat flag at index %zu failed.",
+ index);
+ }
+ return flags;
+}
+
+static int json_parse_nat_type_flag(struct json_ctx *ctx,
+ json_t *root, int *flags)
+{
+ const struct {
+ const char *flag;
+ int val;
+ } flag_tbl[] = {
+ { "interval", STMT_NAT_F_INTERVAL },
+ { "prefix", STMT_NAT_F_PREFIX },
+ { "concat", STMT_NAT_F_CONCAT },
+ };
+ const char *flag;
+ unsigned int i;
+
+ assert(flags);
+
+ if (!json_is_string(root)) {
+ json_error(ctx, "Invalid nat type flag type %s, expected string.",
+ json_typename(root));
+ return 1;
+ }
+ flag = json_string_value(root);
+ for (i = 0; i < array_size(flag_tbl); i++) {
+ if (!strcmp(flag, flag_tbl[i].flag)) {
+ *flags |= flag_tbl[i].val;
+ return 0;
+ }
+ }
+ json_error(ctx, "Unknown nat type flag '%s'.", flag);
+ return 1;
+}
+
+static int json_parse_nat_type_flags(struct json_ctx *ctx, json_t *root)
+{
+ int flags = 0;
+ json_t *value;
+ size_t index;
+
+ if (json_is_string(root)) {
+ json_parse_nat_type_flag(ctx, root, &flags);
+ return flags;
+ } else if (!json_is_array(root)) {
+ json_error(ctx, "Invalid nat flags type %s.",
+ json_typename(root));
+ return -1;
+ }
+ json_array_foreach(root, index, value) {
+ if (json_parse_nat_type_flag(ctx, value, &flags))
+ json_error(ctx, "Parsing nat type flag at index %zu failed.",
+ index);
+ }
+ return flags;
+}
+
+static int nat_type_parse(const char *type)
+{
+ const char * const nat_etypes[] = {
+ [NFT_NAT_SNAT] = "snat",
+ [NFT_NAT_DNAT] = "dnat",
+ [NFT_NAT_MASQ] = "masquerade",
+ [NFT_NAT_REDIR] = "redirect",
+ };
+ size_t i;
+
+ for (i = 0; i < array_size(nat_etypes); i++) {
+ if (!strcmp(type, nat_etypes[i]))
+ return i;
+ }
+ return -1;
+}
+
+static struct stmt *json_parse_nat_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ int type, familyval;
+ struct stmt *stmt;
+ json_t *tmp;
+
+ type = nat_type_parse(key);
+ if (type < 0) {
+ json_error(ctx, "Unknown nat type '%s'.", key);
+ return NULL;
+ }
+
+ familyval = json_parse_family(ctx, value);
+ if (familyval < 0)
+ return NULL;
+
+ stmt = nat_stmt_alloc(int_loc, type);
+ stmt->nat.family = familyval;
+
+ if (!json_unpack(value, "{s:o}", "addr", &tmp)) {
+ stmt->nat.addr = json_parse_stmt_expr(ctx, tmp);
+ if (!stmt->nat.addr) {
+ json_error(ctx, "Invalid nat addr.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ }
+ if (!json_unpack(value, "{s:o}", "port", &tmp)) {
+ stmt->nat.proto = json_parse_stmt_expr(ctx, tmp);
+ if (!stmt->nat.proto) {
+ json_error(ctx, "Invalid nat port.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ }
+ if (!json_unpack(value, "{s:o}", "flags", &tmp)) {
+ int flags = json_parse_nat_flags(ctx, tmp);
+
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->nat.flags = flags;
+ }
+ if (!json_unpack(value, "{s:o}", "type_flags", &tmp)) {
+ int flags = json_parse_nat_type_flags(ctx, tmp);
+
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->nat.type_flags = flags;
+ }
+
+ return stmt;
+}
+
+static struct stmt *json_parse_tproxy_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ json_t *jaddr, *tmp;
+ struct stmt *stmt;
+ int familyval;
+
+ stmt = tproxy_stmt_alloc(int_loc);
+
+ familyval = json_parse_family(ctx, value);
+ if (familyval < 0)
+ goto out_free;
+
+ stmt->tproxy.family = familyval;
+
+ if (!json_unpack(value, "{s:o}", "addr", &jaddr)) {
+ stmt->tproxy.addr = json_parse_stmt_expr(ctx, jaddr);
+ if (!stmt->tproxy.addr) {
+ json_error(ctx, "Invalid addr.");
+ goto out_free;
+ }
+ }
+ if (!json_unpack(value, "{s:o}", "port", &tmp)) {
+ stmt->tproxy.port = json_parse_stmt_expr(ctx, tmp);
+ if (!stmt->tproxy.port) {
+ json_error(ctx, "Invalid port.");
+ goto out_free;
+ }
+ }
+ return stmt;
+
+out_free:
+ stmt_free(stmt);
+ return NULL;
+}
+
+static struct stmt *json_parse_reject_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt = reject_stmt_alloc(int_loc);
+ const struct datatype *dtype = NULL;
+ const char *type;
+ json_t *tmp;
+
+ stmt->reject.type = -1;
+ stmt->reject.icmp_code = -1;
+
+ if (!json_unpack(value, "{s:s}", "type", &type)) {
+ if (!strcmp(type, "tcp reset")) {
+ stmt->reject.type = NFT_REJECT_TCP_RST;
+ stmt->reject.icmp_code = 0;
+ } else if (!strcmp(type, "icmpx")) {
+ stmt->reject.type = NFT_REJECT_ICMPX_UNREACH;
+ dtype = &icmpx_code_type;
+ stmt->reject.icmp_code = 0;
+ } else if (!strcmp(type, "icmp")) {
+ stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
+ stmt->reject.family = NFPROTO_IPV4;
+ dtype = &icmp_code_type;
+ stmt->reject.icmp_code = 0;
+ } else if (!strcmp(type, "icmpv6")) {
+ stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
+ stmt->reject.family = NFPROTO_IPV6;
+ dtype = &icmpv6_code_type;
+ stmt->reject.icmp_code = 0;
+ }
+ }
+ if (!json_unpack(value, "{s:o}", "expr", &tmp)) {
+ stmt->reject.expr = json_parse_immediate(ctx, tmp);
+ if (!stmt->reject.expr) {
+ json_error(ctx, "Illegal reject expr.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ datatype_set(stmt->reject.expr, dtype);
+ }
+ 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 *opstr, *set;
+ struct expr *expr, *expr2;
+ json_t *elem, *stmt_json;
+ struct stmt *stmt;
+ int op;
+
+ if (json_unpack_err(ctx, value, "{s:s, s:o, s:s}",
+ "op", &opstr, "elem", &elem, "set", &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 set statement op '%s'.", opstr);
+ return NULL;
+ }
+
+ expr = json_parse_set_elem_expr_stmt(ctx, elem);
+ if (!expr) {
+ json_error(ctx, "Illegal set statement element.");
+ return NULL;
+ }
+
+ if (set[0] != '@') {
+ json_error(ctx, "Illegal set reference in set statement.");
+ expr_free(expr);
+ return NULL;
+ }
+ expr2 = symbol_expr_alloc(int_loc, SYMBOL_SET, NULL, set + 1);
+
+ stmt = set_stmt_alloc(int_loc);
+ 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;
+}
+
+static int json_parse_log_flag(struct json_ctx *ctx,
+ json_t *root, int *flags)
+{
+ const struct {
+ const char *flag;
+ int val;
+ } flag_tbl[] = {
+ { "tcp sequence", NF_LOG_TCPSEQ },
+ { "tcp options", NF_LOG_TCPOPT },
+ { "ip options", NF_LOG_IPOPT },
+ { "skuid", NF_LOG_UID },
+ { "ether", NF_LOG_MACDECODE },
+ { "all", NF_LOG_MASK },
+ };
+ const char *flag;
+ unsigned int i;
+
+ assert(flags);
+
+ if (!json_is_string(root)) {
+ json_error(ctx, "Invalid log flag type %s, expected string.",
+ json_typename(root));
+ return 1;
+ }
+ flag = json_string_value(root);
+ for (i = 0; i < array_size(flag_tbl); i++) {
+ if (!strcmp(flag, flag_tbl[i].flag)) {
+ *flags |= flag_tbl[i].val;
+ return 0;
+ }
+ }
+ json_error(ctx, "Unknown log flag '%s'.", flag);
+ return 1;
+}
+
+static int json_parse_log_flags(struct json_ctx *ctx, json_t *root)
+{
+ int flags = 0;
+ json_t *value;
+ size_t index;
+
+ if (json_is_string(root)) {
+ json_parse_log_flag(ctx, root, &flags);
+ return flags;
+ } else if (!json_is_array(root)) {
+ json_error(ctx, "Invalid log flags type %s.",
+ json_typename(root));
+ return -1;
+ }
+ json_array_foreach(root, index, value) {
+ if (json_parse_log_flag(ctx, value, &flags))
+ json_error(ctx, "Parsing log flag at index %zu failed.",
+ index);
+ }
+ return flags;
+}
+
+static struct stmt *json_parse_log_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ const char *tmpstr;
+ struct stmt *stmt;
+ json_t *jflags;
+ int tmp;
+
+ stmt = log_stmt_alloc(int_loc);
+
+ if (!json_unpack(value, "{s:s}", "prefix", &tmpstr)) {
+ stmt->log.prefix = constant_expr_alloc(int_loc, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(tmpstr) + 1) * BITS_PER_BYTE, tmpstr);
+ stmt->log.flags |= STMT_LOG_PREFIX;
+ }
+ if (!json_unpack(value, "{s:i}", "group", &tmp)) {
+ stmt->log.group = tmp;
+ stmt->log.flags |= STMT_LOG_GROUP;
+ }
+ if (!json_unpack(value, "{s:i}", "snaplen", &tmp)) {
+ stmt->log.snaplen = tmp;
+ stmt->log.flags |= STMT_LOG_SNAPLEN;
+ }
+ if (!json_unpack(value, "{s:i}", "queue-threshold", &tmp)) {
+ stmt->log.qthreshold = tmp;
+ stmt->log.flags |= STMT_LOG_QTHRESHOLD;
+ }
+ if (!json_unpack(value, "{s:s}", "level", &tmpstr)) {
+ int level = log_level_parse(tmpstr);
+
+ if (level < 0) {
+ json_error(ctx, "Invalid log level '%s'.", tmpstr);
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->log.level = level;
+ stmt->log.flags |= STMT_LOG_LEVEL;
+ }
+ if (!json_unpack(value, "{s:o}", "flags", &jflags)) {
+ int flags = json_parse_log_flags(ctx, jflags);
+
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->log.logflags = flags;
+ }
+ return stmt;
+}
+
+static int json_parse_synproxy_flag(struct json_ctx *ctx,
+ json_t *root, int *flags)
+{
+ const struct {
+ const char *flag;
+ int val;
+ } flag_tbl[] = {
+ { "timestamp", NF_SYNPROXY_OPT_TIMESTAMP },
+ { "sack-perm", NF_SYNPROXY_OPT_SACK_PERM },
+ };
+ const char *flag;
+ unsigned int i;
+
+ assert(flags);
+
+ if (!json_is_string(root)) {
+ json_error(ctx, "Invalid synproxy flag type %s, expected string.",
+ json_typename(root));
+ return 1;
+ }
+ flag = json_string_value(root);
+ for (i = 0; i < array_size(flag_tbl); i++) {
+ if (!strcmp(flag, flag_tbl[i].flag)) {
+ *flags |= flag_tbl[i].val;
+ return 0;
+ }
+ }
+ json_error(ctx, "Unknown synproxy flag '%s'.", flag);
+ return 1;
+}
+
+static int json_parse_synproxy_flags(struct json_ctx *ctx, json_t *root)
+{
+ int flags = 0;
+ json_t *value;
+ size_t index;
+
+ if (json_is_string(root)) {
+ json_parse_synproxy_flag(ctx, root, &flags);
+ return flags;
+ } else if (!json_is_array(root)) {
+ json_error(ctx, "Invalid synproxy flags type %s.",
+ json_typename(root));
+ return -1;
+ }
+ json_array_foreach(root, index, value) {
+ if (json_parse_synproxy_flag(ctx, value, &flags))
+ json_error(ctx, "Parsing synproxy flag at index %zu failed.",
+ index);
+ }
+ return flags;
+}
+
+static struct stmt *json_parse_synproxy_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt = NULL;
+ json_t *jflags;
+ int tmp, flags;
+
+ if (json_typeof(value) == JSON_NULL) {
+ stmt = synproxy_stmt_alloc(int_loc);
+ return stmt;
+ }
+
+ if (!json_unpack(value, "{s:i}", "mss", &tmp)) {
+ if (!stmt)
+ stmt = synproxy_stmt_alloc(int_loc);
+ if (tmp < 0) {
+ json_error(ctx, "Invalid synproxy mss value '%d'", tmp);
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->synproxy.mss = tmp;
+ stmt->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
+ }
+ if (!json_unpack(value, "{s:i}", "wscale", &tmp)) {
+ if (!stmt)
+ stmt = synproxy_stmt_alloc(int_loc);
+ if (tmp < 0) {
+ json_error(ctx, "Invalid synproxy wscale value '%d'", tmp);
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->synproxy.wscale = tmp;
+ stmt->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
+ }
+ if (!json_unpack(value, "{s:o}", "flags", &jflags)) {
+ if (!stmt)
+ stmt = synproxy_stmt_alloc(int_loc);
+ flags = json_parse_synproxy_flags(ctx, jflags);
+
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->synproxy.flags |= flags;
+ }
+
+ if (!stmt) {
+ stmt = objref_stmt_alloc(int_loc);
+ stmt->objref.type = NFT_OBJECT_SYNPROXY;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid synproxy reference");
+ stmt_free(stmt);
+ return NULL;
+ }
+ }
+ return stmt;
+}
+
+static struct stmt *json_parse_cthelper_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt = objref_stmt_alloc(int_loc);
+
+ stmt->objref.type = NFT_OBJECT_CT_HELPER;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid ct helper reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ return stmt;
+}
+
+static struct stmt *json_parse_cttimeout_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt = objref_stmt_alloc(int_loc);
+
+ stmt->objref.type = NFT_OBJECT_CT_TIMEOUT;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid ct timeout reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ return stmt;
+}
+
+static struct stmt *json_parse_ctexpect_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt = objref_stmt_alloc(int_loc);
+
+ stmt->objref.type = NFT_OBJECT_CT_EXPECT;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid ct expectation reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ return stmt;
+}
+
+static struct stmt *json_parse_meter_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ json_t *jkey, *jstmt;
+ struct stmt *stmt;
+ const char *name;
+ uint32_t size = 0;
+
+ if (json_unpack_err(ctx, value, "{s:s, s:o, s:o}",
+ "name", &name, "key", &jkey, "stmt", &jstmt))
+ return NULL;
+ json_unpack(value, "{s:i}", "size", &size);
+
+ stmt = meter_stmt_alloc(int_loc);
+ stmt->meter.name = xstrdup(name);
+ stmt->meter.size = size;
+
+ stmt->meter.key = json_parse_set_elem_expr_stmt(ctx, jkey);
+ if (!stmt->meter.key) {
+ json_error(ctx, "Invalid meter key.");
+ stmt_free(stmt);
+ return NULL;
+ }
+
+ stmt->meter.stmt = json_parse_stmt(ctx, jstmt);
+ if (!stmt->meter.stmt) {
+ json_error(ctx, "Invalid meter statement.");
+ stmt_free(stmt);
+ return NULL;
+ }
+ return stmt;
+}
+
+static int queue_flag_parse(const char *name, uint16_t *flags)
+{
+ if (!strcmp(name, "bypass"))
+ *flags |= NFT_QUEUE_FLAG_BYPASS;
+ else if (!strcmp(name, "fanout"))
+ *flags |= NFT_QUEUE_FLAG_CPU_FANOUT;
+ else
+ return 1;
+ return 0;
+}
+
+static struct stmt *json_parse_queue_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct expr *qexpr = NULL;
+ uint16_t flags = 0;
+ json_t *tmp;
+
+ if (!json_unpack(value, "{s:o}", "num", &tmp)) {
+ qexpr = json_parse_stmt_expr(ctx, tmp);
+ if (!qexpr) {
+ json_error(ctx, "Invalid queue num.");
+ return NULL;
+ }
+ }
+ if (!json_unpack(value, "{s:o}", "flags", &tmp)) {
+ const char *flag;
+ size_t index;
+ json_t *val;
+
+ if (json_is_string(tmp)) {
+ flag = json_string_value(tmp);
+
+ if (queue_flag_parse(flag, &flags)) {
+ json_error(ctx, "Invalid queue flag '%s'.",
+ flag);
+ expr_free(qexpr);
+ return NULL;
+ }
+ } else if (!json_is_array(tmp)) {
+ json_error(ctx, "Unexpected object type in queue flags.");
+ expr_free(qexpr);
+ return NULL;
+ }
+
+ json_array_foreach(tmp, index, val) {
+ if (!json_is_string(val)) {
+ json_error(ctx, "Invalid object in queue flag array at index %zu.",
+ index);
+ expr_free(qexpr);
+ return NULL;
+ }
+ flag = json_string_value(val);
+
+ if (queue_flag_parse(flag, &flags)) {
+ json_error(ctx, "Invalid queue flag '%s'.",
+ flag);
+ expr_free(qexpr);
+ return NULL;
+ }
+ }
+ }
+ return queue_stmt_alloc(int_loc, qexpr, flags);
+}
+
+static struct stmt *json_parse_connlimit_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt = connlimit_stmt_alloc(int_loc);
+
+ if (json_unpack_err(ctx, value, "{s:i}",
+ "val", &stmt->connlimit.count)) {
+ stmt_free(stmt);
+ return NULL;
+ }
+
+ json_unpack(value, "{s:b}", "inv", &stmt->connlimit.flags);
+ if (stmt->connlimit.flags)
+ stmt->connlimit.flags = NFT_CONNLIMIT_F_INV;
+
+ return stmt;
+}
+
+static struct stmt *json_parse_optstrip_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct expr *expr = json_parse_expr(ctx, value);
+
+ if (!expr ||
+ expr->etype != EXPR_EXTHDR ||
+ expr->exthdr.op != NFT_EXTHDR_OP_TCPOPT) {
+ json_error(ctx, "Illegal TCP optstrip argument");
+ return NULL;
+ }
+
+ return optstrip_stmt_alloc(int_loc, expr);
+}
+
+static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
+{
+ struct {
+ const char *key;
+ struct stmt *(*cb)(struct json_ctx *, const char *, json_t *);
+ } stmt_parser_tbl[] = {
+ { "accept", json_parse_verdict_stmt },
+ { "drop", json_parse_verdict_stmt },
+ { "continue", json_parse_verdict_stmt },
+ { "jump", json_parse_verdict_stmt },
+ { "goto", json_parse_verdict_stmt },
+ { "return", json_parse_verdict_stmt },
+ { "match", json_parse_match_stmt },
+ { "counter", json_parse_counter_stmt },
+ { "mangle", json_parse_mangle_stmt },
+ { "quota", json_parse_quota_stmt },
+ { "last", json_parse_last_stmt },
+ { "limit", json_parse_limit_stmt },
+ { "flow", json_parse_flow_offload_stmt },
+ { "fwd", json_parse_fwd_stmt },
+ { "notrack", json_parse_notrack_stmt },
+ { "dup", json_parse_dup_stmt },
+ { "snat", json_parse_nat_stmt },
+ { "dnat", json_parse_nat_stmt },
+ { "masquerade", json_parse_nat_stmt },
+ { "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 },
+ { "ct expectation", json_parse_ctexpect_stmt },
+ { "meter", json_parse_meter_stmt },
+ { "queue", json_parse_queue_stmt },
+ { "ct count", json_parse_connlimit_stmt },
+ { "tproxy", json_parse_tproxy_stmt },
+ { "synproxy", json_parse_synproxy_stmt },
+ { "reset", json_parse_optstrip_stmt },
+ { "secmark", json_parse_secmark_stmt },
+ };
+ const char *type;
+ unsigned int i;
+ json_t *tmp;
+
+ if (json_unpack_stmt(ctx, root, &type, &tmp))
+ return NULL;
+
+ /* Yes, verdict_map_stmt is actually an expression */
+ if (!strcmp(type, "vmap")) {
+ struct expr *expr = json_parse_map_expr(ctx, type, tmp);
+
+ if (!expr) {
+ json_error(ctx, "Illegal vmap statement.");
+ return NULL;
+ }
+ 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);
+ }
+
+ json_error(ctx, "Unknown statement object '%s'.", type);
+ return NULL;
+}
+
+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,
+ };
+ struct table *table = NULL;
+
+ if (json_unpack_err(ctx, root, "{s:s}",
+ "family", &family))
+ 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)) {
+ json_error(ctx, "Either name or handle required to delete a table.");
+ return NULL;
+ }
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ 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, table);
+}
+
+static struct expr *parse_policy(const char *policy)
+{
+ int policy_num;
+
+ if (!strcmp(policy, "accept"))
+ policy_num = NF_ACCEPT;
+ else if (!strcmp(policy, "drop"))
+ policy_num = NF_DROP;
+ else
+ return NULL;
+
+ return constant_expr_alloc(int_loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE, &policy_num);
+}
+
+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, *name, *comment = NULL;
+ struct chain *chain = 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) {
+ 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)) {
+ json_error(ctx, "Either name or handle required to delete a chain.");
+ return NULL;
+ }
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ h.table.name = xstrdup(h.table.name);
+ 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, chain);
+
+ if (!chain)
+ chain = chain_alloc();
+
+ chain->flags |= CHAIN_F_BASECHAIN;
+ chain->type.str = xstrdup(type);
+ chain->priority.expr = constant_expr_alloc(int_loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE,
+ &prio);
+ chain->hook.name = chain_hookname_lookup(hookstr);
+ if (!chain->hook.name) {
+ json_error(ctx, "Invalid chain hook '%s'.", hookstr);
+ chain_free(chain);
+ return NULL;
+ }
+
+ if (!json_unpack(root, "{s:s}", "dev", &name)) {
+ struct expr *dev_expr, *expr;
+
+ 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 (!json_unpack(root, "{s:s}", "policy", &policy)) {
+ chain->policy = parse_policy(policy);
+ if (!chain->policy) {
+ json_error(ctx, "Unknown policy '%s'.", policy);
+ chain_free(chain);
+ return NULL;
+ }
+ }
+
+ if (op == CMD_ADD)
+ json_object_del(root, "handle");
+
+ handle_merge(&chain->handle, &h);
+ return cmd_alloc(op, obj, &h, int_loc, chain);
+}
+
+static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
+ enum cmd_ops op, enum cmd_obj obj)
+{
+ struct handle h = {
+ .table.location = *int_loc,
+ .chain.location = *int_loc,
+ .index.location = *int_loc,
+ };
+ const char *family = "", *comment = NULL;
+ struct rule *rule;
+ size_t index;
+ json_t *tmp, *value;
+
+ if (json_unpack_err(ctx, root, "{s:s, s:s, s:s}",
+ "family", &family,
+ "table", &h.table.name,
+ "chain", &h.chain.name))
+ return NULL;
+ if (op != CMD_DELETE &&
+ json_unpack_err(ctx, root, "{s:o}", "expr", &tmp))
+ return NULL;
+ else if ((op == CMD_DELETE || op == CMD_DESTROY) &&
+ json_unpack_err(ctx, root, "{s:I}", "handle", &h.handle.id))
+ return NULL;
+
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ h.table.name = xstrdup(h.table.name);
+ h.chain.name = xstrdup(h.chain.name);
+
+ if (op == CMD_DELETE || op == CMD_DESTROY)
+ return cmd_alloc(op, obj, &h, int_loc, NULL);
+
+ if (!json_is_array(tmp)) {
+ json_error(ctx, "Value of property \"expr\" must be an array.");
+ return NULL;
+ }
+
+ if (!json_unpack(root, "{s:I}", "index", &h.index.id)) {
+ h.index.id++;
+ }
+
+ rule = rule_alloc(int_loc, NULL);
+
+ json_unpack(root, "{s:s}", "comment", &comment);
+ if (comment)
+ rule->comment = xstrdup(comment);
+
+ json_array_foreach(tmp, index, value) {
+ struct stmt *stmt;
+
+ if (!json_is_object(value)) {
+ json_error(ctx, "Unexpected expr array element of type %s, expected object.",
+ json_typename(value));
+ rule_free(rule);
+ return NULL;
+ }
+
+ stmt = json_parse_stmt(ctx, value);
+
+ if (!stmt) {
+ json_error(ctx, "Parsing expr array at index %zd failed.", index);
+ rule_free(rule);
+ return NULL;
+ }
+
+ rule_stmt_append(rule, stmt);
+ }
+
+ if (op == CMD_ADD)
+ json_object_del(root, "handle");
+
+ return cmd_alloc(op, obj, &h, int_loc, rule);
+}
+
+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",
+ };
+ unsigned int i;
+
+ for (i = 0; i < NFT_OBJECT_MAX; i++) {
+ if (obj_tbl[i] && !strcmp(str, obj_tbl[i]))
+ return i;
+ }
+ return 0;
+}
+
+static int string_to_set_flag(const char *str)
+{
+ const struct {
+ enum nft_set_flags val;
+ const char *name;
+ } flag_tbl[] = {
+ { NFT_SET_CONSTANT, "constant" },
+ { NFT_SET_INTERVAL, "interval" },
+ { NFT_SET_TIMEOUT, "timeout" },
+ { NFT_SET_EVAL, "dynamic" },
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(flag_tbl); i++) {
+ if (!strcmp(str, flag_tbl[i].name))
+ return flag_tbl[i].val;
+ }
+ return 0;
+}
+
+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;
+ json_t *tmp, *stmt_json;
+ struct set *set;
+
+ 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.set.name)) {
+ return NULL;
+ } 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.");
+ return NULL;
+ }
+
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ h.table.name = xstrdup(h.table.name);
+ if (h.set.name)
+ h.set.name = xstrdup(h.set.name);
+
+ 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(&internal_location);
+
+ if (json_unpack(root, "{s:o}", "type", &tmp)) {
+ json_error(ctx, "Invalid set type.");
+ set_free(set);
+ handle_free(&h);
+ return NULL;
+ }
+ set->key = json_parse_dtype_expr(ctx, tmp);
+ if (!set->key) {
+ json_error(ctx, "Invalid set type.");
+ set_free(set);
+ handle_free(&h);
+ return NULL;
+ }
+
+ if (!json_unpack(root, "{s:s}", "map", &dtype_ext)) {
+ const struct datatype *dtype;
+
+ set->objtype = string_to_nft_object(dtype_ext);
+ 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);
+ set->flags |= NFT_SET_MAP;
+ } else {
+ json_error(ctx, "Invalid map type '%s'.", dtype_ext);
+ set_free(set);
+ handle_free(&h);
+ return NULL;
+ }
+ }
+ if (!json_unpack(root, "{s:s}", "policy", &policy)) {
+ if (!strcmp(policy, "performance"))
+ set->policy = NFT_SET_POL_PERFORMANCE;
+ else if (!strcmp(policy, "memory")) {
+ set->policy = NFT_SET_POL_MEMORY;
+ } else {
+ json_error(ctx, "Unknown set policy '%s'.", policy);
+ set_free(set);
+ handle_free(&h);
+ return NULL;
+ }
+ }
+ if (!json_unpack(root, "{s:o}", "flags", &tmp)) {
+ json_t *value;
+ size_t index;
+
+ json_array_foreach(tmp, index, value) {
+ int flag;
+
+ if (!json_is_string(value) ||
+ !(flag = string_to_set_flag(json_string_value(value)))) {
+ json_error(ctx, "Invalid set flag at index %zu.", index);
+ set_free(set);
+ handle_free(&h);
+ return NULL;
+ }
+ set->flags |= flag;
+ }
+ }
+ if (!json_unpack(root, "{s:o}", "elem", &tmp)) {
+ set->init = json_parse_set_expr(ctx, "elem", tmp);
+ if (!set->init) {
+ json_error(ctx, "Invalid set elem expression.");
+ set_free(set);
+ handle_free(&h);
+ return NULL;
+ }
+ }
+ if (!json_unpack(root, "{s:I}", "timeout", &set->timeout))
+ set->timeout *= 1000;
+ if (!json_unpack(root, "{s:i}", "gc-interval", &set->gc_int))
+ set->gc_int *= 1000;
+ json_unpack(root, "{s:i}", "size", &set->desc.size);
+
+ 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);
+
+ if (op == CMD_ADD)
+ json_object_del(root, "handle");
+
+ return cmd_alloc(op, obj, &h, int_loc, set);
+}
+
+static struct cmd *json_parse_cmd_add_element(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op,
+ enum cmd_obj cmd_obj)
+{
+ struct handle h = { 0 };
+ const char *family;
+ struct expr *expr;
+ json_t *tmp;
+
+ if (json_unpack_err(ctx, root, "{s:s, s:s, s:s, s:o}",
+ "family", &family,
+ "table", &h.table.name,
+ "name", &h.set.name,
+ "elem", &tmp))
+ return NULL;
+
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ h.table.name = xstrdup(h.table.name);
+ h.set.name = xstrdup(h.set.name);
+
+ expr = json_parse_set_expr(ctx, "elem", tmp);
+ if (!expr) {
+ json_error(ctx, "Invalid set.");
+ handle_free(&h);
+ return NULL;
+ }
+ 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)
+{
+ const char *family, *hook, *hookstr;
+ struct flowtable *flowtable;
+ struct handle h = { 0 };
+ 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.flowtable.name)) {
+ return NULL;
+ } else if ((op == CMD_DELETE || op == CMD_DESTROY) &&
+ json_unpack(root, "{s:s}", "name", &h.flowtable.name) &&
+ json_unpack(root, "{s:I}", "handle", &h.handle.id)) {
+ json_error(ctx, "Either name or handle required to delete a flowtable.");
+ return NULL;
+ }
+
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ h.table.name = xstrdup(h.table.name);
+ if (h.flowtable.name)
+ h.flowtable.name = xstrdup(h.flowtable.name);
+
+ 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}",
+ "hook", &hook,
+ "prio", &prio)) {
+ handle_free(&h);
+ return NULL;
+ }
+
+ json_unpack(root, "{s:o}", "dev", &devs);
+
+ hookstr = chain_hookname_lookup(hook);
+ if (!hookstr) {
+ json_error(ctx, "Invalid flowtable hook '%s'.", hook);
+ handle_free(&h);
+ return NULL;
+ }
+
+ flowtable = flowtable_alloc(int_loc);
+ flowtable->hook.name = hookstr;
+ flowtable->priority.expr =
+ constant_expr_alloc(int_loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(int) * BITS_PER_BYTE, &prio);
+
+ if (devs) {
+ flowtable->dev_expr = json_parse_flowtable_devs(ctx, devs);
+ if (!flowtable->dev_expr) {
+ json_error(ctx, "Invalid flowtable dev.");
+ flowtable_free(flowtable);
+ handle_free(&h);
+ return NULL;
+ }
+ }
+ return cmd_alloc(op, cmd_obj, &h, int_loc, flowtable);
+}
+
+static int json_parse_ct_timeout_policy(struct json_ctx *ctx,
+ json_t *root, struct obj *obj)
+{
+ json_t *tmp, *val;
+ const char *key;
+
+ if (json_unpack(root, "{s:o}", "policy", &tmp))
+ return 0;
+
+ if (!json_is_object(tmp)) {
+ json_error(ctx, "Invalid ct timeout policy.");
+ return 1;
+ }
+
+ json_object_foreach(tmp, key, val) {
+ struct timeout_state *ts;
+
+ if (!json_is_integer(val)) {
+ json_error(ctx, "Invalid ct timeout policy value for '%s'.", key);
+ return 1;
+ }
+
+ ts = xzalloc(sizeof(*ts));
+ ts->timeout_str = xstrdup(key);
+ ts->timeout_value = json_integer_value(val);
+ ts->location = *int_loc;
+ init_list_head(&ts->head);
+ list_add_tail(&ts->head, &obj->ct_timeout.timeout_list);
+ }
+ return 0;
+}
+
+static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op,
+ enum cmd_obj cmd_obj)
+{
+ 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 };
+ struct obj *obj;
+ json_t *jflags;
+
+ if (json_unpack_err(ctx, root, "{s:s, s:s}",
+ "family", &family,
+ "table", &h.table.name))
+ return NULL;
+ if ((op != CMD_DELETE ||
+ cmd_obj == NFT_OBJECT_CT_HELPER) &&
+ json_unpack_err(ctx, root, "{s:s}", "name", &h.obj.name)) {
+ return NULL;
+ } 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)) {
+ json_error(ctx, "Either name or handle required to delete an object.");
+ return NULL;
+ }
+
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ h.table.name = xstrdup(h.table.name);
+ if (h.obj.name)
+ h.obj.name = xstrdup(h.obj.name);
+
+ 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));
+ return cmd_alloc(op, cmd_obj, &h, int_loc, NULL);
+ }
+
+ 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;
+ json_unpack(root, "{s:I}", "packets", &obj->counter.packets);
+ json_unpack(root, "{s:I}", "bytes", &obj->counter.bytes);
+ break;
+ case CMD_OBJ_QUOTA:
+ obj->type = NFT_OBJECT_QUOTA;
+ json_unpack(root, "{s:I}", "bytes", &obj->quota.bytes);
+ json_unpack(root, "{s:I}", "used", &obj->quota.used);
+ json_unpack(root, "{s:b}", "inv", &obj->quota.flags);
+ if (obj->quota.flags)
+ obj->quota.flags = NFT_QUOTA_F_INV;
+ break;
+ case CMD_OBJ_SECMARK:
+ obj->type = NFT_OBJECT_SECMARK;
+ if (!json_unpack(root, "{s:s}", "context", &tmp)) {
+ int ret;
+ ret = snprintf(obj->secmark.ctx, sizeof(obj->secmark.ctx), "%s", tmp);
+ if (ret < 0 || ret >= (int)sizeof(obj->secmark.ctx)) {
+ json_error(ctx, "Invalid secmark context '%s', max length is %zu.",
+ tmp, sizeof(obj->secmark.ctx));
+ obj_free(obj);
+ return NULL;
+ }
+ }
+ break;
+ case NFT_OBJECT_CT_HELPER:
+ cmd_obj = CMD_OBJ_CT_HELPER;
+ obj->type = NFT_OBJECT_CT_HELPER;
+ if (!json_unpack(root, "{s:s}", "type", &tmp)) {
+ int ret;
+
+ ret = snprintf(obj->ct_helper.name,
+ sizeof(obj->ct_helper.name), "%s", tmp);
+ if (ret < 0 ||
+ ret >= (int)sizeof(obj->ct_helper.name)) {
+ json_error(ctx, "Invalid CT helper type '%s', max length is %zu.",
+ tmp, sizeof(obj->ct_helper.name));
+ obj_free(obj);
+ return NULL;
+ }
+ }
+ if (!json_unpack(root, "{s:s}", "protocol", &tmp)) {
+ if (!strcmp(tmp, "tcp")) {
+ obj->ct_helper.l4proto = IPPROTO_TCP;
+ } else if (!strcmp(tmp, "udp")) {
+ obj->ct_helper.l4proto = IPPROTO_UDP;
+ } else {
+ json_error(ctx, "Invalid ct helper protocol '%s'.", tmp);
+ obj_free(obj);
+ return NULL;
+ }
+ }
+ if (!json_unpack(root, "{s:s}", "l3proto", &tmp) &&
+ parse_family(tmp, &l3proto)) {
+ json_error(ctx, "Invalid ct helper l3proto '%s'.", tmp);
+ obj_free(obj);
+ return NULL;
+ }
+ obj->ct_helper.l3proto = l3proto;
+ break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ cmd_obj = CMD_OBJ_CT_TIMEOUT;
+ obj->type = NFT_OBJECT_CT_TIMEOUT;
+ if (!json_unpack(root, "{s:s}", "protocol", &tmp)) {
+ if (!strcmp(tmp, "tcp")) {
+ obj->ct_timeout.l4proto = IPPROTO_TCP;
+ } else if (!strcmp(tmp, "udp")) {
+ obj->ct_timeout.l4proto = IPPROTO_UDP;
+ } else {
+ json_error(ctx, "Invalid ct timeout protocol '%s'.", tmp);
+ obj_free(obj);
+ return NULL;
+ }
+ }
+ if (!json_unpack(root, "{s:s}", "l3proto", &tmp) &&
+ parse_family(tmp, &l3proto)) {
+ json_error(ctx, "Invalid ct timeout l3proto '%s'.", tmp);
+ obj_free(obj);
+ return NULL;
+ }
+ obj->ct_timeout.l3proto = l3proto;
+
+ init_list_head(&obj->ct_timeout.timeout_list);
+ if (json_parse_ct_timeout_policy(ctx, root, obj)) {
+ obj_free(obj);
+ return NULL;
+ }
+ break;
+ case NFT_OBJECT_CT_EXPECT:
+ cmd_obj = CMD_OBJ_CT_EXPECT;
+ obj->type = NFT_OBJECT_CT_EXPECT;
+ if (!json_unpack(root, "{s:s}", "l3proto", &tmp) &&
+ parse_family(tmp, &l3proto)) {
+ json_error(ctx, "Invalid ct expectation l3proto '%s'.", tmp);
+ obj_free(obj);
+ return NULL;
+ }
+ obj->ct_expect.l3proto = l3proto;
+ if (!json_unpack(root, "{s:s}", "protocol", &tmp)) {
+ if (!strcmp(tmp, "tcp")) {
+ obj->ct_expect.l4proto = IPPROTO_TCP;
+ } else if (!strcmp(tmp, "udp")) {
+ obj->ct_expect.l4proto = IPPROTO_UDP;
+ } else {
+ json_error(ctx, "Invalid ct expectation protocol '%s'.", tmp);
+ obj_free(obj);
+ return NULL;
+ }
+ }
+ 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;
+ if (json_unpack_err(ctx, root, "{s:I, s:s}",
+ "rate", &obj->limit.rate,
+ "per", &tmp)) {
+ obj_free(obj);
+ return NULL;
+ }
+ 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:s}", "burst_unit", &burst_unit);
+
+ if (!strcmp(rate_unit, "packets")) {
+ obj->limit.type = NFT_LIMIT_PKTS;
+ } else {
+ obj->limit.type = NFT_LIMIT_PKT_BYTES;
+ obj->limit.rate = rate_to_bytes(obj->limit.rate,
+ rate_unit);
+ obj->limit.burst = rate_to_bytes(obj->limit.burst,
+ burst_unit);
+ }
+ obj->limit.unit = seconds_from_unit(tmp);
+ obj->limit.flags = inv ? NFT_LIMIT_F_INV : 0;
+ break;
+ case CMD_OBJ_SYNPROXY:
+ obj->type = NFT_OBJECT_SYNPROXY;
+ if (json_unpack_err(ctx, root, "{s:i, s:i}",
+ "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)) {
+ flags = json_parse_synproxy_flags(ctx, jflags);
+ if (flags < 0) {
+ obj_free(obj);
+ return NULL;
+ }
+ obj->synproxy.flags |= flags;
+ }
+ break;
+ default:
+ BUG("Invalid CMD '%d'", cmd_obj);
+ }
+
+ if (op == CMD_ADD)
+ json_object_del(root, "handle");
+
+ return cmd_alloc(op, cmd_obj, &h, int_loc, obj);
+}
+
+static struct cmd *json_parse_cmd_add(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op)
+{
+ struct {
+ const char *key;
+ enum cmd_obj obj;
+ struct cmd *(*cb)(struct json_ctx *, json_t *,
+ enum cmd_ops, enum cmd_obj);
+ } cmd_obj_table[] = {
+ { "table", CMD_OBJ_TABLE, json_parse_cmd_add_table },
+ { "chain", CMD_OBJ_CHAIN, json_parse_cmd_add_chain },
+ { "rule", CMD_OBJ_RULE, json_parse_cmd_add_rule },
+ { "set", CMD_OBJ_SET, json_parse_cmd_add_set },
+ { "map", CMD_OBJ_SET, json_parse_cmd_add_set },
+ { "element", CMD_OBJ_ELEMENTS, json_parse_cmd_add_element },
+ { "flowtable", CMD_OBJ_FLOWTABLE, json_parse_cmd_add_flowtable },
+ { "counter", CMD_OBJ_COUNTER, json_parse_cmd_add_object },
+ { "quota", CMD_OBJ_QUOTA, json_parse_cmd_add_object },
+ { "ct helper", NFT_OBJECT_CT_HELPER, json_parse_cmd_add_object },
+ { "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 }
+ };
+ unsigned int i;
+ json_t *tmp;
+
+ if (!json_is_object(root)) {
+ json_error(ctx, "Value of add command must be object (got %s instead).",
+ json_typename(root));
+ return NULL;
+ }
+
+ for (i = 0; i < array_size(cmd_obj_table); i++) {
+ tmp = json_object_get(root, cmd_obj_table[i].key);
+ if (!tmp)
+ continue;
+
+ if (op == CMD_CREATE && cmd_obj_table[i].obj == CMD_OBJ_RULE) {
+ json_error(ctx, "Create command not available for rules.");
+ return NULL;
+ }
+
+ return cmd_obj_table[i].cb(ctx, tmp, op, cmd_obj_table[i].obj);
+ }
+ json_error(ctx, "Unknown object passed to add command.");
+ return NULL;
+}
+
+static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op)
+{
+ struct handle h = {
+ .table.location = *int_loc,
+ .chain.location = *int_loc,
+ .index.location = *int_loc,
+ };
+ json_t *tmp, *value;
+ const char *family;
+ struct rule *rule;
+ size_t index;
+
+ if (json_unpack_err(ctx, root, "{s:o}", "rule", &tmp))
+ return NULL;
+ root = tmp;
+
+ if (json_unpack_err(ctx, root, "{s:s, s:s, s:s, s:o}",
+ "family", &family,
+ "table", &h.table.name,
+ "chain", &h.chain.name,
+ "expr", &tmp))
+ return NULL;
+ json_unpack(root, "{s:I}", "handle", &h.handle.id);
+ if (!json_unpack(root, "{s:I}", "index", &h.index.id)) {
+ h.index.id++;
+ }
+
+ if (op == CMD_REPLACE && !h.handle.id) {
+ json_error(ctx, "Handle is required when replacing a rule.");
+ return NULL;
+ }
+
+ if ((op == CMD_INSERT || op == CMD_ADD) && h.handle.id) {
+ h.position.id = h.handle.id;
+ h.handle.id = 0;
+ }
+
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+
+ if (!json_is_array(tmp)) {
+ json_error(ctx, "Value of property \"expr\" must be an array.");
+ return NULL;
+ }
+
+ h.table.name = xstrdup(h.table.name);
+ h.chain.name = xstrdup(h.chain.name);
+
+ rule = rule_alloc(int_loc, NULL);
+
+ if (!json_unpack(root, "{s:s}", "comment", &rule->comment))
+ rule->comment = xstrdup(rule->comment);
+
+ json_array_foreach(tmp, index, value) {
+ struct stmt *stmt;
+
+ if (!json_is_object(value)) {
+ json_error(ctx, "Unexpected expr array element of type %s, expected object.",
+ json_typename(value));
+ rule_free(rule);
+ return NULL;
+ }
+
+ stmt = json_parse_stmt(ctx, value);
+
+ if (!stmt) {
+ json_error(ctx, "Parsing expr array at index %zd failed.",
+ index);
+ rule_free(rule);
+ return NULL;
+ }
+
+ rule_stmt_append(rule, stmt);
+ }
+
+ if (op == CMD_REPLACE)
+ json_object_del(root, "handle");
+
+ return cmd_alloc(op, CMD_OBJ_RULE, &h, int_loc, rule);
+}
+
+static struct cmd *json_parse_cmd_list_multiple(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op,
+ enum cmd_obj obj)
+{
+ struct handle h = {
+ .family = NFPROTO_UNSPEC,
+ };
+ const char *tmp;
+
+ if (!json_unpack(root, "{s:s}", "family", &tmp)) {
+ if (parse_family(tmp, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", tmp);
+ return NULL;
+ }
+ }
+ switch (obj) {
+ case CMD_OBJ_SETS:
+ case CMD_OBJ_COUNTERS:
+ case CMD_OBJ_CT_HELPERS:
+ if (!json_unpack(root, "{s:s}", "table", &tmp))
+ h.table.name = xstrdup(tmp);
+ break;
+ default:
+ break;
+ }
+ if (obj == CMD_OBJ_CT_HELPERS && !h.table.name) {
+ json_error(ctx, "Listing ct helpers requires table reference.");
+ return NULL;
+ }
+ return cmd_alloc(op, obj, &h, int_loc, NULL);
+}
+
+static struct cmd *json_parse_cmd_list(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op)
+{
+ struct {
+ const char *key;
+ enum cmd_obj obj;
+ struct cmd *(*cb)(struct json_ctx *, json_t *,
+ enum cmd_ops, enum cmd_obj);
+ } cmd_obj_table[] = {
+ { "table", CMD_OBJ_TABLE, json_parse_cmd_add_table },
+ { "tables", CMD_OBJ_TABLE, json_parse_cmd_list_multiple },
+ { "chain", CMD_OBJ_CHAIN, json_parse_cmd_add_chain },
+ { "chains", CMD_OBJ_CHAINS, json_parse_cmd_list_multiple },
+ { "set", CMD_OBJ_SET, json_parse_cmd_add_set },
+ { "sets", CMD_OBJ_SETS, json_parse_cmd_list_multiple },
+ { "map", CMD_OBJ_MAP, json_parse_cmd_add_set },
+ { "maps", CMD_OBJ_MAPS, json_parse_cmd_list_multiple },
+ { "counter", CMD_OBJ_COUNTER, json_parse_cmd_add_object },
+ { "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 },
+ { "ct helper", NFT_OBJECT_CT_HELPER, json_parse_cmd_add_object },
+ { "ct helpers", CMD_OBJ_CT_HELPERS, json_parse_cmd_list_multiple },
+ { "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 },
+ { "limits", CMD_OBJ_LIMIT, json_parse_cmd_list_multiple },
+ { "ruleset", CMD_OBJ_RULESET, json_parse_cmd_list_multiple },
+ { "meter", CMD_OBJ_METER, json_parse_cmd_add_set },
+ { "meters", CMD_OBJ_METERS, json_parse_cmd_list_multiple },
+ { "flowtables", CMD_OBJ_FLOWTABLES, json_parse_cmd_list_multiple },
+ { "secmark", CMD_OBJ_SECMARK, json_parse_cmd_add_object },
+ { "secmarks", CMD_OBJ_SECMARKS, json_parse_cmd_list_multiple },
+ };
+ unsigned int i;
+ json_t *tmp;
+
+ if (!json_is_object(root)) {
+ json_error(ctx, "Value of list command must be object (got %s instead).",
+ json_typename(root));
+ return NULL;
+ }
+
+ for (i = 0; i < array_size(cmd_obj_table); i++) {
+ tmp = json_object_get(root, cmd_obj_table[i].key);
+ if (!tmp)
+ continue;
+
+ return cmd_obj_table[i].cb(ctx, tmp, op, cmd_obj_table[i].obj);
+ }
+ json_error(ctx, "Unknown object passed to list command.");
+ 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)
+{
+ struct {
+ const char *key;
+ enum cmd_obj obj;
+ struct cmd *(*cb)(struct json_ctx *, json_t *,
+ enum cmd_ops, enum cmd_obj);
+ } cmd_obj_table[] = {
+ { "counter", CMD_OBJ_COUNTER, json_parse_cmd_add_object },
+ { "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;
+
+ if (!json_is_object(root)) {
+ json_error(ctx, "Value of reset command must be object (got %s instead).",
+ json_typename(root));
+ return NULL;
+ }
+
+ for (i = 0; i < array_size(cmd_obj_table); i++) {
+ tmp = json_object_get(root, cmd_obj_table[i].key);
+ if (!tmp)
+ continue;
+
+ return cmd_obj_table[i].cb(ctx, tmp, op, cmd_obj_table[i].obj);
+ }
+ json_error(ctx, "Unknown object passed to reset command.");
+ return NULL;
+}
+
+static struct cmd *json_parse_cmd_flush(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op)
+{
+ struct {
+ const char *key;
+ enum cmd_obj obj;
+ struct cmd *(*cb)(struct json_ctx *, json_t *,
+ enum cmd_ops, enum cmd_obj);
+ } cmd_obj_table[] = {
+ { "table", CMD_OBJ_TABLE, json_parse_cmd_add_table },
+ { "chain", CMD_OBJ_CHAIN, json_parse_cmd_add_chain },
+ { "set", CMD_OBJ_SET, json_parse_cmd_add_set },
+ { "map", CMD_OBJ_MAP, json_parse_cmd_add_set },
+ { "meter", CMD_OBJ_METER, json_parse_cmd_add_set },
+ { "ruleset", CMD_OBJ_RULESET, json_parse_cmd_list_multiple },
+ };
+ unsigned int i;
+ json_t *tmp;
+
+ if (!json_is_object(root)) {
+ json_error(ctx, "Value of flush command must be object (got %s instead).",
+ json_typename(root));
+ return NULL;
+ }
+
+ for (i = 0; i < array_size(cmd_obj_table); i++) {
+ tmp = json_object_get(root, cmd_obj_table[i].key);
+ if (!tmp)
+ continue;
+
+ return cmd_obj_table[i].cb(ctx, tmp, op, cmd_obj_table[i].obj);
+ }
+ json_error(ctx, "Unknown object passed to flush command.");
+ return NULL;
+}
+
+static struct cmd *json_parse_cmd_rename(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op)
+{
+ const char *family, *newname;
+ struct handle h = { 0 };
+ struct cmd *cmd;
+
+ if (json_unpack_err(ctx, root, "{s:{s:s, s:s, s:s, s:s}}", "chain",
+ "family", &family,
+ "table", &h.table.name,
+ "name", &h.chain.name,
+ "newname", &newname))
+ return NULL;
+ if (parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ h.table.name = xstrdup(h.table.name);
+ h.chain.name = xstrdup(h.chain.name);
+
+ cmd = cmd_alloc(op, CMD_OBJ_CHAIN, &h, int_loc, NULL);
+ cmd->arg = xstrdup(newname);
+ return cmd;
+}
+
+static struct cmd *json_parse_cmd(struct json_ctx *ctx, json_t *root)
+{
+ struct {
+ const char *key;
+ enum cmd_ops op;
+ struct cmd *(*cb)(struct json_ctx *ctx, json_t *, enum cmd_ops);
+ } parse_cb_table[] = {
+ { "add", CMD_ADD, json_parse_cmd_add },
+ { "replace", CMD_REPLACE, json_parse_cmd_replace },
+ { "create", CMD_CREATE, json_parse_cmd_add },
+ { "insert", CMD_INSERT, json_parse_cmd_replace },
+ { "delete", CMD_DELETE, json_parse_cmd_add },
+ { "list", CMD_LIST, json_parse_cmd_list },
+ { "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 }
+ };
+ unsigned int i;
+ json_t *tmp;
+
+ for (i = 0; i < array_size(parse_cb_table); i++) {
+ tmp = json_object_get(root, parse_cb_table[i].key);
+ if (!tmp)
+ continue;
+
+ return parse_cb_table[i].cb(ctx, tmp, parse_cb_table[i].op);
+ }
+ /* to accept 'list ruleset' output 1:1, try add command */
+ return json_parse_cmd_add(ctx, root, CMD_ADD);
+}
+
+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)) {
+ 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;
+}
+
+struct json_cmd_assoc {
+ struct json_cmd_assoc *next;
+ struct hlist_node hnode;
+ const struct cmd *cmd;
+ json_t *json;
+};
+
+#define CMD_ASSOC_HSIZE 512
+static struct hlist_head json_cmd_assoc_hash[CMD_ASSOC_HSIZE];
+static struct json_cmd_assoc *json_cmd_assoc_list;
+
+static void json_cmd_assoc_free(void)
+{
+ struct json_cmd_assoc *cur;
+ struct hlist_node *pos, *n;
+ int i;
+
+ while (json_cmd_assoc_list) {
+ cur = json_cmd_assoc_list->next;
+ free(json_cmd_assoc_list);
+ json_cmd_assoc_list = cur;
+ }
+
+ for (i = 0; i < CMD_ASSOC_HSIZE; i++) {
+ hlist_for_each_entry_safe(cur, pos, n,
+ &json_cmd_assoc_hash[i], hnode) {
+ hlist_del(&cur->hnode);
+ free(cur);
+ }
+ }
+}
+
+static void json_cmd_assoc_add(json_t *json, const struct cmd *cmd)
+{
+ struct json_cmd_assoc *new = xzalloc(sizeof *new);
+
+ new->json = json;
+ new->cmd = cmd;
+ new->next = json_cmd_assoc_list;
+
+ json_cmd_assoc_list = new;
+}
+
+static json_t *seqnum_to_json(const uint32_t seqnum)
+{
+ struct json_cmd_assoc *cur;
+ struct hlist_node *n;
+ int key;
+
+ while (json_cmd_assoc_list) {
+ cur = json_cmd_assoc_list;
+ json_cmd_assoc_list = cur->next;
+
+ key = cur->cmd->seqnum % CMD_ASSOC_HSIZE;
+ hlist_add_head(&cur->hnode, &json_cmd_assoc_hash[key]);
+ }
+
+ key = seqnum % CMD_ASSOC_HSIZE;
+ hlist_for_each_entry(cur, n, &json_cmd_assoc_hash[key], hnode) {
+ if (cur->cmd->seqnum == seqnum)
+ return cur->json;
+ }
+
+ return NULL;
+}
+
+static int __json_parse(struct json_ctx *ctx)
+{
+ json_t *tmp, *value;
+ size_t index;
+
+ if (json_unpack_err(ctx, ctx->nft->json_root,
+ "{s:o}", "nftables", &tmp))
+ return -1;
+
+ if (!json_is_array(tmp)) {
+ json_error(ctx, "Value of property \"nftables\" must be an array.");
+ return -1;
+ }
+
+ json_array_foreach(tmp, index, value) {
+ /* this is more or less from parser_bison.y:716 */
+ LIST_HEAD(list);
+ struct cmd *cmd;
+ json_t *tmp2;
+
+ if (!json_is_object(value)) {
+ json_error(ctx, "Unexpected command array element of type %s, expected object.", json_typename(value));
+ return -1;
+ }
+
+ tmp2 = json_object_get(value, "metainfo");
+ if (tmp2) {
+ if (json_verify_metainfo(ctx, tmp2)) {
+ json_error(ctx, "Metainfo verification failed.");
+ return -1;
+ }
+ continue;
+ }
+
+ cmd = json_parse_cmd(ctx, value);
+
+ if (!cmd) {
+ json_error(ctx, "Parsing command array at index %zd failed.", index);
+ return -1;
+ }
+
+ list_add_tail(&cmd->list, &list);
+
+ list_splice_tail(&list, ctx->cmds);
+
+ if (nft_output_echo(&ctx->nft->output))
+ json_cmd_assoc_add(value, cmd);
+ }
+
+ return 0;
+}
+
+int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf,
+ struct list_head *msgs, struct list_head *cmds)
+{
+ struct json_ctx ctx = {
+ .nft = nft,
+ .msgs = msgs,
+ .cmds = cmds,
+ };
+ int ret;
+
+ json_indesc.type = INDESC_BUFFER;
+ json_indesc.data = buf;
+
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
+ nft->json_root = json_loads(buf, 0, NULL);
+ if (!nft->json_root)
+ return -EINVAL;
+
+ ret = __json_parse(&ctx);
+
+ if (!nft_output_echo(&nft->output)) {
+ json_decref(nft->json_root);
+ nft->json_root = NULL;
+ }
+ return ret;
+}
+
+int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
+ struct list_head *msgs, struct list_head *cmds)
+{
+ struct json_ctx ctx = {
+ .nft = nft,
+ .msgs = msgs,
+ .cmds = cmds,
+ };
+ json_error_t err;
+ int ret;
+
+ json_indesc.type = INDESC_FILE;
+ json_indesc.name = filename;
+
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
+ nft->json_root = json_load_file(filename, 0, &err);
+ if (!nft->json_root)
+ return -EINVAL;
+
+ ret = __json_parse(&ctx);
+
+ if (!nft_output_echo(&nft->output)) {
+ json_decref(nft->json_root);
+ nft->json_root = NULL;
+ }
+ return ret;
+}
+
+static int json_echo_error(struct netlink_mon_handler *monh,
+ const char *fmt, ...)
+{
+ struct error_record *erec;
+ va_list ap;
+
+ va_start(ap, fmt);
+ erec = erec_vcreate(EREC_ERROR, int_loc, fmt, ap);
+ va_end(ap);
+ erec_queue(erec, monh->ctx->msgs);
+
+ return MNL_CB_ERROR;
+}
+
+static uint64_t handle_from_nlmsg(const struct nlmsghdr *nlh)
+{
+ struct nftnl_table *nlt;
+ struct nftnl_chain *nlc;
+ struct nftnl_rule *nlr;
+ struct nftnl_set *nls;
+ struct nftnl_obj *nlo;
+ uint64_t handle = 0;
+ uint32_t flags;
+
+ switch (NFNL_MSG_TYPE(nlh->nlmsg_type)) {
+ case NFT_MSG_NEWTABLE:
+ nlt = netlink_table_alloc(nlh);
+ handle = nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE);
+ nftnl_table_free(nlt);
+ break;
+ case NFT_MSG_NEWCHAIN:
+ nlc = netlink_chain_alloc(nlh);
+ handle = nftnl_chain_get_u64(nlc, NFTNL_CHAIN_HANDLE);
+ nftnl_chain_free(nlc);
+ break;
+ case NFT_MSG_NEWRULE:
+ nlr = netlink_rule_alloc(nlh);
+ handle = nftnl_rule_get_u64(nlr, NFTNL_RULE_HANDLE);
+ nftnl_rule_free(nlr);
+ break;
+ case NFT_MSG_NEWSET:
+ nls = netlink_set_alloc(nlh);
+ flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+ if (!set_is_anonymous(flags))
+ handle = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
+ nftnl_set_free(nls);
+ break;
+ case NFT_MSG_NEWOBJ:
+ nlo = netlink_obj_alloc(nlh);
+ handle = nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
+ nftnl_obj_free(nlo);
+ break;
+ }
+ return handle;
+}
+int json_events_cb(const struct nlmsghdr *nlh, struct netlink_mon_handler *monh)
+{
+ uint64_t handle = handle_from_nlmsg(nlh);
+ json_t *tmp, *json;
+ void *iter;
+
+ if (!handle)
+ return MNL_CB_OK;
+
+ json = seqnum_to_json(nlh->nlmsg_seq);
+ if (!json) {
+ json_echo_error(monh, "No JSON command found with seqnum %lu\n",
+ nlh->nlmsg_seq);
+ return MNL_CB_OK;
+ }
+
+ tmp = json_object_get(json, "add");
+ if (!tmp)
+ tmp = json_object_get(json, "insert");
+ if (!tmp)
+ /* assume loading JSON dump */
+ tmp = json;
+
+ iter = json_object_iter(tmp);
+ if (!iter) {
+ json_echo_error(monh, "Empty JSON object in cmd list\n");
+ return MNL_CB_OK;
+ }
+ json = json_object_iter_value(iter);
+ if (!json_is_object(json) || json_object_iter_next(tmp, iter)) {
+ json_echo_error(monh, "Malformed JSON object in cmd list\n");
+ return MNL_CB_OK;
+ }
+
+ json_object_set_new(json, "handle", json_integer(handle));
+ return MNL_CB_OK;
+}
+
+void json_print_echo(struct nft_ctx *ctx)
+{
+ if (!ctx->json_root) {
+ if (!ctx->json_echo)
+ return;
+
+ ctx->json_echo = json_pack("{s:o}", "nftables", ctx->json_echo);
+ json_dumpf(ctx->json_echo, ctx->output.output_fp, JSON_PRESERVE_ORDER);
+ json_decref(ctx->json_echo);
+ ctx->json_echo = NULL;
+ fprintf(ctx->output.output_fp, "\n");
+ fflush(ctx->output.output_fp);
+ } else {
+ json_dumpf(ctx->json_root, ctx->output.output_fp, JSON_PRESERVE_ORDER);
+ json_cmd_assoc_free();
+ json_decref(ctx->json_root);
+ ctx->json_root = NULL;
+ }
+}
diff --git a/src/payload.c b/src/payload.c
new file mode 100644
index 0000000..140ca50
--- /dev/null
+++ b/src/payload.c
@@ -0,0 +1,1494 @@
+/*
+ * Payload expression and related functions.
+ *
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <net/if_arp.h>
+#include <arpa/inet.h>
+#include <linux/netfilter.h>
+#include <linux/if_ether.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+
+#include <rule.h>
+#include <expression.h>
+#include <statement.h>
+#include <payload.h>
+#include <gmputil.h>
+#include <utils.h>
+#include <json.h>
+
+bool payload_is_known(const struct expr *expr)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *desc;
+
+ desc = expr->payload.desc;
+ tmpl = expr->payload.tmpl;
+
+ return desc && tmpl && desc != &proto_unknown &&
+ tmpl != &proto_unknown_template;
+}
+
+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))
+ nft_print(octx, "%s %s", desc->name, tmpl->token);
+ else
+ nft_print(octx, "@%s,%u,%u",
+ proto_base_tokens[expr->payload.base],
+ expr->payload.offset, expr->len);
+}
+
+bool payload_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->payload.desc == e2->payload.desc &&
+ e1->payload.tmpl == e2->payload.tmpl &&
+ e1->payload.base == e2->payload.base &&
+ e1->payload.offset == e2->payload.offset;
+}
+
+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;
+ new->payload.offset = expr->payload.offset;
+}
+
+/**
+ * payload_expr_pctx_update - update protocol context based on payload match
+ *
+ * @ctx: protocol context
+ * @expr: relational payload expression
+ *
+ * Update protocol context for relational payload expressions.
+ */
+static void payload_expr_pctx_update(struct proto_ctx *ctx,
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
+{
+ const struct proto_desc *base, *desc;
+ unsigned int proto = 0;
+
+ /* Export the data in the correct byte order */
+ assert(right->len / BITS_PER_BYTE <= sizeof(proto));
+ mpz_export_data(constant_data_ptr(proto, right->len), right->value,
+ right->byteorder, right->len / BITS_PER_BYTE);
+
+ base = ctx->protocol[left->payload.base].desc;
+ desc = proto_find_upper(base, proto);
+
+ if (!desc) {
+ if (base == &proto_icmp) {
+ /* proto 0 is ECHOREPLY, just pretend its ECHO.
+ * Not doing this would need an additional marker
+ * bit to tell when icmp.type was set.
+ */
+ ctx->th_dep.icmp.type = proto ? proto : ICMP_ECHO;
+ } else if (base == &proto_icmp6) {
+ if (proto == ICMP6_ECHO_REPLY)
+ proto = ICMP6_ECHO_REQUEST;
+ ctx->th_dep.icmp.type = proto;
+ }
+ return;
+ }
+
+ assert(desc->base <= PROTO_BASE_MAX);
+ if (desc->base == base->base) {
+ assert(base->length > 0);
+
+ if (!left->payload.is_raw) {
+ if (desc->base == PROTO_BASE_LL_HDR &&
+ ctx->stacked_ll_count < PROTO_CTX_NUM_PROTOS) {
+ ctx->stacked_ll[ctx->stacked_ll_count] = base;
+ ctx->stacked_ll_count++;
+ }
+ }
+ }
+ proto_ctx_update(ctx, desc->base, loc, desc);
+}
+
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_DESC 0
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE 1
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_BASE 2
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET 3
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_LEN 4
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC 5
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_MAX 6
+
+static unsigned int expr_payload_type(const struct proto_desc *desc,
+ const struct proto_hdr_template *tmpl)
+{
+ if (desc->id == PROTO_DESC_UNKNOWN)
+ return 0;
+
+ return (unsigned int)(tmpl - &desc->templates[0]);
+}
+
+static int payload_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ const struct proto_hdr_template *tmpl = expr->payload.tmpl;
+ const struct proto_desc *desc = expr->payload.desc;
+ unsigned int type = expr_payload_type(desc, tmpl);
+
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_DESC, desc->id);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE, type);
+
+ if (desc->id == 0) {
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_BASE,
+ expr->payload.base);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET,
+ expr->payload.offset);
+ }
+ if (expr->dtype->type == TYPE_INTEGER)
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_LEN, expr->len);
+
+ if (expr->payload.inner_desc) {
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC,
+ expr->payload.inner_desc->id);
+ }
+
+ return 0;
+}
+
+const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud)
+{
+ return proto_find_desc(nftnl_udata_get_u32(ud));
+}
+
+static int payload_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_DESC:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_BASE:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_LEN:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_PAYLOAD_MAX + 1] = {};
+ unsigned int type, base, offset, len = 0;
+ const struct proto_desc *desc;
+ bool is_raw = false;
+ struct expr *expr;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ payload_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_SET_KEY_PAYLOAD_DESC] ||
+ !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE])
+ return NULL;
+
+ desc = find_proto_desc(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_DESC]);
+ if (!desc) {
+ if (!ud[NFTNL_UDATA_SET_KEY_PAYLOAD_BASE] ||
+ !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET])
+ return NULL;
+
+ base = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_BASE]);
+ offset = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET]);
+ is_raw = true;
+ }
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE]);
+ if (ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN])
+ len = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN]);
+
+ expr = payload_expr_alloc(&internal_location, desc, type);
+
+ if (len)
+ expr->len = len;
+
+ if (is_raw) {
+ struct datatype *dtype;
+
+ expr->payload.base = base;
+ expr->payload.offset = offset;
+ expr->payload.is_raw = true;
+ expr->len = len;
+ dtype = datatype_clone(&xinteger_type);
+ dtype->size = len;
+ dtype->byteorder = BYTEORDER_BIG_ENDIAN;
+ __datatype_set(expr, dtype);
+ }
+
+ if (ud[NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC]) {
+ desc = find_proto_desc(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC]);
+ expr->payload.inner_desc = desc;
+ }
+
+ return expr;
+}
+
+const struct expr_ops payload_expr_ops = {
+ .type = EXPR_PAYLOAD,
+ .name = "payload",
+ .print = payload_expr_print,
+ .json = payload_expr_json,
+ .cmp = payload_expr_cmp,
+ .clone = payload_expr_clone,
+ .pctx_update = payload_expr_pctx_update,
+ .build_udata = payload_expr_build_udata,
+ .parse_udata = payload_expr_parse_udata,
+};
+
+/*
+ * We normally use 'meta l4proto' to fetch the last l4 header of the
+ * ipv6 extension header chain so we will also match
+ * tcp after a fragmentation header, for instance.
+ * For consistency we also use meta l4proto for ipv4.
+ *
+ * If user specifically asks for nexthdr x, don't add another (useless)
+ * meta dependency.
+ */
+static bool proto_key_is_protocol(const struct proto_desc *desc, unsigned int type)
+{
+ if (type == desc->protocol_key)
+ return true;
+
+ if (desc == &proto_ip6 && type == IP6HDR_NEXTHDR)
+ return true;
+ if (desc == &proto_ip && type == IPHDR_PROTOCOL)
+ return true;
+
+ return false;
+}
+
+struct expr *payload_expr_alloc(const struct location *loc,
+ const struct proto_desc *desc,
+ unsigned int type)
+{
+ const struct proto_hdr_template *tmpl;
+ enum proto_bases base;
+ struct expr *expr;
+ unsigned int flags = 0;
+
+ if (desc != NULL) {
+ tmpl = &desc->templates[type];
+ base = desc->base;
+ if (proto_key_is_protocol(desc, type))
+ flags = EXPR_F_PROTOCOL;
+ } else {
+ tmpl = &proto_unknown_template;
+ base = PROTO_BASE_INVALID;
+ desc = &proto_unknown;
+ }
+
+ expr = expr_alloc(loc, EXPR_PAYLOAD, tmpl->dtype,
+ tmpl->byteorder, tmpl->len);
+ expr->flags |= flags;
+
+ expr->payload.desc = desc;
+ expr->payload.tmpl = tmpl;
+ expr->payload.base = base;
+ expr->payload.offset = tmpl->offset;
+
+ return expr;
+}
+
+void payload_init_raw(struct expr *expr, enum proto_bases base,
+ unsigned int offset, unsigned int len)
+{
+ enum th_hdr_fields thf;
+
+ expr->payload.base = base;
+ expr->payload.offset = offset;
+ expr->len = len;
+ expr->dtype = &xinteger_type;
+
+ if (base != PROTO_BASE_TRANSPORT_HDR)
+ return;
+ if (len != 16)
+ return;
+
+ switch (offset) {
+ case 0:
+ thf = THDR_SPORT;
+ /* fall through */
+ case 16:
+ if (offset == 16)
+ thf = THDR_DPORT;
+ expr->payload.tmpl = &proto_th.templates[thf];
+ expr->payload.desc = &proto_th;
+ expr->dtype = &inet_service_type;
+ expr->payload.desc = &proto_th;
+ break;
+ default:
+ break;
+ }
+}
+
+unsigned int payload_hdr_field(const struct expr *expr)
+{
+ return expr->payload.tmpl - expr->payload.desc->templates;
+}
+
+static void payload_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ expr_print(stmt->payload.expr, octx);
+ nft_print(octx, " set ");
+ expr_print(stmt->payload.val, octx);
+}
+
+static void payload_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->payload.expr);
+ expr_free(stmt->payload.val);
+}
+
+static const struct stmt_ops payload_stmt_ops = {
+ .type = STMT_PAYLOAD,
+ .name = "payload",
+ .print = payload_stmt_print,
+ .json = payload_stmt_json,
+ .destroy = payload_stmt_destroy,
+};
+
+struct stmt *payload_stmt_alloc(const struct location *loc,
+ struct expr *expr, struct expr *val)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &payload_stmt_ops);
+ stmt->payload.expr = expr;
+ stmt->payload.val = val;
+ return stmt;
+}
+
+static int payload_add_dependency(struct eval_ctx *ctx,
+ const struct proto_desc *desc,
+ const struct proto_desc *upper,
+ const struct expr *expr,
+ struct stmt **res)
+{
+ const struct proto_hdr_template *tmpl;
+ struct expr *dep, *left, *right;
+ struct proto_ctx *pctx;
+ unsigned int stmt_len;
+ struct stmt *stmt;
+ int protocol;
+
+ protocol = proto_find_num(desc, upper);
+ if (protocol < 0)
+ return expr_error(ctx->msgs, expr,
+ "conflicting protocols specified: %s vs. %s",
+ desc->name, upper->name);
+
+ tmpl = &desc->templates[desc->protocol_key];
+ if (tmpl->meta_key)
+ left = meta_expr_alloc(&expr->location, tmpl->meta_key);
+ else
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_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_len = ctx->stmt_len;
+ ctx->stmt_len = 0;
+
+ stmt = expr_stmt_alloc(&dep->location, dep);
+ if (stmt_evaluate(ctx, stmt) < 0) {
+ return expr_error(ctx->msgs, expr,
+ "dependency statement is invalid");
+ }
+ ctx->stmt_len = stmt_len;
+
+ if (ctx->inner_desc) {
+ if (tmpl->meta_key)
+ left->meta.inner_desc = ctx->inner_desc;
+ else
+ left->payload.inner_desc = ctx->inner_desc;
+ }
+
+ 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 proto_ctx *pctx)
+{
+ switch (pctx->family) {
+ case NFPROTO_INET:
+ return &proto_inet;
+ case NFPROTO_BRIDGE:
+ return &proto_eth;
+ case NFPROTO_NETDEV:
+ return &proto_netdev;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+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(pctx);
+ case PROTO_BASE_TRANSPORT_HDR:
+ if (expr->payload.desc == &proto_icmp ||
+ expr->payload.desc == &proto_icmp6 ||
+ expr->payload.desc == &proto_igmp) {
+ const struct proto_desc *desc, *desc_upper;
+ struct stmt *nstmt;
+
+ desc = pctx->protocol[PROTO_BASE_LL_HDR].desc;
+ if (!desc) {
+ 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)
+ desc_upper = &proto_ip;
+
+ if (payload_add_dependency(ctx, desc, desc_upper,
+ expr, &nstmt) < 0)
+ return NULL;
+
+ list_add_tail(&nstmt->list, &ctx->stmt->list);
+ return desc_upper;
+ }
+ return &proto_inet_service;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/**
+ * payload_gen_dependency - generate match expression on payload dependency
+ *
+ * @ctx: evaluation context
+ * @expr: payload expression
+ * @res: dependency expression
+ *
+ * Generate matches on protocol dependencies. There are two different kinds
+ * of dependencies:
+ *
+ * - A payload expression for a base above the hook base requires a match
+ * on the protocol value in the lower layer header.
+ *
+ * - A payload expression for a base below the hook base is invalid in the
+ * output path since the lower layer header does not exist when the packet
+ * is classified. In the input path a payload expressions for a base exactly
+ * one below the hook base is valid. In this case a match on the device type
+ * is required to verify that we're dealing with the expected protocol.
+ *
+ * Note: since it is unknown to userspace which hooks a chain is called from,
+ * it is not explicitly verified. The NFT_META_IIFTYPE match will only match
+ * in the input path though.
+ */
+int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res)
+{
+ const struct hook_proto_desc *h;
+ const struct proto_desc *desc;
+ struct proto_ctx *pctx;
+ unsigned int stmt_len;
+ 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,
+ "payload base is invalid for this "
+ "family");
+
+ if (proto_dev_type(expr->payload.desc, &type) < 0)
+ return expr_error(ctx->msgs, expr,
+ "protocol specification is invalid "
+ "for this family");
+
+ stmt_len = ctx->stmt_len;
+ ctx->stmt_len = 0;
+
+ stmt = meta_stmt_meta_iiftype(&expr->location, type);
+ if (stmt_evaluate(ctx, stmt) < 0) {
+ return expr_error(ctx->msgs, expr,
+ "dependency statement is invalid");
+ }
+ *res = stmt;
+
+ ctx->stmt_len = stmt_len;
+
+ return 0;
+ }
+
+ 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);
+
+ if (desc == NULL)
+ return expr_error(ctx->msgs, expr,
+ "ambiguous payload specification: "
+ "no %s protocol specified",
+ proto_base_names[expr->payload.base - 1]);
+
+ if (pctx->family == NFPROTO_BRIDGE && desc == &proto_eth) {
+ /* prefer netdev proto, which adds dependencies based
+ * on skb->protocol.
+ *
+ * This has the advantage that we will also match
+ * vlan encapsulated traffic.
+ *
+ * eth_hdr(skb)->type would not match, as nft_payload
+ * will pretend vlan tag was not offloaded, i.e.
+ * type is ETH_P_8021Q in such a case, but skb->protocol
+ * would still match the l3 header type.
+ */
+ if (expr->payload.desc == &proto_ip ||
+ expr->payload.desc == &proto_ip6)
+ desc = &proto_netdev;
+ }
+
+ return payload_add_dependency(ctx, desc, expr->payload.desc, expr, res);
+}
+
+int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ const struct proto_desc *dependency,
+ enum proto_bases pb, struct stmt **res)
+{
+ const struct proto_desc *desc;
+ struct proto_ctx *pctx;
+
+ pctx = eval_proto_ctx(ctx);
+ desc = pctx->protocol[pb].desc;
+ if (desc == NULL) {
+ if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
+ switch (pctx->family) {
+ case NFPROTO_NETDEV:
+ case NFPROTO_BRIDGE:
+ case NFPROTO_INET:
+ desc = &proto_inet_service;
+ goto found;
+ default:
+ break;
+ }
+ }
+
+ return expr_error(ctx->msgs, expr,
+ "Cannot generate dependency: "
+ "no %s protocol specified",
+ proto_base_names[pb]);
+ }
+
+ found:
+ return payload_add_dependency(ctx, desc, dependency, expr, res);
+}
+
+/**
+ * payload_is_stacked - return whether a payload protocol match defines a stacked
+ * protocol on the same layer
+ *
+ * @desc: current protocol description on this layer
+ * @expr: payload match
+ */
+bool payload_is_stacked(const struct proto_desc *desc, const struct expr *expr)
+{
+ const struct proto_desc *next;
+
+ if (expr->left->etype != EXPR_PAYLOAD ||
+ !(expr->left->flags & EXPR_F_PROTOCOL) ||
+ expr->op != OP_EQ)
+ return false;
+
+ next = proto_find_upper(desc, mpz_get_be16(expr->right->value));
+ return next && next->base == desc->base;
+}
+
+void payload_dependency_reset(struct payload_dep_ctx *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+static bool payload_dependency_store_icmp_type(struct payload_dep_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct expr *dep = stmt->expr;
+ const struct proto_desc *desc;
+ const struct expr *right;
+ uint8_t type;
+
+ if (dep->left->etype != EXPR_PAYLOAD)
+ return false;
+
+ right = dep->right;
+ if (right->etype != EXPR_VALUE || right->len != BITS_PER_BYTE)
+ return false;
+
+ desc = dep->left->payload.desc;
+ if (desc == &proto_icmp) {
+ type = mpz_get_uint8(right->value);
+
+ if (type == ICMP_ECHOREPLY)
+ type = ICMP_ECHO;
+
+ ctx->icmp_type = type;
+
+ return type == ICMP_ECHO;
+ } else if (desc == &proto_icmp6) {
+ type = mpz_get_uint8(right->value);
+
+ ctx->icmp_type = type;
+ return type == ICMP6_ECHO_REQUEST || type == ICMP6_ECHO_REPLY;
+ }
+
+ return false;
+}
+
+/**
+ * payload_dependency_store - store a possibly redundant protocol match
+ *
+ * @ctx: payload dependency context
+ * @stmt: payload match
+ * @base: base of payload match
+ */
+void payload_dependency_store(struct payload_dep_ctx *ctx,
+ struct stmt *stmt, enum proto_bases base)
+{
+ bool ignore_dep = payload_dependency_store_icmp_type(ctx, stmt);
+
+ if (ignore_dep)
+ return;
+
+ ctx->pdeps[base + 1] = stmt;
+}
+
+/**
+ * payload_dependency_exists - there is a payload dependency in place
+ * @ctx: payload dependency context
+ * @base: payload protocol base
+ *
+ * Check if we have seen a protocol key payload expression for this base, we can
+ * usually remove it if we can infer it from another payload expression in the
+ * upper base.
+ */
+bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
+ enum proto_bases base)
+{
+ if (ctx->pdeps[base])
+ return true;
+
+ return base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR];
+}
+
+/**
+ * payload_dependency_get - return a payload dependency if available
+ * @ctx: payload dependency context
+ * @base: payload protocol base
+ *
+ * If we have seen a protocol key payload expression for this base, we return
+ * it.
+ */
+struct expr *payload_dependency_get(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
+{
+ if (ctx->pdeps[base])
+ return ctx->pdeps[base]->expr;
+
+ if (base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR])
+ return ctx->pdeps[PROTO_BASE_INNER_HDR]->expr;
+
+ return NULL;
+}
+
+static void __payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
+{
+ list_del(&ctx->pdeps[base]->list);
+ stmt_free(ctx->pdeps[base]);
+
+ if (ctx->pdeps[base] == ctx->prev)
+ ctx->prev = NULL;
+ ctx->pdeps[base] = NULL;
+}
+
+void payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
+{
+ if (ctx->pdeps[base])
+ __payload_dependency_release(ctx, base);
+ else if (base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR])
+ __payload_dependency_release(ctx, PROTO_BASE_INNER_HDR);
+}
+
+static uint8_t icmp_dep_to_type(enum icmp_hdr_field_type t)
+{
+ switch (t) {
+ case PROTO_ICMP_ANY:
+ BUG("Invalid map for simple dependency");
+ case PROTO_ICMP_ECHO: return ICMP_ECHO;
+ case PROTO_ICMP6_ECHO: return ICMP6_ECHO_REQUEST;
+ case PROTO_ICMP_MTU: return ICMP_DEST_UNREACH;
+ case PROTO_ICMP_ADDRESS: return ICMP_REDIRECT;
+ case PROTO_ICMP6_MTU: return ICMP6_PACKET_TOO_BIG;
+ case PROTO_ICMP6_MGMQ: return MLD_LISTENER_QUERY;
+ case PROTO_ICMP6_PPTR: return ICMP6_PARAM_PROB;
+ case PROTO_ICMP6_REDIRECT: return ND_REDIRECT;
+ case PROTO_ICMP6_ADDRESS: return ND_NEIGHBOR_SOLICIT;
+ }
+
+ BUG("Missing icmp type mapping");
+}
+
+static bool icmp_dep_type_match(enum icmp_hdr_field_type t, uint8_t type)
+{
+ switch (t) {
+ case PROTO_ICMP_ECHO:
+ return type == ICMP_ECHO || type == ICMP_ECHOREPLY;
+ case PROTO_ICMP6_ECHO:
+ return type == ICMP6_ECHO_REQUEST || type == ICMP6_ECHO_REPLY;
+ case PROTO_ICMP6_ADDRESS:
+ return type == ND_NEIGHBOR_SOLICIT ||
+ type == ND_NEIGHBOR_ADVERT ||
+ type == ND_REDIRECT ||
+ type == MLD_LISTENER_QUERY ||
+ type == MLD_LISTENER_REPORT ||
+ type == MLD_LISTENER_REDUCTION;
+ case PROTO_ICMP_ADDRESS:
+ case PROTO_ICMP_MTU:
+ case PROTO_ICMP6_MTU:
+ case PROTO_ICMP6_MGMQ:
+ case PROTO_ICMP6_PPTR:
+ case PROTO_ICMP6_REDIRECT:
+ return icmp_dep_to_type(t) == type;
+ case PROTO_ICMP_ANY:
+ return true;
+ }
+ BUG("Missing icmp type mapping");
+}
+
+static bool payload_may_dependency_kill_icmp(struct payload_dep_ctx *ctx, struct expr *expr)
+{
+ const struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
+ enum icmp_hdr_field_type icmp_dep;
+
+ icmp_dep = expr->payload.tmpl->icmp_dep;
+ if (icmp_dep == PROTO_ICMP_ANY)
+ return false;
+
+ if (dep->left->payload.desc != expr->payload.desc)
+ return false;
+
+ if (expr->payload.tmpl->icmp_dep == PROTO_ICMP_ECHO ||
+ expr->payload.tmpl->icmp_dep == PROTO_ICMP6_ECHO ||
+ expr->payload.tmpl->icmp_dep == PROTO_ICMP6_ADDRESS)
+ return false;
+
+ return ctx->icmp_type == icmp_dep_to_type(icmp_dep);
+}
+
+static bool payload_may_dependency_kill_ll(struct payload_dep_ctx *ctx, struct expr *expr)
+{
+ const struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
+
+ /* Never remove a 'vlan type 0x...' expression, they are never added
+ * implicitly
+ */
+ if (dep->left->payload.desc == &proto_vlan)
+ return false;
+
+ /* 'vlan id 2' implies 'ether type 8021Q'. If a different protocol is
+ * tested, this is not a redundant expression.
+ */
+ if (dep->left->payload.desc == &proto_eth &&
+ dep->right->etype == EXPR_VALUE && dep->right->len == 16)
+ return mpz_get_uint16(dep->right->value) == ETH_P_8021Q;
+
+ return true;
+}
+
+static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
+ unsigned int family, struct expr *expr)
+{
+ struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
+
+ /* Protocol key payload expression at network base such as 'ip6 nexthdr'
+ * need to be left in place since it implicitly restricts matching to
+ * IPv6 for the bridge, inet and netdev families.
+ */
+ switch (family) {
+ case NFPROTO_BRIDGE:
+ case NFPROTO_NETDEV:
+ case NFPROTO_INET:
+ if (dep->left->etype == EXPR_PAYLOAD &&
+ dep->left->payload.base == PROTO_BASE_NETWORK_HDR &&
+ (dep->left->payload.desc == &proto_ip ||
+ dep->left->payload.desc == &proto_ip6) &&
+ expr->payload.base == PROTO_BASE_TRANSPORT_HDR)
+ return false;
+ /* Do not kill
+ * ether type vlan and vlan type ip and ip protocol icmp
+ * into
+ * ip protocol icmp
+ * as this lacks ether type vlan.
+ * More generally speaking, do not kill protocol type
+ * for stacked protocols if we only have protcol type matches.
+ */
+ if (dep->left->etype == EXPR_PAYLOAD && dep->op == OP_EQ &&
+ expr->payload.base == dep->left->payload.base) {
+ if (expr->flags & EXPR_F_PROTOCOL)
+ return false;
+
+ if (expr->payload.base == PROTO_BASE_LL_HDR)
+ return payload_may_dependency_kill_ll(ctx, expr);
+ }
+
+ break;
+ }
+
+ if (expr->payload.base != PROTO_BASE_TRANSPORT_HDR)
+ return true;
+
+ if (dep->left->payload.base != PROTO_BASE_TRANSPORT_HDR)
+ return true;
+
+ if (dep->left->payload.desc == &proto_icmp)
+ return payload_may_dependency_kill_icmp(ctx, expr);
+
+ if (dep->left->payload.desc == &proto_icmp6)
+ return payload_may_dependency_kill_icmp(ctx, expr);
+
+ return true;
+}
+
+/**
+ * payload_dependency_kill - kill a redundant payload dependency
+ *
+ * @ctx: payload dependency context
+ * @expr: higher layer payload expression
+ *
+ * Kill a redundant payload expression if a higher layer payload expression
+ * implies its existence. Skip this if the dependency is a network payload and
+ * we are in bridge, netdev and inet families.
+ */
+void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
+ unsigned int family)
+{
+ 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);
+}
+
+void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
+ unsigned int family)
+{
+ switch (expr->exthdr.op) {
+ case NFT_EXTHDR_OP_TCPOPT:
+ if (payload_dependency_exists(ctx, PROTO_BASE_TRANSPORT_HDR))
+ payload_dependency_release(ctx, PROTO_BASE_TRANSPORT_HDR);
+ break;
+ case NFT_EXTHDR_OP_IPV6:
+ if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
+ payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR);
+ break;
+ case NFT_EXTHDR_OP_IPV4:
+ if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
+ payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR);
+ break;
+ default:
+ break;
+ }
+}
+
+static const struct proto_desc *get_stacked_desc(const struct proto_ctx *ctx,
+ const struct proto_desc *top,
+ const struct expr *e,
+ unsigned int *skip)
+{
+ unsigned int i, total, payload_offset = e->payload.offset;
+
+ assert(e->etype == EXPR_PAYLOAD);
+
+ if (e->payload.base != PROTO_BASE_LL_HDR ||
+ payload_offset < top->length) {
+ *skip = 0;
+ return top;
+ }
+
+ for (i = 0, total = 0; i < ctx->stacked_ll_count; i++) {
+ const struct proto_desc *stacked;
+
+ stacked = ctx->stacked_ll[i];
+ if (payload_offset < stacked->length) {
+ *skip = total;
+ return stacked;
+ }
+
+ payload_offset -= stacked->length;
+ total += stacked->length;
+ }
+
+ *skip = total;
+ return top;
+}
+
+/**
+ * payload_expr_complete - fill in type information of a raw payload expr
+ *
+ * @expr: the payload expression
+ * @ctx: protocol context
+ *
+ * Complete the type of a raw payload expression based on the context. If
+ * insufficient information is available the expression remains unchanged.
+ */
+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, total;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+
+ desc = ctx->protocol[expr->payload.base].desc;
+ if (desc == NULL || desc == &proto_inet)
+ 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 != payload_offset ||
+ tmpl->len != expr->len)
+ continue;
+
+ if (tmpl->meta_key && i == 0)
+ continue;
+
+ if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
+ !icmp_dep_type_match(tmpl->icmp_dep,
+ ctx->th_dep.icmp.type))
+ continue;
+
+ expr->dtype = tmpl->dtype;
+ expr->payload.desc = desc;
+ expr->byteorder = tmpl->byteorder;
+ expr->payload.tmpl = tmpl;
+ return;
+ }
+}
+
+static unsigned int mask_to_offset(const struct expr *mask)
+{
+ return mask ? mpz_scan1(mask->value, 0) : 0;
+}
+
+static unsigned int mask_length(const struct expr *mask)
+{
+ unsigned long off;
+
+ off = mask_to_offset(mask);
+
+ return mpz_scan0(mask->value, off + 1);
+}
+
+/**
+ * payload_expr_trim - trim payload expression according to mask
+ *
+ * @expr: the payload expression
+ * @mask: mask to use when searching templates
+ * @ctx: protocol context
+ *
+ * Walk the template list and determine if a match can be found without
+ * using the provided mask.
+ *
+ * If the mask has to be used, trim the payload expression length accordingly,
+ * adjust the payload offset and return true to let the caller know that the
+ * mask can be removed. This function also returns the shift for the right hand
+ * constant side of the expression.
+ */
+bool payload_expr_trim(struct expr *expr, struct expr *mask,
+ const struct proto_ctx *ctx, unsigned int *shift)
+{
+ unsigned int payload_offset = expr->payload.offset;
+ unsigned int mask_offset = mask_to_offset(mask);
+ unsigned int mask_len = mask_length(mask);
+ const struct proto_hdr_template *tmpl;
+ 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);
+
+ desc = ctx->protocol[expr->payload.base].desc;
+ if (desc == NULL)
+ return false;
+
+ assert(desc->base == expr->payload.base);
+
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
+
+ off = round_up(mask->len, BITS_PER_BYTE) - mask_len;
+ payload_offset += off;
+
+ for (i = 1; i < array_size(desc->templates); i++) {
+ tmpl = &desc->templates[i];
+ if (tmpl->offset != payload_offset)
+ continue;
+
+ if (tmpl->len > payload_len)
+ return false;
+
+ payload_len -= tmpl->len;
+ payload_offset += tmpl->len;
+ len += tmpl->len;
+ if (payload_len == 0)
+ return false;
+
+ if (mask_offset + len == mask_len) {
+ expr->payload.offset += off;
+ expr->len = len;
+ *shift = mask_offset;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * payload_expr_expand - expand raw merged adjacent payload expressions into its
+ * original components
+ *
+ * @list: list to append expanded payload expressions to
+ * @expr: the payload expression to expand
+ * @ctx: protocol context
+ *
+ * Expand a merged adjacent payload expression into its original components
+ * by splitting elements off the beginning matching a payload template.
+ *
+ * Note: this requires all payload templates to be specified in ascending
+ * offset order.
+ */
+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;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+
+ desc = ctx->protocol[expr->payload.base].desc;
+ 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 != payload_offset)
+ continue;
+
+ if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
+ !icmp_dep_type_match(tmpl->icmp_dep,
+ ctx->th_dep.icmp.type))
+ continue;
+
+ if (tmpl->len <= expr->len) {
+ new = payload_expr_alloc(&expr->location, desc, i);
+ list_add_tail(&new->list, list);
+ expr->len -= tmpl->len;
+ expr->payload.offset += tmpl->len;
+ payload_offset += tmpl->len;
+ if (expr->len == 0)
+ return;
+ } else if (expr->len > 0) {
+ new = payload_expr_alloc(&expr->location, desc, i);
+ new->len = expr->len;
+ list_add_tail(&new->list, list);
+ return;
+ } else
+ break;
+ }
+raw:
+ new = payload_expr_alloc(&expr->location, NULL, 0);
+ payload_init_raw(new, expr->payload.base, payload_offset,
+ expr->len);
+
+ if (expr->payload.inner_desc)
+ new->dtype = &integer_type;
+
+ list_add_tail(&new->list, list);
+}
+
+static bool payload_is_adjacent(const struct expr *e1, const struct expr *e2)
+{
+ if (e1->payload.base == e2->payload.base &&
+ e1->payload.offset + e1->len == e2->payload.offset)
+ return true;
+ return false;
+}
+
+/**
+ * payload_can_merge - return whether two payload expressions can be merged
+ *
+ * @e1: first payload expression
+ * @e2: second payload expression
+ */
+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;
+
+ if (e1->payload.offset % BITS_PER_BYTE || e1->len % BITS_PER_BYTE ||
+ e2->payload.offset % BITS_PER_BYTE || e2->len % BITS_PER_BYTE)
+ return false;
+
+ total = e1->len + e2->len;
+ if (total < e1->len || total > (NFT_REG_SIZE * BITS_PER_BYTE))
+ return false;
+
+ /* could return true after this, the expressions are mergeable.
+ *
+ * However, there are some caveats.
+ *
+ * Loading anything <= sizeof(u32) with base >= network header
+ * is fast, because its handled directly from eval loop in the
+ * kernel.
+ *
+ * We thus restrict merging a bit more.
+ */
+
+ /* can still be handled by fastpath after merge */
+ if (total <= NFT_REG32_SIZE * BITS_PER_BYTE)
+ return true;
+
+ /* Linklayer base is not handled in fastpath, merge */
+ if (e1->payload.base == PROTO_BASE_LL_HDR)
+ return true;
+
+ /* Also merge if at least one expression is already
+ * above REG32 size, in this case merging is faster.
+ */
+ if (e1->len > (NFT_REG32_SIZE * BITS_PER_BYTE) ||
+ e2->len > (NFT_REG32_SIZE * BITS_PER_BYTE))
+ return true;
+
+ return false;
+}
+
+/**
+ * payload_expr_join - join two adjacent payload expressions
+ *
+ * @e1: first payload expression
+ * @e2: second payload expression
+ */
+struct expr *payload_expr_join(const struct expr *e1, const struct expr *e2)
+{
+ struct expr *expr;
+
+ assert(payload_is_adjacent(e1, e2));
+
+ expr = payload_expr_alloc(&internal_location, NULL, 0);
+ expr->payload.base = e1->payload.base;
+ expr->payload.offset = e1->payload.offset;
+ expr->len = e1->len + e2->len;
+ expr->payload.inner_desc = e1->payload.inner_desc;
+
+ return expr;
+}
+
+static struct stmt *
+__payload_gen_icmp_simple_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ const struct datatype *icmp_type,
+ const struct proto_desc *desc,
+ uint8_t type)
+{
+ struct expr *left, *right, *dep;
+
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+ right = constant_expr_alloc(&expr->location, icmp_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(type, BITS_PER_BYTE));
+
+ dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+ return expr_stmt_alloc(&dep->location, dep);
+}
+
+static struct stmt *
+__payload_gen_icmp_echo_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ uint8_t echo, uint8_t reply,
+ const struct datatype *icmp_type,
+ const struct proto_desc *desc)
+{
+ struct expr *left, *right, *dep, *set;
+
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+
+ set = set_expr_alloc(&expr->location, NULL);
+
+ right = constant_expr_alloc(&expr->location, icmp_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(echo, BITS_PER_BYTE));
+ right = set_elem_expr_alloc(&expr->location, right);
+ compound_expr_add(set, right);
+
+ right = constant_expr_alloc(&expr->location, icmp_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(reply, BITS_PER_BYTE));
+ right = set_elem_expr_alloc(&expr->location, right);
+ compound_expr_add(set, right);
+
+ dep = relational_expr_alloc(&expr->location, OP_IMPLICIT, left, set);
+ return expr_stmt_alloc(&dep->location, dep);
+}
+
+static struct stmt *
+__payload_gen_icmp6_addr_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ const struct proto_desc *desc)
+{
+ static const uint8_t icmp_addr_types[] = {
+ MLD_LISTENER_QUERY,
+ MLD_LISTENER_REPORT,
+ MLD_LISTENER_REDUCTION,
+ ND_NEIGHBOR_SOLICIT,
+ ND_NEIGHBOR_ADVERT,
+ ND_REDIRECT
+ };
+ struct expr *left, *right, *dep, *set;
+ size_t i;
+
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+
+ set = set_expr_alloc(&expr->location, NULL);
+
+ for (i = 0; i < array_size(icmp_addr_types); ++i) {
+ right = constant_expr_alloc(&expr->location, &icmp6_type_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(icmp_addr_types[i],
+ BITS_PER_BYTE));
+ right = set_elem_expr_alloc(&expr->location, right);
+ compound_expr_add(set, right);
+ }
+
+ dep = relational_expr_alloc(&expr->location, OP_IMPLICIT, left, set);
+ return expr_stmt_alloc(&dep->location, dep);
+}
+
+int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *desc;
+ struct stmt *stmt = NULL;
+ uint8_t type;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+
+ tmpl = expr->payload.tmpl;
+ desc = expr->payload.desc;
+
+ switch (tmpl->icmp_dep) {
+ case PROTO_ICMP_ANY:
+ BUG("No dependency needed");
+ break;
+ case PROTO_ICMP_ECHO:
+ /* do not test ICMP_ECHOREPLY here: its 0 */
+ if (pctx->th_dep.icmp.type == ICMP_ECHO)
+ goto done;
+
+ type = ICMP_ECHO;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+
+ stmt = __payload_gen_icmp_echo_dependency(ctx, expr,
+ ICMP_ECHO, ICMP_ECHOREPLY,
+ &icmp_type_type,
+ desc);
+ break;
+ case PROTO_ICMP_MTU:
+ case PROTO_ICMP_ADDRESS:
+ type = icmp_dep_to_type(tmpl->icmp_dep);
+ if (pctx->th_dep.icmp.type == type)
+ goto done;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+ stmt = __payload_gen_icmp_simple_dependency(ctx, expr,
+ &icmp_type_type,
+ desc, type);
+ break;
+ case PROTO_ICMP6_ECHO:
+ if (pctx->th_dep.icmp.type == ICMP6_ECHO_REQUEST ||
+ pctx->th_dep.icmp.type == ICMP6_ECHO_REPLY)
+ goto done;
+
+ type = ICMP6_ECHO_REQUEST;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+
+ stmt = __payload_gen_icmp_echo_dependency(ctx, expr,
+ ICMP6_ECHO_REQUEST,
+ ICMP6_ECHO_REPLY,
+ &icmp6_type_type,
+ desc);
+ break;
+ case PROTO_ICMP6_ADDRESS:
+ if (icmp_dep_type_match(PROTO_ICMP6_ADDRESS,
+ pctx->th_dep.icmp.type))
+ goto done;
+ type = ND_NEIGHBOR_SOLICIT;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+ stmt = __payload_gen_icmp6_addr_dependency(ctx, expr, desc);
+ break;
+ case PROTO_ICMP6_REDIRECT:
+ case PROTO_ICMP6_MTU:
+ case PROTO_ICMP6_MGMQ:
+ case PROTO_ICMP6_PPTR:
+ type = icmp_dep_to_type(tmpl->icmp_dep);
+ if (pctx->th_dep.icmp.type == type)
+ goto done;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+ stmt = __payload_gen_icmp_simple_dependency(ctx, expr,
+ &icmp6_type_type,
+ desc, type);
+ break;
+ break;
+ default:
+ BUG("Unhandled icmp dependency code");
+ }
+
+ pctx->th_dep.icmp.type = type;
+
+ if (stmt_evaluate(ctx, stmt) < 0)
+ return expr_error(ctx->msgs, expr,
+ "icmp dependency statement is invalid");
+done:
+ *res = stmt;
+ return 0;
+
+bad_proto:
+ return expr_error(ctx->msgs, expr, "incompatible icmp match: rule has %d, need %u",
+ pctx->th_dep.icmp.type, type);
+}
+
+int payload_gen_inner_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *desc, *inner_desc;
+ struct expr *left, *right, *dep;
+ struct stmt *stmt = NULL;
+ int protocol;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+
+ inner_desc = expr->payload.inner_desc;
+ desc = pctx->protocol[inner_desc->base - 1].desc;
+ if (desc == NULL)
+ desc = &proto_ip;
+
+ tmpl = &inner_desc->templates[0];
+ assert(tmpl);
+
+ protocol = proto_find_num(desc, inner_desc);
+ if (protocol < 0)
+ return expr_error(ctx->msgs, expr,
+ "conflicting protocols specified: %s vs. %s",
+ desc->name, inner_desc->name);
+
+ left = meta_expr_alloc(&expr->location, tmpl->meta_key);
+
+ right = constant_expr_alloc(&expr->location, tmpl->dtype,
+ tmpl->dtype->byteorder, tmpl->len,
+ constant_data_ptr(protocol, tmpl->len));
+
+ dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+ stmt = expr_stmt_alloc(&dep->location, dep);
+
+ *res = stmt;
+ return 0;
+}
diff --git a/src/print.c b/src/print.c
new file mode 100644
index 0000000..8aefa96
--- /dev/null
+++ b/src/print.c
@@ -0,0 +1,39 @@
+/*
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <stdarg.h>
+#include <nftables.h>
+#include <utils.h>
+
+int nft_print(struct output_ctx *octx, const char *fmt, ...)
+{
+ int ret;
+ va_list arg;
+
+ va_start(arg, fmt);
+ ret = vfprintf(octx->output_fp, fmt, arg);
+ va_end(arg);
+ fflush(octx->output_fp);
+
+ return ret;
+}
+
+int nft_gmp_print(struct output_ctx *octx, const char *fmt, ...)
+{
+ int ret;
+ va_list arg;
+
+ va_start(arg, fmt);
+ ret = gmp_vfprintf(octx->output_fp, fmt, arg);
+ va_end(arg);
+ fflush(octx->output_fp);
+
+ return ret;
+}
diff --git a/src/proto.c b/src/proto.c
new file mode 100644
index 0000000..553b6a4
--- /dev/null
+++ b/src/proto.c
@@ -0,0 +1,1320 @@
+/*
+ * Protocol header and type definitions and related functions.
+ *
+ * Copyright (c) 2014 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <net/if_arp.h>
+#include <arpa/inet.h>
+#include <linux/netfilter.h>
+
+#include <expression.h>
+#include <headers.h>
+#include <proto.h>
+#include <gmputil.h>
+#include <utils.h>
+
+const char *proto_base_names[] = {
+ [PROTO_BASE_INVALID] = "invalid",
+ [PROTO_BASE_LL_HDR] = "link layer",
+ [PROTO_BASE_NETWORK_HDR] = "network layer",
+ [PROTO_BASE_TRANSPORT_HDR] = "transport layer",
+ [PROTO_BASE_INNER_HDR] = "payload data",
+};
+
+const char *proto_base_tokens[] = {
+ [PROTO_BASE_INVALID] = "invalid",
+ [PROTO_BASE_LL_HDR] = "ll",
+ [PROTO_BASE_NETWORK_HDR] = "nh",
+ [PROTO_BASE_TRANSPORT_HDR] = "th",
+ [PROTO_BASE_INNER_HDR] = "ih",
+};
+
+const struct proto_hdr_template proto_unknown_template =
+ PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
+
+const struct proto_desc proto_unknown = {
+ .name = "unknown",
+ .base = PROTO_BASE_INVALID,
+};
+
+/**
+ * proto_find_upper - find higher layer protocol description by protocol value
+ * linking it to the lower layer protocol
+ *
+ * @base: lower layer protocol description
+ * @num: protocol value
+ */
+const struct proto_desc *
+proto_find_upper(const struct proto_desc *base, unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(base->protocols); i++) {
+ if (!base->protocols[i].desc)
+ break;
+ if (base->protocols[i].num == num)
+ return base->protocols[i].desc;
+ }
+ return NULL;
+}
+
+/**
+ * proto_find_num - return protocol number linking two protocols together
+ *
+ * @base: lower layer protocol description
+ * @desc: upper layer protocol description
+ */
+int proto_find_num(const struct proto_desc *base,
+ const struct proto_desc *desc)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(base->protocols); i++) {
+ if (!base->protocols[i].desc)
+ break;
+ if (base->protocols[i].desc == desc)
+ return base->protocols[i].num;
+ }
+ return -1;
+}
+
+static const struct proto_desc *inner_protocols[] = {
+ &proto_vxlan,
+ &proto_geneve,
+ &proto_gre,
+ &proto_gretap,
+};
+
+const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize,
+ uint32_t flags)
+{
+ const struct proto_desc *desc;
+ unsigned int i;
+
+ for (i = 0; i < array_size(inner_protocols); i++) {
+ desc = inner_protocols[i];
+ if (desc->inner.type == type &&
+ desc->inner.hdrsize == hdrsize &&
+ desc->inner.flags == flags)
+ return inner_protocols[i];
+ }
+
+ return &proto_unknown;
+}
+
+static const struct dev_proto_desc dev_proto_desc[] = {
+ DEV_PROTO_DESC(ARPHRD_ETHER, &proto_eth),
+};
+
+/**
+ * proto_dev_type - return arphrd type linking a device and a protocol together
+ *
+ * @desc: the protocol description
+ * @res: pointer to result
+ */
+int proto_dev_type(const struct proto_desc *desc, uint16_t *res)
+{
+ const struct proto_desc *base;
+ unsigned int i, j;
+
+ for (i = 0; i < array_size(dev_proto_desc); i++) {
+ base = dev_proto_desc[i].desc;
+ if (base == desc) {
+ *res = dev_proto_desc[i].type;
+ return 0;
+ }
+ for (j = 0; j < array_size(base->protocols); j++) {
+ if (!base->protocols[j].desc)
+ break;
+ if (base->protocols[j].desc == desc) {
+ *res = dev_proto_desc[i].type;
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+/**
+ * proto_dev_desc - return protocol description for an arphrd type
+ *
+ * @type: the arphrd type
+ */
+const struct proto_desc *proto_dev_desc(uint16_t type)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(dev_proto_desc); i++) {
+ if (dev_proto_desc[i].type == type)
+ return dev_proto_desc[i].desc;
+ }
+ return NULL;
+}
+
+const struct hook_proto_desc hook_proto_desc[] = {
+ [NFPROTO_BRIDGE] = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR, &proto_eth),
+ [NFPROTO_NETDEV] = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR, &proto_netdev),
+ [NFPROTO_INET] = HOOK_PROTO_DESC(PROTO_BASE_LL_HDR, &proto_inet),
+ [NFPROTO_IPV4] = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_ip),
+ [NFPROTO_IPV6] = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_ip6),
+ [NFPROTO_ARP] = HOOK_PROTO_DESC(PROTO_BASE_NETWORK_HDR, &proto_arp),
+};
+
+static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
+ unsigned int debug_mask)
+{
+ unsigned int i;
+
+ if (!(debug_mask & NFT_DEBUG_PROTO_CTX))
+ return;
+
+ 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 (i == base)
+ pr_debug(" <-");
+ pr_debug("\n");
+ }
+ pr_debug("\n");
+}
+
+/**
+ * proto_ctx_init - initialize protocol context for a given hook family
+ *
+ * @ctx: protocol context
+ * @family: hook family
+ * @debug_mask: display debugging information
+ */
+void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
+ unsigned int debug_mask, bool inner)
+{
+ const struct hook_proto_desc *h = &hook_proto_desc[family];
+
+ memset(ctx, 0, sizeof(*ctx));
+ 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);
+}
+
+/**
+ * proto_ctx_update: update protocol context for given protocol base
+ *
+ * @ctx: protocol context
+ * @base: protocol base
+ * @loc: location of the relational expression definiting the context
+ * @desc: protocol description for the given layer
+ */
+void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
+ const struct location *loc,
+ const struct proto_desc *desc)
+{
+ bool found = false;
+ unsigned int i;
+
+ switch (base) {
+ case PROTO_BASE_LL_HDR:
+ case PROTO_BASE_NETWORK_HDR:
+ break;
+ case PROTO_BASE_TRANSPORT_HDR:
+ if (ctx->protocol[base].num_protos >= PROTO_CTX_NUM_PROTOS)
+ break;
+
+ for (i = 0; i < ctx->protocol[base].num_protos; i++) {
+ if (ctx->protocol[base].protos[i].desc == desc) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ i = ctx->protocol[base].num_protos++;
+ ctx->protocol[base].protos[i].desc = desc;
+ ctx->protocol[base].protos[i].location = *loc;
+ }
+ break;
+ case PROTO_BASE_INNER_HDR:
+ break;
+ default:
+ BUG("unknown protocol base %d", base);
+ }
+
+ ctx->protocol[base].location = *loc;
+ ctx->protocol[base].desc = desc;
+
+ proto_ctx_debug(ctx, base, ctx->debug_mask);
+}
+
+bool proto_ctx_is_ambiguous(struct proto_ctx *ctx, enum proto_bases base)
+{
+ return ctx->protocol[base].num_protos > 1;
+}
+
+const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx,
+ enum proto_bases base,
+ const struct proto_desc *desc)
+{
+ unsigned int i;
+
+ switch (base) {
+ case PROTO_BASE_LL_HDR:
+ case PROTO_BASE_NETWORK_HDR:
+ if (desc != ctx->protocol[base].desc)
+ return ctx->protocol[base].desc;
+ break;
+ case PROTO_BASE_TRANSPORT_HDR:
+ for (i = 0; i < ctx->protocol[base].num_protos; i++) {
+ if (desc != ctx->protocol[base].protos[i].desc)
+ return ctx->protocol[base].protos[i].desc;
+ }
+ break;
+ default:
+ BUG("unknown protocol base %d", base);
+ }
+
+ return NULL;
+}
+
+#define HDR_TEMPLATE(__name, __dtype, __type, __member) \
+ PROTO_HDR_TEMPLATE(__name, __dtype, \
+ BYTEORDER_BIG_ENDIAN, \
+ offsetof(__type, __member) * 8, \
+ field_sizeof(__type, __member) * 8)
+
+#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)
+#define HDR_TYPE(__name, __dtype, __struct, __member) \
+ HDR_TEMPLATE(__name, __dtype, __struct, __member)
+
+#define INET_PROTOCOL(__name, __struct, __member) \
+ HDR_TYPE(__name, &inet_protocol_type, __struct, __member)
+#define INET_SERVICE(__name, __struct, __member) \
+ HDR_TYPE(__name, &inet_service_type, __struct, __member)
+
+/*
+ * AH
+ */
+
+#define AHHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct ip_auth_hdr, __member)
+
+const struct proto_desc proto_ah = {
+ .name = "ah",
+ .id = PROTO_DESC_AH,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = AHHDR_NEXTHDR,
+ .protocols = {
+ PROTO_LINK(IPPROTO_ESP, &proto_esp),
+ PROTO_LINK(IPPROTO_AH, &proto_ah),
+ PROTO_LINK(IPPROTO_COMP, &proto_comp),
+ PROTO_LINK(IPPROTO_UDP, &proto_udp),
+ PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite),
+ PROTO_LINK(IPPROTO_TCP, &proto_tcp),
+ PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
+ PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
+ },
+ .templates = {
+ [AHHDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ip_auth_hdr, nexthdr),
+ [AHHDR_HDRLENGTH] = AHHDR_FIELD("hdrlength", hdrlen),
+ [AHHDR_RESERVED] = AHHDR_FIELD("reserved", reserved),
+ [AHHDR_SPI] = AHHDR_FIELD("spi", spi),
+ [AHHDR_SEQUENCE] = AHHDR_FIELD("sequence", seq_no),
+ },
+ .format = {
+ .order = {
+ AHHDR_SPI, AHHDR_HDRLENGTH, AHHDR_NEXTHDR,
+ },
+ .filter = (1 << AHHDR_RESERVED) | (1 << AHHDR_SEQUENCE)
+ },
+};
+
+/*
+ * ESP
+ */
+
+#define ESPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct ip_esp_hdr, __member)
+
+const struct proto_desc proto_esp = {
+ .name = "esp",
+ .id = PROTO_DESC_ESP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .templates = {
+ [ESPHDR_SPI] = ESPHDR_FIELD("spi", spi),
+ [ESPHDR_SEQUENCE] = ESPHDR_FIELD("sequence", seq_no),
+ },
+};
+
+/*
+ * IPCOMP
+ */
+
+#define COMPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct ip_comp_hdr, __member)
+
+const struct proto_desc proto_comp = {
+ .name = "comp",
+ .id = PROTO_DESC_COMP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = COMPHDR_NEXTHDR,
+ .protocols = {
+ PROTO_LINK(IPPROTO_ESP, &proto_esp),
+ PROTO_LINK(IPPROTO_AH, &proto_ah),
+ PROTO_LINK(IPPROTO_COMP, &proto_comp),
+ PROTO_LINK(IPPROTO_UDP, &proto_udp),
+ PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite),
+ PROTO_LINK(IPPROTO_TCP, &proto_tcp),
+ PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
+ PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
+ },
+ .templates = {
+ [COMPHDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ip_comp_hdr, nexthdr),
+ [COMPHDR_FLAGS] = HDR_TEMPLATE("flags", &bitmask_type, struct ip_comp_hdr, flags),
+ [COMPHDR_CPI] = COMPHDR_FIELD("cpi", cpi),
+ },
+};
+
+/*
+ * ICMP
+ */
+
+#include <netinet/ip_icmp.h>
+
+static const struct symbol_table icmp_type_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("echo-reply", ICMP_ECHOREPLY),
+ SYMBOL("destination-unreachable", ICMP_DEST_UNREACH),
+ SYMBOL("source-quench", ICMP_SOURCE_QUENCH),
+ SYMBOL("redirect", ICMP_REDIRECT),
+ SYMBOL("echo-request", ICMP_ECHO),
+ SYMBOL("router-advertisement", ICMP_ROUTERADVERT),
+ SYMBOL("router-solicitation", ICMP_ROUTERSOLICIT),
+ SYMBOL("time-exceeded", ICMP_TIME_EXCEEDED),
+ SYMBOL("parameter-problem", ICMP_PARAMETERPROB),
+ SYMBOL("timestamp-request", ICMP_TIMESTAMP),
+ SYMBOL("timestamp-reply", ICMP_TIMESTAMPREPLY),
+ SYMBOL("info-request", ICMP_INFO_REQUEST),
+ SYMBOL("info-reply", ICMP_INFO_REPLY),
+ SYMBOL("address-mask-request", ICMP_ADDRESS),
+ SYMBOL("address-mask-reply", ICMP_ADDRESSREPLY),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype icmp_type_type = {
+ .type = TYPE_ICMP_TYPE,
+ .name = "icmp_type",
+ .desc = "ICMP type",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &icmp_type_tbl,
+};
+
+#define ICMP46HDR_FIELD(__token, __dtype, __struct, __member, __dep) \
+ { \
+ .token = (__token), \
+ .dtype = &__dtype, \
+ .byteorder = BYTEORDER_BIG_ENDIAN, \
+ .offset = offsetof(__struct, __member) * 8, \
+ .len = field_sizeof(__struct, __member) * 8, \
+ .icmp_dep = (__dep), \
+ }
+
+#define ICMPHDR_FIELD(__token, __member, __dep) \
+ ICMP46HDR_FIELD(__token, integer_type, struct icmphdr, __member, __dep)
+
+#define ICMPHDR_TYPE(__name, __type, __member) \
+ HDR_TYPE(__name, __type, struct icmphdr, __member)
+
+const struct proto_desc proto_icmp = {
+ .name = "icmp",
+ .id = PROTO_DESC_ICMP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = ICMPHDR_TYPE,
+ .checksum_key = ICMPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
+ .templates = {
+ [ICMPHDR_TYPE] = ICMPHDR_TYPE("type", &icmp_type_type, type),
+ [ICMPHDR_CODE] = ICMPHDR_TYPE("code", &icmp_code_type, code),
+ [ICMPHDR_CHECKSUM] = ICMPHDR_FIELD("checksum", checksum, PROTO_ICMP_ANY),
+ [ICMPHDR_ID] = ICMPHDR_FIELD("id", un.echo.id, PROTO_ICMP_ECHO),
+ [ICMPHDR_SEQ] = ICMPHDR_FIELD("sequence", un.echo.sequence, PROTO_ICMP_ECHO),
+ [ICMPHDR_GATEWAY] = ICMPHDR_FIELD("gateway", un.gateway, PROTO_ICMP_ADDRESS),
+ [ICMPHDR_MTU] = ICMPHDR_FIELD("mtu", un.frag.mtu, PROTO_ICMP_MTU),
+ },
+};
+
+/*
+ * IGMP
+ */
+
+#include <netinet/igmp.h>
+
+#ifndef IGMP_V3_MEMBERSHIP_REPORT
+#define IGMP_V3_MEMBERSHIP_REPORT 0x22
+#endif
+
+static const struct symbol_table igmp_type_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("membership-query", IGMP_MEMBERSHIP_QUERY),
+ SYMBOL("membership-report-v1", IGMP_V1_MEMBERSHIP_REPORT),
+ SYMBOL("membership-report-v2", IGMP_V2_MEMBERSHIP_REPORT),
+ SYMBOL("membership-report-v3", IGMP_V3_MEMBERSHIP_REPORT),
+ SYMBOL("leave-group", IGMP_V2_LEAVE_GROUP),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype igmp_type_type = {
+ .type = TYPE_IGMP_TYPE,
+ .name = "igmp_type",
+ .desc = "IGMP type",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &igmp_type_tbl,
+};
+
+#define IGMPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct igmp, __member)
+#define IGMPHDR_TYPE(__name, __type, __member) \
+ HDR_TYPE(__name, __type, struct igmp, __member)
+
+const struct proto_desc proto_igmp = {
+ .name = "igmp",
+ .id = PROTO_DESC_IGMP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .checksum_key = IGMPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
+ .templates = {
+ [IGMPHDR_TYPE] = IGMPHDR_TYPE("type", &igmp_type_type, igmp_type),
+ [IGMPHDR_MRT] = IGMPHDR_FIELD("mrt", igmp_code),
+ [IGMPHDR_CHECKSUM] = IGMPHDR_FIELD("checksum", igmp_cksum),
+ [IGMPHDR_GROUP] = IGMPHDR_FIELD("group", igmp_group),
+ },
+};
+
+/*
+ * UDP/UDP-Lite
+ */
+
+#include <netinet/udp.h>
+#define UDPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct udphdr, __member)
+
+const struct proto_desc proto_udp = {
+ .name = "udp",
+ .id = PROTO_DESC_UDP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .checksum_key = UDPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
+ .templates = {
+ [UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
+ [UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest),
+ [UDPHDR_LENGTH] = UDPHDR_FIELD("length", len),
+ [UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check),
+ },
+ .protocols = {
+ PROTO_LINK(0, &proto_vxlan),
+ PROTO_LINK(0, &proto_geneve),
+ },
+};
+
+const struct proto_desc proto_udplite = {
+ .name = "udplite",
+ .id = PROTO_DESC_UDPLITE,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .templates = {
+ [UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
+ [UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest),
+ [UDPHDR_CSUMCOV] = UDPHDR_FIELD("csumcov", len),
+ [UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check),
+ },
+};
+
+/*
+ * TCP
+ */
+
+#include <netinet/tcp.h>
+
+static const struct symbol_table tcp_flag_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("fin", TCP_FLAG_FIN),
+ SYMBOL("syn", TCP_FLAG_SYN),
+ SYMBOL("rst", TCP_FLAG_RST),
+ SYMBOL("psh", TCP_FLAG_PSH),
+ SYMBOL("ack", TCP_FLAG_ACK),
+ SYMBOL("urg", TCP_FLAG_URG),
+ SYMBOL("ecn", TCP_FLAG_ECN),
+ SYMBOL("cwr", TCP_FLAG_CWR),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype tcp_flag_type = {
+ .type = TYPE_TCP_FLAG,
+ .name = "tcp_flag",
+ .desc = "TCP flag",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = BITS_PER_BYTE,
+ .basetype = &bitmask_type,
+ .sym_tbl = &tcp_flag_tbl,
+};
+
+#define TCPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct tcphdr, __member)
+
+const struct proto_desc proto_tcp = {
+ .name = "tcp",
+ .id = PROTO_DESC_TCP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .checksum_key = TCPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
+ .templates = {
+ [TCPHDR_SPORT] = INET_SERVICE("sport", struct tcphdr, source),
+ [TCPHDR_DPORT] = INET_SERVICE("dport", struct tcphdr, dest),
+ [TCPHDR_SEQ] = TCPHDR_FIELD("sequence", seq),
+ [TCPHDR_ACKSEQ] = TCPHDR_FIELD("ackseq", ack_seq),
+ [TCPHDR_DOFF] = HDR_BITFIELD("doff", &integer_type,
+ (12 * BITS_PER_BYTE), 4),
+ [TCPHDR_RESERVED] = HDR_BITFIELD("reserved", &integer_type,
+ (12 * BITS_PER_BYTE) + 4, 4),
+ [TCPHDR_FLAGS] = HDR_BITFIELD("flags", &tcp_flag_type,
+ 13 * BITS_PER_BYTE,
+ BITS_PER_BYTE),
+ [TCPHDR_WINDOW] = TCPHDR_FIELD("window", window),
+ [TCPHDR_CHECKSUM] = TCPHDR_FIELD("checksum", check),
+ [TCPHDR_URGPTR] = TCPHDR_FIELD("urgptr", urg_ptr),
+ },
+ .format = {
+ .filter = (1 << TCPHDR_SEQ) | (1 << TCPHDR_ACKSEQ) |
+ (1 << TCPHDR_DOFF) | (1 << TCPHDR_RESERVED) |
+ (1 << TCPHDR_URGPTR),
+ },
+};
+
+/*
+ * DCCP
+ */
+
+static const struct symbol_table dccp_pkttype_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("request", DCCP_PKT_REQUEST),
+ SYMBOL("response", DCCP_PKT_RESPONSE),
+ SYMBOL("data", DCCP_PKT_DATA),
+ SYMBOL("ack", DCCP_PKT_ACK),
+ SYMBOL("dataack", DCCP_PKT_DATAACK),
+ SYMBOL("closereq", DCCP_PKT_CLOSEREQ),
+ SYMBOL("close", DCCP_PKT_CLOSE),
+ SYMBOL("reset", DCCP_PKT_RESET),
+ SYMBOL("sync", DCCP_PKT_SYNC),
+ SYMBOL("syncack", DCCP_PKT_SYNCACK),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype dccp_pkttype_type = {
+ .type = TYPE_DCCP_PKTTYPE,
+ .name = "dccp_pkttype",
+ .desc = "DCCP packet type",
+ .byteorder = BYTEORDER_INVALID,
+ .size = 4,
+ .basetype = &integer_type,
+ .sym_tbl = &dccp_pkttype_tbl,
+};
+
+
+#define DCCPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct dccp_hdr, __member)
+
+const struct proto_desc proto_dccp = {
+ .name = "dccp",
+ .id = PROTO_DESC_DCCP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .templates = {
+ [DCCPHDR_SPORT] = INET_SERVICE("sport", struct dccp_hdr, dccph_sport),
+ [DCCPHDR_DPORT] = INET_SERVICE("dport", struct dccp_hdr, dccph_dport),
+ [DCCPHDR_TYPE] = HDR_BITFIELD("type", &dccp_pkttype_type,
+ (8 * BITS_PER_BYTE) + 3, 4),
+ },
+};
+
+/*
+ * SCTP
+ */
+
+#define SCTPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct sctphdr, __member)
+
+const struct proto_desc proto_sctp = {
+ .name = "sctp",
+ .id = PROTO_DESC_SCTP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .checksum_key = SCTPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_SCTP,
+ .templates = {
+ [SCTPHDR_SPORT] = INET_SERVICE("sport", struct sctphdr, source),
+ [SCTPHDR_DPORT] = INET_SERVICE("dport", struct sctphdr, dest),
+ [SCTPHDR_VTAG] = SCTPHDR_FIELD("vtag", vtag),
+ [SCTPHDR_CHECKSUM] = SCTPHDR_FIELD("checksum", checksum),
+ },
+};
+
+/*
+ * Dummy Transpor Header (common udp/tcp/dccp/sctp fields)
+ */
+const struct proto_desc proto_th = {
+ .name = "th",
+ .id = PROTO_DESC_TH,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .templates = {
+ [THDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
+ [THDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest),
+ },
+};
+
+/*
+ * IPv4
+ */
+
+#include <netinet/ip.h>
+
+static const struct symbol_table dscp_type_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("cs0", 0x00),
+ SYMBOL("cs1", 0x08),
+ SYMBOL("cs2", 0x10),
+ SYMBOL("cs3", 0x18),
+ SYMBOL("cs4", 0x20),
+ 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),
+ SYMBOL("af21", 0x12),
+ SYMBOL("af22", 0x14),
+ SYMBOL("af23", 0x16),
+ SYMBOL("af31", 0x1a),
+ SYMBOL("af32", 0x1c),
+ SYMBOL("af33", 0x1e),
+ SYMBOL("af41", 0x22),
+ SYMBOL("af42", 0x24),
+ SYMBOL("af43", 0x26),
+ SYMBOL("va", 0x2c),
+ SYMBOL("ef", 0x2e),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype dscp_type = {
+ .type = TYPE_DSCP,
+ .name = "dscp",
+ .desc = "Differentiated Services Code Point",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = 6,
+ .basetype = &integer_type,
+ .basefmt = "0x%.2Zx",
+ .sym_tbl = &dscp_type_tbl,
+};
+
+static const struct symbol_table ecn_type_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("not-ect", 0x00),
+ SYMBOL("ect1", 0x01),
+ SYMBOL("ect0", 0x02),
+ SYMBOL("ce", 0x03),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype ecn_type = {
+ .type = TYPE_ECN,
+ .name = "ecn",
+ .desc = "Explicit Congestion Notification",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = 2,
+ .basetype = &integer_type,
+ .basefmt = "0x%.1Zx",
+ .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) \
+ HDR_TYPE(__name, &ipaddr_type, struct iphdr, __member)
+
+const struct proto_desc proto_ip = {
+ .name = "ip",
+ .id = PROTO_DESC_IP,
+ .base = PROTO_BASE_NETWORK_HDR,
+ .checksum_key = IPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
+ .protocols = {
+ PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
+ PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
+ PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
+ PROTO_LINK(IPPROTO_ESP, &proto_esp),
+ PROTO_LINK(IPPROTO_AH, &proto_ah),
+ PROTO_LINK(IPPROTO_COMP, &proto_comp),
+ PROTO_LINK(IPPROTO_UDP, &proto_udp),
+ PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite),
+ 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),
+ [IPHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4),
+ [IPHDR_HDRLENGTH] = HDR_BITFIELD("hdrlength", &integer_type, 4, 4),
+ [IPHDR_DSCP] = HDR_BITFIELD("dscp", &dscp_type, 8, 6),
+ [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] = 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),
+ [IPHDR_SADDR] = IPHDR_ADDR("saddr", saddr),
+ [IPHDR_DADDR] = IPHDR_ADDR("daddr", daddr),
+ },
+ .format = {
+ .order = {
+ IPHDR_SADDR, IPHDR_DADDR, IPHDR_DSCP, IPHDR_ECN,
+ IPHDR_TTL, IPHDR_ID, IPHDR_PROTOCOL, IPHDR_LENGTH,
+ },
+ .filter = (1 << IPHDR_VERSION) | (1 << IPHDR_HDRLENGTH) |
+ (1 << IPHDR_FRAG_OFF),
+ },
+ .pseudohdr = {
+ IPHDR_SADDR, IPHDR_DADDR, IPHDR_PROTOCOL, IPHDR_LENGTH,
+ },
+};
+
+/*
+ * ICMPv6
+ */
+
+#include <netinet/icmp6.h>
+
+#define IND_NEIGHBOR_SOLICIT 141
+#define IND_NEIGHBOR_ADVERT 142
+#define ICMPV6_MLD2_REPORT 143
+
+static const struct symbol_table icmp6_type_tbl = {
+ .base = BASE_DECIMAL,
+ .symbols = {
+ SYMBOL("destination-unreachable", ICMP6_DST_UNREACH),
+ SYMBOL("packet-too-big", ICMP6_PACKET_TOO_BIG),
+ SYMBOL("time-exceeded", ICMP6_TIME_EXCEEDED),
+ SYMBOL("parameter-problem", ICMP6_PARAM_PROB),
+ SYMBOL("echo-request", ICMP6_ECHO_REQUEST),
+ SYMBOL("echo-reply", ICMP6_ECHO_REPLY),
+ SYMBOL("mld-listener-query", MLD_LISTENER_QUERY),
+ SYMBOL("mld-listener-report", MLD_LISTENER_REPORT),
+ SYMBOL("mld-listener-done", MLD_LISTENER_REDUCTION),
+ SYMBOL("mld-listener-reduction", MLD_LISTENER_REDUCTION),
+ SYMBOL("nd-router-solicit", ND_ROUTER_SOLICIT),
+ SYMBOL("nd-router-advert", ND_ROUTER_ADVERT),
+ SYMBOL("nd-neighbor-solicit", ND_NEIGHBOR_SOLICIT),
+ SYMBOL("nd-neighbor-advert", ND_NEIGHBOR_ADVERT),
+ SYMBOL("nd-redirect", ND_REDIRECT),
+ SYMBOL("router-renumbering", ICMP6_ROUTER_RENUMBERING),
+ SYMBOL("ind-neighbor-solicit", IND_NEIGHBOR_SOLICIT),
+ SYMBOL("ind-neighbor-advert", IND_NEIGHBOR_ADVERT),
+ SYMBOL("mld2-listener-report", ICMPV6_MLD2_REPORT),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype icmp6_type_type = {
+ .type = TYPE_ICMP6_TYPE,
+ .name = "icmpv6_type",
+ .desc = "ICMPv6 type",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &icmp6_type_tbl,
+};
+
+#define ICMP6HDR_FIELD(__token, __member, __dep) \
+ ICMP46HDR_FIELD(__token, integer_type, struct icmp6_hdr, __member, __dep)
+#define ICMP6HDR_TYPE(__name, __type, __member) \
+ HDR_TYPE(__name, __type, struct icmp6_hdr, __member)
+
+const struct proto_desc proto_icmp6 = {
+ .name = "icmpv6",
+ .id = PROTO_DESC_ICMPV6,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = ICMP6HDR_TYPE,
+ .checksum_key = ICMP6HDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
+ .templates = {
+ [ICMP6HDR_TYPE] = ICMP6HDR_TYPE("type", &icmp6_type_type, icmp6_type),
+ [ICMP6HDR_CODE] = ICMP6HDR_TYPE("code", &icmpv6_code_type, icmp6_code),
+ [ICMP6HDR_CHECKSUM] = ICMP6HDR_FIELD("checksum", icmp6_cksum, PROTO_ICMP_ANY),
+ [ICMP6HDR_PPTR] = ICMP6HDR_FIELD("parameter-problem", icmp6_pptr, PROTO_ICMP6_PPTR),
+ [ICMP6HDR_MTU] = ICMP6HDR_FIELD("mtu", icmp6_mtu, PROTO_ICMP6_MTU),
+ [ICMP6HDR_ID] = ICMP6HDR_FIELD("id", icmp6_id, PROTO_ICMP6_ECHO),
+ [ICMP6HDR_SEQ] = ICMP6HDR_FIELD("sequence", icmp6_seq, PROTO_ICMP6_ECHO),
+ [ICMP6HDR_MAXDELAY] = ICMP6HDR_FIELD("max-delay", icmp6_maxdelay, PROTO_ICMP6_MGMQ),
+ [ICMP6HDR_TADDR] = ICMP46HDR_FIELD("taddr", ip6addr_type,
+ struct nd_neighbor_solicit, nd_ns_target,
+ PROTO_ICMP6_ADDRESS),
+ [ICMP6HDR_DADDR] = ICMP46HDR_FIELD("daddr", ip6addr_type,
+ struct nd_redirect, nd_rd_dst,
+ PROTO_ICMP6_REDIRECT),
+ },
+};
+
+/*
+ * IPv6
+ */
+
+#define IP6HDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct ipv6hdr, __member)
+#define IP6HDR_ADDR(__name, __member) \
+ HDR_TYPE(__name, &ip6addr_type, struct ipv6hdr, __member)
+#define IP6HDR_PROTOCOL(__name, __member) \
+ HDR_TYPE(__name, &inet_service_type, struct ipv6hdr, __member)
+
+const struct proto_desc proto_ip6 = {
+ .name = "ip6",
+ .id = PROTO_DESC_IP6,
+ .base = PROTO_BASE_NETWORK_HDR,
+ .protocols = {
+ PROTO_LINK(IPPROTO_ESP, &proto_esp),
+ PROTO_LINK(IPPROTO_AH, &proto_ah),
+ PROTO_LINK(IPPROTO_COMP, &proto_comp),
+ PROTO_LINK(IPPROTO_UDP, &proto_udp),
+ PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite),
+ PROTO_LINK(IPPROTO_TCP, &proto_tcp),
+ PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
+ PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
+ 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),
+ [IP6HDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4),
+ [IP6HDR_DSCP] = HDR_BITFIELD("dscp", &dscp_type, 4, 6),
+ [IP6HDR_ECN] = HDR_BITFIELD("ecn", &ecn_type, 10, 2),
+ [IP6HDR_FLOWLABEL] = HDR_BITFIELD("flowlabel", &integer_type, 12, 20),
+ [IP6HDR_LENGTH] = IP6HDR_FIELD("length", payload_len),
+ [IP6HDR_NEXTHDR] = INET_PROTOCOL("nexthdr", struct ipv6hdr, nexthdr),
+ [IP6HDR_HOPLIMIT] = IP6HDR_FIELD("hoplimit", hop_limit),
+ [IP6HDR_SADDR] = IP6HDR_ADDR("saddr", saddr),
+ [IP6HDR_DADDR] = IP6HDR_ADDR("daddr", daddr),
+ },
+ .format = {
+ .order = {
+ IP6HDR_SADDR, IP6HDR_DADDR, IP6HDR_DSCP, IP6HDR_ECN,
+ IP6HDR_HOPLIMIT, IP6HDR_FLOWLABEL, IP6HDR_NEXTHDR,
+ IP6HDR_LENGTH,
+ },
+ .filter = (1 << IP6HDR_VERSION),
+ },
+ .pseudohdr = {
+ IP6HDR_SADDR, IP6HDR_DADDR, IP6HDR_NEXTHDR, IP6HDR_LENGTH,
+ },
+};
+
+/*
+ * Dummy protocol for mixed IPv4/IPv6 tables. The protocol is set at the link
+ * layer header, the upper layer protocols are IPv4 and IPv6.
+ */
+
+const struct proto_desc proto_inet = {
+ .name = "inet",
+ .base = PROTO_BASE_LL_HDR,
+ .protocols = {
+ PROTO_LINK(NFPROTO_IPV4, &proto_ip),
+ PROTO_LINK(NFPROTO_IPV6, &proto_ip6),
+ },
+ .templates = {
+ [0] = PROTO_META_TEMPLATE("nfproto", &nfproto_type, NFT_META_NFPROTO, 8),
+ },
+};
+
+/*
+ * Dummy protocol for cases where the network layer protocol isn't known
+ * (IPv4 or IPv6), The higher layer protocols are the protocols common to
+ * both.
+ */
+
+const struct proto_desc proto_inet_service = {
+ .name = "inet-service",
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = 0,
+ .protocols = {
+ PROTO_LINK(IPPROTO_ESP, &proto_esp),
+ PROTO_LINK(IPPROTO_AH, &proto_ah),
+ PROTO_LINK(IPPROTO_COMP, &proto_comp),
+ PROTO_LINK(IPPROTO_UDP, &proto_udp),
+ PROTO_LINK(IPPROTO_UDPLITE, &proto_udplite),
+ PROTO_LINK(IPPROTO_TCP, &proto_tcp),
+ PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
+ PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
+ 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),
+ },
+};
+
+/*
+ * ARP
+ */
+
+#include <net/if_arp.h>
+
+static const struct symbol_table arpop_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("request", __constant_htons(ARPOP_REQUEST)),
+ SYMBOL("reply", __constant_htons(ARPOP_REPLY)),
+ SYMBOL("rrequest", __constant_htons(ARPOP_RREQUEST)),
+ SYMBOL("rreply", __constant_htons(ARPOP_RREPLY)),
+ SYMBOL("inrequest", __constant_htons(ARPOP_InREQUEST)),
+ SYMBOL("inreply", __constant_htons(ARPOP_InREPLY)),
+ SYMBOL("nak", __constant_htons(ARPOP_NAK)),
+ SYMBOL_LIST_END
+ },
+};
+
+const struct datatype arpop_type = {
+ .type = TYPE_ARPOP,
+ .name = "arp_op",
+ .desc = "ARP operation",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = 2 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .sym_tbl = &arpop_tbl,
+};
+
+#define ARPHDR_TYPE(__name, __type, __member) \
+ HDR_TYPE(__name, __type, struct arp_hdr, __member)
+#define ARPHDR_FIELD(__name, __member) \
+ HDR_FIELD(__name, struct arp_hdr, __member)
+
+const struct proto_desc proto_arp = {
+ .name = "arp",
+ .id = PROTO_DESC_ARP,
+ .base = PROTO_BASE_NETWORK_HDR,
+ .templates = {
+ [ARPHDR_HRD] = ARPHDR_FIELD("htype", htype),
+ [ARPHDR_PRO] = ARPHDR_TYPE("ptype", &ethertype_type, ptype),
+ [ARPHDR_HLN] = ARPHDR_FIELD("hlen", hlen),
+ [ARPHDR_PLN] = ARPHDR_FIELD("plen", plen),
+ [ARPHDR_OP] = ARPHDR_TYPE("operation", &arpop_type, oper),
+ [ARPHDR_SADDR_ETHER] = ARPHDR_TYPE("saddr ether", &etheraddr_type, sha),
+ [ARPHDR_SADDR_IP] = ARPHDR_TYPE("saddr ip", &ipaddr_type, spa),
+ [ARPHDR_DADDR_ETHER] = ARPHDR_TYPE("daddr ether", &etheraddr_type, tha),
+ [ARPHDR_DADDR_IP] = ARPHDR_TYPE("daddr ip", &ipaddr_type, tpa),
+ },
+ .format = {
+ .filter = (1 << ARPHDR_HRD) | (1 << ARPHDR_PRO) |
+ (1 << ARPHDR_HLN) | (1 << ARPHDR_PLN) |
+ (1 << ARPHDR_SADDR_ETHER) | (1 << ARPHDR_DADDR_ETHER) |
+ (1 << ARPHDR_SADDR_IP) | (1 << ARPHDR_DADDR_IP),
+ },
+};
+
+/*
+ * VLAN
+ */
+
+#include <net/ethernet.h>
+
+#define VLANHDR_BITFIELD(__name, __offset, __len) \
+ HDR_BITFIELD(__name, &integer_type, __offset, __len)
+#define VLANHDR_TYPE(__name, __type, __member) \
+ HDR_TYPE(__name, __type, struct vlan_hdr, __member)
+
+const struct proto_desc proto_vlan = {
+ .name = "vlan",
+ .id = PROTO_DESC_VLAN,
+ .base = PROTO_BASE_LL_HDR,
+ .protocol_key = VLANHDR_TYPE,
+ .length = sizeof(struct vlan_hdr) * BITS_PER_BYTE,
+ .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),
+ PROTO_LINK(__constant_htons(ETH_P_8021AD), &proto_vlan),
+
+ },
+ .templates = {
+ [VLANHDR_PCP] = VLANHDR_BITFIELD("pcp", 0, 3),
+ [VLANHDR_DEI] = VLANHDR_BITFIELD("dei", 3, 1),
+ [VLANHDR_CFI] = VLANHDR_BITFIELD("cfi", 3, 1),
+ [VLANHDR_VID] = VLANHDR_BITFIELD("id", 4, 12),
+ [VLANHDR_TYPE] = VLANHDR_TYPE("type", &ethertype_type, vlan_type),
+ },
+};
+
+/*
+ * Ethernet
+ */
+
+const struct datatype etheraddr_type = {
+ .type = TYPE_ETHERADDR,
+ .name = "ether_addr",
+ .desc = "Ethernet address",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = ETH_ALEN * BITS_PER_BYTE,
+ .basetype = &lladdr_type,
+};
+
+static const struct symbol_table ethertype_tbl = {
+ .base = BASE_HEXADECIMAL,
+ .symbols = {
+ SYMBOL("ip", __constant_htons(ETH_P_IP)),
+ SYMBOL("arp", __constant_htons(ETH_P_ARP)),
+ SYMBOL("ip6", __constant_htons(ETH_P_IPV6)),
+ SYMBOL("8021q", __constant_htons(ETH_P_8021Q)),
+ SYMBOL("8021ad", __constant_htons(ETH_P_8021AD)),
+
+ /* for compatibility with older versions */
+ SYMBOL("vlan", __constant_htons(ETH_P_8021Q)),
+ SYMBOL_LIST_END
+ },
+};
+
+static void ethertype_print(const struct expr *expr, struct output_ctx *octx)
+{
+ return symbolic_constant_print(&ethertype_tbl, expr, false, octx);
+}
+
+const struct datatype ethertype_type = {
+ .type = TYPE_ETHERTYPE,
+ .name = "ether_type",
+ .desc = "Ethernet protocol",
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .size = 2 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .basefmt = "0x%.4Zx",
+ .print = ethertype_print,
+ .sym_tbl = &ethertype_tbl,
+};
+
+#define ETHHDR_TEMPLATE(__name, __dtype, __member) \
+ HDR_TEMPLATE(__name, __dtype, struct ether_header, __member)
+#define ETHHDR_TYPE(__name, __member) \
+ ETHHDR_TEMPLATE(__name, &ethertype_type, __member)
+#define ETHHDR_ADDR(__name, __member) \
+ PROTO_HDR_TEMPLATE(__name, &etheraddr_type, \
+ BYTEORDER_BIG_ENDIAN, \
+ offsetof(struct ether_header, __member) * 8, \
+ field_sizeof(struct ether_header, __member) * 8)
+
+const struct proto_desc proto_eth = {
+ .name = "ether",
+ .id = PROTO_DESC_ETHER,
+ .base = PROTO_BASE_LL_HDR,
+ .protocol_key = ETHHDR_TYPE,
+ .length = sizeof(struct ether_header) * BITS_PER_BYTE,
+ .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),
+ PROTO_LINK(__constant_htons(ETH_P_8021AD), &proto_vlan),
+ },
+ .templates = {
+ [ETHHDR_DADDR] = ETHHDR_ADDR("daddr", ether_dhost),
+ [ETHHDR_SADDR] = ETHHDR_ADDR("saddr", ether_shost),
+ [ETHHDR_TYPE] = ETHHDR_TYPE("type", ether_type),
+ },
+ .format = {
+ .order = {
+ ETHHDR_SADDR, ETHHDR_DADDR, ETHHDR_TYPE,
+ },
+ },
+
+};
+
+/*
+ * 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 = {
+ .name = "netdev",
+ .base = PROTO_BASE_LL_HDR,
+ .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),
+ PROTO_LINK(__constant_htons(ETH_P_8021AD), &proto_vlan),
+ },
+ .templates = {
+ [0] = PROTO_META_TEMPLATE("protocol", &ethertype_type, NFT_META_PROTOCOL, 16),
+ },
+};
+
+static const struct proto_desc *const proto_definitions[PROTO_DESC_MAX + 1] = {
+ [PROTO_DESC_AH] = &proto_ah,
+ [PROTO_DESC_ESP] = &proto_esp,
+ [PROTO_DESC_COMP] = &proto_comp,
+ [PROTO_DESC_ICMP] = &proto_icmp,
+ [PROTO_DESC_IGMP] = &proto_igmp,
+ [PROTO_DESC_UDP] = &proto_udp,
+ [PROTO_DESC_UDPLITE] = &proto_udplite,
+ [PROTO_DESC_TCP] = &proto_tcp,
+ [PROTO_DESC_DCCP] = &proto_dccp,
+ [PROTO_DESC_SCTP] = &proto_sctp,
+ [PROTO_DESC_TH] = &proto_th,
+ [PROTO_DESC_IP] = &proto_ip,
+ [PROTO_DESC_IP6] = &proto_ip6,
+ [PROTO_DESC_ICMPV6] = &proto_icmp6,
+ [PROTO_DESC_ARP] = &proto_arp,
+ [PROTO_DESC_VLAN] = &proto_vlan,
+ [PROTO_DESC_ETHER] = &proto_eth,
+ [PROTO_DESC_VXLAN] = &proto_vxlan,
+ [PROTO_DESC_GENEVE] = &proto_geneve,
+ [PROTO_DESC_GRE] = &proto_gre,
+ [PROTO_DESC_GRETAP] = &proto_gretap,
+};
+
+const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id)
+{
+ if (desc_id >= PROTO_DESC_UNKNOWN &&
+ desc_id <= PROTO_DESC_MAX)
+ return proto_definitions[desc_id];
+
+ return NULL;
+}
diff --git a/src/rt.c b/src/rt.c
new file mode 100644
index 0000000..f5c8055
--- /dev/null
+++ b/src/rt.c
@@ -0,0 +1,211 @@
+/*
+ * Routing expression related definition and types.
+ *
+ * Copyright (c) 2016 Anders K. Pedersen <akp@cohaesio.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.
+ */
+
+#include <nft.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <linux/netfilter.h>
+
+#include <nftables.h>
+#include <expression.h>
+#include <datatype.h>
+#include <rt.h>
+#include <rule.h>
+#include <json.h>
+
+void realm_table_rt_init(struct nft_ctx *ctx)
+{
+ ctx->output.tbl.realm = rt_symbol_table_init("/etc/iproute2/rt_realms");
+}
+
+void realm_table_rt_exit(struct nft_ctx *ctx)
+{
+ rt_symbol_table_free(ctx->output.tbl.realm);
+}
+
+static void realm_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ return symbolic_constant_print(octx->tbl.realm, expr, true, octx);
+}
+
+static struct error_record *realm_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ return symbolic_constant_parse(ctx, sym, ctx->tbl->realm, res);
+}
+
+const struct datatype realm_type = {
+ .type = TYPE_REALM,
+ .name = "realm",
+ .desc = "routing realm",
+ .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[] = {
+ [NFT_RT_CLASSID] = RT_TEMPLATE("classid",
+ &realm_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN,
+ false),
+ [NFT_RT_NEXTHOP4] = RT_TEMPLATE("nexthop",
+ &ipaddr_type,
+ 4 * BITS_PER_BYTE,
+ BYTEORDER_BIG_ENDIAN,
+ true),
+ [NFT_RT_NEXTHOP6] = RT_TEMPLATE("nexthop",
+ &ip6addr_type,
+ 16 * BITS_PER_BYTE,
+ BYTEORDER_BIG_ENDIAN,
+ true),
+ [NFT_RT_TCPMSS] = RT_TEMPLATE("mtu",
+ &integer_type,
+ 2 * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN,
+ false),
+ [NFT_RT_XFRM] = RT_TEMPLATE("ipsec",
+ &boolean_type,
+ BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN,
+ false),
+};
+
+static void rt_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ const char *ip = "";
+
+ switch (expr->rt.key) {
+ case NFT_RT_NEXTHOP4:
+ ip = "ip ";
+ break;
+ case NFT_RT_NEXTHOP6:
+ ip = "ip6 ";
+ break;
+ default:
+ break;
+ }
+
+ nft_print(octx, "rt %s%s", ip, rt_templates[expr->rt.key].token);
+}
+
+static bool rt_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->rt.key == e2->rt.key;
+}
+
+static void rt_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->rt.key = expr->rt.key;
+}
+
+#define NFTNL_UDATA_RT_KEY 0
+#define NFTNL_UDATA_RT_MAX 1
+
+static int rt_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_RT_KEY, expr->rt.key);
+
+ return 0;
+}
+
+static int rt_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_RT_KEY:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *rt_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_RT_MAX + 1] = {};
+ uint32_t key;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ rt_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_RT_KEY])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_RT_KEY]);
+
+ return rt_expr_alloc(&internal_location, key, false);
+}
+
+const struct expr_ops rt_expr_ops = {
+ .type = EXPR_RT,
+ .name = "rt",
+ .print = rt_expr_print,
+ .json = rt_expr_json,
+ .cmp = rt_expr_cmp,
+ .clone = rt_expr_clone,
+ .parse_udata = rt_expr_parse_udata,
+ .build_udata = rt_expr_build_udata,
+};
+
+struct expr *rt_expr_alloc(const struct location *loc, enum nft_rt_keys key,
+ bool invalid)
+{
+ const struct rt_template *tmpl = &rt_templates[key];
+ struct expr *expr;
+
+ if (invalid && tmpl->invalid)
+ expr = expr_alloc(loc, EXPR_RT, &invalid_type,
+ tmpl->byteorder, 0);
+ else
+ expr = expr_alloc(loc, EXPR_RT, tmpl->dtype,
+ tmpl->byteorder, tmpl->len);
+ expr->rt.key = key;
+
+ return expr;
+}
+
+void rt_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
+{
+ const struct proto_desc *desc;
+
+ switch (expr->rt.key) {
+ case NFT_RT_NEXTHOP4:
+ desc = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc == &proto_ip)
+ datatype_set(expr, &ipaddr_type);
+ else if (desc == &proto_ip6) {
+ expr->rt.key++;
+ datatype_set(expr, &ip6addr_type);
+ }
+ expr->len = expr->dtype->size;
+ break;
+ default:
+ break;
+ }
+}
diff --git a/src/rule.c b/src/rule.c
new file mode 100644
index 0000000..739b7a5
--- /dev/null
+++ b/src/rule.c
@@ -0,0 +1,2799 @@
+/*
+ * Copyright (c) 2008-2012 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include <statement.h>
+#include <rule.h>
+#include <utils.h>
+#include <netdb.h>
+#include <netlink.h>
+#include <mnl.h>
+#include <misspell.h>
+#include <json.h>
+#include <cache.h>
+#include <owner.h>
+#include <intervals.h>
+#include "nftutils.h"
+
+#include <libnftnl/common.h>
+#include <libnftnl/ruleset.h>
+#include <netinet/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/nf_synproxy.h>
+#include <net/if.h>
+#include <linux/netfilter_bridge.h>
+
+static const char *const tcp_state_to_name[] = {
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT] = "syn_sent",
+ [NFTNL_CTTIMEOUT_TCP_SYN_RECV] = "syn_recv",
+ [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] = "established",
+ [NFTNL_CTTIMEOUT_TCP_FIN_WAIT] = "fin_wait",
+ [NFTNL_CTTIMEOUT_TCP_CLOSE_WAIT] = "close_wait",
+ [NFTNL_CTTIMEOUT_TCP_LAST_ACK] = "last_ack",
+ [NFTNL_CTTIMEOUT_TCP_TIME_WAIT] = "time_wait",
+ [NFTNL_CTTIMEOUT_TCP_CLOSE] = "close",
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT2] = "syn_sent2",
+ [NFTNL_CTTIMEOUT_TCP_RETRANS] = "retrans",
+ [NFTNL_CTTIMEOUT_TCP_UNACK] = "unack",
+};
+
+static const char *const udp_state_to_name[] = {
+ [NFTNL_CTTIMEOUT_UDP_UNREPLIED] = "unreplied",
+ [NFTNL_CTTIMEOUT_UDP_REPLIED] = "replied",
+};
+
+static uint32_t tcp_dflt_timeout[] = {
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT] = 120,
+ [NFTNL_CTTIMEOUT_TCP_SYN_RECV] = 60,
+ [NFTNL_CTTIMEOUT_TCP_ESTABLISHED] = 432000,
+ [NFTNL_CTTIMEOUT_TCP_FIN_WAIT] = 120,
+ [NFTNL_CTTIMEOUT_TCP_CLOSE_WAIT] = 60,
+ [NFTNL_CTTIMEOUT_TCP_LAST_ACK] = 30,
+ [NFTNL_CTTIMEOUT_TCP_TIME_WAIT] = 120,
+ [NFTNL_CTTIMEOUT_TCP_CLOSE] = 10,
+ [NFTNL_CTTIMEOUT_TCP_SYN_SENT2] = 120,
+ [NFTNL_CTTIMEOUT_TCP_RETRANS] = 300,
+ [NFTNL_CTTIMEOUT_TCP_UNACK] = 300,
+};
+
+static uint32_t udp_dflt_timeout[] = {
+ [NFTNL_CTTIMEOUT_UDP_UNREPLIED] = 30,
+ [NFTNL_CTTIMEOUT_UDP_REPLIED] = 120,
+};
+
+struct timeout_protocol timeout_protocol[UINT8_MAX + 1] = {
+ [IPPROTO_TCP] = {
+ .array_size = NFTNL_CTTIMEOUT_TCP_MAX,
+ .state_to_name = tcp_state_to_name,
+ .dflt_timeout = tcp_dflt_timeout,
+ },
+ [IPPROTO_UDP] = {
+ .array_size = NFTNL_CTTIMEOUT_UDP_MAX,
+ .state_to_name = udp_state_to_name,
+ .dflt_timeout = udp_dflt_timeout,
+ },
+};
+
+int timeout_str2num(uint16_t l4proto, struct timeout_state *ts)
+{
+ unsigned int i;
+
+ for (i = 0; i < timeout_protocol[l4proto].array_size; i++) {
+ if (!strcmp(timeout_protocol[l4proto].state_to_name[i], ts->timeout_str)) {
+ ts->timeout_index = i;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+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);
+}
+
+void handle_merge(struct handle *dst, const struct handle *src)
+{
+ if (dst->family == 0)
+ dst->family = src->family;
+ if (dst->table.name == NULL && src->table.name != NULL) {
+ dst->table.name = xstrdup(src->table.name);
+ dst->table.location = src->table.location;
+ }
+ if (dst->chain.name == NULL && src->chain.name != NULL) {
+ dst->chain.name = xstrdup(src->chain.name);
+ dst->chain.location = src->chain.location;
+ }
+ if (dst->set.name == NULL && src->set.name != NULL) {
+ dst->set.name = xstrdup(src->set.name);
+ dst->set.location = src->set.location;
+ }
+ if (dst->flowtable.name == NULL && src->flowtable.name != NULL)
+ dst->flowtable.name = xstrdup(src->flowtable.name);
+ if (dst->obj.name == NULL && src->obj.name != NULL)
+ dst->obj.name = xstrdup(src->obj.name);
+ if (dst->handle.id == 0)
+ dst->handle = src->handle;
+ if (dst->position.id == 0)
+ dst->position = src->position;
+ if (dst->index.id == 0)
+ dst->index = src->index;
+}
+
+/* internal ID to uniquely identify a set in the batch */
+static uint32_t set_id;
+
+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;
+ set->location = *loc;
+
+ init_list_head(&set->stmt_list);
+
+ return set;
+}
+
+struct set *set_clone(const struct set *set)
+{
+ struct set *new_set;
+
+ new_set = set_alloc(&internal_location);
+ handle_merge(&new_set->handle, &set->handle);
+ new_set->flags = set->flags;
+ new_set->gc_int = set->gc_int;
+ new_set->timeout = set->timeout;
+ new_set->key = expr_clone(set->key);
+ if (set->data)
+ new_set->data = expr_clone(set->data);
+ new_set->objtype = set->objtype;
+ new_set->policy = set->policy;
+ new_set->automerge = set->automerge;
+ new_set->desc = set->desc;
+ init_list_head(&new_set->stmt_list);
+
+ return new_set;
+}
+
+struct set *set_get(struct set *set)
+{
+ set->refcnt++;
+ return set;
+}
+
+void set_free(struct set *set)
+{
+ struct stmt *stmt, *next;
+
+ if (--set->refcnt > 0)
+ return;
+
+ expr_free(set->init);
+ if (set->comment)
+ xfree(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);
+}
+
+struct set *set_lookup_fuzzy(const char *set_name,
+ const struct nft_cache *cache,
+ const struct table **t)
+{
+ struct string_misspell_state st;
+ struct table *table;
+ struct set *set;
+
+ string_misspell_init(&st);
+
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (set_is_anonymous(set->flags))
+ continue;
+ if (string_misspell_update(set->handle.set.name,
+ set_name, set, &st))
+ *t = table;
+ }
+ }
+ return st.obj;
+}
+
+struct set *set_lookup_global(uint32_t family, const char *table,
+ const char *name, struct nft_cache *cache)
+{
+ struct table *t;
+
+ t = table_cache_find(&cache->table_cache, table, family);
+ if (t == NULL)
+ return NULL;
+
+ return set_cache_find(t, name);
+}
+
+struct print_fmt_options {
+ const char *tab;
+ const char *nl;
+ const char *table;
+ const char *family;
+ const char *stmt_separator;
+};
+
+const char *set_policy2str(uint32_t policy)
+{
+ switch (policy) {
+ case NFT_SET_POL_PERFORMANCE:
+ return "performance";
+ case NFT_SET_POL_MEMORY:
+ return "memory";
+ default:
+ return "unknown";
+ }
+}
+
+static void set_print_key(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct datatype *dtype = expr->dtype;
+
+ if (dtype->size || dtype->type == TYPE_VERDICT)
+ nft_print(octx, "%s", dtype->name);
+ else
+ expr_print(expr, octx);
+}
+
+static void set_print_key_and_data(const struct set *set, struct output_ctx *octx)
+{
+ bool use_typeof = set->key_typeof_valid;
+
+ nft_print(octx, "%s ", use_typeof ? "typeof" : "type");
+
+ if (use_typeof)
+ expr_print(set->key, octx);
+ else
+ set_print_key(set->key, octx);
+
+ if (set_is_datamap(set->flags)) {
+ nft_print(octx, " : ");
+ if (set->data->flags & EXPR_F_INTERVAL)
+ nft_print(octx, "interval ");
+
+ if (use_typeof)
+ expr_print(set->data, octx);
+ else
+ set_print_key(set->data, octx);
+ } else if (set_is_objmap(set->flags)) {
+ nft_print(octx, " : %s", obj_type_name(set->objtype));
+ }
+}
+
+static void set_print_declaration(const struct set *set,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ const char *delim = "";
+ struct stmt *stmt;
+ const char *type;
+ uint32_t flags;
+
+ if (set_is_meter(set->flags))
+ type = "meter";
+ else if (set_is_map(set->flags))
+ type = "map";
+ else
+ type = "set";
+
+ nft_print(octx, "%s%s", opts->tab, type);
+
+ if (opts->family != NULL)
+ nft_print(octx, " %s", opts->family);
+
+ if (opts->table != NULL)
+ nft_print(octx, " %s", opts->table);
+
+ nft_print(octx, " %s {", set->handle.set.name);
+
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, set->handle.handle.id);
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+
+ set_print_key_and_data(set, octx);
+
+ nft_print(octx, "%s", opts->stmt_separator);
+
+ if (!(set->flags & (NFT_SET_CONSTANT))) {
+ if (set->policy != NFT_SET_POL_PERFORMANCE) {
+ nft_print(octx, "%s%spolicy %s%s",
+ opts->tab, opts->tab,
+ set_policy2str(set->policy),
+ opts->stmt_separator);
+ }
+
+ if (set->desc.size > 0) {
+ nft_print(octx, "%s%ssize %u%s",
+ opts->tab, opts->tab,
+ set->desc.size,
+ opts->stmt_separator);
+ }
+ }
+
+ flags = set->flags;
+ /* "timeout" flag is redundant if a default timeout exists */
+ if (set->timeout)
+ flags &= ~NFT_SET_TIMEOUT;
+
+ if (flags & (NFT_SET_CONSTANT | NFT_SET_INTERVAL | NFT_SET_TIMEOUT | NFT_SET_EVAL)) {
+ nft_print(octx, "%s%sflags ", opts->tab, opts->tab);
+ if (set->flags & NFT_SET_CONSTANT) {
+ nft_print(octx, "%sconstant", delim);
+ delim = ",";
+ }
+ if (set->flags & NFT_SET_EVAL) {
+ nft_print(octx, "%sdynamic", delim);
+ delim = ",";
+ }
+ if (set->flags & NFT_SET_INTERVAL) {
+ nft_print(octx, "%sinterval", delim);
+ delim = ",";
+ }
+ if (set->flags & NFT_SET_TIMEOUT) {
+ nft_print(octx, "%stimeout", delim);
+ delim = ",";
+ }
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+
+ if (!list_empty(&set->stmt_list)) {
+ unsigned int flags = octx->flags;
+
+ nft_print(octx, "%s%s", opts->tab, opts->tab);
+
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ list_for_each_entry(stmt, &set->stmt_list, list) {
+ stmt_print(stmt, octx);
+ if (!list_is_last(&stmt->list, &set->stmt_list))
+ nft_print(octx, " ");
+ }
+ octx->flags = flags;
+
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+
+ if (set->automerge)
+ nft_print(octx, "%s%sauto-merge%s", opts->tab, opts->tab,
+ opts->stmt_separator);
+
+ if (set->timeout) {
+ nft_print(octx, "%s%stimeout ", opts->tab, opts->tab);
+ time_print(set->timeout, octx);
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+ if (set->gc_int) {
+ nft_print(octx, "%s%sgc-interval ", opts->tab, opts->tab);
+ time_print(set->gc_int, octx);
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+
+ if (set->comment) {
+ nft_print(octx, "%s%scomment \"%s\"%s",
+ opts->tab, opts->tab,
+ set->comment,
+ opts->stmt_separator);
+ }
+}
+
+static void do_set_print(const struct set *set, struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ set_print_declaration(set, opts, octx);
+
+ if ((set_is_meter(set->flags) && nft_output_stateless(octx)) ||
+ nft_output_terse(octx)) {
+ nft_print(octx, "%s}%s", opts->tab, opts->nl);
+ return;
+ }
+
+ if (set->init != NULL && set->init->size > 0) {
+ nft_print(octx, "%s%selements = ", opts->tab, opts->tab);
+ expr_print(set->init, octx);
+ nft_print(octx, "%s", opts->nl);
+ }
+ nft_print(octx, "%s}%s", opts->tab, opts->nl);
+}
+
+void set_print(const struct set *s, struct output_ctx *octx)
+{
+ struct print_fmt_options opts = {
+ .tab = "\t",
+ .nl = "\n",
+ .stmt_separator = "\n",
+ };
+
+ do_set_print(s, &opts, octx);
+}
+
+void set_print_plain(const struct set *s, struct output_ctx *octx)
+{
+ struct print_fmt_options opts = {
+ .tab = "",
+ .nl = " ",
+ .table = s->handle.table.name,
+ .family = family2str(s->handle.family),
+ .stmt_separator = "; ",
+ };
+
+ do_set_print(s, &opts, octx);
+}
+
+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);
+ init_list_head(&rule->stmts);
+ rule->refcnt = 1;
+ if (h != NULL)
+ rule->handle = *h;
+
+ return rule;
+}
+
+struct rule *rule_get(struct rule *rule)
+{
+ rule->refcnt++;
+ return rule;
+}
+
+void rule_free(struct rule *rule)
+{
+ if (--rule->refcnt > 0)
+ return;
+ stmt_list_free(&rule->stmts);
+ handle_free(&rule->handle);
+ xfree(rule->comment);
+ xfree(rule);
+}
+
+void rule_print(const struct rule *rule, struct output_ctx *octx)
+{
+ const struct stmt *stmt;
+
+ list_for_each_entry(stmt, &rule->stmts, list) {
+ stmt->ops->print(stmt, octx);
+ if (!list_is_last(&stmt->list, &rule->stmts))
+ nft_print(octx, " ");
+ }
+
+ if (rule->comment)
+ nft_print(octx, " comment \"%s\"", rule->comment);
+
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, rule->handle.handle.id);
+}
+
+struct rule *rule_lookup(const struct chain *chain, uint64_t handle)
+{
+ struct rule *rule;
+
+ list_for_each_entry(rule, &chain->rules, list) {
+ if (rule->handle.handle.id == handle)
+ return rule;
+ }
+ return NULL;
+}
+
+struct rule *rule_lookup_by_index(const struct chain *chain, uint64_t index)
+{
+ struct rule *rule;
+
+ list_for_each_entry(rule, &chain->rules, list) {
+ if (!--index)
+ return rule;
+ }
+ return NULL;
+}
+
+void rule_stmt_append(struct rule *rule, struct stmt *stmt)
+{
+ list_add_tail(&stmt->list, &rule->stmts);
+ rule->num_stmts++;
+}
+
+void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
+ struct stmt *stmt)
+{
+ list_add_tail(&nstmt->list, &stmt->list);
+ rule->num_stmts++;
+}
+
+struct scope *scope_alloc(void)
+{
+ struct scope *scope = xzalloc(sizeof(struct scope));
+
+ init_list_head(&scope->symbols);
+
+ return scope;
+}
+
+struct scope *scope_init(struct scope *scope, const struct scope *parent)
+{
+ scope->parent = parent;
+ return scope;
+}
+
+void scope_release(const struct scope *scope)
+{
+ struct symbol *sym, *next;
+
+ list_for_each_entry_safe(sym, next, &scope->symbols, list) {
+ assert(sym->refcnt == 1);
+ list_del(&sym->list);
+ xfree(sym->identifier);
+ expr_free(sym->expr);
+ xfree(sym);
+ }
+}
+
+void scope_free(struct scope *scope)
+{
+ scope_release(scope);
+ xfree(scope);
+}
+
+void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
+{
+ struct symbol *sym;
+
+ sym = xzalloc(sizeof(*sym));
+ sym->identifier = xstrdup(identifier);
+ sym->expr = expr;
+ sym->refcnt = 1;
+
+ list_add(&sym->list, &scope->symbols);
+}
+
+struct symbol *symbol_get(const struct scope *scope, const char *identifier)
+{
+ struct symbol *sym;
+
+ sym = symbol_lookup(scope, identifier);
+ if (!sym)
+ return NULL;
+
+ sym->refcnt++;
+
+ return sym;
+}
+
+static void symbol_put(struct symbol *sym)
+{
+ if (--sym->refcnt == 0) {
+ xfree(sym->identifier);
+ expr_free(sym->expr);
+ xfree(sym);
+ }
+}
+
+static void symbol_remove(struct symbol *sym)
+{
+ list_del(&sym->list);
+ symbol_put(sym);
+}
+
+int symbol_unbind(const struct scope *scope, const char *identifier)
+{
+ struct symbol *sym, *next;
+
+ list_for_each_entry_safe(sym, next, &scope->symbols, list) {
+ if (!strcmp(sym->identifier, identifier))
+ symbol_remove(sym);
+ }
+
+ return 0;
+}
+
+struct symbol *symbol_lookup(const struct scope *scope, const char *identifier)
+{
+ struct symbol *sym;
+
+ while (scope != NULL) {
+ list_for_each_entry(sym, &scope->symbols, list) {
+ if (!strcmp(sym->identifier, identifier))
+ return sym;
+ }
+ scope = scope->parent;
+ }
+ return NULL;
+}
+
+struct symbol *symbol_lookup_fuzzy(const struct scope *scope,
+ const char *identifier)
+{
+ struct string_misspell_state st;
+ struct symbol *sym;
+
+ string_misspell_init(&st);
+
+ while (scope != NULL) {
+ list_for_each_entry(sym, &scope->symbols, list)
+ string_misspell_update(sym->identifier, identifier,
+ sym, &st);
+
+ scope = scope->parent;
+ }
+ return st.obj;
+}
+
+static const char * const chain_type_str_array[] = {
+ "filter",
+ "nat",
+ "route",
+ NULL,
+};
+
+const char *chain_type_name_lookup(const char *name)
+{
+ int i;
+
+ for (i = 0; chain_type_str_array[i]; i++) {
+ if (!strcmp(name, chain_type_str_array[i]))
+ return chain_type_str_array[i];
+ }
+
+ return NULL;
+}
+
+static const char * const chain_hookname_str_array[] = {
+ "prerouting",
+ "input",
+ "forward",
+ "postrouting",
+ "output",
+ "ingress",
+ "egress",
+ NULL,
+};
+
+const char *chain_hookname_lookup(const char *name)
+{
+ int i;
+
+ for (i = 0; chain_hookname_str_array[i]; i++) {
+ if (!strcmp(name, chain_hookname_str_array[i]))
+ return chain_hookname_str_array[i];
+ }
+
+ return NULL;
+}
+
+/* internal ID to uniquely identify a set in the batch */
+static uint32_t chain_id;
+
+struct chain *chain_alloc(void)
+{
+ struct chain *chain;
+
+ chain = xzalloc(sizeof(*chain));
+ chain->location = internal_location;
+ chain->refcnt = 1;
+ chain->handle.chain_id = ++chain_id;
+ init_list_head(&chain->rules);
+ init_list_head(&chain->scope.symbols);
+
+ chain->policy = NULL;
+ return chain;
+}
+
+struct chain *chain_get(struct chain *chain)
+{
+ chain->refcnt++;
+ return chain;
+}
+
+void chain_free(struct chain *chain)
+{
+ struct rule *rule, *next;
+ int i;
+
+ if (--chain->refcnt > 0)
+ return;
+ list_for_each_entry_safe(rule, next, &chain->rules, list)
+ rule_free(rule);
+ handle_free(&chain->handle);
+ scope_release(&chain->scope);
+ xfree(chain->type.str);
+ expr_free(chain->dev_expr);
+ for (i = 0; i < chain->dev_array_len; i++)
+ xfree(chain->dev_array[i]);
+ xfree(chain->dev_array);
+ expr_free(chain->priority.expr);
+ expr_free(chain->policy);
+ xfree(chain->comment);
+ xfree(chain);
+}
+
+struct chain *chain_binding_lookup(const struct table *table,
+ const char *chain_name)
+{
+ struct chain *chain;
+
+ list_for_each_entry(chain, &table->chain_bindings, cache.list) {
+ if (!strcmp(chain->handle.chain.name, chain_name))
+ return chain;
+ }
+ return NULL;
+}
+
+struct chain *chain_lookup_fuzzy(const struct handle *h,
+ const struct nft_cache *cache,
+ const struct table **t)
+{
+ struct string_misspell_state st;
+ struct table *table;
+ struct chain *chain;
+
+ if (!h->chain.name)
+ return NULL;
+
+ string_misspell_init(&st);
+
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
+ if (string_misspell_update(chain->handle.chain.name,
+ h->chain.name, chain, &st))
+ *t = table;
+ }
+ }
+ return st.obj;
+}
+
+const char *family2str(unsigned int family)
+{
+ switch (family) {
+ case NFPROTO_IPV4:
+ return "ip";
+ case NFPROTO_IPV6:
+ return "ip6";
+ case NFPROTO_INET:
+ return "inet";
+ case NFPROTO_NETDEV:
+ return "netdev";
+ case NFPROTO_ARP:
+ return "arp";
+ case NFPROTO_BRIDGE:
+ return "bridge";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+const char *hooknum2str(unsigned int family, unsigned int hooknum)
+{
+ switch (family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_BRIDGE:
+ case NFPROTO_IPV6:
+ case NFPROTO_INET:
+ switch (hooknum) {
+ case NF_INET_PRE_ROUTING:
+ return "prerouting";
+ case NF_INET_LOCAL_IN:
+ return "input";
+ case NF_INET_FORWARD:
+ return "forward";
+ case NF_INET_POST_ROUTING:
+ return "postrouting";
+ case NF_INET_LOCAL_OUT:
+ return "output";
+ case NF_INET_INGRESS:
+ return "ingress";
+ default:
+ break;
+ };
+ break;
+ case NFPROTO_ARP:
+ switch (hooknum) {
+ case NF_ARP_IN:
+ return "input";
+ case NF_ARP_FORWARD:
+ return "forward";
+ case NF_ARP_OUT:
+ return "output";
+ case __NF_ARP_INGRESS:
+ return "ingress";
+ default:
+ break;
+ }
+ break;
+ case NFPROTO_NETDEV:
+ switch (hooknum) {
+ case NF_NETDEV_INGRESS:
+ return "ingress";
+ case NF_NETDEV_EGRESS:
+ return "egress";
+ }
+ break;
+ default:
+ break;
+ };
+
+ return "unknown";
+}
+
+const char *chain_policy2str(uint32_t policy)
+{
+ switch (policy) {
+ case NF_DROP:
+ return "drop";
+ case NF_ACCEPT:
+ return "accept";
+ }
+ return "unknown";
+}
+
+struct prio_tag {
+ int val;
+ const char *str;
+};
+
+static const struct prio_tag std_prios[] = {
+ { NF_IP_PRI_RAW, "raw" },
+ { NF_IP_PRI_MANGLE, "mangle" },
+ { NF_IP_PRI_NAT_DST, "dstnat" },
+ { NF_IP_PRI_FILTER, "filter" },
+ { NF_IP_PRI_SECURITY, "security" },
+ { NF_IP_PRI_NAT_SRC, "srcnat" },
+};
+
+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" },
+ { NF_BR_PRI_NAT_SRC, "srcnat" },
+};
+
+static bool std_prio_family_hook_compat(int prio, int family, int hook)
+{
+ /* bridge family has different values */
+ if (family == NFPROTO_BRIDGE) {
+ switch (prio) {
+ case NF_BR_PRI_NAT_DST_BRIDGED:
+ if (hook == NF_BR_PRE_ROUTING)
+ return true;
+ break;
+ case NF_BR_PRI_FILTER_BRIDGED:
+ return true;
+ case NF_BR_PRI_NAT_DST_OTHER:
+ if (hook == NF_BR_LOCAL_OUT)
+ return true;
+ break;
+ case NF_BR_PRI_NAT_SRC:
+ if (hook == NF_BR_POST_ROUTING)
+ return true;
+ }
+ return false;
+ }
+ switch(prio) {
+ case NF_IP_PRI_FILTER:
+ switch (family) {
+ case NFPROTO_INET:
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_ARP:
+ case NFPROTO_NETDEV:
+ return true;
+ }
+ break;
+ case NF_IP_PRI_RAW:
+ case NF_IP_PRI_MANGLE:
+ case NF_IP_PRI_SECURITY:
+ switch (family) {
+ case NFPROTO_INET:
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ return true;
+ }
+ break;
+ case NF_IP_PRI_NAT_DST:
+ switch(family) {
+ case NFPROTO_INET:
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ if (hook == NF_INET_PRE_ROUTING ||
+ hook == NF_INET_LOCAL_OUT)
+ return true;
+ }
+ break;
+ case NF_IP_PRI_NAT_SRC:
+ switch(family) {
+ case NFPROTO_INET:
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ if (hook == NF_INET_LOCAL_IN ||
+ hook == NF_INET_POST_ROUTING)
+ return true;
+ }
+ }
+ return false;
+}
+
+int std_prio_lookup(const char *std_prio_name, int family, int hook)
+{
+ const struct prio_tag *prio_arr;
+ size_t i, arr_size;
+
+ if (family == NFPROTO_BRIDGE) {
+ prio_arr = bridge_std_prios;
+ arr_size = array_size(bridge_std_prios);
+ } else {
+ prio_arr = std_prios;
+ arr_size = array_size(std_prios);
+ }
+
+ for (i = 0; i < arr_size; ++i) {
+ if (strcmp(prio_arr[i].str, std_prio_name) == 0 &&
+ std_prio_family_hook_compat(prio_arr[i].val, family, hook))
+ return prio_arr[i].val;
+ }
+ return NF_IP_PRI_LAST;
+}
+
+static const char *prio2str(const struct output_ctx *octx,
+ char *buf, size_t bufsize, int family, int hook,
+ const struct expr *expr)
+{
+ const struct prio_tag *prio_arr;
+ int std_prio, offset, prio;
+ const char *std_prio_str;
+ const int reach = 10;
+ size_t i, arr_size;
+
+ mpz_export_data(&prio, expr->value, BYTEORDER_HOST_ENDIAN, sizeof(int));
+ if (family == NFPROTO_BRIDGE) {
+ prio_arr = bridge_std_prios;
+ arr_size = array_size(bridge_std_prios);
+ } else {
+ prio_arr = std_prios;
+ arr_size = array_size(std_prios);
+ }
+
+ if (!nft_output_numeric_prio(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) {
+ 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",
+ offset);
+ else if (offset < 0)
+ snprintf(buf + strlen(buf),
+ bufsize - strlen(buf), " - %d",
+ -offset);
+ return buf;
+ }
+ }
+ }
+ snprintf(buf, bufsize, "%d", prio);
+ return buf;
+}
+
+static void chain_print_declaration(const struct chain *chain,
+ struct output_ctx *octx)
+{
+ char priobuf[STD_PRIO_BUFSIZE];
+ int policy, i;
+
+ if (chain->flags & CHAIN_F_BINDING)
+ return;
+
+ nft_print(octx, "\tchain %s {", chain->handle.chain.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
+ if (chain->comment)
+ nft_print(octx, "\n\t\tcomment \"%s\"", chain->comment);
+ nft_print(octx, "\n");
+ if (chain->flags & CHAIN_F_BASECHAIN) {
+ nft_print(octx, "\t\ttype %s hook %s", chain->type.str,
+ hooknum2str(chain->handle.family, chain->hook.num));
+ if (chain->dev_array_len == 1) {
+ nft_print(octx, " device \"%s\"", chain->dev_array[0]);
+ } else if (chain->dev_array_len > 1) {
+ nft_print(octx, " devices = { ");
+ for (i = 0; i < chain->dev_array_len; i++) {
+ nft_print(octx, "%s", chain->dev_array[i]);
+ if (i + 1 != chain->dev_array_len)
+ nft_print(octx, ", ");
+ }
+ nft_print(octx, " }");
+ }
+ nft_print(octx, " priority %s;",
+ prio2str(octx, priobuf, sizeof(priobuf),
+ chain->handle.family, chain->hook.num,
+ chain->priority.expr));
+ if (chain->policy) {
+ mpz_export_data(&policy, chain->policy->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ nft_print(octx, " policy %s;",
+ chain_policy2str(policy));
+ }
+ if (chain->flags & CHAIN_F_HW_OFFLOAD)
+ nft_print(octx, " flags offload;");
+
+ nft_print(octx, "\n");
+ }
+}
+
+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)
+{
+ chain_print_declaration(chain, octx);
+ chain_rules_print(chain, octx, NULL);
+ nft_print(octx, "\t}\n");
+}
+
+void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
+{
+ char priobuf[STD_PRIO_BUFSIZE];
+ int policy;
+
+ nft_print(octx, "chain %s %s %s", family2str(chain->handle.family),
+ chain->handle.table.name, chain->handle.chain.name);
+
+ 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 ",
+ 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),
+ chain_policy2str(policy));
+ }
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
+}
+
+struct table *table_alloc(void)
+{
+ struct table *table;
+
+ table = xzalloc(sizeof(*table));
+ table->location = internal_location;
+ init_list_head(&table->chains);
+ init_list_head(&table->sets);
+ init_list_head(&table->objs);
+ init_list_head(&table->flowtables);
+ init_list_head(&table->chain_bindings);
+ init_list_head(&table->scope.symbols);
+ table->refcnt = 1;
+
+ cache_init(&table->chain_cache);
+ cache_init(&table->set_cache);
+ cache_init(&table->obj_cache);
+ cache_init(&table->ft_cache);
+
+ return table;
+}
+
+void table_free(struct table *table)
+{
+ struct chain *chain, *next;
+ struct flowtable *ft, *nft;
+ struct set *set, *nset;
+ struct obj *obj, *nobj;
+
+ if (--table->refcnt > 0)
+ return;
+ if (table->comment)
+ xfree(table->comment);
+ list_for_each_entry_safe(chain, next, &table->chains, list)
+ chain_free(chain);
+ list_for_each_entry_safe(chain, next, &table->chain_bindings, cache.list)
+ chain_free(chain);
+ /* this is implicitly releasing chains in the hashtable cache */
+ list_for_each_entry_safe(chain, next, &table->chain_cache.list, cache.list)
+ chain_free(chain);
+ list_for_each_entry_safe(set, nset, &table->sets, list)
+ set_free(set);
+ /* this is implicitly releasing sets in the hashtable cache */
+ list_for_each_entry_safe(set, nset, &table->set_cache.list, cache.list)
+ set_free(set);
+ list_for_each_entry_safe(ft, nft, &table->flowtables, list)
+ flowtable_free(ft);
+ /* this is implicitly releasing flowtables in the hashtable cache */
+ list_for_each_entry_safe(ft, nft, &table->ft_cache.list, cache.list)
+ flowtable_free(ft);
+ list_for_each_entry_safe(obj, nobj, &table->objs, list)
+ obj_free(obj);
+ /* this is implicitly releasing objs in the hashtable cache */
+ list_for_each_entry_safe(obj, nobj, &table->obj_cache.list, cache.list)
+ obj_free(obj);
+
+ handle_free(&table->handle);
+ scope_release(&table->scope);
+ cache_free(&table->chain_cache);
+ cache_free(&table->set_cache);
+ cache_free(&table->obj_cache);
+ cache_free(&table->ft_cache);
+ xfree(table);
+}
+
+struct table *table_get(struct table *table)
+{
+ table->refcnt++;
+ return table;
+}
+
+struct table *table_lookup_fuzzy(const struct handle *h,
+ const struct nft_cache *cache)
+{
+ struct string_misspell_state st;
+ struct table *table;
+
+ string_misspell_init(&st);
+
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ string_misspell_update(table->handle.table.name,
+ h->table.name, table, &st);
+ }
+ return st.obj;
+}
+
+static const char *table_flags_name[TABLE_FLAGS_MAX] = {
+ "dormant",
+ "owner",
+};
+
+const char *table_flag_name(uint32_t flag)
+{
+ if (flag >= TABLE_FLAGS_MAX)
+ return "unknown";
+
+ return table_flags_name[flag];
+}
+
+static void table_print_flags(const struct table *table, const char **delim,
+ struct output_ctx *octx)
+{
+ uint32_t flags = table->flags;
+ bool comma = false;
+ int i;
+
+ if (!table->flags)
+ return;
+
+ nft_print(octx, "\tflags ");
+ for (i = 0; i < TABLE_FLAGS_MAX; i++) {
+ if (flags & (1 << i)) {
+ if (comma)
+ nft_print(octx, ",");
+
+ nft_print(octx, "%s", table_flag_name(i));
+ comma = true;
+ }
+ }
+ nft_print(octx, "\n");
+ *delim = "\n";
+}
+
+static void table_print(const struct table *table, struct output_ctx *octx)
+{
+ struct flowtable *flowtable;
+ struct chain *chain;
+ struct obj *obj;
+ struct set *set;
+ const char *delim = "";
+ const char *family = family2str(table->handle.family);
+
+ if (table->has_xt_stmts)
+ fprintf(octx->error_fp,
+ "# Warning: table %s %s is managed by iptables-nft, do not touch!\n",
+ family, table->handle.table.name);
+
+ nft_print(octx, "table %s %s {", family, table->handle.table.name);
+ if (nft_output_handle(octx) || table->flags & TABLE_F_OWNER)
+ nft_print(octx, " #");
+ if (nft_output_handle(octx))
+ nft_print(octx, " handle %" PRIu64, table->handle.handle.id);
+ if (table->flags & TABLE_F_OWNER)
+ nft_print(octx, " progname %s", get_progname(table->owner));
+
+ nft_print(octx, "\n");
+ table_print_flags(table, &delim, octx);
+
+ if (table->comment)
+ nft_print(octx, "\tcomment \"%s\"\n", table->comment);
+
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
+ nft_print(octx, "%s", delim);
+ obj_print(obj, octx);
+ delim = "\n";
+ }
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (set_is_anonymous(set->flags))
+ continue;
+ nft_print(octx, "%s", delim);
+ set_print(set, octx);
+ delim = "\n";
+ }
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
+ nft_print(octx, "%s", delim);
+ flowtable_print(flowtable, octx);
+ delim = "\n";
+ }
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
+ nft_print(octx, "%s", delim);
+ chain_print(chain, octx);
+ delim = "\n";
+ }
+ nft_print(octx, "}\n");
+}
+
+struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
+ const struct handle *h, const struct location *loc,
+ void *data)
+{
+ struct cmd *cmd;
+
+ assert(loc);
+
+ cmd = xzalloc(sizeof(*cmd));
+ init_list_head(&cmd->list);
+ cmd->op = op;
+ cmd->obj = obj;
+ cmd->handle = *h;
+ cmd->location = *loc;
+ cmd->data = data;
+ 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);
+
+ return cmd;
+}
+
+struct markup *markup_alloc(uint32_t format)
+{
+ struct markup *markup;
+
+ markup = xmalloc(sizeof(struct markup));
+ markup->format = format;
+
+ return markup;
+}
+
+void markup_free(struct markup *m)
+{
+ xfree(m);
+}
+
+struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
+{
+ struct monitor *mon;
+
+ mon = xmalloc(sizeof(struct monitor));
+ mon->format = format;
+ mon->type = type;
+ mon->event = event;
+ mon->flags = 0;
+
+ return mon;
+}
+
+void monitor_free(struct monitor *m)
+{
+ xfree(m->event);
+ xfree(m);
+}
+
+void cmd_free(struct cmd *cmd)
+{
+ handle_free(&cmd->handle);
+ if (cmd->data != NULL) {
+ switch (cmd->obj) {
+ case CMD_OBJ_ELEMENTS:
+ expr_free(cmd->expr);
+ if (cmd->elem.set)
+ set_free(cmd->elem.set);
+ break;
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_METER:
+ case CMD_OBJ_SETELEMS:
+ set_free(cmd->set);
+ break;
+ case CMD_OBJ_RULE:
+ rule_free(cmd->rule);
+ break;
+ case CMD_OBJ_CHAIN:
+ chain_free(cmd->chain);
+ break;
+ case CMD_OBJ_TABLE:
+ table_free(cmd->table);
+ break;
+ case CMD_OBJ_EXPR:
+ expr_free(cmd->expr);
+ break;
+ case CMD_OBJ_MONITOR:
+ monitor_free(cmd->monitor);
+ break;
+ case CMD_OBJ_MARKUP:
+ markup_free(cmd->markup);
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_SYNPROXY:
+ obj_free(cmd->object);
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ flowtable_free(cmd->flowtable);
+ break;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ }
+ xfree(cmd->attr);
+ xfree(cmd->arg);
+ xfree(cmd);
+}
+
+#include <netlink.h>
+#include <mnl.h>
+
+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, cmd, set, expr, flags) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int do_add_elements(struct netlink_ctx *ctx, struct cmd *cmd,
+ uint32_t flags)
+{
+ struct expr *init = cmd->expr;
+ struct set *set = cmd->elem.set;
+
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, init, true) < 0)
+ return -1;
+
+ return __do_add_elements(ctx, cmd, set, init, flags);
+}
+
+static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
+ uint32_t flags)
+{
+ struct set *set = cmd->set;
+
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
+}
+
+static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
+ uint32_t flags)
+{
+ struct set *set = cmd->set;
+
+ if (set->init != NULL) {
+ /* Update set->init->size (NFTNL_SET_DESC_SIZE) before adding
+ * the set to the kernel. Calling this from do_add_setelems()
+ * comes too late which might result in spurious ENFILE errors.
+ */
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, set->init, true) < 0)
+ return -1;
+ }
+
+ if (mnl_nft_set_add(ctx, cmd, flags) < 0)
+ return -1;
+
+ if (set_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)
+{
+ uint32_t flags = excl ? NLM_F_EXCL : 0;
+
+ if (nft_output_echo(&ctx->nft->output))
+ flags |= NLM_F_ECHO;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ return mnl_nft_table_add(ctx, cmd, flags);
+ case CMD_OBJ_CHAIN:
+ return mnl_nft_chain_add(ctx, cmd, flags);
+ case CMD_OBJ_RULE:
+ return mnl_nft_rule_add(ctx, cmd, flags | NLM_F_APPEND);
+ case CMD_OBJ_SET:
+ return do_add_set(ctx, cmd, flags);
+ case CMD_OBJ_SETELEMS:
+ return do_add_setelems(ctx, cmd, flags);
+ case CMD_OBJ_ELEMENTS:
+ return do_add_elements(ctx, cmd, flags);
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_SYNPROXY:
+ return mnl_nft_obj_add(ctx, cmd, flags);
+ case CMD_OBJ_FLOWTABLE:
+ return mnl_nft_flowtable_add(ctx, cmd, flags);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ return 0;
+}
+
+static int do_command_replace(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_RULE:
+ return mnl_nft_rule_replace(ctx, cmd);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ return 0;
+}
+
+static int do_command_insert(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ uint32_t flags = 0;
+
+ if (nft_output_echo(&ctx->nft->output))
+ flags |= NLM_F_ECHO;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_RULE:
+ return mnl_nft_rule_add(ctx, cmd, flags);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ return 0;
+}
+
+static int do_delete_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct expr *expr = cmd->elem.expr;
+ struct set *set = cmd->elem.set;
+
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, expr, false) < 0)
+ return -1;
+
+ if (mnl_nft_setelem_del(ctx, cmd, &cmd->handle, cmd->elem.expr) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ return mnl_nft_table_del(ctx, cmd);
+ case CMD_OBJ_CHAIN:
+ return mnl_nft_chain_del(ctx, cmd);
+ case CMD_OBJ_RULE:
+ return mnl_nft_rule_del(ctx, cmd);
+ case CMD_OBJ_SET:
+ return mnl_nft_set_del(ctx, cmd);
+ case CMD_OBJ_ELEMENTS:
+ return do_delete_setelems(ctx, cmd);
+ case CMD_OBJ_COUNTER:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_COUNTER);
+ case CMD_OBJ_QUOTA:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_QUOTA);
+ case CMD_OBJ_CT_HELPER:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_CT_TIMEOUT:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
+ case CMD_OBJ_CT_EXPECT:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_CT_EXPECT);
+ case CMD_OBJ_LIMIT:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_LIMIT);
+ case CMD_OBJ_SECMARK:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_SECMARK);
+ case CMD_OBJ_SYNPROXY:
+ return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_SYNPROXY);
+ case CMD_OBJ_FLOWTABLE:
+ return mnl_nft_flowtable_del(ctx, cmd);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+}
+
+static int do_list_table(struct netlink_ctx *ctx, struct table *table)
+{
+ table_print(table, &ctx->nft->output);
+ return 0;
+}
+
+static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+ struct set *set;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ nft_print(&ctx->nft->output, "table %s %s {\n",
+ family2str(table->handle.family),
+ table->handle.table.name);
+
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cmd->obj == CMD_OBJ_SETS &&
+ !set_is_literal(set->flags))
+ continue;
+ if (cmd->obj == CMD_OBJ_METERS &&
+ !set_is_meter(set->flags))
+ continue;
+ if (cmd->obj == CMD_OBJ_MAPS &&
+ !map_is_literal(set->flags))
+ continue;
+ set_print(set, &ctx->nft->output);
+ }
+
+ nft_print(&ctx->nft->output, "}\n");
+ }
+ return 0;
+}
+
+struct obj *obj_alloc(const struct location *loc)
+{
+ struct obj *obj;
+
+ assert(loc);
+
+ obj = xzalloc(sizeof(*obj));
+ obj->location = *loc;
+
+ obj->refcnt = 1;
+ return obj;
+}
+
+struct obj *obj_get(struct obj *obj)
+{
+ obj->refcnt++;
+ return obj;
+}
+
+void obj_free(struct obj *obj)
+{
+ if (--obj->refcnt > 0)
+ return;
+ xfree(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);
+ }
+ }
+ xfree(obj);
+}
+
+struct obj *obj_lookup_fuzzy(const char *obj_name,
+ const struct nft_cache *cache,
+ const struct table **t)
+{
+ struct string_misspell_state st;
+ struct table *table;
+ struct obj *obj;
+
+ string_misspell_init(&st);
+
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
+ if (string_misspell_update(obj->handle.obj.name,
+ obj_name, obj, &st))
+ *t = table;
+ }
+ }
+ return st.obj;
+}
+
+static void print_proto_name_proto(uint8_t l4, struct output_ctx *octx)
+{
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (nft_getprotobynumber(l4, name, sizeof(name)))
+ nft_print(octx, "%s", name);
+ else
+ nft_print(octx, "%d", l4);
+}
+
+static void print_proto_timeout_policy(uint8_t l4, const uint32_t *timeout,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ bool comma = false;
+ unsigned int i;
+
+ 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, ", ");
+ timeout_ms = timeout[i] * 1000u;
+ nft_print(octx, "%s : ",
+ timeout_protocol[l4].state_to_name[i]);
+ time_print(timeout_ms, octx);
+ comma = true;
+ }
+ }
+ nft_print(octx, " }%s", opts->stmt_separator);
+}
+
+static const char *synproxy_sack_to_str(const uint32_t flags)
+{
+ if (flags & NF_SYNPROXY_OPT_SACK_PERM)
+ return "sack-perm";
+
+ return "";
+}
+
+static const char *synproxy_timestamp_to_str(const uint32_t flags)
+{
+ if (flags & NF_SYNPROXY_OPT_TIMESTAMP)
+ return "timestamp";
+
+ return "";
+}
+
+static void obj_print_comment(const struct obj *obj,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ if (obj->comment)
+ nft_print(octx, "%s%s%scomment \"%s\"",
+ opts->nl, opts->tab, opts->tab,
+ obj->comment);
+}
+
+static void obj_print_data(const struct obj *obj,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ switch (obj->type) {
+ case NFT_OBJECT_COUNTER:
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+ if (nft_output_stateless(octx))
+ nft_print(octx, "%s", opts->nl);
+ else
+ nft_print(octx, "%s%s%spackets %" PRIu64 " bytes %" PRIu64 "%s",
+ opts->nl, opts->tab, opts->tab,
+ obj->counter.packets, obj->counter.bytes, opts->nl);
+ break;
+ case NFT_OBJECT_QUOTA: {
+ const char *data_unit;
+ uint64_t bytes;
+
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+ data_unit = get_rate(obj->quota.bytes, &bytes);
+ nft_print(octx, "%s%" PRIu64 " %s",
+ obj->quota.flags & NFT_QUOTA_F_INV ? "over " : "",
+ bytes, data_unit);
+ if (!nft_output_stateless(octx) && obj->quota.used) {
+ data_unit = get_rate(obj->quota.used, &bytes);
+ nft_print(octx, " used %" PRIu64 " %s",
+ bytes, data_unit);
+ }
+ nft_print(octx, "%s", opts->nl);
+ }
+ break;
+ case NFT_OBJECT_SECMARK:
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+ nft_print(octx, "\"%s\"%s", obj->secmark.ctx, opts->nl);
+ break;
+ case NFT_OBJECT_CT_HELPER:
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+ nft_print(octx, "%s", opts->nl);
+ nft_print(octx, "%s%stype \"%s\" protocol ",
+ opts->tab, opts->tab, obj->ct_helper.name);
+ print_proto_name_proto(obj->ct_helper.l4proto, octx);
+ nft_print(octx, "%s", opts->stmt_separator);
+ nft_print(octx, "%s%sl3proto %s%s",
+ opts->tab, opts->tab,
+ family2str(obj->ct_helper.l3proto),
+ opts->stmt_separator);
+ break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+ nft_print(octx, "%s", opts->nl);
+ nft_print(octx, "%s%sprotocol ", opts->tab, opts->tab);
+ print_proto_name_proto(obj->ct_timeout.l4proto, octx);
+ nft_print(octx, "%s", opts->stmt_separator);
+ nft_print(octx, "%s%sl3proto %s%s",
+ opts->tab, opts->tab,
+ family2str(obj->ct_timeout.l3proto),
+ opts->stmt_separator);
+ print_proto_timeout_policy(obj->ct_timeout.l4proto,
+ obj->ct_timeout.timeout, opts, octx);
+ break;
+ case NFT_OBJECT_CT_EXPECT:
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+ nft_print(octx, "%s", opts->nl);
+ nft_print(octx, "%s%sprotocol ", opts->tab, opts->tab);
+ print_proto_name_proto(obj->ct_expect.l4proto, octx);
+ nft_print(octx, "%s", opts->stmt_separator);
+ nft_print(octx, "%s%sdport %d%s",
+ opts->tab, opts->tab,
+ obj->ct_expect.dport,
+ opts->stmt_separator);
+ nft_print(octx, "%s%stimeout ", opts->tab, opts->tab);
+ time_print(obj->ct_expect.timeout, octx);
+ nft_print(octx, "%s", opts->stmt_separator);
+ nft_print(octx, "%s%ssize %d%s",
+ opts->tab, opts->tab,
+ obj->ct_expect.size,
+ opts->stmt_separator);
+ nft_print(octx, "%s%sl3proto %s%s",
+ opts->tab, opts->tab,
+ family2str(obj->ct_expect.l3proto),
+ opts->stmt_separator);
+ break;
+ case NFT_OBJECT_LIMIT: {
+ bool inv = obj->limit.flags & NFT_LIMIT_F_INV;
+ const char *data_unit;
+ uint64_t rate;
+
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+ switch (obj->limit.type) {
+ case NFT_LIMIT_PKTS:
+ nft_print(octx, "rate %s%" PRIu64 "/%s",
+ inv ? "over " : "", obj->limit.rate,
+ get_unit(obj->limit.unit));
+ if (obj->limit.burst > 0 && obj->limit.burst != 5)
+ nft_print(octx, " burst %u packets",
+ obj->limit.burst);
+ break;
+ case NFT_LIMIT_PKT_BYTES:
+ data_unit = get_rate(obj->limit.rate, &rate);
+
+ nft_print(octx, "rate %s%" PRIu64 " %s/%s",
+ inv ? "over " : "", rate, data_unit,
+ get_unit(obj->limit.unit));
+ if (obj->limit.burst > 0) {
+ uint64_t burst;
+
+ data_unit = get_rate(obj->limit.burst, &burst);
+ nft_print(octx, " burst %"PRIu64" %s",
+ burst, data_unit);
+ }
+ break;
+ }
+ nft_print(octx, "%s", opts->nl);
+ }
+ break;
+ case NFT_OBJECT_SYNPROXY: {
+ uint32_t flags = obj->synproxy.flags;
+ const char *sack_str = synproxy_sack_to_str(flags);
+ const char *ts_str = synproxy_timestamp_to_str(flags);
+
+ nft_print(octx, " %s {", obj->handle.obj.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
+
+ if (flags & NF_SYNPROXY_OPT_MSS) {
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+ nft_print(octx, "mss %u", obj->synproxy.mss);
+ }
+ if (flags & NF_SYNPROXY_OPT_WSCALE) {
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+ nft_print(octx, "wscale %u", obj->synproxy.wscale);
+ }
+ if (flags & (NF_SYNPROXY_OPT_TIMESTAMP | NF_SYNPROXY_OPT_SACK_PERM)) {
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+ nft_print(octx, "%s %s", ts_str, sack_str);
+ }
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+ break;
+ default:
+ nft_print(octx, " unknown {%s", opts->nl);
+ break;
+ }
+}
+
+static const char * const obj_type_name_array[] = {
+ [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_SYNPROXY] = "synproxy",
+ [NFT_OBJECT_CT_EXPECT] = "ct expectation",
+};
+
+const char *obj_type_name(unsigned int type)
+{
+ assert(type <= NFT_OBJECT_MAX && obj_type_name_array[type]);
+
+ return obj_type_name_array[type];
+}
+
+static uint32_t obj_type_cmd_array[NFT_OBJECT_MAX + 1] = {
+ [NFT_OBJECT_COUNTER] = CMD_OBJ_COUNTER,
+ [NFT_OBJECT_QUOTA] = CMD_OBJ_QUOTA,
+ [NFT_OBJECT_CT_HELPER] = CMD_OBJ_CT_HELPER,
+ [NFT_OBJECT_LIMIT] = CMD_OBJ_LIMIT,
+ [NFT_OBJECT_CT_TIMEOUT] = CMD_OBJ_CT_TIMEOUT,
+ [NFT_OBJECT_SECMARK] = CMD_OBJ_SECMARK,
+ [NFT_OBJECT_SYNPROXY] = CMD_OBJ_SYNPROXY,
+ [NFT_OBJECT_CT_EXPECT] = CMD_OBJ_CT_EXPECT,
+};
+
+enum cmd_obj obj_type_to_cmd(uint32_t type)
+{
+ assert(type <= NFT_OBJECT_MAX && obj_type_cmd_array[type]);
+
+ return obj_type_cmd_array[type];
+}
+
+static void obj_print_declaration(const struct obj *obj,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "%s%s", opts->tab, obj_type_name(obj->type));
+
+ if (opts->family != NULL)
+ nft_print(octx, " %s", opts->family);
+
+ if (opts->table != NULL)
+ nft_print(octx, " %s", opts->table);
+
+ obj_print_data(obj, opts, octx);
+
+ nft_print(octx, "%s}%s", opts->tab, opts->nl);
+}
+
+void obj_print(const struct obj *obj, struct output_ctx *octx)
+{
+ struct print_fmt_options opts = {
+ .tab = "\t",
+ .nl = "\n",
+ .stmt_separator = "\n",
+ };
+
+ obj_print_declaration(obj, &opts, octx);
+}
+
+void obj_print_plain(const struct obj *obj, struct output_ctx *octx)
+{
+ struct print_fmt_options opts = {
+ .tab = "",
+ .nl = " ",
+ .table = obj->handle.table.name,
+ .family = family2str(obj->handle.family),
+ .stmt_separator = "; ",
+ };
+
+ obj_print_declaration(obj, &opts, octx);
+}
+
+static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
+{
+ struct print_fmt_options opts = {
+ .tab = "\t",
+ .nl = "\n",
+ .stmt_separator = "\n",
+ };
+ struct table *table;
+ struct obj *obj;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ if (cmd->handle.table.name != NULL &&
+ strcmp(cmd->handle.table.name, table->handle.table.name))
+ continue;
+
+ if (list_empty(&table->obj_cache.list))
+ continue;
+
+ nft_print(&ctx->nft->output, "table %s %s {\n",
+ family2str(table->handle.family),
+ table->handle.table.name);
+
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
+ if (obj->type != type ||
+ (cmd->handle.obj.name != NULL &&
+ strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
+ continue;
+
+ obj_print_declaration(obj, &opts, &ctx->nft->output);
+ }
+
+ nft_print(&ctx->nft->output, "}\n");
+ }
+ return 0;
+}
+
+struct flowtable *flowtable_alloc(const struct location *loc)
+{
+ struct flowtable *flowtable;
+
+ assert(loc);
+
+ flowtable = xzalloc(sizeof(*flowtable));
+ flowtable->location = *loc;
+
+ flowtable->refcnt = 1;
+ return flowtable;
+}
+
+struct flowtable *flowtable_get(struct flowtable *flowtable)
+{
+ flowtable->refcnt++;
+ return flowtable;
+}
+
+void flowtable_free(struct flowtable *flowtable)
+{
+ int i;
+
+ if (--flowtable->refcnt > 0)
+ return;
+ handle_free(&flowtable->handle);
+ expr_free(flowtable->priority.expr);
+ expr_free(flowtable->dev_expr);
+
+ if (flowtable->dev_array != NULL) {
+ for (i = 0; i < flowtable->dev_array_len; i++)
+ xfree(flowtable->dev_array[i]);
+ xfree(flowtable->dev_array);
+ }
+ xfree(flowtable);
+}
+
+static void flowtable_print_declaration(const struct flowtable *flowtable,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ char priobuf[STD_PRIO_BUFSIZE];
+ int i;
+
+ nft_print(octx, "%sflowtable", opts->tab);
+
+ if (opts->family != NULL)
+ nft_print(octx, " %s", opts->family);
+
+ if (opts->table != NULL)
+ nft_print(octx, " %s", opts->table);
+
+ nft_print(octx, " %s {", flowtable->handle.flowtable.name);
+
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, flowtable->handle.handle.id);
+ nft_print(octx, "%s", opts->nl);
+ nft_print(octx, "%s%shook %s priority %s%s",
+ opts->tab, opts->tab,
+ hooknum2str(NFPROTO_NETDEV, flowtable->hook.num),
+ prio2str(octx, priobuf, sizeof(priobuf), NFPROTO_NETDEV,
+ flowtable->hook.num, flowtable->priority.expr),
+ opts->stmt_separator);
+
+ if (flowtable->dev_array_len > 0) {
+ nft_print(octx, "%s%sdevices = { ", opts->tab, opts->tab);
+ for (i = 0; i < flowtable->dev_array_len; i++) {
+ nft_print(octx, "%s", flowtable->dev_array[i]);
+ if (i + 1 != flowtable->dev_array_len)
+ nft_print(octx, ", ");
+ }
+ nft_print(octx, " }%s", opts->stmt_separator);
+ }
+
+ if (flowtable->flags & NFT_FLOWTABLE_HW_OFFLOAD)
+ nft_print(octx, "%s%sflags offload%s", opts->tab, opts->tab,
+ opts->stmt_separator);
+
+ if (flowtable->flags & NFT_FLOWTABLE_COUNTER)
+ nft_print(octx, "%s%scounter%s", opts->tab, opts->tab,
+ opts->stmt_separator);
+}
+
+static void do_flowtable_print(const struct flowtable *flowtable,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ flowtable_print_declaration(flowtable, opts, octx);
+ nft_print(octx, "%s}%s", opts->tab, opts->nl);
+}
+
+void flowtable_print(const struct flowtable *s, struct output_ctx *octx)
+{
+ struct print_fmt_options opts = {
+ .tab = "\t",
+ .nl = "\n",
+ .stmt_separator = "\n",
+ };
+
+ do_flowtable_print(s, &opts, octx);
+}
+
+struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
+ const struct nft_cache *cache,
+ const struct table **t)
+{
+ struct string_misspell_state st;
+ struct table *table;
+ struct flowtable *ft;
+
+ string_misspell_init(&st);
+
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(ft, &table->ft_cache.list, cache.list) {
+ if (string_misspell_update(ft->handle.flowtable.name,
+ ft_name, ft, &st))
+ *t = table;
+ }
+ }
+ return st.obj;
+}
+
+static int do_list_flowtable(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct table *table)
+{
+ struct flowtable *ft;
+
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return -1;
+
+ nft_print(&ctx->nft->output, "table %s %s {\n",
+ family2str(table->handle.family),
+ table->handle.table.name);
+
+ flowtable_print(ft, &ctx->nft->output);
+ nft_print(&ctx->nft->output, "}\n");
+
+ return 0;
+}
+
+static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct print_fmt_options opts = {
+ .tab = "\t",
+ .nl = "\n",
+ .stmt_separator = "\n",
+ };
+ struct flowtable *flowtable;
+ struct table *table;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ nft_print(&ctx->nft->output, "table %s %s {\n",
+ family2str(table->handle.family),
+ table->handle.table.name);
+
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
+ flowtable_print_declaration(flowtable, &opts, &ctx->nft->output);
+ nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
+ }
+
+ nft_print(&ctx->nft->output, "}\n");
+ }
+ return 0;
+}
+
+static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ unsigned int family = cmd->handle.family;
+ struct table *table;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (family != NFPROTO_UNSPEC &&
+ table->handle.family != family)
+ continue;
+
+ if (do_list_table(ctx, table) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int do_list_tables(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ nft_print(&ctx->nft->output, "table %s %s\n",
+ family2str(table->handle.family),
+ table->handle.table.name);
+ }
+
+ return 0;
+}
+
+static void table_print_declaration(struct table *table,
+ struct output_ctx *octx)
+{
+ 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,
+ struct table *table)
+{
+ struct chain *chain;
+
+ table_print_declaration(table, &ctx->nft->output);
+
+ chain = chain_cache_find(table, cmd->handle.chain.name);
+ if (chain)
+ chain_print(chain, &ctx->nft->output);
+
+ nft_print(&ctx->nft->output, "}\n");
+
+ return 0;
+}
+
+static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+ struct chain *chain;
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ table_print_declaration(table, &ctx->nft->output);
+
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
+ chain_print_declaration(chain, &ctx->nft->output);
+ nft_print(&ctx->nft->output, "\t}\n");
+ }
+ nft_print(&ctx->nft->output, "}\n");
+ }
+
+ return 0;
+}
+
+static void __do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct set *set)
+{
+ struct table *table = table_alloc();
+
+ table->handle.table.name = xstrdup(cmd->handle.table.name);
+ table->handle.family = cmd->handle.family;
+ table_print_declaration(table, &ctx->nft->output);
+ table_free(table);
+
+ set_print(set, &ctx->nft->output);
+ nft_print(&ctx->nft->output, "}\n");
+}
+
+static int do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct table *table)
+{
+ struct set *set = cmd->set;
+
+ if (!set) {
+ set = set_cache_find(table, cmd->handle.set.name);
+ if (set == NULL)
+ return -1;
+ }
+
+ __do_list_set(ctx, cmd, set);
+
+ return 0;
+}
+
+static int do_list_hooks(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ const char *devname = cmd->handle.obj.name;
+ int hooknum = -1;
+
+ if (cmd->handle.chain.name)
+ hooknum = cmd->handle.chain_id;
+
+ return mnl_nft_dump_nf_hooks(ctx, cmd->handle.family, hooknum, devname);
+}
+
+static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table = NULL;
+
+ if (nft_output_json(&ctx->nft->output))
+ return do_command_list_json(ctx, cmd);
+
+ if (cmd->handle.table.name != NULL)
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (!cmd->handle.table.name)
+ return do_list_tables(ctx, cmd);
+ return do_list_table(ctx, table);
+ case CMD_OBJ_CHAIN:
+ return do_list_chain(ctx, cmd, table);
+ case CMD_OBJ_CHAINS:
+ return do_list_chains(ctx, cmd);
+ case CMD_OBJ_SETS:
+ return do_list_sets(ctx, 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);
+ case CMD_OBJ_METER:
+ return do_list_set(ctx, cmd, table);
+ case CMD_OBJ_MAPS:
+ return do_list_sets(ctx, cmd);
+ case CMD_OBJ_MAP:
+ return do_list_set(ctx, cmd, table);
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_COUNTERS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_COUNTER);
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_QUOTAS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_QUOTA);
+ case CMD_OBJ_CT_HELPER:
+ 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:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_SECMARKS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_SECMARK);
+ case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_SYNPROXYS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_SYNPROXY);
+ case CMD_OBJ_FLOWTABLE:
+ return do_list_flowtable(ctx, cmd, table);
+ case CMD_OBJ_FLOWTABLES:
+ return do_list_flowtables(ctx, cmd);
+ case CMD_OBJ_HOOKS:
+ return do_list_hooks(ctx, cmd);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+
+ return 0;
+}
+
+static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd, bool reset)
+{
+ struct set *set, *new_set;
+ struct expr *init;
+ int err;
+
+ set = cmd->elem.set;
+
+ /* Create a list of elements based of what we got from command line. */
+ if (set_is_non_concat_range(set))
+ init = get_set_intervals(set, cmd->expr);
+ else
+ init = cmd->expr;
+
+ new_set = set_clone(set);
+
+ /* Fetch from kernel the elements that have been requested .*/
+ err = netlink_get_setelem(ctx, &cmd->handle, &cmd->location,
+ cmd->elem.set, new_set, init, reset);
+ if (err >= 0)
+ __do_list_set(ctx, cmd, new_set);
+
+ if (set_is_non_concat_range(set))
+ expr_free(init);
+
+ set_free(new_set);
+
+ return err;
+}
+
+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, false);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+
+ return 0;
+}
+
+static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct obj *obj, *next;
+ struct table *table;
+ bool dump = false;
+ uint32_t type;
+ int ret;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_COUNTERS:
+ dump = true;
+ /* fall through */
+ case CMD_OBJ_COUNTER:
+ type = NFT_OBJECT_COUNTER;
+ break;
+ case CMD_OBJ_QUOTAS:
+ dump = true;
+ /* fall through */
+ case CMD_OBJ_QUOTA:
+ type = NFT_OBJECT_QUOTA;
+ break;
+ case CMD_OBJ_RULES:
+ ret = netlink_reset_rules(ctx, cmd, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
+ case CMD_OBJ_RULE:
+ return netlink_reset_rules(ctx, cmd, false);
+ case CMD_OBJ_ELEMENTS:
+ return do_get_setelems(ctx, cmd, true);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ ret = netlink_list_setelems(ctx, &cmd->handle, cmd->set, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+
+ ret = netlink_reset_objs(ctx, cmd, type, dump);
+ list_for_each_entry_safe(obj, next, &ctx->list, list) {
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ obj->handle.table.name,
+ obj->handle.family);
+ if (!obj_cache_find(table, obj->handle.obj.name, obj->type)) {
+ list_del(&obj->list);
+ obj_cache_add(obj, table);
+ }
+ }
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
+}
+
+static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ case CMD_OBJ_CHAIN:
+ return mnl_nft_rule_del(ctx, cmd);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_METER:
+ return mnl_nft_setelem_flush(ctx, cmd);
+ case CMD_OBJ_RULESET:
+ return mnl_nft_table_del(ctx, cmd);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ return 0;
+}
+
+static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ const struct chain *chain;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_CHAIN:
+ chain = chain_cache_find(table, cmd->handle.chain.name);
+
+ return mnl_nft_chain_rename(ctx, cmd, chain);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+ return 0;
+}
+
+static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct netlink_mon_handler monhandler = {
+ .monitor_flags = cmd->monitor->flags,
+ .format = cmd->monitor->format,
+ .ctx = ctx,
+ .loc = &cmd->location,
+ .cache = &ctx->nft->cache,
+ .debug_mask = ctx->nft->debug_mask,
+ };
+
+ if (nft_output_json(&ctx->nft->output))
+ monhandler.format = NFTNL_OUTPUT_JSON;
+
+ return netlink_monitor(&monhandler, ctx->nft->nf_sock);
+}
+
+static int do_command_describe(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct output_ctx *octx)
+{
+ expr_describe(cmd->expr, octx);
+ return 0;
+}
+
+struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type, const struct handle *h,
+ const struct location *loc, struct obj *obj)
+{
+ enum cmd_obj cmd_obj;
+
+ if (obj)
+ obj->type = type;
+
+ switch (type) {
+ case NFT_OBJECT_CT_HELPER:
+ cmd_obj = CMD_OBJ_CT_HELPER;
+ break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ cmd_obj = CMD_OBJ_CT_TIMEOUT;
+ break;
+ case NFT_OBJECT_CT_EXPECT:
+ cmd_obj = CMD_OBJ_CT_EXPECT;
+ break;
+ default:
+ BUG("missing type mapping");
+ }
+
+ return cmd_alloc(op, cmd_obj, h, loc, obj);
+}
+
+int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ switch (cmd->op) {
+ case CMD_ADD:
+ return do_command_add(ctx, cmd, false);
+ case CMD_CREATE:
+ return do_command_add(ctx, cmd, true);
+ case CMD_INSERT:
+ return do_command_insert(ctx, 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);
+ case CMD_LIST:
+ return do_command_list(ctx, cmd);
+ case CMD_RESET:
+ return do_command_reset(ctx, cmd);
+ case CMD_FLUSH:
+ return do_command_flush(ctx, cmd);
+ case CMD_RENAME:
+ return do_command_rename(ctx, cmd);
+ case CMD_IMPORT:
+ case CMD_EXPORT:
+ errno = EOPNOTSUPP;
+ return -1;
+ case CMD_MONITOR:
+ return do_command_monitor(ctx, cmd);
+ case CMD_DESCRIBE:
+ return do_command_describe(ctx, cmd, &ctx->nft->output);
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+}
+
+static int payload_match_stmt_cmp(const void *p1, const void *p2)
+{
+ const struct stmt *s1 = *(struct stmt * const *)p1;
+ const struct stmt *s2 = *(struct stmt * const *)p2;
+ const struct expr *e1 = s1->expr, *e2 = s2->expr;
+ int d;
+
+ d = e1->left->payload.base - e2->left->payload.base;
+ if (d != 0)
+ return d;
+ return e1->left->payload.offset - e2->left->payload.offset;
+}
+
+static bool relational_ops_match(const struct expr *e1, const struct expr *e2)
+{
+ enum ops op1, op2;
+
+ op1 = e1->op == OP_IMPLICIT ? OP_EQ : e1->op;
+ op2 = e2->op == OP_IMPLICIT ? OP_EQ : e2->op;
+
+ return op1 == op2;
+}
+
+static void payload_do_merge(struct stmt *sa[], unsigned int n)
+{
+ struct expr *last, *this, *expr1, *expr2;
+ struct stmt *stmt;
+ unsigned int i, j;
+
+ qsort(sa, n, sizeof(sa[0]), payload_match_stmt_cmp);
+
+ last = sa[0]->expr;
+ for (j = 0, i = 1; i < n; i++) {
+ stmt = sa[i];
+ this = stmt->expr;
+
+ if (!payload_can_merge(last->left, this->left) ||
+ !relational_ops_match(last, this)) {
+ last = this;
+ j = i;
+ continue;
+ }
+
+ expr1 = payload_expr_join(last->left, this->left);
+ expr2 = constant_expr_join(last->right, this->right);
+
+ /* We can merge last into this, but we can't replace
+ * the statement associated with this if it does contain
+ * a higher level protocol.
+ *
+ * ether type ip ip saddr X ether saddr Y
+ * ... can be changed to
+ * ether type ip ether saddr Y ip saddr X
+ * ... but not
+ * ip saddr X ether type ip ether saddr Y
+ *
+ * The latter form means we perform ip saddr test before
+ * ensuring ip dependency, plus it makes decoding harder
+ * since we don't know the type of the network header
+ * right away.
+ *
+ * So, if we're about to replace a statement
+ * containing a protocol identifier, just swap this and last
+ * and replace the other one (i.e., replace 'load ether type ip'
+ * with the combined 'load both ether type and saddr') and not
+ * the other way around.
+ */
+ if (this->left->flags & EXPR_F_PROTOCOL) {
+ struct expr *tmp = last;
+
+ last = this;
+ this = tmp;
+
+ expr1->flags |= EXPR_F_PROTOCOL;
+ stmt = sa[j];
+ assert(stmt->expr == this);
+ j = i;
+ }
+
+ expr_free(last->left);
+ last->left = expr1;
+
+ expr_free(last->right);
+ last->right = expr2;
+
+ list_del(&stmt->list);
+ stmt_free(stmt);
+ }
+}
+
+/**
+ * stmt_reduce - reduce statements in rule
+ *
+ * @rule: nftables rule
+ *
+ * This function aims to:
+ *
+ * - remove redundant statement, e.g. remove 'meta protocol ip' if family is ip
+ * - merge consecutive payload match statements
+ *
+ * Locate sequences of payload match statements referring to adjacent
+ * header locations and merge those using only equality relations.
+ *
+ * As a side-effect, payload match statements are ordered in ascending
+ * order according to the location of the payload.
+ */
+static void stmt_reduce(const struct rule *rule)
+{
+ struct stmt *stmt, *dstmt = NULL, *next;
+ struct stmt *sa[rule->num_stmts];
+ unsigned int idx = 0;
+
+ list_for_each_entry_safe(stmt, next, &rule->stmts, list) {
+ /* delete this redundant statement */
+ if (dstmt) {
+ list_del(&dstmt->list);
+ stmt_free(dstmt);
+ dstmt = NULL;
+ }
+
+ /* Must not merge across other statements */
+ if (stmt->ops->type != STMT_EXPRESSION) {
+ if (idx >= 2)
+ payload_do_merge(sa, idx);
+ idx = 0;
+ continue;
+ }
+
+ if (stmt->expr->etype != EXPR_RELATIONAL)
+ continue;
+ if (stmt->expr->right->etype != EXPR_VALUE)
+ continue;
+
+ if (stmt->expr->left->etype == EXPR_PAYLOAD) {
+ switch (stmt->expr->op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ case OP_NEQ:
+ break;
+ default:
+ continue;
+ }
+
+ sa[idx++] = stmt;
+ } else if (stmt->expr->left->etype == EXPR_META) {
+ switch (stmt->expr->op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ if (stmt->expr->left->meta.key == NFT_META_PROTOCOL &&
+ !stmt->expr->left->meta.inner_desc) {
+ uint16_t protocol;
+
+ protocol = mpz_get_uint16(stmt->expr->right->value);
+ if ((rule->handle.family == NFPROTO_IPV4 &&
+ protocol == ETH_P_IP) ||
+ (rule->handle.family == NFPROTO_IPV6 &&
+ protocol == ETH_P_IPV6))
+ dstmt = stmt;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (idx > 1)
+ payload_do_merge(sa, idx);
+}
+
+struct error_record *rule_postprocess(struct rule *rule)
+{
+ stmt_reduce(rule);
+ return NULL;
+}
diff --git a/src/scanner.c b/src/scanner.c
new file mode 100644
index 0000000..7810f55
--- /dev/null
+++ b/src/scanner.c
@@ -0,0 +1,8546 @@
+#line 2 "scanner.c"
+
+#line 4 "scanner.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+/* %not-for-header */
+/* %if-c-only */
+/* %if-not-reentrant */
+/* %endif */
+/* %endif */
+/* %ok-for-header */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 6
+#define YY_FLEX_SUBMINOR_VERSION 4
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* %if-c++-only */
+/* %endif */
+
+/* %if-c-only */
+#ifdef yy_create_buffer
+#define nft__create_buffer_ALREADY_DEFINED
+#else
+#define yy_create_buffer nft__create_buffer
+#endif
+
+#ifdef yy_delete_buffer
+#define nft__delete_buffer_ALREADY_DEFINED
+#else
+#define yy_delete_buffer nft__delete_buffer
+#endif
+
+#ifdef yy_scan_buffer
+#define nft__scan_buffer_ALREADY_DEFINED
+#else
+#define yy_scan_buffer nft__scan_buffer
+#endif
+
+#ifdef yy_scan_string
+#define nft__scan_string_ALREADY_DEFINED
+#else
+#define yy_scan_string nft__scan_string
+#endif
+
+#ifdef yy_scan_bytes
+#define nft__scan_bytes_ALREADY_DEFINED
+#else
+#define yy_scan_bytes nft__scan_bytes
+#endif
+
+#ifdef yy_init_buffer
+#define nft__init_buffer_ALREADY_DEFINED
+#else
+#define yy_init_buffer nft__init_buffer
+#endif
+
+#ifdef yy_flush_buffer
+#define nft__flush_buffer_ALREADY_DEFINED
+#else
+#define yy_flush_buffer nft__flush_buffer
+#endif
+
+#ifdef yy_load_buffer_state
+#define nft__load_buffer_state_ALREADY_DEFINED
+#else
+#define yy_load_buffer_state nft__load_buffer_state
+#endif
+
+#ifdef yy_switch_to_buffer
+#define nft__switch_to_buffer_ALREADY_DEFINED
+#else
+#define yy_switch_to_buffer nft__switch_to_buffer
+#endif
+
+#ifdef yypush_buffer_state
+#define nft_push_buffer_state_ALREADY_DEFINED
+#else
+#define yypush_buffer_state nft_push_buffer_state
+#endif
+
+#ifdef yypop_buffer_state
+#define nft_pop_buffer_state_ALREADY_DEFINED
+#else
+#define yypop_buffer_state nft_pop_buffer_state
+#endif
+
+#ifdef yyensure_buffer_stack
+#define nft_ensure_buffer_stack_ALREADY_DEFINED
+#else
+#define yyensure_buffer_stack nft_ensure_buffer_stack
+#endif
+
+#ifdef yylex
+#define nft_lex_ALREADY_DEFINED
+#else
+#define yylex nft_lex
+#endif
+
+#ifdef yyrestart
+#define nft_restart_ALREADY_DEFINED
+#else
+#define yyrestart nft_restart
+#endif
+
+#ifdef yylex_init
+#define nft_lex_init_ALREADY_DEFINED
+#else
+#define yylex_init nft_lex_init
+#endif
+
+#ifdef yylex_init_extra
+#define nft_lex_init_extra_ALREADY_DEFINED
+#else
+#define yylex_init_extra nft_lex_init_extra
+#endif
+
+#ifdef yylex_destroy
+#define nft_lex_destroy_ALREADY_DEFINED
+#else
+#define yylex_destroy nft_lex_destroy
+#endif
+
+#ifdef yyget_debug
+#define nft_get_debug_ALREADY_DEFINED
+#else
+#define yyget_debug nft_get_debug
+#endif
+
+#ifdef yyset_debug
+#define nft_set_debug_ALREADY_DEFINED
+#else
+#define yyset_debug nft_set_debug
+#endif
+
+#ifdef yyget_extra
+#define nft_get_extra_ALREADY_DEFINED
+#else
+#define yyget_extra nft_get_extra
+#endif
+
+#ifdef yyset_extra
+#define nft_set_extra_ALREADY_DEFINED
+#else
+#define yyset_extra nft_set_extra
+#endif
+
+#ifdef yyget_in
+#define nft_get_in_ALREADY_DEFINED
+#else
+#define yyget_in nft_get_in
+#endif
+
+#ifdef yyset_in
+#define nft_set_in_ALREADY_DEFINED
+#else
+#define yyset_in nft_set_in
+#endif
+
+#ifdef yyget_out
+#define nft_get_out_ALREADY_DEFINED
+#else
+#define yyget_out nft_get_out
+#endif
+
+#ifdef yyset_out
+#define nft_set_out_ALREADY_DEFINED
+#else
+#define yyset_out nft_set_out
+#endif
+
+#ifdef yyget_leng
+#define nft_get_leng_ALREADY_DEFINED
+#else
+#define yyget_leng nft_get_leng
+#endif
+
+#ifdef yyget_text
+#define nft_get_text_ALREADY_DEFINED
+#else
+#define yyget_text nft_get_text
+#endif
+
+#ifdef yyget_lineno
+#define nft_get_lineno_ALREADY_DEFINED
+#else
+#define yyget_lineno nft_get_lineno
+#endif
+
+#ifdef yyset_lineno
+#define nft_set_lineno_ALREADY_DEFINED
+#else
+#define yyset_lineno nft_set_lineno
+#endif
+
+#ifdef yyget_column
+#define nft_get_column_ALREADY_DEFINED
+#else
+#define yyget_column nft_get_column
+#endif
+
+#ifdef yyset_column
+#define nft_set_column_ALREADY_DEFINED
+#else
+#define yyset_column nft_set_column
+#endif
+
+#ifdef yywrap
+#define nft_wrap_ALREADY_DEFINED
+#else
+#define yywrap nft_wrap
+#endif
+
+/* %endif */
+
+#ifdef yyget_lval
+#define nft_get_lval_ALREADY_DEFINED
+#else
+#define yyget_lval nft_get_lval
+#endif
+
+#ifdef yyset_lval
+#define nft_set_lval_ALREADY_DEFINED
+#else
+#define yyset_lval nft_set_lval
+#endif
+
+#ifdef yyget_lloc
+#define nft_get_lloc_ALREADY_DEFINED
+#else
+#define yyget_lloc nft_get_lloc
+#endif
+
+#ifdef yyset_lloc
+#define nft_set_lloc_ALREADY_DEFINED
+#else
+#define yyset_lloc nft_set_lloc
+#endif
+
+#ifdef yyalloc
+#define nft_alloc_ALREADY_DEFINED
+#else
+#define yyalloc nft_alloc
+#endif
+
+#ifdef yyrealloc
+#define nft_realloc_ALREADY_DEFINED
+#else
+#define yyrealloc nft_realloc
+#endif
+
+#ifdef yyfree
+#define nft_free_ALREADY_DEFINED
+#else
+#define yyfree nft_free
+#endif
+
+/* %if-c-only */
+
+/* %endif */
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+/* %if-c-only */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+/* %endif */
+
+/* %if-tables-serialization */
+/* %endif */
+/* end standard C headers. */
+
+/* %if-c-or-c++ */
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#ifndef SIZE_MAX
+#define SIZE_MAX (~(size_t)0)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+/* %endif */
+
+/* begin standard C++ headers. */
+/* %if-c++-only */
+/* %endif */
+
+/* TODO: this is always defined, so inline it */
+#define yyconst const
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define yynoreturn __attribute__((__noreturn__))
+#else
+#define yynoreturn
+#endif
+
+/* %not-for-header */
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+/* %ok-for-header */
+
+/* %not-for-header */
+/* Promotes a possibly negative, possibly signed char to an
+ * integer in range [0..255] for use as an array index.
+ */
+#define YY_SC_TO_UI(c) ((YY_CHAR) (c))
+/* %ok-for-header */
+
+/* %if-reentrant */
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* %endif */
+
+/* %if-not-reentrant */
+/* %endif */
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin , yyscanner )
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+/* %if-not-reentrant */
+/* %endif */
+
+/* %if-c-only */
+/* %if-not-reentrant */
+/* %endif */
+/* %endif */
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+ #define YY_LINENO_REWIND_TO(dst) \
+ do {\
+ const char *p;\
+ for ( p = yy_cp-1; p >= (dst); --p)\
+ if ( *p == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+/* %if-c-only */
+ FILE *yy_input_file;
+/* %endif */
+
+/* %if-c++-only */
+/* %endif */
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ int yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* %if-c-only Standard (non-C++) definition */
+/* %not-for-header */
+/* %if-not-reentrant */
+/* %endif */
+/* %ok-for-header */
+
+/* %endif */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+/* %if-c-only Standard (non-C++) definition */
+
+/* %if-not-reentrant */
+/* %not-for-header */
+/* %ok-for-header */
+
+/* %endif */
+
+void yyrestart ( FILE *input_file , yyscan_t yyscanner );
+void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
+void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
+void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
+void yypop_buffer_state ( yyscan_t yyscanner );
+
+static void yyensure_buffer_stack ( yyscan_t yyscanner );
+static void yy_load_buffer_state ( yyscan_t yyscanner );
+static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner );
+#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
+
+/* %endif */
+
+void *yyalloc ( yy_size_t , yyscan_t yyscanner );
+void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
+void yyfree ( void * , yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* %% [1.0] yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here */
+/* Begin user sect3 */
+
+#define nft_wrap(yyscanner) (/*CONSTCOND*/1)
+#define YY_SKIP_YYWRAP
+
+#define FLEX_DEBUG
+typedef flex_uint8_t YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+/* %% [1.5] DFA */
+
+/* %if-c-only Standard (non-C++) definition */
+
+static yy_state_type yy_get_previous_state ( yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner);
+static int yy_get_next_buffer ( yyscan_t yyscanner );
+static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner );
+
+/* %endif */
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\
+ yyleng = (int) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\
+ yyg->yy_c_buf_p = yy_cp;
+/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
+#define YY_NUM_RULES 412
+#define YY_END_OF_BUFFER 413
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static const flex_int16_t yy_accept[2383] =
+ { 0,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 413, 411, 407, 406, 408, 33, 411, 411, 39, 29,
+ 21, 22, 37, 42, 13, 36, 14, 35, 400, 400,
+ 400, 15, 16, 7, 40, 11, 38, 404, 404, 19,
+ 411, 20, 27, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 17, 31, 18, 407, 408,
+ 411, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 407, 408, 3, 0, 402,
+ 0, 410, 403, 404, 0, 0, 400, 0, 0, 0,
+ 398, 398, 398, 398, 400, 396, 23, 5, 1, 9,
+ 25, 404, 0, 0, 405, 404, 404, 250, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 345, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 2,
+ 404, 404, 404, 404, 404, 404, 404, 404, 10, 404,
+ 404, 12, 404, 404, 404, 404, 404, 404, 404, 404,
+
+ 404, 184, 404, 404, 404, 6, 404, 404, 404, 8,
+ 404, 404, 316, 404, 404, 4, 404, 404, 404, 404,
+ 404, 404, 32, 404, 404, 404, 404, 404, 404, 404,
+ 404, 306, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 164, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 395, 407, 0, 0, 408,
+ 0, 409, 404, 404, 404, 404, 404, 404, 404, 162,
+ 163, 404, 404, 404, 404, 404, 404, 404, 404, 172,
+ 404, 404, 32, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 6, 404, 404,
+ 404, 404, 197, 195, 404, 77, 404, 404, 404, 404,
+ 4, 404, 4, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 6, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 385, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 392, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 4, 404, 404, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 4, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 6, 404, 404, 404, 404, 6, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 403, 0, 400, 0, 398, 0, 396, 399, 0,
+ 0, 0, 398, 0, 400, 396, 396, 396, 404, 0,
+ 0, 0, 404, 80, 382, 30, 178, 404, 404, 404,
+ 404, 404, 404, 404, 334, 404, 150, 404, 404, 404,
+ 404, 404, 404, 404, 315, 370, 404, 188, 404, 253,
+ 404, 404, 404, 404, 372, 404, 404, 404, 404, 371,
+
+ 404, 404, 86, 404, 266, 404, 311, 404, 404, 404,
+ 404, 404, 319, 404, 404, 404, 404, 404, 404, 245,
+ 404, 404, 404, 404, 404, 404, 129, 404, 61, 404,
+ 404, 404, 404, 404, 404, 404, 34, 404, 404, 404,
+ 322, 373, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 307, 308, 404, 404,
+ 404, 404, 59, 404, 404, 404, 404, 404, 309, 404,
+ 404, 404, 268, 404, 404, 404, 257, 404, 404, 404,
+ 404, 264, 404, 28, 0, 409, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 238, 404,
+ 404, 404, 404, 243, 80, 404, 404, 404, 404, 404,
+ 404, 404, 198, 404, 191, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 207, 404, 404, 404,
+ 404, 404, 209, 404, 210, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 173, 174, 175, 404,
+ 383, 404, 404, 404, 404, 404, 61, 404, 404, 404,
+ 404, 59, 404, 404, 404, 404, 252, 255, 404, 404,
+
+ 404, 368, 404, 404, 393, 404, 404, 364, 404, 404,
+ 136, 404, 340, 404, 404, 343, 342, 404, 404, 404,
+ 404, 404, 285, 404, 188, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 293, 404, 290, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 377, 404, 404, 404, 403, 0,
+ 0, 400, 0, 0, 398, 0, 401, 0, 401, 396,
+ 0, 400, 0, 396, 0, 396, 396, 404, 0, 0,
+ 0, 0, 0, 0, 397, 404, 404, 404, 404, 404,
+ 404, 254, 404, 404, 404, 404, 269, 404, 404, 404,
+
+ 404, 404, 155, 72, 404, 404, 404, 404, 404, 404,
+ 404, 404, 110, 404, 312, 404, 404, 75, 404, 404,
+ 53, 149, 404, 404, 232, 242, 404, 404, 404, 404,
+ 404, 404, 78, 404, 404, 404, 404, 74, 124, 404,
+ 87, 404, 318, 404, 317, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 58, 270, 404, 107, 404, 404,
+ 154, 404, 404, 404, 404, 231, 404, 169, 404, 404,
+ 404, 171, 41, 404, 404, 181, 404, 404, 182, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 145, 404, 404, 404, 404, 350, 121,
+ 404, 404, 404, 235, 404, 404, 404, 404, 404, 404,
+ 404, 310, 187, 312, 404, 404, 194, 404, 404, 196,
+ 404, 110, 404, 404, 404, 148, 404, 404, 140, 404,
+ 144, 404, 404, 404, 404, 404, 272, 404, 404, 203,
+ 206, 404, 223, 404, 404, 404, 211, 404, 404, 404,
+ 212, 404, 231, 404, 404, 404, 404, 404, 384, 404,
+ 404, 110, 53, 404, 116, 404, 404, 58, 404, 49,
+ 404, 404, 58, 404, 404, 404, 404, 404, 367, 404,
+
+ 404, 404, 404, 124, 404, 404, 404, 404, 404, 404,
+ 404, 273, 284, 404, 404, 404, 274, 404, 404, 404,
+ 294, 291, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 161, 232, 152, 404,
+ 404, 231, 404, 403, 0, 0, 400, 398, 0, 0,
+ 0, 0, 396, 396, 0, 0, 177, 0, 396, 396,
+ 396, 396, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 404, 404, 404, 404, 57, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 166, 404,
+ 404, 404, 404, 256, 404, 89, 404, 404, 404, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 404, 96, 404,
+ 404, 389, 365, 139, 404, 404, 112, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 135, 146, 404, 404, 404, 404, 404,
+ 404, 88, 404, 404, 404, 404, 404, 326, 325, 404,
+ 404, 404, 56, 404, 404, 404, 404, 404, 404, 263,
+ 168, 179, 404, 180, 167, 404, 123, 362, 404, 261,
+ 354, 404, 404, 404, 404, 359, 404, 404, 404, 352,
+ 360, 404, 404, 404, 404, 240, 404, 404, 404, 404,
+ 239, 244, 404, 404, 404, 404, 404, 199, 404, 404,
+
+ 404, 125, 141, 404, 404, 404, 404, 147, 271, 260,
+ 404, 225, 404, 404, 404, 221, 404, 404, 224, 404,
+ 213, 214, 215, 216, 404, 404, 227, 226, 404, 404,
+ 404, 57, 404, 404, 119, 139, 112, 146, 128, 404,
+ 404, 56, 51, 52, 404, 404, 404, 404, 390, 391,
+ 404, 404, 404, 404, 404, 404, 278, 404, 404, 404,
+ 281, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 304, 404, 404, 404, 69, 404, 404, 404, 134,
+ 133, 135, 404, 404, 404, 153, 404, 404, 404, 404,
+ 0, 0, 0, 401, 0, 0, 0, 396, 396, 396,
+
+ 176, 0, 0, 396, 396, 0, 396, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 71, 404, 165,
+ 337, 404, 404, 404, 404, 83, 44, 85, 404, 404,
+ 54, 404, 404, 386, 404, 92, 388, 404, 404, 265,
+ 267, 63, 404, 404, 233, 404, 404, 404, 91, 404,
+ 84, 404, 24, 404, 404, 404, 79, 404, 404, 363,
+ 404, 404, 404, 404, 404, 404, 404, 106, 404, 404,
+ 158, 404, 404, 151, 90, 404, 76, 26, 404, 404,
+ 404, 65, 404, 404, 404, 70, 170, 404, 404, 82,
+ 404, 346, 404, 404, 404, 357, 404, 404, 404, 404,
+
+ 404, 361, 404, 404, 404, 404, 404, 404, 404, 404,
+ 189, 200, 130, 404, 404, 404, 143, 142, 109, 404,
+ 202, 404, 208, 222, 230, 404, 404, 404, 404, 205,
+ 204, 404, 48, 404, 404, 115, 113, 127, 404, 404,
+ 50, 262, 404, 404, 369, 137, 138, 404, 404, 404,
+ 296, 289, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 404, 404, 292, 337, 404, 404,
+ 404, 404, 404, 404, 404, 376, 404, 404, 375, 396,
+ 0, 0, 0, 0, 396, 396, 0, 396, 396, 0,
+ 0, 0, 396, 396, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 404, 97, 404,
+ 404, 120, 404, 94, 55, 100, 60, 105, 404, 404,
+ 404, 330, 404, 320, 321, 43, 404, 404, 387, 93,
+ 327, 381, 404, 332, 111, 404, 323, 324, 333, 404,
+ 404, 404, 404, 81, 404, 64, 394, 366, 404, 102,
+ 258, 404, 404, 404, 404, 404, 358, 347, 404, 122,
+ 404, 404, 404, 185, 404, 234, 404, 404, 404, 404,
+ 404, 201, 404, 404, 249, 404, 404, 229, 404, 404,
+ 228, 404, 344, 120, 404, 394, 404, 404, 404, 404,
+ 338, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 259, 404, 131, 404, 404, 404, 404, 396, 0, 0,
+ 0, 0, 0, 396, 396, 396, 396, 396, 0, 0,
+ 396, 396, 0, 396, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 404, 98, 73,
+ 47, 104, 404, 404, 329, 335, 99, 404, 331, 336,
+ 95, 246, 45, 157, 404, 374, 46, 404, 404, 404,
+ 404, 351, 404, 404, 192, 193, 404, 404, 241, 190,
+ 404, 404, 248, 404, 220, 251, 404, 404, 126, 404,
+ 117, 374, 404, 251, 404, 339, 404, 404, 404, 404,
+
+ 404, 404, 275, 295, 404, 404, 404, 404, 404, 404,
+ 404, 279, 68, 404, 67, 404, 404, 404, 404, 404,
+ 396, 0, 0, 0, 396, 396, 0, 396, 396, 0,
+ 396, 396, 0, 396, 0, 396, 396, 0, 396, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 404, 62, 404, 404, 328, 183, 353,
+ 404, 404, 349, 348, 237, 404, 186, 247, 404, 218,
+ 219, 62, 118, 404, 313, 404, 404, 404, 404, 404,
+ 404, 276, 404, 404, 404, 404, 404, 404, 404, 404,
+ 404, 404, 404, 404, 380, 378, 0, 0, 0, 0,
+
+ 0, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+ 396, 0, 0, 396, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 101, 404, 156, 404, 356, 404, 404, 404, 114,
+ 404, 341, 287, 283, 404, 404, 404, 404, 404, 303,
+ 404, 404, 404, 404, 404, 404, 404, 404, 404, 404,
+ 160, 404, 0, 0, 396, 396, 396, 0, 396, 396,
+ 0, 396, 396, 0, 396, 396, 0, 396, 396, 396,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 103, 355,
+
+ 404, 108, 404, 404, 282, 300, 288, 404, 299, 305,
+ 404, 404, 404, 404, 404, 404, 66, 404, 404, 404,
+ 0, 0, 0, 396, 0, 396, 396, 396, 396, 396,
+ 396, 396, 396, 396, 396, 396, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 404, 404,
+ 404, 404, 302, 404, 404, 404, 280, 404, 404, 159,
+ 404, 0, 0, 0, 396, 396, 0, 396, 396, 0,
+ 396, 396, 0, 396, 396, 0, 396, 396, 0, 396,
+ 396, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 236, 404, 404, 277, 404, 404, 404, 404, 404, 404,
+ 0, 0, 0, 0, 396, 396, 396, 396, 396, 396,
+ 396, 396, 396, 396, 396, 396, 396, 0, 396, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 217, 314, 404, 404, 404, 404, 404, 379, 0,
+ 396, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+ 396, 396, 396, 396, 396, 396, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 404, 404, 404, 404, 132,
+ 0, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+ 396, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 404, 404,
+ 404, 404, 396, 396, 396, 396, 396, 396, 396, 396,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 404, 404, 404, 286, 396, 0, 0, 0, 0,
+ 0, 0, 0, 0, 301, 404, 404, 0, 298, 404,
+ 297, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 4, 5, 6, 7, 8, 1, 9, 1, 10,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 22, 25, 22, 26, 27, 28,
+ 29, 30, 1, 31, 32, 32, 32, 32, 32, 33,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 35, 34, 34,
+ 36, 37, 38, 39, 40, 1, 41, 42, 43, 44,
+
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const YY_CHAR yy_meta[70] =
+ { 0,
+ 1, 2, 2, 2, 1, 1, 1, 1, 1, 1,
+ 1, 3, 1, 2, 4, 5, 6, 7, 7, 7,
+ 7, 7, 7, 7, 7, 8, 1, 1, 1, 1,
+ 1, 9, 9, 10, 10, 1, 3, 11, 1, 10,
+ 9, 9, 9, 12, 9, 9, 10, 13, 10, 10,
+ 10, 10, 13, 10, 10, 10, 10, 10, 13, 10,
+ 10, 10, 10, 10, 10, 10, 1, 1, 2
+ } ;
+
+static const flex_int16_t yy_base[2695] =
+ { 0,
+ 0, 68, 29, 72, 26, 85, 99, 164, 39, 96,
+ 27, 102, 34, 108, 58, 229, 76, 171, 249, 271,
+ 128, 295, 71, 187, 184, 356, 70, 193, 38, 179,
+ 156, 332, 207, 318, 0, 197, 379, 250, 159, 338,
+ 212, 400, 0, 256, 0, 260, 71, 401, 215, 414,
+ 402, 477, 309, 481, 102, 464, 330, 490, 54, 292,
+ 247, 473, 76, 393, 3472, 491, 90, 498, 450, 507,
+ 228, 511, 108, 565, 519, 577, 458, 569, 172, 584,
+ 492, 588, 543, 592, 606, 665, 685, 744, 555, 618,
+ 133, 683, 347, 758, 185, 736, 3466, 602, 3451, 649,
+
+ 627, 700, 426, 708, 50, 673, 635, 759, 3409, 751,
+ 3468, 9866, 3423, 9866, 3415, 3385, 3390, 3378, 9866, 9866,
+ 9866, 9866, 9866, 9866, 9866, 9866, 234, 9866, 807, 132,
+ 268, 3340, 9866, 54, 3329, 245, 9866, 860, 364, 3331,
+ 353, 9866, 9866, 815, 3251, 645, 853, 856, 553, 888,
+ 779, 898, 514, 912, 925, 932, 946, 905, 521, 953,
+ 972, 991, 833, 996, 964, 9866, 9866, 9866, 669, 765,
+ 3303, 977, 1017, 1029, 1031, 3261, 1053, 1055, 1063, 263,
+ 726, 1077, 1087, 1111, 3257, 405, 1122, 1128, 1117, 193,
+ 380, 1148, 1155, 1160, 1175, 874, 323, 1189, 1205, 1204,
+
+ 3254, 1226, 997, 1221, 1249, 1241, 750, 933, 1259, 802,
+ 1271, 1268, 1163, 259, 1294, 1299, 948, 1320, 384, 1310,
+ 1309, 3235, 1333, 1336, 522, 1356, 1354, 1365, 3228, 618,
+ 1386, 1395, 1405, 1396, 144, 3204, 1418, 1425, 1433, 559,
+ 1442, 1021, 579, 1459, 1402, 1475, 1498, 1195, 1327, 1472,
+ 825, 1490, 1114, 1505, 1521, 1532, 1537, 1552, 1542, 1552,
+ 1370, 1572, 378, 1574, 938, 1580, 408, 656, 1576, 1608,
+ 3204, 783, 1596, 1625, 340, 1616, 1645, 1634, 1636, 1658,
+ 1686, 3202, 3190, 1688, 1714, 372, 3164, 3154, 599, 1666,
+ 1715, 417, 1697, 1742, 235, 868, 1747, 1762, 1149, 1755,
+
+ 1714, 1790, 3135, 934, 1792, 1727, 1795, 585, 1786, 669,
+ 1314, 1170, 1801, 1827, 725, 1231, 3127, 1813, 1838, 3119,
+ 1275, 1532, 3112, 1044, 738, 3125, 3120, 9866, 3114, 9866,
+ 3115, 9866, 9866, 631, 3104, 1879, 1889, 3088, 3087, 0,
+ 1931, 1960, 1968, 1976, 3063, 2010, 9866, 9866, 9866, 9866,
+ 9866, 2039, 3042, 3035, 9866, 3007, 3002, 771, 1162, 1297,
+ 1039, 1321, 1371, 1455, 927, 1906, 1574, 1453, 853, 2963,
+ 2984, 1660, 1120, 1591, 1671, 1728, 1774, 2972, 1556, 1236,
+ 1869, 1240, 1880, 1483, 1883, 1425, 1699, 1643, 2013, 1721,
+ 1755, 1372, 1814, 1840, 2032, 1904, 2012, 2033, 1784, 2010,
+
+ 2062, 2064, 1882, 2063, 2009, 1543, 2065, 2001, 2066, 1544,
+ 2078, 1756, 1610, 2067, 2096, 2080, 2082, 2083, 2098, 2101,
+ 2115, 2116, 1854, 2117, 2118, 2120, 2119, 2129, 2127, 2132,
+ 2146, 2153, 2133, 2163, 2165, 2168, 2175, 1999, 2177, 2181,
+ 2187, 2189, 2191, 1933, 2195, 2198, 2201, 2205, 2207, 2209,
+ 2000, 2218, 2215, 2221, 2225, 1934, 1525, 2000, 3006, 2001,
+ 2990, 9866, 426, 2231, 2233, 2237, 2242, 2238, 2248, 2002,
+ 2251, 2253, 2254, 2257, 2259, 2260, 2268, 2272, 2283, 2265,
+ 2269, 2287, 2289, 2296, 2300, 2307, 2310, 2311, 2318, 2322,
+ 2324, 2328, 2337, 2339, 445, 2330, 2351, 2359, 2365, 2368,
+
+ 2375, 2369, 2379, 2946, 2389, 2392, 2385, 2401, 2409, 2415,
+ 2419, 2422, 2423, 2424, 2425, 2428, 2429, 2432, 2435, 2433,
+ 2441, 2442, 2461, 2470, 2473, 2474, 2480, 2481, 2485, 2483,
+ 2488, 2500, 2514, 2490, 2501, 332, 2517, 2502, 962, 2520,
+ 2924, 2537, 2540, 2544, 2549, 2551, 2552, 2553, 2580, 2550,
+ 2557, 2564, 2568, 2581, 2590, 2591, 2607, 2933, 2457, 2604,
+ 2583, 2610, 2613, 2617, 2619, 2620, 2630, 2634, 2640, 2637,
+ 2647, 2651, 2652, 2657, 2641, 2664, 2670, 2667, 2678, 2688,
+ 2694, 2697, 2702, 2706, 2707, 2720, 2729, 2708, 2747, 2759,
+ 2755, 2765, 2922, 2711, 2710, 2758, 2773, 2775, 2797, 2805,
+
+ 2774, 2918, 2793, 2811, 2808, 2812, 631, 2915, 2813, 2816,
+ 2814, 2832, 2831, 2819, 2846, 2847, 2817, 2850, 2861, 2874,
+ 2868, 2876, 2877, 2878, 2883, 2890, 2888, 2892, 2894, 2896,
+ 2897, 2906, 2907, 2909, 2911, 2920, 2933, 2940, 2938, 2941,
+ 2942, 0, 2982, 2992, 2940, 3034, 3017, 0, 0, 1519,
+ 3069, 3077, 9866, 3085, 2936, 3123, 2913, 842, 3152, 2910,
+ 2891, 3181, 2871, 0, 2705, 2947, 2950, 3010, 2951, 3027,
+ 3032, 3175, 3011, 3100, 2959, 3120, 3037, 2856, 2854, 3113,
+ 3174, 3103, 3122, 3123, 3114, 3151, 3179, 3171, 3195, 3178,
+ 3198, 3209, 3217, 3221, 3218, 3224, 3225, 3226, 3227, 3228,
+
+ 3230, 3233, 3238, 3239, 3240, 3245, 3244, 3247, 3268, 3271,
+ 3274, 3275, 3280, 3278, 3284, 3279, 3281, 3292, 3298, 3285,
+ 3301, 3291, 3295, 3302, 3307, 3311, 3330, 3333, 3335, 3337,
+ 3340, 3342, 3341, 3343, 3347, 3348, 3349, 3352, 3356, 3357,
+ 3361, 3353, 3364, 3383, 3390, 3391, 3392, 3399, 3400, 3405,
+ 3404, 3406, 3411, 3419, 3401, 3418, 3414, 3421, 3423, 3428,
+ 3433, 3440, 3445, 3449, 3454, 3459, 3460, 3462, 3464, 3467,
+ 3468, 3469, 3472, 3473, 3475, 3480, 3486, 3490, 3495, 3502,
+ 3504, 3507, 3510, 3516, 2898, 9866, 2823, 3517, 3521, 3522,
+ 3525, 3528, 3530, 3531, 3533, 3536, 3538, 3545, 3551, 3549,
+
+ 3552, 3554, 3564, 3560, 3569, 3573, 3580, 3581, 3583, 3584,
+ 3599, 3588, 3601, 3602, 3604, 2813, 3610, 3616, 3614, 3620,
+ 3622, 3625, 3630, 3634, 2788, 3638, 3640, 3644, 3642, 3651,
+ 3653, 3658, 3656, 3660, 3661, 3662, 3664, 3668, 3666, 3670,
+ 3673, 3674, 3688, 3694, 3700, 3701, 3704, 3710, 3709, 3707,
+ 3717, 3720, 3723, 3731, 3728, 3733, 3736, 3739, 3750, 3752,
+ 3754, 3757, 3759, 3760, 3765, 3766, 3767, 3769, 3768, 3771,
+ 3781, 3786, 3783, 3772, 3795, 3809, 3810, 3813, 3815, 3818,
+ 3821, 3822, 3823, 3824, 3825, 3826, 3829, 3828, 3830, 3833,
+ 3842, 3837, 3844, 3845, 3868, 3871, 3852, 3872, 3873, 3874,
+
+ 3879, 3880, 3881, 3886, 3889, 3890, 3891, 3892, 3894, 3895,
+ 3900, 3908, 3909, 3922, 3926, 3924, 3930, 3936, 3937, 3939,
+ 3941, 3942, 3943, 3944, 3946, 3950, 3952, 3953, 3959, 3963,
+ 3986, 3991, 3960, 3965, 3972, 3976, 3981, 3995, 3998, 4000,
+ 4002, 4005, 4008, 4009, 4012, 4013, 4017, 4019, 4029, 4031,
+ 4032, 4039, 4045, 4048, 4049, 4051, 4052, 4059, 0, 4090,
+ 4100, 4091, 2814, 2812, 4108, 4046, 9866, 4134, 2790, 2757,
+ 2720, 4114, 4156, 4188, 0, 2750, 1292, 4131, 2749, 2709,
+ 2691, 4219, 4166, 441, 9866, 4190, 4157, 4158, 4186, 4129,
+ 4180, 4181, 4189, 4187, 4216, 4236, 4185, 4238, 4242, 4243,
+
+ 4246, 4244, 4247, 4254, 4256, 4258, 4257, 4260, 4270, 4273,
+ 4262, 4274, 4276, 4277, 4286, 4293, 4300, 4304, 4305, 4306,
+ 4307, 4312, 4314, 4315, 4317, 4320, 4322, 4323, 4326, 4328,
+ 4336, 4338, 4341, 4355, 4356, 4357, 4359, 4362, 4364, 4369,
+ 4371, 4372, 4373, 4375, 4378, 4383, 4386, 4391, 4393, 4405,
+ 4407, 4410, 4412, 4413, 4415, 4419, 4420, 4421, 4422, 4428,
+ 4425, 4441, 4427, 4451, 4454, 4457, 4461, 4463, 4464, 4467,
+ 4468, 4477, 4470, 4481, 4478, 4483, 4484, 4490, 4499, 4501,
+ 4511, 4512, 4514, 4517, 4519, 4521, 4522, 4528, 4529, 4534,
+ 4530, 4532, 4535, 4540, 4548, 4550, 4551, 4556, 4558, 4567,
+
+ 4561, 4570, 4572, 4577, 4579, 4580, 4587, 4589, 4588, 4590,
+ 4593, 4591, 4596, 4599, 4617, 4601, 4622, 4627, 4629, 4630,
+ 4637, 4632, 4638, 4639, 4645, 4641, 4640, 4643, 4646, 4648,
+ 4649, 4653, 4656, 4658, 4682, 4685, 4686, 4687, 4688, 4689,
+ 4695, 4696, 4697, 4699, 4701, 4698, 4702, 4704, 4706, 4716,
+ 4717, 4718, 4732, 4737, 4740, 4738, 4745, 4748, 4746, 4749,
+ 4751, 4753, 4755, 4759, 4760, 4766, 4768, 4782, 4783, 4787,
+ 4795, 4788, 4789, 4799, 4790, 4809, 4817, 4818, 4819, 4821,
+ 4822, 4823, 4826, 4827, 4828, 4833, 4837, 4839, 4849, 4855,
+ 4856, 4859, 4868, 4872, 4869, 4882, 4876, 4883, 4888, 4889,
+
+ 4895, 4898, 4900, 4903, 4904, 4910, 4909, 4917, 4918, 4919,
+ 4927, 4930, 4932, 4933, 4937, 4938, 4964, 4946, 4947, 4948,
+ 4959, 4969, 4970, 4974, 4982, 4977, 4987, 4990, 4992, 4997,
+ 4996, 5004, 5000, 5005, 5009, 5010, 5014, 5016, 5018, 5024,
+ 5048, 5031, 5036, 0, 5073, 2689, 1419, 5081, 5105, 4313,
+ 5108, 2660, 0, 2644, 0, 2624, 9866, 5117, 137, 789,
+ 2640, 4058, 2636, 2629, 2609, 521, 5125, 5162, 0, 5135,
+ 595, 5115, 5156, 5038, 5154, 5042, 5159, 5160, 5161, 5177,
+ 5180, 5187, 5190, 5199, 5200, 5204, 5207, 5206, 5050, 5208,
+ 5209, 5214, 5221, 5153, 5216, 5222, 5226, 5227, 5228, 5238,
+
+ 5240, 5250, 5254, 5256, 5257, 5259, 5261, 5264, 5268, 5269,
+ 5270, 5276, 5277, 5280, 5285, 5288, 5287, 5290, 5297, 5300,
+ 5304, 5306, 5311, 5314, 5318, 5316, 5319, 5323, 5324, 5326,
+ 5327, 5330, 5338, 5346, 5347, 5354, 5356, 5358, 5360, 5361,
+ 5365, 5373, 5374, 5376, 5378, 5377, 5382, 5384, 5387, 5388,
+ 5392, 5389, 5397, 5404, 5405, 5406, 5418, 5419, 5421, 5420,
+ 5423, 5426, 5427, 5434, 5435, 5437, 5438, 5447, 5442, 5449,
+ 5457, 5461, 5464, 5469, 5470, 5471, 5477, 5473, 5476, 5478,
+ 5481, 5483, 5491, 5488, 5487, 5492, 5499, 5500, 5511, 5504,
+ 5510, 5520, 5523, 5526, 5527, 5532, 5537, 5539, 5540, 5542,
+
+ 5547, 5550, 5553, 5555, 5559, 5556, 5560, 5561, 5570, 5571,
+ 5573, 5577, 5576, 5582, 5587, 5590, 5594, 5599, 5600, 5603,
+ 5604, 5605, 5608, 5613, 5614, 5616, 5621, 5623, 5626, 5627,
+ 5631, 5632, 5634, 5637, 5635, 5640, 5644, 5645, 5650, 5655,
+ 5661, 5663, 5673, 5671, 5674, 5677, 5682, 5689, 5684, 5690,
+ 5693, 5694, 5695, 5713, 5697, 5721, 5700, 5723, 5708, 5724,
+ 5726, 5727, 5729, 5735, 5736, 5743, 5744, 5747, 5750, 5755,
+ 5762, 5763, 5767, 5774, 5770, 5776, 5777, 5778, 5781, 5784,
+ 5794, 5805, 5798, 5813, 5800, 5804, 5817, 5812, 5818, 5820,
+ 5851, 5861, 5885, 2607, 5888, 2589, 2588, 2558, 2556, 2553,
+
+ 9866, 5897, 5907, 2542, 2540, 0, 2532, 2527, 2524, 2470,
+ 694, 0, 5917, 2392, 3046, 697, 5918, 5826, 5931, 5912,
+ 5933, 5934, 5935, 5936, 5938, 5940, 5941, 5943, 5946, 5947,
+ 5948, 5949, 5950, 5953, 5954, 5962, 5967, 5969, 5981, 5983,
+ 5986, 5988, 5990, 5991, 5993, 5996, 5997, 6002, 6003, 6004,
+ 6007, 6009, 6017, 6019, 6023, 6025, 6026, 6031, 6041, 6043,
+ 6047, 6049, 6052, 6053, 6054, 6061, 6063, 6060, 6067, 6070,
+ 6073, 6075, 6076, 6081, 6083, 6089, 6090, 6091, 6099, 6103,
+ 6104, 6105, 6109, 6111, 6112, 6113, 6119, 6123, 6125, 6127,
+ 6132, 6133, 6139, 6141, 6140, 6147, 6149, 6153, 6154, 6155,
+
+ 6161, 6159, 6168, 6171, 6173, 6175, 6181, 6183, 6197, 6199,
+ 6191, 6203, 6205, 6207, 6211, 6213, 6217, 6218, 6219, 6221,
+ 6227, 6233, 6229, 6235, 6239, 6240, 6245, 6247, 6256, 6249,
+ 6251, 6257, 6263, 6267, 6268, 6269, 6271, 6275, 6277, 6279,
+ 6283, 6284, 6287, 6290, 6295, 6297, 6299, 6301, 6303, 6305,
+ 6307, 6311, 6334, 6310, 6317, 6321, 6319, 6338, 6340, 6345,
+ 6341, 6351, 6353, 6356, 6358, 6360, 6362, 6364, 6369, 6371,
+ 6368, 6374, 6377, 6375, 6379, 6384, 6390, 6391, 6388, 6422,
+ 2488, 2473, 2445, 2432, 0, 2424, 0, 2422, 2416, 0,
+ 6432, 2387, 2373, 2372, 6440, 2369, 2368, 2363, 818, 900,
+
+ 1071, 6469, 6479, 1199, 1556, 0, 1600, 6412, 6401, 6459,
+ 6468, 6494, 6495, 6496, 6497, 6498, 6499, 6500, 6502, 6504,
+ 6505, 6506, 6508, 6509, 6510, 6511, 6514, 6512, 6513, 6515,
+ 6518, 6526, 6532, 6544, 6545, 6547, 6548, 6549, 6556, 6558,
+ 6559, 6560, 6561, 6562, 6564, 6563, 6565, 6567, 6571, 6577,
+ 6578, 6582, 6579, 6594, 6595, 6598, 6605, 6606, 6608, 6611,
+ 6613, 6616, 6614, 6617, 6625, 6621, 6626, 6627, 6628, 6634,
+ 6632, 6640, 6644, 6645, 6647, 6649, 6656, 6658, 6663, 6664,
+ 6667, 6671, 6675, 6676, 6679, 6682, 6684, 6686, 6699, 6691,
+ 6697, 6702, 6703, 6705, 6717, 6718, 6726, 6708, 6735, 6741,
+
+ 6736, 6746, 6753, 6754, 6740, 6752, 6748, 6764, 6762, 6763,
+ 6767, 6768, 6769, 6774, 6776, 6775, 6781, 6804, 2359, 2358,
+ 2342, 2332, 2327, 2324, 2305, 2281, 2267, 2263, 6817, 6827,
+ 2260, 2252, 0, 6837, 2241, 2213, 2177, 1683, 0, 1841,
+ 1852, 0, 6868, 2195, 1901, 1980, 6876, 6807, 6780, 6865,
+ 6873, 6891, 6892, 6893, 6894, 6895, 6899, 6901, 6902, 6903,
+ 6904, 6911, 6912, 6913, 6914, 6915, 6922, 6923, 6930, 6931,
+ 6932, 6934, 6935, 6942, 6941, 6944, 6945, 6949, 6951, 6952,
+ 6953, 6954, 6961, 6962, 6963, 6971, 6980, 6981, 6982, 6984,
+ 6985, 6990, 6991, 6993, 6995, 6997, 6999, 7002, 7003, 7011,
+
+ 7013, 7014, 7019, 7023, 7029, 7031, 7032, 7035, 7042, 7043,
+ 7045, 7047, 7049, 7051, 7064, 7065, 7066, 7073, 7069, 7075,
+ 9866, 2180, 2172, 2169, 0, 2141, 0, 2123, 2121, 0,
+ 2120, 2099, 0, 7114, 2096, 2085, 2072, 7122, 7132, 2070,
+ 2065, 2063, 2071, 2122, 2171, 2178, 2278, 7161, 7171, 2301,
+ 2319, 0, 7181, 7079, 7081, 7196, 7197, 7082, 7093, 7151,
+ 7198, 7203, 7199, 7204, 7206, 7208, 7209, 7217, 7218, 7219,
+ 7226, 7227, 7232, 7235, 7236, 7237, 7239, 7240, 7246, 7250,
+ 7247, 7255, 7248, 7259, 7263, 7266, 7267, 7277, 7268, 7283,
+ 7286, 7296, 7299, 7297, 7300, 7305, 2000, 1997, 1994, 1993,
+
+ 1991, 1990, 1989, 1984, 1983, 1943, 1942, 1940, 7340, 1939,
+ 1935, 0, 7350, 820, 1932, 1921, 1890, 2425, 0, 2509,
+ 2547, 0, 2585, 2695, 0, 7358, 1910, 2698, 2700, 7366,
+ 7381, 7307, 7315, 7309, 7380, 7316, 7381, 7383, 7398, 7318,
+ 7399, 7400, 7403, 7404, 7409, 7417, 7418, 7419, 7420, 7426,
+ 7430, 7433, 7438, 7436, 7439, 7440, 7441, 7449, 7453, 7467,
+ 7454, 7457, 1860, 1858, 1854, 0, 1847, 0, 1843, 1837,
+ 0, 1832, 1798, 0, 1768, 1754, 0, 9866, 1745, 1724,
+ 7505, 7515, 1722, 1716, 1694, 2702, 2752, 2755, 2756, 2801,
+ 2859, 2934, 7523, 2948, 3003, 0, 7533, 3047, 7469, 7470,
+
+ 7473, 7476, 7538, 7547, 7483, 7548, 7550, 7551, 7552, 7553,
+ 7554, 7555, 7556, 7560, 7565, 7562, 7566, 7569, 7568, 7570,
+ 1690, 1684, 1679, 1666, 1662, 1653, 1639, 1635, 1634, 1633,
+ 1624, 1616, 1603, 1545, 1515, 1514, 0, 7604, 1520, 1497,
+ 1496, 1467, 3004, 0, 3085, 3091, 0, 3093, 3095, 0,
+ 3154, 3215, 0, 1458, 3337, 3396, 7613, 7623, 7628, 7574,
+ 7637, 7638, 7571, 7640, 7639, 7641, 7642, 7643, 7646, 7647,
+ 7648, 1449, 1448, 1432, 0, 1412, 0, 1410, 1403, 0,
+ 1395, 1392, 0, 1389, 1373, 0, 1363, 1359, 0, 1313,
+ 1290, 7648, 7684, 1289, 1284, 1252, 3452, 3457, 3462, 3597,
+
+ 3698, 3704, 3996, 4027, 4116, 4121, 4125, 0, 7694, 1256,
+ 7649, 7650, 7683, 7651, 7684, 7710, 7712, 7711, 7713, 7714,
+ 1244, 1231, 1209, 1205, 0, 1176, 0, 1169, 0, 1165,
+ 0, 1162, 0, 1124, 0, 1119, 1117, 0, 7709, 1125,
+ 1111, 1102, 1089, 4126, 0, 4127, 4252, 0, 4351, 4378,
+ 0, 4824, 4873, 0, 4927, 4962, 0, 4994, 5032, 7754,
+ 7764, 7723, 7725, 7744, 7732, 7731, 7755, 7781, 7727, 1093,
+ 0, 9866, 0, 1088, 0, 1070, 0, 1055, 0, 1054,
+ 0, 1048, 0, 1038, 0, 7783, 1037, 1035, 1020, 987,
+ 5038, 969, 5039, 964, 5046, 943, 5087, 921, 5088, 917,
+
+ 5090, 5091, 0, 7791, 920, 7783, 7782, 7784, 7785, 7729,
+ 901, 0, 0, 0, 0, 0, 0, 0, 893, 0,
+ 9866, 869, 853, 826, 819, 5092, 797, 5138, 776, 5141,
+ 769, 5204, 756, 5628, 740, 5691, 738, 7812, 7811, 7812,
+ 7826, 7827, 0, 9866, 9866, 9866, 9866, 9866, 9866, 0,
+ 745, 661, 644, 591, 572, 563, 555, 517, 5808, 489,
+ 481, 7828, 7829, 7832, 7831, 9866, 452, 414, 328, 310,
+ 286, 272, 232, 141, 7839, 7840, 7842, 98, 7843, 7844,
+ 7846, 9866, 7903, 7916, 7927, 7934, 7946, 7953, 7959, 7965,
+ 7971, 7983, 7992, 7999, 8010, 8016, 8022, 8028, 8034, 8043,
+
+ 8050, 8057, 8063, 8075, 8081, 8087, 8093, 8099, 8105, 8111,
+ 8117, 8128, 8139, 8145, 8151, 8157, 8163, 8171, 8177, 8183,
+ 8189, 8195, 8201, 8212, 8218, 8224, 8230, 8236, 8242, 8248,
+ 8254, 8260, 8266, 8272, 8278, 8284, 8290, 8298, 8304, 8310,
+ 8316, 8322, 8328, 8334, 8340, 8346, 8352, 8358, 8364, 8370,
+ 8376, 8382, 8388, 8394, 8400, 8406, 8412, 8418, 8424, 8430,
+ 8436, 8442, 8448, 8454, 8460, 8466, 8472, 8478, 8484, 8490,
+ 8496, 8502, 8508, 8514, 8520, 8526, 8532, 8538, 8544, 8550,
+ 8556, 8562, 8568, 8574, 8580, 8586, 8592, 8598, 8604, 8610,
+ 8616, 8622, 8628, 8634, 8640, 8646, 8652, 8658, 8664, 8670,
+
+ 8676, 8682, 8688, 8694, 8700, 8706, 8712, 8718, 8724, 8730,
+ 8738, 8744, 8750, 8756, 8762, 8768, 8774, 8780, 8786, 8792,
+ 8798, 8804, 8810, 8816, 8822, 8828, 8834, 8840, 8846, 8852,
+ 8858, 8864, 8870, 8876, 8882, 8888, 8894, 8900, 8906, 8912,
+ 8918, 8924, 8930, 8936, 8942, 8948, 8954, 8962, 8968, 8974,
+ 8980, 8986, 8992, 8998, 9004, 9010, 9016, 9022, 9028, 9034,
+ 9040, 9046, 9052, 9058, 9064, 9070, 9076, 9082, 9088, 9094,
+ 9100, 9106, 9112, 9118, 9124, 9130, 9140, 9147, 9153, 9159,
+ 9165, 9171, 9177, 9183, 9189, 9195, 9201, 9207, 9213, 9219,
+ 9225, 9231, 9237, 9243, 9249, 9255, 9261, 9267, 9273, 9279,
+
+ 9285, 9291, 9297, 9303, 9309, 9315, 9325, 9332, 9338, 9344,
+ 9350, 9356, 9362, 9368, 9374, 9380, 9386, 9392, 9398, 9404,
+ 9410, 9416, 9422, 9428, 9434, 9440, 9446, 9452, 9458, 9464,
+ 9470, 9476, 9482, 9488, 9494, 9500, 9506, 9512, 9522, 9529,
+ 9535, 9541, 9547, 9553, 9559, 9565, 9571, 9577, 9583, 9589,
+ 9595, 9601, 9607, 9613, 9619, 9625, 9631, 9637, 9643, 9649,
+ 9655, 9661, 9667, 9673, 9679, 9685, 9691, 9697, 9703, 9709,
+ 9715, 9721, 9727, 9733, 9739, 9745, 9751, 9757, 9763, 9769,
+ 9775, 9781, 9787, 9793, 9799, 9805, 9811, 9817, 9823, 9829,
+ 9835, 9841, 9847, 9853
+
+ } ;
+
+static const flex_int16_t yy_def[2695] =
+ { 0,
+ 2382, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 8,
+ 1, 20, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 37, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2383, 2384, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2385, 2382, 2382, 129,
+ 129, 2382, 2382, 2382, 2382, 2382, 2382, 2385, 2385, 2386,
+ 2382, 2382, 2382, 138, 138, 138, 138, 138, 138, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2382, 2382, 2382, 2382, 2382,
+ 2387, 138, 2385, 2385, 2385, 161, 2385, 2385, 138, 138,
+ 138, 138, 138, 2385, 152, 177, 2385, 2385, 2385, 161,
+ 2385, 2385, 2385, 2385, 2385, 138, 182, 2385, 2385, 2385,
+
+ 161, 2385, 138, 2385, 2385, 138, 182, 138, 2385, 177,
+ 2385, 2385, 2385, 161, 2385, 2385, 138, 2385, 177, 2385,
+ 2385, 215, 2385, 2385, 138, 2385, 2385, 2385, 161, 2385,
+ 2385, 2385, 2385, 138, 182, 161, 2385, 138, 138, 182,
+ 138, 138, 177, 177, 2385, 2385, 2385, 161, 215, 2385,
+ 2385, 138, 182, 138, 182, 2385, 2385, 2385, 2385, 138,
+ 138, 2385, 177, 244, 2385, 2385, 161, 215, 138, 2385,
+ 161, 215, 138, 2385, 161, 138, 2385, 244, 2385, 244,
+ 2385, 161, 152, 2385, 2385, 161, 152, 215, 138, 138,
+ 2385, 177, 244, 2385, 161, 215, 138, 138, 182, 138,
+
+ 138, 2385, 152, 177, 2385, 2385, 161, 215, 138, 177,
+ 215, 2385, 138, 2385, 177, 2385, 161, 138, 2385, 152,
+ 2385, 244, 161, 215, 2385, 2382, 2382, 2382, 2383, 2382,
+ 2384, 2382, 2382, 2385, 2382, 2382, 2382, 2388, 2389, 2390,
+ 2382, 2382, 2382, 2382, 337, 2382, 2382, 2382, 2382, 2382,
+ 2382, 138, 2391, 2382, 2382, 352, 352, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 352,
+ 352, 352, 2385, 2385, 2385, 2385, 2385, 352, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2382, 2382, 2392, 2382,
+ 2387, 2382, 352, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 352, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 352, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 352, 2385, 2385, 352, 2385,
+ 352, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 352, 352, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 352, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 352, 2385, 2385, 2385, 2385, 352, 352, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2393, 2382, 2382, 2394, 2382, 2395, 2396, 2390, 646,
+ 2382, 2382, 2382, 2382, 644, 2382, 2397, 2397, 352, 2398,
+ 2399, 2382, 659, 659, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 659, 659, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2392, 2382, 659, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 659, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 659, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2400, 2382,
+ 2382, 2401, 2402, 2382, 2382, 2403, 2382, 2404, 2405, 2406,
+ 2382, 2401, 2382, 2382, 2407, 2408, 2408, 2385, 2409, 2410,
+ 2411, 2382, 982, 983, 2382, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2400, 2382, 2382, 972, 2382, 2412, 2403,
+ 2413, 2414, 2415, 2416, 2417, 2382, 2382, 2382, 2418, 2418,
+ 2419, 2418, 2382, 2420, 2421, 2422, 2382, 2382, 2423, 1268,
+ 1270, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2382, 2382, 2424, 2425, 2382, 2426, 2427, 2428, 2429, 2430,
+
+ 2382, 2382, 2382, 2382, 2431, 2432, 2382, 2433, 2434, 2435,
+ 2436, 2437, 2382, 2438, 2438, 2439, 2438, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2382,
+ 2382, 2440, 2441, 2442, 2443, 2444, 2445, 2382, 2446, 2447,
+ 2382, 2382, 2448, 2449, 2382, 2382, 2450, 2451, 2452, 2453,
+
+ 2454, 2382, 2382, 2382, 2455, 2456, 2382, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2382, 2457, 2458,
+ 2382, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2382, 2382,
+ 2382, 2466, 2467, 2382, 2468, 2469, 2470, 2471, 2472, 2382,
+ 2473, 2474, 2382, 2382, 2475, 2476, 2382, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2382, 2477, 2478, 2479, 2480, 2481, 2482, 2382, 2483, 2484,
+ 2382, 2485, 2486, 2382, 2382, 2487, 2488, 2382, 2382, 2382,
+ 2489, 2490, 2491, 2492, 2493, 2494, 2495, 2382, 2382, 2382,
+ 2496, 2497, 2382, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2498, 2499, 2382, 2500,
+
+ 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2382, 2382,
+ 2509, 2510, 2382, 2511, 2512, 2513, 2514, 2515, 2516, 2382,
+ 2517, 2518, 2382, 2519, 2520, 2382, 2382, 2521, 2522, 2382,
+ 2382, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2523, 2524, 2525, 2526, 2527, 2528, 2382, 2529,
+ 2530, 2382, 2531, 2532, 2382, 2533, 2534, 2382, 2535, 2536,
+ 2382, 2382, 2382, 2537, 2538, 2539, 2540, 2541, 2542, 2543,
+ 2544, 2545, 2382, 2382, 2546, 2547, 2382, 2548, 2385, 2385,
+
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
+ 2549, 2550, 2382, 2551, 2552, 2553, 2554, 2555, 2556, 2557,
+ 2558, 2559, 2560, 2561, 2382, 2562, 2563, 2382, 2382, 2564,
+ 2565, 2566, 2567, 2568, 2382, 2569, 2570, 2382, 2571, 2572,
+ 2382, 2573, 2574, 2382, 2575, 2576, 2382, 2382, 2577, 2577,
+ 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577, 2577,
+ 2577, 2578, 2579, 2580, 2581, 2582, 2583, 2382, 2584, 2585,
+ 2382, 2586, 2587, 2382, 2588, 2589, 2382, 2590, 2591, 2592,
+ 2593, 2382, 2382, 2382, 2594, 2595, 2596, 2597, 2598, 2599,
+
+ 2600, 2601, 2602, 2603, 2604, 2382, 2605, 2606, 2382, 2382,
+ 2607, 2607, 2607, 2607, 2607, 2607, 2607, 2607, 2607, 2607,
+ 2608, 2382, 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616,
+ 2617, 2618, 2619, 2620, 2621, 2382, 2622, 2623, 2382, 2382,
+ 2624, 2625, 2626, 2627, 2628, 2382, 2629, 2630, 2382, 2631,
+ 2632, 2382, 2633, 2634, 2382, 2635, 2636, 2637, 2638, 2382,
+ 2382, 2639, 2639, 2639, 2639, 2639, 2639, 2639, 2639, 2640,
+ 2641, 2382, 2642, 2382, 2643, 2382, 2644, 2382, 2645, 2382,
+ 2646, 2382, 2647, 2648, 2649, 2382, 2382, 2650, 2651, 2652,
+ 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662,
+
+ 2382, 2663, 2664, 2382, 2382, 2639, 2639, 2639, 2639, 2639,
+ 2382, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2382, 2672,
+ 2382, 2673, 2674, 2382, 2675, 2382, 2676, 2382, 2677, 2382,
+ 2678, 2382, 2679, 2382, 2680, 2681, 2682, 2382, 2639, 2639,
+ 2639, 2639, 2683, 2382, 2382, 2382, 2382, 2382, 2382, 2684,
+ 2382, 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2382, 2692,
+ 2382, 2639, 2639, 2639, 2639, 2382, 2693, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2694, 2639, 2639, 2639, 2382, 2639, 2639,
+ 2639, 0, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382
+
+ } ;
+
+static const flex_int16_t yy_nxt[9936] =
+ { 0,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
+ 122, 123, 124, 125, 126, 127, 128, 129, 130, 130,
+ 130, 130, 130, 130, 131, 132, 133, 134, 135, 136,
+ 137, 138, 138, 139, 139, 140, 141, 142, 143, 139,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
+ 139, 154, 155, 156, 157, 158, 159, 160, 161, 162,
+ 163, 164, 139, 165, 139, 139, 166, 167, 168, 169,
+ 172, 170, 172, 169, 171, 170, 173, 177, 171, 178,
+ 180, 347, 348, 174, 175, 176, 169, 176, 170, 194,
+ 231, 171, 192, 232, 193, 195, 276, 169, 320, 170,
+
+ 196, 197, 171, 169, 198, 170, 185, 220, 171, 169,
+ 199, 170, 321, 200, 171, 172, 201, 202, 203, 173,
+ 257, 219, 204, 209, 223, 194, 174, 175, 205, 220,
+ 176, 224, 258, 172, 259, 985, 177, 180, 178, 179,
+ 180, 181, 182, 183, 273, 172, 184, 185, 176, 192,
+ 186, 193, 973, 187, 188, 209, 189, 190, 265, 266,
+ 176, 220, 975, 194, 191, 169, 2382, 170, 206, 195,
+ 171, 207, 169, 217, 170, 218, 235, 171, 985, 219,
+ 169, 220, 170, 221, 370, 171, 176, 222, 169, 195,
+ 170, 236, 334, 171, 169, 2382, 170, 180, 169, 171,
+
+ 170, 252, 253, 171, 179, 180, 181, 182, 183, 192,
+ 227, 184, 185, 203, 194, 186, 233, 204, 187, 188,
+ 287, 189, 190, 205, 280, 225, 281, 313, 235, 191,
+ 169, 231, 170, 469, 232, 171, 226, 192, 227, 193,
+ 223, 228, 229, 236, 219, 333, 230, 224, 194, 234,
+ 235, 169, 488, 170, 254, 255, 171, 169, 219, 170,
+ 185, 169, 171, 170, 257, 236, 171, 256, 237, 985,
+ 335, 196, 197, 350, 351, 198, 258, 185, 259, 598,
+ 280, 199, 281, 599, 200, 345, 282, 201, 202, 206,
+ 235, 203, 207, 169, 208, 170, 209, 185, 171, 469,
+
+ 210, 277, 2382, 211, 212, 236, 213, 214, 215, 985,
+ 216, 206, 145, 203, 207, 148, 208, 515, 209, 169,
+ 363, 170, 210, 985, 171, 211, 212, 473, 213, 214,
+ 215, 2382, 216, 169, 276, 170, 139, 146, 171, 169,
+ 217, 170, 218, 152, 171, 220, 219, 985, 220, 157,
+ 221, 269, 160, 176, 222, 355, 195, 169, 257, 170,
+ 234, 235, 171, 495, 333, 985, 270, 271, 272, 219,
+ 258, 334, 259, 180, 663, 333, 236, 209, 334, 237,
+ 252, 253, 853, 220, 500, 192, 227, 274, 275, 203,
+ 235, 333, 233, 194, 169, 579, 170, 225, 219, 171,
+
+ 335, 169, 169, 170, 170, 236, 171, 171, 226, 192,
+ 227, 193, 469, 228, 229, 169, 335, 170, 230, 238,
+ 171, 239, 240, 241, 242, 481, 568, 590, 508, 334,
+ 243, 244, 245, 246, 489, 334, 247, 248, 249, 250,
+ 209, 251, 254, 255, 260, 482, 220, 261, 185, 262,
+ 257, 985, 573, 263, 264, 256, 334, 595, 265, 266,
+ 267, 268, 258, 257, 259, 169, 206, 170, 334, 787,
+ 171, 318, 574, 1271, 169, 258, 170, 259, 169, 171,
+ 170, 319, 169, 171, 170, 222, 1271, 171, 816, 985,
+ 677, 169, 169, 170, 170, 208, 171, 171, 185, 169,
+
+ 203, 170, 278, 220, 171, 209, 273, 279, 169, 677,
+ 170, 220, 169, 171, 170, 274, 235, 171, 985, 260,
+ 265, 266, 261, 269, 262, 333, 985, 277, 263, 264,
+ 257, 236, 333, 265, 266, 267, 268, 209, 270, 271,
+ 272, 172, 258, 220, 259, 192, 1512, 274, 275, 275,
+ 335, 288, 208, 195, 985, 185, 176, 335, 985, 278,
+ 220, 403, 172, 280, 279, 281, 169, 283, 170, 282,
+ 169, 171, 170, 284, 404, 171, 285, 286, 169, 363,
+ 170, 428, 525, 171, 289, 169, 473, 170, 290, 169,
+ 171, 170, 985, 169, 171, 170, 291, 309, 171, 370,
+
+ 985, 384, 222, 169, 385, 170, 310, 334, 171, 985,
+ 386, 203, 209, 538, 311, 387, 209, 312, 220, 169,
+ 172, 170, 220, 542, 171, 283, 274, 1517, 985, 333,
+ 334, 284, 287, 289, 285, 286, 280, 290, 281, 334,
+ 1517, 192, 333, 622, 334, 291, 206, 288, 252, 195,
+ 169, 222, 170, 209, 335, 171, 363, 292, 293, 294,
+ 309, 222, 529, 592, 295, 296, 169, 335, 170, 310,
+ 457, 171, 458, 314, 169, 459, 170, 311, 315, 171,
+ 312, 985, 221, 316, 169, 317, 170, 322, 192, 171,
+ 924, 364, 365, 323, 324, 677, 575, 325, 985, 366,
+
+ 367, 169, 368, 170, 369, 206, 171, 252, 222, 169,
+ 334, 170, 209, 624, 171, 334, 292, 293, 294, 1512,
+ 334, 320, 1706, 295, 296, 297, 235, 298, 299, 300,
+ 301, 985, 302, 303, 985, 321, 304, 169, 305, 170,
+ 306, 236, 171, 307, 308, 169, 314, 170, 206, 333,
+ 171, 315, 169, 318, 170, 221, 316, 171, 317, 169,
+ 169, 170, 170, 319, 171, 171, 458, 222, 460, 629,
+ 2289, 459, 364, 365, 335, 985, 334, 985, 313, 235,
+ 474, 367, 333, 368, 297, 369, 298, 299, 300, 301,
+ 333, 302, 303, 985, 236, 304, 641, 305, 334, 306,
+
+ 203, 235, 307, 308, 2382, 334, 985, 335, 505, 219,
+ 222, 322, 192, 985, 975, 335, 236, 323, 324, 393,
+ 394, 325, 336, 575, 337, 337, 337, 337, 337, 337,
+ 337, 337, 338, 395, 985, 1938, 333, 334, 339, 339,
+ 578, 340, 334, 1839, 333, 1506, 508, 339, 339, 339,
+ 341, 339, 339, 334, 342, 985, 985, 356, 357, 343,
+ 509, 335, 358, 985, 333, 344, 359, 975, 360, 335,
+ 340, 333, 361, 556, 977, 362, 448, 352, 352, 352,
+ 352, 352, 352, 352, 352, 338, 449, 977, 450, 335,
+ 985, 352, 352, 370, 2289, 371, 335, 372, 378, 333,
+
+ 352, 352, 352, 352, 352, 352, 373, 379, 600, 333,
+ 374, 375, 380, 376, 381, 382, 333, 377, 2238, 383,
+ 364, 493, 334, 333, 335, 1512, 2224, 334, 494, 367,
+ 388, 368, 389, 369, 335, 2260, 333, 985, 333, 396,
+ 397, 335, 390, 333, 398, 391, 399, 392, 335, 333,
+ 400, 401, 405, 402, 985, 425, 406, 333, 985, 426,
+ 407, 335, 427, 335, 333, 411, 408, 671, 335, 412,
+ 409, 410, 413, 414, 335, 333, 416, 417, 508, 415,
+ 985, 384, 335, 333, 385, 334, 418, 420, 613, 335,
+ 506, 421, 419, 429, 422, 387, 384, 430, 571, 519,
+
+ 335, 985, 333, 423, 424, 386, 985, 333, 335, 856,
+ 387, 431, 432, 433, 434, 688, 435, 463, 455, 371,
+ 436, 372, 437, 456, 985, 438, 439, 335, 333, 440,
+ 373, 442, 335, 443, 374, 375, 441, 376, 444, 445,
+ 333, 377, 333, 364, 493, 2324, 446, 451, 452, 453,
+ 333, 366, 367, 335, 368, 447, 369, 393, 394, 454,
+ 2289, 541, 2196, 2238, 333, 335, 333, 335, 464, 384,
+ 420, 395, 385, 2189, 421, 335, 465, 422, 386, 2186,
+ 2183, 425, 467, 387, 466, 426, 423, 424, 427, 335,
+ 468, 335, 640, 405, 667, 2180, 1842, 406, 334, 416,
+
+ 417, 407, 471, 334, 470, 356, 357, 408, 985, 418,
+ 358, 409, 410, 2177, 359, 419, 360, 463, 2224, 371,
+ 361, 372, 333, 362, 472, 475, 985, 2289, 333, 378,
+ 373, 333, 476, 333, 374, 375, 2196, 376, 379, 333,
+ 2192, 377, 2238, 380, 2137, 381, 382, 335, 477, 2189,
+ 478, 393, 394, 335, 370, 479, 335, 429, 335, 333,
+ 683, 487, 334, 420, 335, 395, 333, 421, 485, 334,
+ 422, 333, 505, 333, 333, 431, 432, 433, 425, 483,
+ 424, 333, 426, 484, 335, 486, 333, 2186, 490, 607,
+ 2183, 335, 416, 417, 2180, 485, 335, 334, 335, 335,
+
+ 333, 2177, 418, 513, 334, 425, 335, 430, 419, 426,
+ 425, 335, 427, 665, 426, 333, 333, 491, 626, 492,
+ 514, 431, 432, 433, 1269, 335, 451, 452, 453, 496,
+ 2272, 388, 333, 389, 2224, 551, 985, 333, 454, 500,
+ 335, 335, 333, 390, 499, 497, 391, 333, 392, 412,
+ 534, 333, 413, 414, 425, 552, 2125, 335, 426, 415,
+ 333, 427, 335, 388, 498, 389, 501, 335, 443, 2125,
+ 333, 2157, 335, 444, 445, 390, 335, 2243, 502, 333,
+ 392, 446, 333, 356, 504, 335, 333, 691, 358, 411,
+ 447, 630, 359, 412, 360, 335, 413, 414, 361, 393,
+
+ 394, 362, 507, 415, 335, 333, 503, 335, 333, 2196,
+ 333, 335, 420, 395, 2085, 2238, 421, 975, 425, 422,
+ 333, 333, 426, 636, 1262, 511, 510, 512, 423, 424,
+ 335, 333, 333, 335, 442, 335, 443, 1262, 2137, 518,
+ 666, 444, 445, 492, 333, 335, 335, 333, 516, 446,
+ 451, 452, 453, 517, 521, 417, 335, 335, 447, 425,
+ 393, 394, 454, 426, 418, 333, 522, 333, 334, 335,
+ 419, 625, 335, 334, 520, 553, 333, 523, 417, 448,
+ 668, 334, 333, 333, 2189, 554, 334, 418, 2077, 449,
+ 335, 450, 335, 419, 524, 420, 411, 333, 2186, 421,
+
+ 412, 335, 422, 413, 526, 527, 333, 335, 335, 430,
+ 415, 423, 424, 333, 2074, 484, 333, 2183, 384, 669,
+ 2071, 566, 335, 431, 432, 433, 411, 386, 2180, 333,
+ 530, 335, 387, 413, 414, 2068, 333, 2177, 335, 531,
+ 415, 335, 364, 533, 2382, 425, 416, 417, 448, 426,
+ 366, 367, 427, 368, 335, 369, 547, 2224, 532, 2382,
+ 450, 335, 419, 524, 333, 699, 333, 536, 357, 451,
+ 452, 453, 358, 2125, 2125, 2382, 359, 535, 360, 364,
+ 493, 454, 361, 333, 539, 362, 333, 537, 367, 335,
+ 368, 335, 369, 379, 333, 985, 540, 676, 380, 543,
+
+ 381, 382, 544, 412, 985, 383, 413, 414, 335, 333,
+ 334, 335, 670, 415, 545, 448, 420, 546, 334, 335,
+ 421, 2196, 2085, 422, 695, 449, 457, 450, 458, 555,
+ 548, 459, 423, 424, 335, 2081, 364, 365, 429, 2137,
+ 2012, 557, 549, 333, 366, 367, 550, 368, 333, 369,
+ 558, 364, 365, 333, 333, 333, 431, 432, 433, 366,
+ 367, 370, 368, 333, 369, 559, 342, 333, 335, 334,
+ 2189, 343, 637, 335, 560, 334, 334, 344, 335, 335,
+ 335, 1706, 425, 333, 403, 333, 426, 334, 335, 427,
+ 638, 333, 335, 985, 563, 561, 455, 404, 364, 564,
+
+ 689, 456, 333, 451, 562, 453, 565, 367, 335, 368,
+ 335, 369, 393, 394, 569, 454, 335, 334, 570, 333,
+ 429, 333, 364, 564, 430, 1847, 567, 335, 2077, 334,
+ 366, 367, 334, 368, 675, 369, 333, 985, 431, 432,
+ 572, 2186, 364, 365, 335, 684, 335, 333, 429, 2074,
+ 565, 367, 430, 368, 333, 369, 333, 701, 2183, 2071,
+ 2180, 335, 364, 365, 2068, 429, 431, 432, 576, 549,
+ 366, 580, 335, 368, 411, 369, 429, 334, 2177, 335,
+ 583, 335, 333, 431, 432, 433, 420, 2175, 582, 334,
+ 421, 2125, 334, 422, 431, 432, 433, 333, 411, 333,
+
+ 581, 334, 423, 424, 2122, 679, 593, 335, 1839, 2066,
+ 333, 680, 584, 334, 384, 2122, 334, 385, 681, 2142,
+ 985, 682, 335, 386, 335, 333, 333, 420, 387, 420,
+ 685, 585, 333, 421, 422, 335, 422, 411, 333, 333,
+ 334, 2085, 700, 423, 424, 423, 424, 1942, 588, 2137,
+ 335, 335, 334, 333, 429, 334, 596, 335, 589, 416,
+ 417, 601, 384, 335, 335, 385, 333, 333, 610, 418,
+ 2012, 386, 431, 432, 433, 594, 387, 425, 335, 2077,
+ 704, 426, 616, 686, 427, 333, 597, 417, 602, 356,
+ 357, 335, 335, 1933, 358, 333, 418, 608, 359, 705,
+
+ 360, 333, 419, 333, 361, 603, 379, 362, 364, 365,
+ 335, 380, 609, 381, 382, 732, 604, 367, 383, 368,
+ 335, 369, 605, 2074, 606, 333, 335, 687, 335, 713,
+ 393, 394, 623, 365, 611, 617, 614, 417, 333, 618,
+ 366, 367, 619, 368, 395, 369, 418, 364, 493, 333,
+ 335, 333, 615, 620, 621, 366, 367, 1930, 368, 627,
+ 369, 384, 2071, 335, 385, 333, 1512, 706, 1927, 388,
+ 386, 389, 2068, 632, 335, 387, 335, 1842, 985, 2125,
+ 333, 390, 633, 2122, 628, 2122, 392, 707, 425, 985,
+ 335, 333, 634, 333, 333, 522, 643, 643, 643, 643,
+
+ 643, 643, 643, 643, 336, 335, 644, 644, 644, 644,
+ 644, 644, 644, 644, 338, 333, 335, 333, 335, 335,
+ 645, 645, 722, 696, 690, 1948, 1706, 985, 692, 645,
+ 645, 645, 646, 645, 645, 693, 342, 697, 985, 694,
+ 335, 343, 335, 698, 333, 333, 2085, 344, 650, 650,
+ 650, 650, 650, 650, 650, 650, 338, 1942, 672, 673,
+ 2012, 710, 645, 645, 1833, 2077, 674, 1933, 2074, 335,
+ 335, 645, 645, 645, 645, 645, 645, 651, 651, 651,
+ 651, 651, 651, 651, 651, 652, 652, 652, 652, 652,
+ 652, 652, 652, 654, 654, 654, 654, 654, 654, 654,
+
+ 654, 458, 458, 458, 460, 1952, 459, 459, 1930, 2071,
+ 333, 333, 333, 333, 1927, 2068, 2066, 985, 2001, 1998,
+ 333, 333, 1925, 333, 333, 1998, 653, 656, 656, 656,
+ 656, 656, 656, 656, 656, 335, 335, 335, 335, 767,
+ 780, 657, 658, 333, 333, 335, 335, 727, 335, 335,
+ 657, 657, 657, 657, 657, 658, 659, 659, 659, 659,
+ 659, 659, 659, 659, 711, 714, 702, 724, 335, 335,
+ 659, 659, 703, 333, 333, 333, 333, 333, 333, 659,
+ 659, 659, 659, 659, 659, 712, 708, 720, 2017, 333,
+ 1942, 333, 709, 333, 333, 1698, 2019, 2012, 335, 335,
+
+ 335, 335, 335, 335, 715, 716, 717, 333, 985, 333,
+ 1833, 1829, 333, 728, 335, 723, 335, 725, 335, 335,
+ 718, 719, 721, 726, 1933, 733, 333, 333, 333, 333,
+ 333, 333, 335, 729, 335, 730, 731, 335, 333, 735,
+ 333, 736, 737, 333, 333, 1690, 1930, 1839, 1687, 734,
+ 738, 335, 335, 335, 335, 335, 335, 333, 739, 985,
+ 740, 741, 742, 335, 333, 335, 1927, 746, 335, 335,
+ 757, 744, 758, 747, 333, 750, 333, 743, 745, 333,
+ 749, 751, 335, 748, 760, 752, 333, 753, 333, 335,
+ 754, 755, 333, 756, 2001, 759, 2022, 1998, 333, 335,
+
+ 333, 335, 333, 1842, 335, 1998, 333, 762, 985, 333,
+ 1702, 335, 333, 335, 985, 985, 333, 335, 333, 768,
+ 333, 765, 761, 335, 763, 335, 333, 335, 769, 333,
+ 772, 335, 333, 764, 335, 766, 333, 335, 1942, 770,
+ 771, 335, 333, 335, 333, 335, 773, 774, 333, 333,
+ 778, 335, 779, 333, 335, 775, 776, 335, 781, 333,
+ 777, 335, 333, 782, 333, 333, 1698, 335, 333, 335,
+ 333, 333, 783, 335, 335, 788, 333, 1833, 335, 333,
+ 333, 790, 784, 333, 335, 1506, 791, 335, 1933, 335,
+ 335, 793, 1690, 335, 333, 335, 335, 789, 333, 794,
+
+ 333, 335, 792, 2025, 335, 335, 1930, 333, 335, 672,
+ 673, 333, 799, 795, 798, 985, 797, 796, 333, 335,
+ 692, 333, 333, 335, 802, 335, 1706, 800, 803, 333,
+ 1687, 694, 335, 333, 801, 333, 335, 804, 985, 333,
+ 805, 333, 806, 335, 1952, 724, 335, 335, 333, 1927,
+ 333, 809, 1925, 750, 335, 746, 985, 1823, 335, 751,
+ 335, 807, 333, 752, 335, 808, 335, 1820, 754, 755,
+ 333, 810, 746, 335, 811, 335, 333, 671, 812, 333,
+ 333, 814, 815, 1685, 1820, 813, 333, 335, 1837, 817,
+ 333, 672, 673, 1698, 1265, 335, 333, 1833, 1506, 674,
+
+ 333, 335, 1502, 333, 335, 335, 729, 1267, 730, 731,
+ 762, 335, 333, 705, 818, 335, 772, 1269, 822, 819,
+ 333, 335, 820, 823, 821, 335, 333, 763, 335, 985,
+ 333, 826, 827, 333, 333, 333, 333, 335, 824, 333,
+ 333, 1690, 828, 333, 333, 335, 333, 1255, 685, 1687,
+ 2019, 335, 333, 333, 829, 335, 728, 1823, 335, 335,
+ 335, 335, 985, 832, 335, 335, 830, 746, 335, 335,
+ 1820, 335, 333, 812, 831, 696, 749, 335, 335, 833,
+ 835, 333, 834, 836, 333, 333, 832, 708, 838, 837,
+ 746, 333, 333, 709, 333, 698, 333, 335, 1820, 333,
+
+ 735, 333, 679, 1491, 839, 878, 335, 985, 680, 335,
+ 335, 333, 333, 333, 841, 681, 335, 335, 682, 335,
+ 735, 335, 840, 845, 335, 333, 335, 843, 333, 846,
+ 842, 333, 733, 749, 1839, 847, 335, 335, 335, 844,
+ 763, 852, 732, 778, 851, 848, 985, 855, 333, 1698,
+ 335, 333, 1265, 335, 671, 333, 335, 1695, 814, 849,
+ 333, 333, 333, 333, 333, 1506, 861, 975, 333, 672,
+ 673, 857, 2022, 335, 850, 333, 335, 854, 1690, 333,
+ 335, 1255, 859, 1687, 985, 335, 335, 335, 335, 335,
+ 829, 333, 333, 335, 333, 729, 868, 730, 731, 869,
+
+ 335, 333, 333, 860, 335, 870, 864, 865, 862, 863,
+ 1842, 737, 866, 1685, 1497, 333, 335, 335, 333, 335,
+ 871, 333, 985, 750, 333, 872, 335, 335, 333, 751,
+ 333, 333, 1253, 752, 1510, 753, 874, 880, 867, 755,
+ 335, 333, 873, 335, 875, 333, 335, 876, 333, 335,
+ 781, 333, 333, 335, 1265, 335, 335, 882, 333, 879,
+ 696, 661, 333, 333, 881, 1506, 335, 1501, 333, 1255,
+ 335, 672, 673, 335, 884, 333, 335, 335, 333, 883,
+ 698, 333, 894, 335, 885, 1497, 886, 335, 335, 333,
+ 709, 747, 726, 335, 891, 887, 888, 730, 731, 333,
+
+ 335, 889, 890, 335, 960, 333, 335, 896, 333, 770,
+ 893, 892, 762, 333, 335, 895, 333, 333, 333, 333,
+ 2025, 333, 333, 1952, 335, 2096, 897, 2144, 985, 892,
+ 335, 333, 985, 335, 1265, 985, 898, 985, 335, 985,
+ 333, 335, 335, 335, 335, 750, 335, 335, 675, 902,
+ 734, 751, 903, 899, 900, 752, 335, 753, 333, 734,
+ 901, 755, 762, 911, 904, 335, 333, 905, 912, 333,
+ 333, 715, 716, 717, 661, 975, 333, 2019, 653, 763,
+ 2147, 2022, 1255, 335, 333, 333, 333, 718, 719, 985,
+ 750, 335, 985, 985, 335, 335, 751, 908, 716, 717,
+
+ 752, 335, 753, 906, 333, 754, 755, 897, 333, 335,
+ 335, 335, 907, 718, 719, 1253, 333, 762, 913, 333,
+ 909, 915, 333, 333, 333, 333, 2150, 333, 333, 335,
+ 333, 918, 735, 335, 763, 920, 914, 963, 985, 648,
+ 916, 335, 333, 333, 335, 1132, 772, 335, 335, 335,
+ 335, 917, 335, 335, 928, 335, 1125, 333, 333, 934,
+ 922, 333, 764, 672, 673, 921, 1095, 335, 335, 923,
+ 926, 674, 333, 927, 715, 716, 717, 727, 735, 333,
+ 929, 931, 335, 335, 2025, 333, 335, 333, 333, 333,
+ 718, 719, 762, 930, 333, 933, 985, 335, 932, 333,
+
+ 786, 333, 998, 333, 335, 333, 935, 333, 333, 763,
+ 335, 997, 335, 335, 335, 986, 981, 333, 333, 335,
+ 333, 936, 333, 942, 335, 938, 335, 937, 335, 939,
+ 335, 333, 335, 335, 940, 661, 705, 948, 975, 941,
+ 947, 943, 335, 335, 333, 335, 945, 335, 944, 333,
+ 748, 333, 333, 333, 972, 946, 335, 949, 333, 2153,
+ 744, 333, 333, 952, 950, 963, 951, 745, 925, 335,
+ 333, 985, 919, 1952, 335, 910, 335, 335, 335, 953,
+ 956, 877, 858, 335, 958, 985, 335, 335, 729, 825,
+ 730, 731, 462, 957, 988, 335, 954, 960, 955, 961,
+
+ 961, 961, 961, 961, 961, 961, 961, 336, 786, 962,
+ 962, 962, 962, 962, 962, 962, 962, 963, 967, 967,
+ 967, 333, 333, 964, 964, 688, 678, 677, 2096, 2144,
+ 967, 967, 964, 964, 964, 965, 964, 964, 333, 342,
+ 985, 985, 969, 333, 343, 664, 335, 335, 333, 663,
+ 344, 966, 966, 966, 966, 966, 966, 966, 966, 963,
+ 662, 2382, 2030, 335, 987, 964, 964, 661, 335, 993,
+ 994, 1269, 1706, 335, 964, 964, 964, 964, 964, 964,
+ 990, 989, 655, 985, 985, 967, 651, 651, 651, 651,
+ 651, 651, 651, 651, 652, 652, 652, 652, 652, 652,
+
+ 652, 652, 654, 654, 654, 654, 654, 654, 654, 654,
+ 2019, 333, 338, 648, 333, 642, 2147, 332, 2022, 330,
+ 2150, 343, 985, 327, 333, 333, 326, 344, 985, 971,
+ 985, 333, 985, 333, 333, 344, 335, 971, 973, 335,
+ 974, 974, 974, 974, 974, 974, 974, 974, 975, 335,
+ 335, 1002, 639, 995, 976, 976, 335, 999, 335, 335,
+ 996, 635, 333, 976, 976, 976, 976, 976, 976, 978,
+ 978, 978, 978, 978, 978, 978, 978, 963, 1004, 2025,
+ 631, 1003, 333, 978, 978, 333, 333, 335, 612, 333,
+ 333, 985, 978, 978, 978, 978, 978, 978, 982, 982,
+
+ 982, 982, 982, 982, 982, 982, 333, 335, 334, 333,
+ 335, 335, 983, 984, 335, 335, 1000, 591, 985, 1005,
+ 333, 983, 983, 983, 983, 983, 984, 991, 333, 333,
+ 992, 335, 333, 1001, 335, 333, 333, 333, 333, 333,
+ 2153, 333, 1007, 587, 333, 335, 586, 1006, 577, 333,
+ 333, 333, 985, 335, 335, 333, 333, 335, 333, 534,
+ 335, 335, 335, 335, 335, 1009, 335, 1008, 1011, 335,
+ 1012, 1010, 528, 1015, 335, 335, 335, 1017, 1016, 333,
+ 335, 335, 333, 335, 1014, 333, 333, 1013, 1020, 333,
+ 333, 333, 333, 1018, 334, 333, 333, 1021, 500, 1019,
+
+ 480, 469, 333, 333, 335, 462, 333, 335, 363, 333,
+ 335, 335, 333, 333, 335, 335, 335, 335, 333, 1023,
+ 335, 335, 333, 1032, 1024, 1022, 1027, 335, 335, 1025,
+ 1026, 335, 1030, 1028, 335, 1031, 1034, 335, 335, 1029,
+ 1033, 333, 1035, 335, 333, 1036, 333, 335, 333, 1037,
+ 1038, 333, 333, 333, 333, 1040, 354, 349, 333, 333,
+ 333, 1039, 2096, 333, 333, 346, 335, 333, 333, 335,
+ 1041, 335, 333, 335, 985, 333, 335, 335, 335, 335,
+ 332, 1042, 1045, 335, 335, 335, 1046, 1043, 335, 335,
+ 1049, 1048, 335, 335, 333, 330, 1044, 335, 1052, 1047,
+
+ 335, 333, 333, 333, 1053, 1050, 1051, 1056, 1055, 1054,
+ 333, 333, 333, 328, 1057, 333, 333, 333, 327, 335,
+ 1058, 2208, 333, 1059, 326, 333, 335, 335, 335, 333,
+ 333, 1060, 333, 985, 333, 335, 335, 335, 1061, 333,
+ 335, 335, 335, 1065, 333, 1062, 1069, 335, 1068, 1066,
+ 335, 333, 1063, 1067, 335, 335, 333, 335, 1064, 335,
+ 333, 1072, 1070, 1071, 335, 333, 1073, 2382, 222, 335,
+ 333, 333, 1075, 333, 1074, 333, 335, 2245, 333, 333,
+ 333, 335, 2144, 333, 333, 335, 333, 2248, 1076, 985,
+ 335, 333, 1077, 1078, 985, 335, 335, 333, 335, 985,
+
+ 335, 333, 1079, 335, 335, 335, 333, 1080, 335, 335,
+ 222, 335, 1082, 333, 1083, 333, 335, 1086, 333, 1081,
+ 1085, 333, 335, 1084, 1088, 222, 335, 333, 333, 1087,
+ 275, 335, 333, 333, 1090, 1091, 333, 1089, 335, 333,
+ 335, 333, 333, 335, 333, 2382, 335, 333, 2382, 333,
+ 1094, 2382, 335, 335, 2382, 1092, 333, 335, 335, 1093,
+ 333, 335, 333, 333, 335, 333, 335, 335, 2382, 335,
+ 1096, 333, 335, 1101, 335, 333, 1097, 1103, 1099, 1098,
+ 333, 335, 1105, 1100, 333, 335, 1102, 335, 335, 1104,
+ 335, 333, 333, 1108, 333, 333, 335, 1109, 2382, 333,
+
+ 335, 2382, 1106, 1010, 1107, 335, 1113, 1110, 1112, 335,
+ 333, 1111, 333, 333, 2382, 333, 335, 335, 2382, 335,
+ 335, 333, 2147, 1115, 335, 333, 1114, 333, 1119, 2382,
+ 1127, 333, 1117, 333, 985, 335, 333, 335, 335, 1116,
+ 335, 333, 1118, 1120, 1123, 333, 335, 1121, 1124, 333,
+ 335, 333, 335, 333, 1126, 333, 335, 2382, 335, 1122,
+ 1128, 335, 333, 2382, 333, 2382, 335, 333, 1130, 333,
+ 335, 333, 333, 333, 335, 333, 335, 333, 335, 333,
+ 335, 333, 1129, 2382, 333, 333, 1134, 335, 1136, 335,
+ 1131, 2382, 335, 1133, 335, 1135, 335, 335, 335, 333,
+
+ 335, 1138, 335, 1139, 335, 333, 335, 2382, 1137, 335,
+ 335, 333, 333, 2382, 1145, 333, 1146, 1140, 333, 1143,
+ 333, 333, 1141, 2251, 335, 1144, 1142, 2382, 333, 2150,
+ 335, 333, 1147, 2382, 333, 985, 335, 335, 1149, 333,
+ 335, 985, 333, 335, 333, 335, 335, 333, 1148, 2382,
+ 333, 1151, 1077, 335, 1150, 1153, 335, 1154, 1152, 335,
+ 1155, 333, 2382, 333, 335, 333, 1157, 335, 333, 335,
+ 333, 333, 335, 1160, 1156, 335, 333, 333, 333, 333,
+ 333, 1158, 333, 333, 1159, 2382, 335, 1161, 335, 2382,
+ 335, 2382, 333, 335, 333, 335, 335, 333, 1162, 1166,
+
+ 2382, 335, 335, 335, 335, 335, 333, 335, 335, 1163,
+ 1164, 1169, 1165, 2382, 1168, 1167, 1170, 335, 1171, 335,
+ 333, 333, 335, 1175, 333, 1173, 333, 1176, 1174, 333,
+ 1172, 335, 333, 333, 333, 333, 333, 333, 1177, 333,
+ 333, 333, 2382, 2382, 333, 335, 335, 2382, 333, 335,
+ 2382, 335, 2382, 333, 335, 333, 333, 335, 335, 335,
+ 335, 335, 335, 333, 335, 335, 335, 1178, 1045, 335,
+ 1180, 1179, 1186, 335, 1184, 1183, 1181, 1188, 335, 333,
+ 335, 335, 333, 333, 333, 333, 1182, 1185, 335, 1187,
+ 333, 333, 333, 2382, 1189, 1190, 1192, 333, 2382, 1191,
+
+ 333, 333, 333, 333, 335, 333, 333, 335, 335, 335,
+ 335, 333, 1193, 1194, 2382, 335, 335, 335, 1196, 333,
+ 333, 1195, 335, 1197, 2382, 335, 335, 335, 335, 1199,
+ 335, 335, 1055, 333, 1202, 333, 335, 333, 1200, 1198,
+ 1206, 333, 2382, 1031, 335, 335, 1052, 333, 333, 1203,
+ 333, 1201, 333, 333, 333, 333, 1211, 333, 335, 2382,
+ 335, 333, 335, 333, 333, 2382, 335, 1204, 2382, 2382,
+ 333, 333, 335, 335, 333, 335, 333, 335, 335, 335,
+ 335, 1205, 335, 333, 1212, 2382, 335, 333, 335, 335,
+ 1213, 1210, 333, 1209, 1208, 335, 335, 333, 1207, 335,
+
+ 1219, 335, 333, 1221, 1214, 1220, 333, 1218, 335, 333,
+ 1216, 333, 335, 333, 1215, 1222, 333, 335, 1217, 333,
+ 333, 2254, 335, 333, 333, 1223, 2382, 335, 333, 2382,
+ 333, 335, 2382, 985, 335, 1224, 335, 1052, 335, 1225,
+ 333, 335, 333, 333, 335, 335, 1227, 2382, 335, 335,
+ 333, 1229, 2153, 335, 1226, 335, 333, 1232, 1228, 333,
+ 333, 1230, 333, 333, 985, 335, 2382, 335, 335, 2382,
+ 333, 963, 1231, 2382, 1234, 335, 2382, 1233, 1081, 2382,
+ 1235, 335, 2382, 975, 335, 335, 2382, 335, 335, 1236,
+ 1507, 1237, 1239, 342, 1238, 335, 1242, 2382, 343, 1243,
+
+ 2382, 1241, 2382, 1507, 344, 2382, 1240, 1245, 1245, 1245,
+ 1245, 1245, 1245, 1245, 1245, 960, 963, 1246, 1246, 1246,
+ 1246, 1246, 1246, 1246, 1246, 1250, 1250, 1250, 1250, 1250,
+ 1250, 1250, 1250, 963, 1248, 967, 967, 967, 342, 963,
+ 333, 2257, 333, 343, 2382, 2382, 2096, 967, 967, 344,
+ 2208, 2245, 2144, 985, 1256, 2382, 963, 1248, 985, 969,
+ 2382, 342, 985, 985, 985, 335, 343, 335, 333, 333,
+ 1257, 1273, 344, 1258, 1258, 1258, 1258, 1258, 1258, 1258,
+ 1258, 2382, 1276, 1270, 1270, 1270, 1270, 1270, 1270, 1270,
+ 1270, 333, 333, 335, 335, 2382, 333, 333, 333, 2382,
+
+ 333, 333, 967, 973, 1274, 1259, 1259, 1259, 1259, 1259,
+ 1259, 1259, 1259, 975, 2382, 963, 335, 335, 2382, 1260,
+ 1260, 335, 335, 335, 1277, 335, 335, 333, 1260, 1260,
+ 1260, 1260, 1260, 1260, 1267, 1279, 1268, 1268, 1268, 1268,
+ 1268, 1268, 1268, 1268, 1269, 1272, 1275, 333, 1278, 333,
+ 1270, 1270, 335, 333, 333, 333, 985, 333, 333, 1270,
+ 1270, 1270, 1270, 1270, 1270, 333, 2382, 333, 333, 333,
+ 2382, 333, 335, 333, 335, 1280, 2382, 2248, 335, 335,
+ 335, 333, 335, 335, 333, 333, 1286, 333, 333, 985,
+ 335, 1282, 335, 335, 335, 1281, 335, 333, 335, 2382,
+
+ 1284, 1283, 1288, 1285, 333, 1293, 335, 2382, 1287, 335,
+ 335, 333, 335, 335, 1289, 333, 333, 333, 333, 1290,
+ 2382, 2382, 335, 333, 1296, 333, 333, 1291, 333, 335,
+ 1292, 333, 1294, 333, 333, 1295, 335, 333, 2382, 333,
+ 335, 335, 335, 335, 2382, 1299, 1297, 333, 335, 333,
+ 335, 335, 333, 335, 2382, 1302, 335, 1300, 335, 335,
+ 342, 1298, 335, 1305, 335, 343, 333, 333, 333, 1301,
+ 333, 344, 335, 333, 335, 333, 2147, 335, 1303, 1304,
+ 333, 2382, 333, 333, 333, 1307, 333, 2382, 985, 333,
+ 1306, 335, 335, 335, 333, 335, 1308, 333, 335, 1312,
+
+ 335, 1309, 333, 2251, 333, 335, 1313, 335, 335, 335,
+ 2382, 335, 1310, 1311, 335, 985, 333, 1315, 333, 335,
+ 2382, 333, 335, 333, 333, 2382, 333, 335, 1314, 335,
+ 333, 333, 333, 333, 1318, 1316, 333, 1320, 333, 333,
+ 1317, 335, 2382, 335, 2382, 1321, 335, 1322, 335, 335,
+ 1319, 335, 333, 1325, 1323, 335, 335, 335, 335, 2382,
+ 1328, 335, 333, 335, 335, 333, 2382, 1324, 333, 1326,
+ 1331, 1334, 333, 2382, 333, 333, 1327, 335, 333, 333,
+ 2382, 333, 2382, 2382, 1332, 1329, 1330, 335, 333, 333,
+ 335, 1335, 333, 335, 333, 333, 2382, 335, 1333, 335,
+
+ 335, 333, 1337, 335, 335, 1339, 335, 1341, 1336, 2382,
+ 333, 2382, 333, 335, 335, 1344, 1340, 335, 1338, 335,
+ 335, 1345, 333, 333, 1347, 333, 335, 1342, 333, 2382,
+ 333, 2382, 333, 333, 1343, 335, 1346, 335, 2382, 333,
+ 333, 333, 1348, 333, 1349, 333, 333, 335, 335, 2382,
+ 335, 333, 2382, 335, 1351, 335, 1350, 335, 335, 333,
+ 2382, 333, 333, 1353, 335, 335, 335, 333, 335, 333,
+ 335, 335, 333, 963, 1352, 1354, 335, 1357, 333, 1358,
+ 2382, 333, 1356, 333, 335, 1355, 335, 335, 333, 1359,
+ 333, 333, 335, 1360, 335, 1362, 1363, 335, 333, 333,
+
+ 333, 333, 333, 335, 333, 1361, 335, 333, 335, 2382,
+ 333, 1364, 333, 335, 2382, 335, 335, 2382, 1365, 2382,
+ 1366, 1369, 2382, 335, 335, 335, 335, 335, 333, 335,
+ 1367, 1372, 335, 333, 1374, 335, 1368, 335, 333, 1370,
+ 333, 333, 1376, 333, 1377, 1373, 1371, 1375, 333, 333,
+ 333, 333, 333, 335, 333, 1379, 333, 333, 335, 333,
+ 333, 1378, 1341, 335, 333, 335, 335, 333, 335, 333,
+ 963, 1381, 1393, 335, 335, 335, 335, 335, 2382, 335,
+ 1384, 335, 335, 1388, 335, 335, 1380, 1382, 1385, 335,
+ 1390, 1383, 335, 333, 335, 1389, 333, 333, 333, 333,
+
+ 333, 2382, 1386, 1387, 1392, 1391, 333, 333, 333, 333,
+ 333, 2382, 333, 333, 2382, 333, 2382, 333, 335, 2382,
+ 2382, 335, 335, 335, 335, 335, 1394, 333, 333, 333,
+ 2382, 335, 335, 335, 335, 335, 1397, 335, 335, 1398,
+ 335, 1396, 335, 333, 1395, 1400, 1401, 1399, 333, 333,
+ 2382, 333, 335, 335, 335, 1295, 333, 333, 1402, 333,
+ 333, 1403, 333, 1404, 333, 2382, 333, 2382, 335, 1405,
+ 333, 333, 2382, 335, 335, 1406, 335, 333, 2382, 333,
+ 2382, 335, 335, 2382, 335, 335, 1407, 335, 1408, 335,
+ 1409, 335, 1411, 333, 333, 335, 335, 1410, 333, 333,
+
+ 333, 333, 335, 1414, 335, 1412, 333, 1413, 1415, 1420,
+ 333, 2382, 1421, 1422, 1423, 1424, 2382, 2382, 335, 335,
+ 333, 1416, 2382, 335, 335, 335, 335, 2382, 333, 333,
+ 333, 335, 333, 333, 333, 335, 1417, 333, 333, 333,
+ 1418, 1428, 1342, 1354, 333, 335, 1419, 1426, 333, 2150,
+ 333, 2382, 1425, 335, 335, 335, 1427, 335, 335, 335,
+ 333, 985, 335, 335, 335, 2382, 333, 333, 1429, 335,
+ 333, 1430, 2382, 335, 1432, 335, 1431, 1438, 2382, 333,
+ 333, 1433, 1434, 333, 1435, 335, 1436, 333, 2382, 1440,
+ 1437, 335, 335, 333, 333, 335, 1446, 1439, 2254, 333,
+
+ 333, 2382, 2382, 1442, 335, 335, 333, 2382, 335, 333,
+ 985, 333, 335, 1441, 333, 333, 1444, 1453, 335, 335,
+ 333, 333, 2382, 1445, 335, 335, 1443, 1448, 333, 333,
+ 333, 335, 1449, 1447, 335, 1342, 335, 2382, 333, 335,
+ 335, 333, 2382, 333, 333, 335, 335, 1450, 333, 333,
+ 2382, 1454, 2153, 335, 335, 335, 1451, 333, 333, 333,
+ 1452, 1455, 1456, 335, 985, 2382, 335, 1459, 335, 335,
+ 333, 1458, 2382, 335, 335, 333, 1457, 1462, 1464, 2382,
+ 333, 333, 335, 335, 335, 333, 1460, 2257, 333, 1467,
+ 1461, 1468, 2382, 333, 1469, 335, 1470, 1463, 333, 985,
+
+ 335, 333, 1471, 333, 1466, 335, 335, 333, 333, 2382,
+ 335, 333, 1465, 335, 2382, 333, 333, 1473, 335, 2208,
+ 333, 333, 1474, 335, 1472, 333, 335, 333, 335, 333,
+ 2382, 985, 335, 335, 1478, 333, 335, 1475, 1476, 1479,
+ 335, 335, 333, 2382, 1482, 335, 335, 333, 1477, 333,
+ 335, 1480, 335, 333, 335, 1481, 1483, 2303, 1485, 333,
+ 335, 333, 1488, 2245, 2248, 2382, 2382, 335, 1487, 985,
+ 2382, 2251, 335, 1484, 335, 985, 985, 1303, 335, 1486,
+ 2382, 2382, 1520, 985, 335, 1354, 335, 1490, 1491, 1489,
+ 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1492, 1250, 1250,
+
+ 1250, 1250, 1250, 1250, 1250, 1250, 967, 967, 967, 967,
+ 967, 967, 2254, 2257, 2382, 2208, 2303, 2245, 967, 967,
+ 2382, 967, 967, 2382, 985, 985, 333, 985, 985, 985,
+ 1494, 2382, 1502, 1494, 1503, 1503, 1503, 1503, 1503, 1503,
+ 1503, 1503, 1513, 1513, 1513, 1513, 1513, 1513, 1513, 1513,
+ 2382, 335, 1515, 1515, 1515, 1515, 1515, 1515, 1515, 1515,
+ 2382, 2382, 2382, 2248, 333, 333, 2251, 333, 2382, 2382,
+ 333, 333, 333, 967, 1518, 985, 967, 1267, 985, 1514,
+ 1514, 1514, 1514, 1514, 1514, 1514, 1514, 1269, 333, 335,
+ 335, 333, 335, 1515, 1515, 335, 335, 335, 333, 985,
+
+ 1523, 333, 1515, 1515, 1515, 1515, 1515, 1515, 1519, 1521,
+ 333, 333, 1522, 335, 1524, 333, 335, 333, 333, 333,
+ 333, 1525, 2382, 335, 1526, 333, 335, 333, 2382, 2254,
+ 2382, 1527, 333, 333, 1528, 335, 335, 333, 333, 333,
+ 335, 985, 335, 335, 335, 335, 2382, 1529, 1531, 333,
+ 335, 333, 335, 1535, 1530, 1532, 1538, 335, 335, 1533,
+ 2382, 333, 335, 335, 335, 333, 1534, 333, 333, 2382,
+ 333, 1540, 333, 1536, 335, 333, 335, 1545, 1537, 333,
+ 333, 333, 1542, 1541, 2382, 1539, 335, 333, 333, 2382,
+ 335, 333, 335, 335, 1543, 335, 333, 335, 333, 333,
+
+ 335, 333, 1544, 2382, 335, 335, 335, 1550, 333, 1547,
+ 1546, 333, 335, 335, 1548, 333, 335, 333, 2382, 2382,
+ 1549, 335, 333, 335, 335, 333, 335, 333, 1551, 333,
+ 333, 1552, 1554, 335, 333, 333, 335, 333, 333, 2382,
+ 335, 333, 335, 1555, 1553, 2382, 1558, 335, 1559, 333,
+ 335, 1556, 335, 2382, 335, 335, 1563, 333, 333, 335,
+ 335, 1557, 335, 335, 1560, 333, 335, 333, 1561, 333,
+ 1562, 333, 333, 1564, 335, 1565, 333, 2382, 1569, 1566,
+ 2382, 1567, 335, 335, 333, 333, 1570, 333, 333, 333,
+ 335, 1568, 335, 333, 335, 333, 335, 335, 333, 333,
+
+ 333, 335, 1573, 333, 1572, 1575, 1571, 1576, 333, 335,
+ 335, 2382, 335, 335, 335, 333, 333, 333, 335, 1574,
+ 335, 1580, 2382, 335, 335, 335, 2382, 1577, 335, 333,
+ 333, 333, 333, 335, 333, 1578, 1579, 333, 333, 1581,
+ 335, 335, 335, 1584, 2382, 333, 333, 1582, 333, 333,
+ 1583, 1587, 2382, 333, 335, 335, 335, 335, 333, 335,
+ 333, 2382, 335, 335, 1585, 1590, 2382, 1589, 333, 1586,
+ 335, 335, 333, 335, 335, 333, 2382, 1588, 335, 2382,
+ 333, 333, 333, 335, 333, 335, 1591, 333, 333, 333,
+ 1600, 1525, 333, 335, 333, 2382, 1592, 335, 333, 333,
+
+ 335, 1593, 333, 333, 1595, 335, 335, 335, 1535, 335,
+ 333, 333, 335, 335, 335, 333, 2382, 335, 1601, 335,
+ 1594, 333, 333, 335, 335, 1607, 1596, 335, 335, 1597,
+ 1598, 333, 1599, 1601, 333, 335, 335, 333, 333, 1605,
+ 335, 1602, 1603, 333, 1606, 1604, 335, 335, 333, 2382,
+ 333, 333, 2382, 333, 2382, 2382, 335, 1608, 333, 335,
+ 2382, 333, 335, 335, 333, 2382, 333, 333, 335, 2382,
+ 333, 333, 333, 335, 1611, 335, 335, 1609, 335, 1610,
+ 1614, 333, 333, 335, 333, 1612, 335, 333, 333, 335,
+ 1616, 335, 335, 333, 1615, 335, 335, 335, 333, 1617,
+
+ 1613, 333, 1618, 2382, 2382, 333, 335, 335, 2382, 335,
+ 333, 333, 335, 335, 333, 333, 333, 1620, 335, 333,
+ 1619, 1525, 2382, 335, 333, 333, 335, 333, 1623, 1621,
+ 335, 1622, 333, 1624, 333, 335, 335, 333, 333, 335,
+ 335, 335, 333, 333, 335, 333, 333, 1625, 333, 335,
+ 335, 333, 335, 2257, 2382, 333, 333, 335, 1627, 335,
+ 1626, 333, 335, 335, 2382, 985, 333, 335, 335, 1628,
+ 335, 335, 333, 335, 333, 1629, 335, 1635, 1634, 1632,
+ 335, 335, 333, 1630, 333, 333, 335, 2382, 333, 1631,
+ 1633, 335, 2382, 333, 1580, 333, 2382, 335, 1636, 335,
+
+ 333, 333, 1637, 1638, 333, 333, 333, 335, 333, 335,
+ 335, 333, 1639, 335, 2382, 1640, 2303, 1580, 335, 333,
+ 335, 1641, 1643, 2382, 333, 335, 335, 1642, 985, 335,
+ 335, 335, 333, 335, 333, 333, 335, 333, 333, 1648,
+ 333, 1650, 2382, 1644, 335, 2382, 333, 333, 1645, 335,
+ 2382, 1646, 1653, 1647, 333, 333, 1616, 335, 333, 335,
+ 335, 333, 335, 335, 1651, 335, 333, 1649, 1652, 2382,
+ 1656, 335, 335, 333, 333, 1657, 1659, 2382, 333, 335,
+ 335, 333, 1654, 335, 1655, 333, 335, 333, 333, 333,
+ 1663, 335, 333, 2382, 1658, 333, 2382, 2382, 335, 335,
+
+ 2382, 2382, 1660, 335, 1661, 333, 335, 1662, 1664, 333,
+ 335, 333, 335, 335, 335, 333, 333, 335, 1670, 1672,
+ 335, 1666, 1665, 333, 333, 1668, 1667, 1674, 333, 333,
+ 335, 333, 1669, 2303, 335, 1671, 335, 333, 2382, 2382,
+ 335, 335, 1673, 2382, 2382, 985, 2382, 2382, 335, 335,
+ 2382, 2382, 2382, 335, 335, 2382, 335, 2382, 1675, 2382,
+ 2382, 2382, 335, 1676, 1679, 2382, 2382, 1677, 1680, 1680,
+ 1680, 1680, 1680, 1680, 1680, 1680, 1491, 1678, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 967, 967, 967, 967,
+ 967, 967, 2382, 2382, 2382, 2382, 2382, 2382, 967, 967,
+
+ 2382, 967, 967, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 1494, 2382, 2382, 1494, 1691, 1691, 1691, 1691, 1691, 1691,
+ 1691, 1691, 1502, 333, 1692, 1692, 1692, 1692, 1692, 1692,
+ 1692, 1692, 1702, 2382, 1703, 1703, 1703, 1703, 1703, 1703,
+ 1703, 1703, 333, 1269, 333, 333, 333, 333, 335, 333,
+ 1707, 333, 333, 967, 333, 985, 967, 333, 333, 333,
+ 333, 333, 2382, 1707, 333, 333, 2382, 335, 2382, 335,
+ 335, 335, 335, 333, 335, 1708, 335, 335, 333, 335,
+ 333, 2382, 335, 335, 335, 335, 335, 1713, 1710, 335,
+ 335, 1716, 333, 1709, 333, 1712, 1711, 333, 335, 333,
+
+ 2382, 333, 333, 335, 333, 335, 1715, 333, 333, 1717,
+ 1719, 1714, 1718, 333, 333, 333, 2382, 335, 333, 335,
+ 333, 2382, 335, 2382, 335, 1720, 335, 335, 333, 335,
+ 333, 2382, 335, 335, 333, 1722, 333, 333, 335, 335,
+ 335, 1724, 333, 335, 2382, 335, 1725, 1721, 1726, 1727,
+ 2382, 2382, 333, 335, 333, 335, 1723, 2382, 333, 335,
+ 333, 335, 335, 333, 333, 333, 2382, 335, 2382, 1729,
+ 2382, 333, 333, 2382, 333, 1731, 1728, 335, 333, 335,
+ 2382, 333, 1730, 335, 333, 335, 333, 333, 335, 335,
+ 335, 1732, 333, 1734, 333, 1735, 335, 335, 1737, 335,
+
+ 333, 333, 333, 335, 1733, 1738, 335, 1739, 2382, 335,
+ 333, 335, 335, 1736, 333, 333, 333, 335, 1743, 335,
+ 333, 1740, 333, 333, 333, 335, 335, 335, 1742, 1741,
+ 333, 2382, 2382, 1744, 333, 335, 333, 2382, 333, 335,
+ 335, 335, 2382, 333, 333, 335, 2382, 335, 335, 335,
+ 333, 333, 333, 2382, 1747, 335, 1748, 1745, 333, 335,
+ 333, 335, 1746, 335, 333, 333, 333, 1751, 335, 335,
+ 333, 1750, 333, 2382, 1749, 335, 335, 335, 1752, 333,
+ 1753, 1755, 333, 335, 333, 335, 333, 1754, 2382, 335,
+ 335, 335, 333, 1759, 333, 335, 2382, 335, 1761, 1756,
+
+ 2382, 2382, 333, 1758, 335, 1757, 2382, 335, 333, 335,
+ 333, 335, 1760, 1762, 333, 1763, 333, 335, 333, 335,
+ 2382, 1764, 333, 2382, 333, 1769, 1767, 335, 333, 333,
+ 333, 1765, 333, 335, 2382, 335, 1768, 1766, 333, 335,
+ 333, 335, 1770, 335, 333, 1771, 333, 335, 1773, 335,
+ 333, 333, 2382, 335, 335, 335, 333, 335, 333, 1774,
+ 333, 1772, 333, 335, 2382, 335, 2382, 333, 333, 335,
+ 1775, 335, 2382, 1776, 333, 335, 335, 1777, 333, 333,
+ 333, 335, 333, 335, 1779, 335, 333, 335, 333, 1780,
+ 333, 1781, 335, 335, 333, 333, 1782, 1778, 333, 335,
+
+ 1783, 333, 2382, 335, 335, 335, 333, 335, 333, 1785,
+ 333, 335, 333, 335, 333, 335, 333, 2382, 333, 335,
+ 335, 333, 333, 335, 1784, 1793, 335, 1786, 333, 2382,
+ 333, 335, 333, 335, 1789, 335, 2382, 335, 2382, 335,
+ 2382, 335, 1787, 335, 1788, 333, 335, 335, 1794, 333,
+ 1792, 333, 333, 335, 1790, 335, 333, 335, 1791, 1801,
+ 1796, 1798, 333, 1795, 333, 1797, 2382, 333, 2382, 333,
+ 335, 333, 2382, 333, 335, 333, 335, 335, 1799, 333,
+ 333, 335, 333, 2382, 2382, 333, 333, 335, 333, 335,
+ 333, 1800, 335, 1802, 335, 333, 335, 1805, 335, 333,
+
+ 335, 333, 333, 2382, 335, 335, 1803, 335, 1804, 1809,
+ 335, 335, 333, 335, 2382, 335, 2382, 1806, 2382, 2382,
+ 335, 2382, 1807, 333, 335, 1808, 335, 335, 1810, 1811,
+ 1813, 1817, 1814, 1812, 1816, 2382, 2382, 335, 1815, 1818,
+ 1818, 1818, 1818, 1818, 1818, 1818, 1818, 1829, 335, 1830,
+ 1830, 1830, 1830, 1830, 1830, 1830, 1830, 1834, 1834, 1834,
+ 1834, 1834, 1834, 1834, 1834, 2382, 2382, 2382, 2382, 1848,
+ 333, 1261, 1261, 2382, 2382, 2382, 2382, 2382, 2382, 333,
+ 1261, 1261, 1261, 1261, 1261, 1261, 1843, 1843, 1843, 1843,
+ 1843, 1843, 1843, 1843, 1702, 335, 1844, 1844, 1844, 1844,
+
+ 1844, 1844, 1844, 1844, 335, 333, 333, 333, 333, 333,
+ 333, 333, 1850, 333, 2382, 333, 333, 333, 1849, 333,
+ 333, 333, 333, 333, 333, 333, 333, 2382, 2382, 333,
+ 335, 335, 335, 335, 335, 335, 335, 333, 335, 1851,
+ 335, 335, 335, 333, 335, 335, 335, 335, 335, 335,
+ 335, 335, 1858, 1853, 335, 333, 333, 1852, 333, 333,
+ 333, 1854, 335, 1856, 1855, 1857, 2382, 333, 335, 333,
+ 333, 333, 333, 333, 333, 333, 333, 2382, 333, 2382,
+ 335, 335, 333, 335, 335, 335, 2382, 2382, 333, 333,
+ 333, 1859, 335, 333, 335, 335, 335, 335, 335, 335,
+
+ 335, 335, 1860, 335, 1863, 333, 333, 335, 2382, 333,
+ 2382, 1861, 1865, 335, 335, 335, 333, 333, 335, 333,
+ 1864, 2382, 333, 1862, 333, 333, 1867, 333, 333, 2382,
+ 335, 335, 333, 1868, 335, 1866, 333, 333, 333, 333,
+ 2382, 335, 335, 333, 335, 333, 1871, 335, 1869, 335,
+ 335, 333, 335, 335, 1870, 333, 333, 335, 333, 1872,
+ 333, 335, 335, 335, 335, 1875, 1877, 333, 335, 333,
+ 335, 1873, 1879, 1874, 333, 333, 335, 1876, 333, 1880,
+ 335, 335, 333, 335, 1878, 335, 333, 333, 1882, 1884,
+ 333, 1881, 335, 333, 335, 333, 2382, 333, 2382, 335,
+
+ 335, 2382, 333, 335, 1883, 2382, 1886, 335, 333, 1885,
+ 333, 335, 335, 333, 333, 335, 333, 2382, 335, 333,
+ 335, 1887, 335, 1888, 2382, 2382, 1893, 335, 333, 333,
+ 1890, 1900, 1901, 335, 1889, 335, 2382, 333, 335, 335,
+ 1891, 335, 1894, 1897, 335, 1898, 333, 333, 1892, 1899,
+ 1895, 333, 333, 335, 335, 1905, 2382, 333, 1903, 333,
+ 1907, 1896, 335, 333, 333, 333, 1902, 1908, 1909, 2382,
+ 2382, 335, 335, 333, 333, 333, 335, 335, 333, 333,
+ 333, 1904, 335, 1913, 335, 333, 333, 333, 335, 335,
+ 335, 333, 333, 1911, 1910, 1906, 2382, 2382, 335, 335,
+
+ 335, 1912, 2382, 335, 335, 335, 1915, 2382, 2382, 2382,
+ 335, 335, 335, 2382, 1917, 1916, 335, 335, 333, 1914,
+ 1918, 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921, 2382,
+ 2382, 2382, 1919, 1920, 1934, 1934, 1934, 1934, 1934, 1934,
+ 1934, 1934, 1829, 335, 1935, 1935, 1935, 1935, 1935, 1935,
+ 1935, 1935, 1938, 1954, 1939, 1939, 1939, 1939, 1939, 1939,
+ 1939, 1939, 1506, 2382, 2382, 2382, 2382, 2382, 1505, 1505,
+ 2382, 2382, 2382, 2382, 2382, 2382, 333, 1505, 1505, 1505,
+ 1505, 1505, 1505, 1948, 333, 1949, 1949, 1949, 1949, 1949,
+ 1949, 1949, 1949, 1953, 1953, 1953, 1953, 1953, 1953, 1953,
+
+ 1953, 335, 333, 333, 333, 333, 333, 1516, 1516, 335,
+ 333, 2382, 333, 333, 333, 333, 1516, 1516, 1516, 1516,
+ 1516, 1516, 333, 333, 333, 333, 333, 335, 335, 335,
+ 335, 335, 2382, 333, 333, 335, 1955, 335, 335, 335,
+ 335, 333, 333, 333, 1957, 333, 333, 335, 335, 335,
+ 335, 335, 333, 333, 1956, 333, 333, 1958, 335, 335,
+ 333, 2382, 333, 333, 333, 333, 335, 335, 335, 2382,
+ 335, 335, 333, 333, 333, 2382, 1959, 335, 335, 1961,
+ 335, 335, 333, 1960, 1964, 335, 1962, 335, 335, 335,
+ 335, 333, 333, 333, 1963, 333, 333, 335, 335, 335,
+
+ 1967, 333, 333, 1966, 333, 1968, 333, 335, 333, 1965,
+ 333, 2382, 1975, 333, 333, 1969, 335, 335, 335, 2382,
+ 335, 335, 333, 2382, 333, 333, 335, 335, 1972, 335,
+ 333, 335, 1970, 335, 333, 335, 1971, 1974, 335, 335,
+ 333, 1977, 333, 333, 1978, 1979, 333, 335, 1973, 335,
+ 335, 1980, 1976, 333, 333, 335, 333, 2382, 333, 335,
+ 333, 1990, 333, 2382, 2382, 335, 2382, 335, 335, 2382,
+ 2382, 335, 1981, 1982, 2382, 333, 333, 333, 335, 335,
+ 333, 335, 1987, 335, 333, 335, 333, 335, 1983, 1984,
+ 333, 1985, 333, 333, 1986, 1991, 2382, 2382, 2382, 1989,
+
+ 335, 335, 335, 1988, 333, 335, 2382, 2382, 2382, 335,
+ 2382, 335, 2382, 2382, 2382, 335, 2382, 335, 335, 1993,
+ 2382, 1995, 1992, 2032, 2382, 2382, 1994, 2382, 2382, 335,
+ 1996, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2009, 2013,
+ 2013, 2013, 2013, 2013, 2013, 2013, 2013, 1938, 2382, 2014,
+ 2014, 2014, 2014, 2014, 2014, 2014, 2014, 1506, 2382, 2382,
+ 2382, 2382, 333, 1693, 1693, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 1693, 1693, 1693, 1693, 1693, 1693, 2026, 2026,
+ 2026, 2026, 2026, 2026, 2026, 2026, 1948, 335, 2027, 2027,
+ 2027, 2027, 2027, 2027, 2027, 2027, 2030, 2382, 2031, 2031,
+
+ 2031, 2031, 2031, 2031, 2031, 2031, 1706, 333, 333, 333,
+ 333, 2382, 1705, 1705, 333, 333, 2382, 333, 985, 333,
+ 333, 1705, 1705, 1705, 1705, 1705, 1705, 2382, 333, 333,
+ 333, 2382, 335, 335, 335, 335, 2033, 333, 333, 335,
+ 335, 2034, 335, 333, 335, 335, 333, 333, 333, 2037,
+ 333, 333, 2035, 335, 335, 335, 2036, 333, 333, 333,
+ 2038, 333, 335, 335, 2382, 2382, 333, 2039, 335, 2048,
+ 333, 335, 335, 335, 333, 335, 335, 333, 333, 333,
+ 2382, 2382, 335, 335, 335, 2040, 335, 2041, 333, 2043,
+ 2044, 335, 2046, 2045, 333, 335, 2382, 333, 2382, 335,
+
+ 2382, 2042, 335, 335, 335, 2047, 2049, 333, 333, 2053,
+ 333, 333, 2050, 335, 2382, 2382, 333, 2382, 333, 335,
+ 333, 2051, 335, 2056, 2052, 2057, 333, 333, 2055, 333,
+ 2054, 2382, 335, 335, 2382, 335, 335, 2382, 2382, 2058,
+ 2059, 335, 2060, 335, 2382, 335, 2382, 2382, 2062, 2382,
+ 2382, 335, 335, 2382, 335, 2382, 2061, 2078, 2078, 2078,
+ 2078, 2078, 2078, 2078, 2078, 2081, 2099, 2082, 2082, 2082,
+ 2082, 2082, 2082, 2082, 2082, 2093, 2093, 2093, 2093, 2093,
+ 2093, 2093, 2093, 2097, 2097, 2097, 2097, 2097, 2097, 2097,
+ 2097, 333, 333, 2382, 333, 985, 2030, 2382, 2098, 2098,
+
+ 2098, 2098, 2098, 2098, 2098, 2098, 1706, 2382, 2382, 333,
+ 333, 333, 1845, 1845, 333, 333, 335, 335, 985, 335,
+ 333, 1845, 1845, 1845, 1845, 1845, 1845, 2102, 333, 333,
+ 333, 333, 2101, 2100, 335, 335, 335, 333, 2382, 335,
+ 335, 333, 2382, 2104, 333, 335, 2382, 333, 2382, 333,
+ 333, 333, 333, 335, 335, 335, 335, 2103, 2382, 2108,
+ 333, 2382, 335, 2105, 333, 333, 335, 2106, 333, 335,
+ 2382, 2107, 335, 2109, 335, 335, 335, 335, 333, 2113,
+ 333, 333, 2115, 2110, 333, 335, 2111, 333, 2112, 335,
+ 335, 2382, 2114, 335, 333, 2116, 2382, 2382, 2382, 2382,
+
+ 2382, 2382, 2382, 335, 2382, 335, 335, 2382, 2117, 335,
+ 2382, 2118, 335, 2382, 2382, 2382, 2120, 2159, 2382, 335,
+ 2382, 2119, 2138, 2138, 2138, 2138, 2138, 2138, 2138, 2138,
+ 2081, 2382, 2139, 2139, 2139, 2139, 2139, 2139, 2139, 2139,
+ 2154, 2154, 2154, 2154, 2154, 2154, 2154, 2154, 2157, 333,
+ 2158, 2158, 2158, 2158, 2158, 2158, 2158, 2158, 333, 333,
+ 985, 333, 333, 333, 333, 333, 333, 333, 2382, 2164,
+ 2165, 333, 2382, 333, 335, 2382, 333, 333, 2382, 333,
+ 333, 333, 333, 335, 335, 333, 335, 335, 335, 335,
+ 335, 335, 335, 2162, 2382, 2382, 335, 2160, 335, 2382,
+
+ 2161, 335, 335, 2166, 335, 335, 335, 335, 2382, 2382,
+ 335, 2382, 2163, 2382, 2168, 2167, 2169, 2382, 2212, 2192,
+ 2170, 2193, 2193, 2193, 2193, 2193, 2193, 2193, 2193, 2171,
+ 2209, 2209, 2209, 2209, 2209, 2209, 2209, 2209, 2157, 333,
+ 2210, 2210, 2210, 2210, 2210, 2210, 2210, 2210, 333, 333,
+ 333, 333, 333, 333, 333, 2217, 2382, 333, 333, 333,
+ 333, 333, 333, 2382, 335, 2239, 2239, 2239, 2239, 2239,
+ 2239, 2239, 2239, 335, 335, 335, 335, 335, 335, 335,
+ 2211, 2215, 335, 335, 335, 335, 335, 335, 2214, 2382,
+ 2382, 2382, 2220, 2262, 333, 333, 2213, 2216, 2218, 2192,
+
+ 2219, 2240, 2240, 2240, 2240, 2240, 2240, 2240, 2240, 2260,
+ 2382, 2261, 2261, 2261, 2261, 2261, 2261, 2261, 2261, 335,
+ 335, 333, 333, 333, 333, 333, 2286, 2286, 2286, 2286,
+ 2286, 2286, 2286, 2286, 333, 2264, 333, 2382, 333, 2382,
+ 333, 2263, 333, 333, 2382, 2382, 335, 335, 335, 335,
+ 335, 2382, 2382, 2382, 2382, 333, 2382, 2269, 2382, 335,
+ 2382, 335, 2267, 335, 2268, 335, 333, 335, 335, 2265,
+ 2266, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2260,
+ 335, 2305, 2305, 2305, 2305, 2305, 2305, 2305, 2305, 2307,
+ 2308, 335, 333, 333, 333, 333, 333, 2382, 2306, 2309,
+
+ 2321, 2321, 2321, 2321, 2321, 2321, 2321, 2321, 2338, 2338,
+ 2338, 2338, 2338, 2338, 2338, 2338, 2382, 335, 335, 335,
+ 335, 335, 333, 333, 2310, 2339, 2340, 2382, 985, 2361,
+ 2361, 2361, 2361, 2361, 2361, 2361, 2361, 333, 333, 333,
+ 333, 2341, 333, 333, 2342, 2382, 2382, 335, 335, 985,
+ 333, 333, 2363, 333, 333, 333, 2382, 333, 2382, 2382,
+ 2382, 2362, 335, 335, 335, 335, 2382, 335, 335, 2382,
+ 2364, 2365, 2377, 2382, 2382, 335, 335, 2382, 335, 335,
+ 335, 2376, 335, 2382, 2382, 2382, 2375, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2380, 2382, 2382, 2382, 2379, 2382,
+
+ 2382, 2382, 2381, 329, 329, 329, 329, 329, 329, 329,
+ 329, 329, 329, 329, 329, 329, 331, 331, 331, 331,
+ 331, 331, 331, 331, 331, 331, 331, 331, 331, 334,
+ 334, 334, 334, 334, 2382, 334, 334, 2382, 334, 334,
+ 353, 353, 353, 2382, 2382, 353, 461, 461, 461, 461,
+ 461, 461, 461, 461, 461, 461, 461, 461, 461, 647,
+ 647, 647, 2382, 2382, 647, 645, 645, 645, 2382, 2382,
+ 645, 649, 2382, 649, 2382, 2382, 649, 660, 660, 660,
+ 2382, 2382, 660, 785, 785, 785, 785, 785, 785, 785,
+ 785, 785, 785, 785, 785, 785, 959, 2382, 2382, 2382,
+
+ 959, 959, 2382, 959, 959, 964, 964, 964, 2382, 2382,
+ 964, 968, 2382, 968, 2382, 2382, 968, 968, 968, 2382,
+ 2382, 968, 970, 2382, 970, 2382, 2382, 970, 976, 976,
+ 976, 2382, 2382, 976, 979, 979, 979, 2382, 2382, 979,
+ 980, 980, 980, 2382, 2382, 980, 1244, 1244, 1244, 1244,
+ 2382, 1244, 1244, 2382, 1244, 1244, 1247, 1247, 2382, 2382,
+ 2382, 1247, 1247, 1249, 1249, 1249, 2382, 2382, 1249, 1250,
+ 1250, 2382, 2382, 2382, 2382, 1250, 1251, 2382, 1251, 2382,
+ 2382, 1251, 1251, 1251, 2382, 2382, 1251, 1252, 1252, 1252,
+ 2382, 2382, 1252, 1254, 1254, 1254, 2382, 2382, 1254, 1261,
+
+ 2382, 1261, 2382, 2382, 1261, 1260, 1260, 1260, 2382, 2382,
+ 1260, 1263, 1263, 1263, 2382, 2382, 1263, 1264, 1264, 1264,
+ 2382, 2382, 1264, 1266, 2382, 1266, 2382, 1266, 1266, 1493,
+ 2382, 1493, 2382, 2382, 1493, 1493, 1493, 2382, 2382, 1493,
+ 1495, 2382, 1495, 2382, 2382, 1495, 1495, 1495, 2382, 2382,
+ 1495, 1496, 1496, 1496, 2382, 2382, 1496, 1498, 2382, 1498,
+ 2382, 2382, 1498, 1499, 1499, 1499, 2382, 2382, 1499, 1500,
+ 2382, 1500, 2382, 2382, 1500, 1504, 2382, 1504, 1504, 1504,
+ 2382, 2382, 1504, 1505, 1505, 1505, 2382, 2382, 1505, 1508,
+ 1508, 1508, 2382, 2382, 1508, 1509, 1509, 1509, 2382, 2382,
+
+ 1509, 1511, 1511, 1511, 2382, 1511, 1511, 1516, 2382, 1516,
+ 2382, 2382, 1516, 1251, 2382, 1251, 2382, 2382, 1251, 1251,
+ 1251, 2382, 2382, 1251, 1682, 1682, 1682, 2382, 2382, 1682,
+ 1683, 1683, 1683, 2382, 2382, 1683, 1684, 1684, 1684, 2382,
+ 2382, 1684, 1686, 1686, 1686, 2382, 2382, 1686, 1688, 1688,
+ 1688, 2382, 2382, 1688, 1689, 1689, 1689, 2382, 2382, 1689,
+ 1693, 1693, 1693, 2382, 2382, 1693, 1694, 2382, 1694, 2382,
+ 2382, 1694, 1696, 1696, 1696, 2382, 2382, 1696, 1697, 1697,
+ 1697, 2382, 2382, 1697, 1699, 2382, 1699, 2382, 1699, 1699,
+ 1700, 1700, 1700, 2382, 1700, 1700, 1701, 2382, 1701, 2382,
+
+ 2382, 1701, 1704, 2382, 1704, 1704, 1704, 2382, 1704, 1704,
+ 1705, 1705, 1705, 2382, 1705, 1705, 1819, 1819, 1819, 2382,
+ 2382, 1819, 1821, 1821, 1821, 2382, 2382, 1821, 1822, 1822,
+ 1822, 2382, 2382, 1822, 1824, 2382, 1824, 2382, 2382, 1824,
+ 1825, 1825, 1825, 2382, 2382, 1825, 1826, 2382, 1826, 2382,
+ 2382, 1826, 1827, 1827, 1827, 2382, 2382, 1827, 1828, 2382,
+ 1828, 2382, 2382, 1828, 1831, 1831, 1831, 2382, 2382, 1831,
+ 1832, 1832, 1832, 2382, 2382, 1832, 1835, 1835, 1835, 2382,
+ 2382, 1835, 1836, 1836, 1836, 2382, 2382, 1836, 1838, 1838,
+ 1838, 2382, 1838, 1838, 1840, 1840, 1840, 2382, 1840, 1840,
+
+ 1841, 1841, 1841, 2382, 1841, 1841, 1845, 1845, 1845, 2382,
+ 1845, 1845, 1846, 2382, 1846, 2382, 2382, 1846, 1683, 1683,
+ 1683, 2382, 2382, 1683, 1922, 1922, 1922, 2382, 2382, 1922,
+ 1923, 1923, 1923, 2382, 2382, 1923, 1924, 1924, 1924, 2382,
+ 2382, 1924, 1926, 1926, 1926, 2382, 2382, 1926, 1928, 1928,
+ 1928, 2382, 2382, 1928, 1929, 1929, 1929, 2382, 2382, 1929,
+ 1931, 1931, 1931, 2382, 2382, 1931, 1932, 1932, 1932, 2382,
+ 2382, 1932, 1936, 1936, 1936, 2382, 2382, 1936, 1937, 2382,
+ 1937, 2382, 2382, 1937, 1940, 1940, 1940, 2382, 2382, 1940,
+ 1941, 1941, 1941, 2382, 2382, 1941, 1943, 2382, 1943, 2382,
+
+ 1943, 1943, 1944, 1944, 1944, 2382, 1944, 1944, 1945, 2382,
+ 1945, 2382, 2382, 1945, 1946, 1946, 1946, 2382, 1946, 1946,
+ 1947, 2382, 1947, 2382, 2382, 1947, 1950, 1950, 1950, 2382,
+ 1950, 1950, 1951, 1951, 1951, 2382, 1951, 1951, 1997, 1997,
+ 1997, 2382, 2382, 1997, 1999, 1999, 1999, 2382, 2382, 1999,
+ 2000, 2000, 2000, 2382, 2382, 2000, 2002, 2382, 2002, 2382,
+ 2382, 2002, 2003, 2003, 2003, 2382, 2382, 2003, 2004, 2382,
+ 2004, 2382, 2382, 2004, 2005, 2005, 2005, 2382, 2382, 2005,
+ 2006, 2382, 2006, 2382, 2382, 2006, 2007, 2007, 2007, 2382,
+ 2382, 2007, 2008, 2382, 2008, 2382, 2382, 2008, 2010, 2010,
+
+ 2010, 2382, 2382, 2010, 2011, 2011, 2011, 2382, 2382, 2011,
+ 2015, 2015, 2015, 2382, 2382, 2015, 2016, 2016, 2016, 2382,
+ 2382, 2016, 2018, 2018, 2018, 2382, 2018, 2018, 2020, 2020,
+ 2020, 2382, 2020, 2020, 2021, 2021, 2021, 2382, 2021, 2021,
+ 2023, 2023, 2023, 2382, 2023, 2023, 2024, 2024, 2024, 2382,
+ 2024, 2024, 2028, 2028, 2028, 2382, 2028, 2028, 2029, 2382,
+ 2029, 2382, 2382, 2029, 1923, 1923, 1923, 2382, 2382, 1923,
+ 2063, 2063, 2063, 2382, 2382, 2063, 2064, 2064, 2064, 2382,
+ 2382, 2064, 2065, 2065, 2065, 2382, 2382, 2065, 2067, 2067,
+ 2067, 2382, 2382, 2067, 2069, 2069, 2069, 2382, 2382, 2069,
+
+ 2070, 2070, 2070, 2382, 2382, 2070, 2072, 2072, 2072, 2382,
+ 2382, 2072, 2073, 2073, 2073, 2382, 2382, 2073, 2075, 2075,
+ 2075, 2382, 2382, 2075, 2076, 2076, 2076, 2382, 2382, 2076,
+ 2079, 2079, 2079, 2382, 2382, 2079, 2080, 2382, 2080, 2382,
+ 2382, 2080, 1831, 2382, 1831, 1831, 1831, 2382, 2382, 1831,
+ 2083, 2083, 2083, 2382, 2382, 2083, 2084, 2084, 2084, 2382,
+ 2382, 2084, 2086, 2382, 2086, 2382, 2086, 2086, 2087, 2087,
+ 2087, 2382, 2087, 2087, 2088, 2382, 2088, 2382, 2382, 2088,
+ 2089, 2089, 2089, 2382, 2089, 2089, 2090, 2382, 2090, 2382,
+ 2382, 2090, 2091, 2091, 2091, 2382, 2091, 2091, 2092, 2382,
+
+ 2092, 2382, 2382, 2092, 2094, 2094, 2094, 2382, 2094, 2094,
+ 2095, 2095, 2095, 2382, 2095, 2095, 2121, 2121, 2121, 2382,
+ 2382, 2121, 2123, 2123, 2123, 2382, 2382, 2123, 2124, 2124,
+ 2124, 2382, 2382, 2124, 2126, 2382, 2126, 2382, 2382, 2126,
+ 2127, 2127, 2127, 2382, 2382, 2127, 2128, 2382, 2128, 2382,
+ 2382, 2128, 2129, 2129, 2129, 2382, 2382, 2129, 2130, 2382,
+ 2130, 2382, 2382, 2130, 2131, 2131, 2131, 2382, 2382, 2131,
+ 2132, 2382, 2132, 2382, 2382, 2132, 2133, 2133, 2133, 2382,
+ 2382, 2133, 2134, 2382, 2134, 2382, 2382, 2134, 2135, 2135,
+ 2135, 2382, 2382, 2135, 2136, 2136, 2136, 2382, 2382, 2136,
+
+ 2140, 2140, 2140, 2382, 2382, 2140, 2141, 2141, 2141, 2382,
+ 2382, 2141, 2143, 2143, 2143, 2382, 2143, 2143, 2145, 2145,
+ 2145, 2382, 2145, 2145, 2146, 2146, 2146, 2382, 2146, 2146,
+ 2148, 2148, 2148, 2382, 2148, 2148, 2149, 2149, 2149, 2382,
+ 2149, 2149, 2151, 2151, 2151, 2382, 2151, 2151, 2152, 2152,
+ 2152, 2382, 2152, 2152, 2155, 2155, 2155, 2382, 2155, 2155,
+ 2156, 2382, 2156, 2382, 2382, 2156, 1950, 2382, 1950, 1950,
+ 1950, 2382, 1950, 1950, 2064, 2064, 2064, 2382, 2382, 2064,
+ 2172, 2172, 2172, 2382, 2382, 2172, 2173, 2173, 2173, 2382,
+ 2382, 2173, 2174, 2174, 2174, 2382, 2382, 2174, 2176, 2176,
+
+ 2176, 2382, 2382, 2176, 2178, 2178, 2178, 2382, 2382, 2178,
+ 2179, 2179, 2179, 2382, 2382, 2179, 2181, 2181, 2181, 2382,
+ 2382, 2181, 2182, 2182, 2182, 2382, 2382, 2182, 2184, 2184,
+ 2184, 2382, 2382, 2184, 2185, 2185, 2185, 2382, 2382, 2185,
+ 2187, 2187, 2187, 2382, 2382, 2187, 2188, 2188, 2188, 2382,
+ 2382, 2188, 2190, 2190, 2190, 2382, 2382, 2190, 2191, 2382,
+ 2191, 2382, 2382, 2191, 2194, 2194, 2194, 2382, 2382, 2194,
+ 2195, 2195, 2195, 2382, 2382, 2195, 2197, 2382, 2197, 2382,
+ 2197, 2197, 2198, 2198, 2198, 2382, 2198, 2198, 2199, 2382,
+ 2199, 2382, 2382, 2199, 2200, 2200, 2200, 2382, 2200, 2200,
+
+ 2201, 2382, 2201, 2382, 2382, 2201, 2202, 2202, 2202, 2382,
+ 2202, 2202, 2203, 2382, 2203, 2382, 2382, 2203, 2204, 2204,
+ 2204, 2382, 2204, 2204, 2205, 2382, 2205, 2382, 2382, 2205,
+ 2206, 2206, 2206, 2382, 2206, 2206, 2207, 2207, 2207, 2382,
+ 2207, 2207, 334, 334, 334, 334, 334, 2382, 334, 334,
+ 2382, 334, 334, 2221, 2221, 2221, 2382, 2382, 2221, 2222,
+ 2222, 2222, 2382, 2382, 2222, 2223, 2223, 2223, 2382, 2382,
+ 2223, 2225, 2382, 2225, 2382, 2382, 2225, 2226, 2226, 2226,
+ 2382, 2382, 2226, 2227, 2382, 2227, 2382, 2382, 2227, 2228,
+ 2228, 2228, 2382, 2382, 2228, 2229, 2382, 2229, 2382, 2382,
+
+ 2229, 2230, 2230, 2230, 2382, 2382, 2230, 2231, 2382, 2231,
+ 2382, 2382, 2231, 2232, 2232, 2232, 2382, 2382, 2232, 2233,
+ 2382, 2233, 2382, 2382, 2233, 2234, 2234, 2234, 2382, 2382,
+ 2234, 2235, 2382, 2235, 2382, 2382, 2235, 2236, 2236, 2236,
+ 2382, 2382, 2236, 2237, 2237, 2237, 2382, 2382, 2237, 2241,
+ 2241, 2241, 2382, 2382, 2241, 2242, 2242, 2242, 2382, 2382,
+ 2242, 2244, 2244, 2244, 2382, 2244, 2244, 2246, 2246, 2246,
+ 2382, 2246, 2246, 2247, 2247, 2247, 2382, 2247, 2247, 2249,
+ 2249, 2249, 2382, 2249, 2249, 2250, 2250, 2250, 2382, 2250,
+ 2250, 2252, 2252, 2252, 2382, 2252, 2252, 2253, 2253, 2253,
+
+ 2382, 2253, 2253, 2255, 2255, 2255, 2382, 2255, 2255, 2256,
+ 2256, 2256, 2382, 2256, 2256, 2258, 2258, 2258, 2382, 2258,
+ 2258, 2259, 2382, 2259, 2382, 2382, 2259, 334, 334, 334,
+ 334, 334, 2382, 334, 334, 2382, 334, 334, 2173, 2173,
+ 2173, 2382, 2382, 2173, 2270, 2270, 2270, 2382, 2382, 2270,
+ 2271, 2271, 2271, 2382, 2382, 2271, 2273, 2382, 2273, 2382,
+ 2382, 2273, 2274, 2274, 2274, 2382, 2382, 2274, 2275, 2382,
+ 2275, 2382, 2382, 2275, 2276, 2276, 2276, 2382, 2382, 2276,
+ 2277, 2382, 2277, 2382, 2382, 2277, 2278, 2278, 2278, 2382,
+ 2382, 2278, 2279, 2382, 2279, 2382, 2382, 2279, 2280, 2280,
+
+ 2280, 2382, 2382, 2280, 2281, 2382, 2281, 2382, 2382, 2281,
+ 2282, 2282, 2282, 2382, 2382, 2282, 2283, 2382, 2283, 2382,
+ 2382, 2283, 2284, 2284, 2284, 2382, 2382, 2284, 2285, 2382,
+ 2285, 2382, 2382, 2285, 2287, 2287, 2287, 2382, 2382, 2287,
+ 2288, 2288, 2288, 2382, 2382, 2288, 2290, 2382, 2290, 2382,
+ 2290, 2290, 2291, 2291, 2291, 2382, 2291, 2291, 2292, 2382,
+ 2292, 2382, 2382, 2292, 2293, 2293, 2293, 2382, 2293, 2293,
+ 2294, 2382, 2294, 2382, 2382, 2294, 2295, 2295, 2295, 2382,
+ 2295, 2295, 2296, 2382, 2296, 2382, 2382, 2296, 2297, 2297,
+ 2297, 2382, 2297, 2297, 2298, 2382, 2298, 2382, 2382, 2298,
+
+ 2299, 2299, 2299, 2382, 2299, 2299, 2300, 2382, 2300, 2382,
+ 2382, 2300, 2301, 2301, 2301, 2382, 2301, 2301, 2302, 2302,
+ 2302, 2382, 2302, 2302, 334, 334, 334, 334, 334, 2382,
+ 334, 334, 2382, 334, 334, 2311, 2311, 2311, 2382, 2382,
+ 2311, 2312, 2382, 2312, 2382, 2382, 2312, 2313, 2382, 2313,
+ 2382, 2382, 2313, 2314, 2382, 2314, 2382, 2382, 2314, 2315,
+ 2382, 2315, 2382, 2382, 2315, 2316, 2382, 2316, 2382, 2382,
+ 2316, 2317, 2382, 2317, 2382, 2382, 2317, 2318, 2382, 2318,
+ 2382, 2382, 2318, 2319, 2319, 2319, 2382, 2382, 2319, 2320,
+ 2382, 2320, 2382, 2382, 2320, 2322, 2322, 2322, 2382, 2382,
+
+ 2322, 2323, 2323, 2323, 2382, 2382, 2323, 2325, 2382, 2325,
+ 2382, 2325, 2325, 2326, 2326, 2326, 2382, 2326, 2326, 2327,
+ 2382, 2327, 2382, 2327, 2327, 2328, 2328, 2328, 2382, 2328,
+ 2328, 2329, 2382, 2329, 2382, 2329, 2329, 2330, 2330, 2330,
+ 2382, 2330, 2330, 2331, 2382, 2331, 2382, 2331, 2331, 2332,
+ 2332, 2332, 2382, 2332, 2332, 2333, 2382, 2333, 2382, 2333,
+ 2333, 2334, 2334, 2334, 2382, 2334, 2334, 2335, 2382, 2335,
+ 2382, 2335, 2335, 2336, 2336, 2336, 2382, 2336, 2336, 2337,
+ 2382, 2337, 2382, 2382, 2337, 2343, 2382, 2343, 2382, 2382,
+ 2343, 2344, 2382, 2344, 2382, 2382, 2344, 2345, 2382, 2345,
+
+ 2382, 2382, 2345, 2346, 2382, 2346, 2382, 2382, 2346, 2347,
+ 2382, 2347, 2382, 2382, 2347, 2348, 2382, 2348, 2382, 2382,
+ 2348, 2349, 2382, 2349, 2382, 2382, 2349, 2350, 2382, 2350,
+ 2382, 2382, 2350, 2351, 2351, 2351, 2382, 2382, 2351, 2352,
+ 2382, 2352, 2382, 2352, 2352, 2353, 2382, 2353, 2382, 2353,
+ 2353, 2354, 2382, 2354, 2382, 2354, 2354, 2355, 2382, 2355,
+ 2382, 2355, 2355, 2356, 2382, 2356, 2382, 2356, 2356, 2357,
+ 2382, 2357, 2382, 2357, 2357, 2358, 2382, 2358, 2382, 2358,
+ 2358, 2359, 2359, 2359, 2382, 2359, 2359, 2360, 2382, 2360,
+ 2382, 2360, 2360, 2366, 2382, 2366, 2382, 2382, 2366, 2272,
+
+ 2382, 2272, 2382, 2382, 2272, 2367, 2382, 2367, 2382, 2367,
+ 2367, 2368, 2382, 2368, 2382, 2368, 2368, 2369, 2382, 2369,
+ 2382, 2369, 2369, 2370, 2382, 2370, 2382, 2370, 2370, 2371,
+ 2382, 2371, 2382, 2371, 2371, 2372, 2382, 2372, 2382, 2372,
+ 2372, 2373, 2382, 2373, 2382, 2373, 2373, 2374, 2382, 2374,
+ 2382, 2374, 2374, 2378, 2382, 2378, 2382, 2378, 2378, 2324,
+ 2382, 2324, 2382, 2324, 2324, 111, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382
+ } ;
+
+static const flex_int16_t yy_chk[9936] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
+ 11, 2, 3, 4, 2, 4, 3, 5, 4, 5,
+ 9, 134, 134, 3, 3, 11, 6, 3, 6, 13,
+ 29, 6, 9, 29, 9, 13, 59, 10, 105, 10,
+
+ 15, 15, 10, 12, 15, 12, 15, 59, 12, 14,
+ 15, 14, 105, 15, 14, 4, 15, 15, 17, 4,
+ 47, 27, 17, 63, 23, 27, 4, 4, 17, 63,
+ 4, 23, 47, 67, 47, 2378, 6, 10, 6, 7,
+ 7, 7, 7, 7, 55, 12, 7, 7, 67, 10,
+ 7, 10, 1259, 7, 7, 73, 7, 7, 55, 55,
+ 12, 73, 1259, 14, 7, 8, 130, 8, 21, 14,
+ 8, 21, 18, 21, 18, 21, 91, 18, 2374, 21,
+ 30, 21, 30, 21, 235, 30, 21, 21, 24, 21,
+ 24, 91, 235, 24, 28, 130, 28, 31, 36, 28,
+
+ 36, 39, 39, 36, 8, 8, 8, 8, 8, 31,
+ 31, 8, 8, 18, 39, 8, 31, 18, 8, 8,
+ 79, 8, 8, 18, 79, 25, 79, 95, 95, 8,
+ 16, 30, 16, 190, 30, 16, 25, 25, 25, 25,
+ 24, 25, 25, 95, 28, 127, 25, 24, 28, 33,
+ 33, 38, 190, 38, 41, 41, 38, 44, 33, 44,
+ 41, 46, 44, 46, 49, 33, 46, 41, 33, 2373,
+ 127, 16, 16, 136, 136, 16, 49, 16, 49, 295,
+ 71, 16, 71, 295, 16, 131, 71, 16, 16, 19,
+ 61, 19, 19, 60, 19, 60, 19, 19, 60, 214,
+
+ 19, 61, 131, 19, 19, 61, 19, 19, 19, 2372,
+ 19, 20, 20, 20, 20, 20, 20, 214, 20, 34,
+ 180, 34, 20, 2371, 34, 20, 20, 180, 20, 20,
+ 20, 131, 20, 32, 60, 32, 20, 22, 32, 40,
+ 22, 40, 22, 22, 40, 60, 22, 2370, 22, 22,
+ 22, 53, 22, 22, 22, 141, 22, 26, 53, 26,
+ 34, 34, 26, 197, 141, 2369, 53, 53, 53, 34,
+ 53, 197, 53, 32, 536, 139, 34, 57, 197, 34,
+ 40, 40, 536, 57, 275, 32, 32, 57, 57, 93,
+ 93, 191, 32, 40, 64, 275, 64, 26, 93, 64,
+
+ 139, 42, 48, 42, 48, 93, 42, 48, 26, 26,
+ 26, 26, 286, 26, 26, 50, 191, 50, 26, 37,
+ 50, 37, 37, 37, 37, 186, 263, 286, 219, 263,
+ 37, 37, 37, 37, 191, 219, 37, 37, 37, 37,
+ 64, 37, 42, 42, 51, 186, 64, 51, 42, 51,
+ 48, 2368, 267, 51, 51, 42, 186, 292, 51, 51,
+ 51, 51, 48, 50, 48, 56, 103, 56, 292, 463,
+ 56, 103, 267, 984, 62, 50, 62, 50, 52, 62,
+ 52, 103, 54, 52, 54, 103, 984, 54, 495, 2367,
+ 463, 58, 66, 58, 66, 69, 58, 66, 69, 68,
+
+ 77, 68, 69, 69, 68, 77, 56, 69, 70, 495,
+ 70, 77, 72, 70, 72, 77, 62, 72, 2361, 52,
+ 56, 56, 52, 54, 52, 153, 2360, 62, 52, 52,
+ 54, 62, 159, 52, 52, 52, 52, 58, 54, 54,
+ 54, 68, 54, 58, 54, 81, 1266, 58, 58, 66,
+ 153, 81, 70, 81, 2358, 70, 68, 159, 1266, 70,
+ 70, 153, 75, 72, 70, 72, 74, 75, 74, 72,
+ 78, 74, 78, 75, 153, 78, 75, 75, 76, 225,
+ 76, 159, 225, 76, 83, 80, 225, 80, 83, 82,
+ 80, 82, 2357, 84, 82, 84, 83, 89, 84, 240,
+
+ 2356, 149, 83, 98, 149, 98, 89, 240, 98, 2355,
+ 149, 78, 74, 240, 89, 149, 78, 89, 74, 90,
+ 76, 90, 78, 243, 90, 76, 78, 1271, 2354, 230,
+ 243, 76, 80, 84, 76, 76, 80, 84, 80, 308,
+ 1271, 82, 334, 308, 308, 84, 85, 82, 85, 82,
+ 100, 84, 100, 85, 230, 100, 289, 85, 85, 85,
+ 90, 98, 230, 289, 85, 85, 86, 334, 86, 90,
+ 169, 86, 169, 101, 106, 169, 106, 90, 101, 106,
+ 90, 2353, 101, 101, 92, 101, 92, 107, 107, 92,
+ 607, 146, 146, 107, 107, 607, 268, 107, 2352, 146,
+
+ 146, 102, 146, 102, 146, 86, 102, 86, 100, 104,
+ 268, 104, 86, 310, 104, 268, 86, 86, 86, 1511,
+ 310, 106, 1516, 86, 86, 87, 92, 87, 87, 87,
+ 87, 1511, 87, 87, 1516, 106, 87, 96, 87, 96,
+ 87, 92, 96, 87, 87, 88, 102, 88, 104, 325,
+ 88, 102, 110, 104, 110, 102, 102, 110, 102, 94,
+ 108, 94, 108, 104, 94, 108, 170, 104, 170, 315,
+ 2351, 170, 181, 181, 325, 2337, 315, 2335, 96, 96,
+ 181, 181, 358, 181, 88, 181, 88, 88, 88, 88,
+ 151, 88, 88, 2333, 96, 88, 325, 88, 207, 88,
+
+ 94, 94, 88, 88, 1260, 207, 2331, 358, 207, 94,
+ 110, 108, 108, 2329, 1260, 151, 94, 108, 108, 151,
+ 151, 108, 129, 272, 129, 129, 129, 129, 129, 129,
+ 129, 129, 129, 151, 2327, 2014, 251, 272, 129, 129,
+ 272, 129, 272, 1699, 163, 2014, 210, 129, 129, 129,
+ 129, 129, 129, 210, 129, 1699, 2325, 144, 144, 129,
+ 210, 251, 144, 2324, 369, 129, 144, 658, 144, 163,
+ 129, 138, 144, 251, 658, 144, 163, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 163, 658, 163, 369,
+ 2323, 138, 138, 147, 2322, 147, 138, 147, 148, 150,
+
+ 138, 138, 138, 138, 138, 138, 147, 148, 296, 152,
+ 147, 147, 148, 147, 148, 148, 158, 147, 2319, 148,
+ 196, 196, 296, 154, 150, 1700, 2311, 296, 196, 196,
+ 150, 196, 150, 196, 152, 2305, 155, 1700, 365, 152,
+ 152, 158, 150, 156, 152, 150, 152, 150, 154, 265,
+ 152, 152, 154, 152, 2300, 158, 154, 157, 2298, 158,
+ 154, 155, 158, 365, 160, 155, 154, 365, 156, 155,
+ 154, 154, 155, 155, 265, 165, 156, 156, 304, 155,
+ 2296, 208, 157, 161, 208, 304, 156, 157, 304, 160,
+ 208, 157, 156, 160, 157, 208, 217, 160, 265, 217,
+
+ 165, 2294, 162, 157, 157, 217, 2292, 164, 161, 539,
+ 217, 160, 160, 160, 161, 539, 161, 172, 165, 172,
+ 161, 172, 161, 165, 2290, 161, 161, 162, 173, 161,
+ 172, 162, 164, 162, 172, 172, 161, 172, 162, 162,
+ 174, 172, 175, 203, 203, 2289, 162, 164, 164, 164,
+ 361, 203, 203, 173, 203, 162, 203, 173, 173, 164,
+ 2288, 242, 2287, 2284, 177, 174, 178, 175, 173, 242,
+ 174, 173, 242, 2282, 174, 361, 173, 174, 242, 2280,
+ 2278, 175, 175, 242, 174, 175, 174, 174, 175, 177,
+ 175, 178, 324, 177, 361, 2276, 1701, 177, 324, 178,
+
+ 178, 177, 178, 324, 177, 179, 179, 177, 1701, 178,
+ 179, 177, 177, 2274, 179, 178, 179, 182, 2270, 182,
+ 179, 182, 184, 179, 179, 182, 2243, 2242, 189, 183,
+ 182, 373, 182, 187, 182, 182, 2241, 182, 183, 188,
+ 2240, 182, 2237, 183, 2236, 183, 183, 184, 183, 2234,
+ 183, 184, 184, 189, 253, 184, 373, 189, 187, 192,
+ 373, 189, 253, 187, 188, 184, 193, 187, 188, 253,
+ 187, 194, 253, 359, 213, 189, 189, 189, 188, 187,
+ 187, 312, 188, 187, 192, 188, 195, 2232, 192, 299,
+ 2230, 193, 192, 192, 2228, 193, 194, 299, 359, 213,
+
+ 198, 2226, 192, 213, 299, 193, 312, 213, 192, 193,
+ 194, 195, 193, 359, 194, 200, 199, 194, 312, 195,
+ 213, 213, 213, 213, 1704, 198, 195, 195, 195, 198,
+ 2224, 198, 204, 198, 2223, 248, 1704, 202, 195, 248,
+ 200, 199, 316, 198, 200, 199, 198, 380, 198, 199,
+ 248, 382, 199, 199, 200, 248, 2222, 204, 200, 199,
+ 205, 200, 202, 204, 199, 204, 202, 316, 202, 2221,
+ 209, 2210, 380, 202, 202, 204, 382, 2196, 204, 212,
+ 204, 202, 211, 206, 206, 205, 321, 382, 206, 205,
+ 202, 316, 206, 205, 206, 209, 205, 205, 206, 209,
+
+ 209, 206, 209, 205, 212, 215, 205, 211, 360, 2195,
+ 216, 321, 211, 209, 2194, 2191, 211, 977, 212, 211,
+ 221, 220, 212, 321, 977, 212, 211, 212, 211, 211,
+ 215, 218, 362, 360, 215, 216, 215, 977, 2190, 216,
+ 360, 215, 215, 216, 223, 221, 220, 224, 215, 215,
+ 216, 216, 216, 215, 220, 220, 218, 362, 215, 221,
+ 218, 218, 216, 221, 220, 227, 221, 226, 311, 223,
+ 220, 311, 224, 311, 218, 249, 228, 223, 223, 224,
+ 362, 249, 363, 392, 2188, 249, 249, 223, 2187, 224,
+ 227, 224, 226, 223, 224, 227, 226, 231, 2185, 227,
+
+ 226, 228, 227, 226, 226, 228, 232, 363, 392, 228,
+ 226, 227, 227, 245, 2184, 227, 233, 2182, 261, 363,
+ 2181, 261, 231, 228, 228, 228, 231, 261, 2179, 237,
+ 231, 232, 261, 231, 231, 2178, 386, 2176, 245, 232,
+ 231, 233, 234, 234, 1247, 232, 245, 245, 233, 232,
+ 234, 234, 232, 234, 237, 234, 245, 2174, 233, 1247,
+ 233, 386, 245, 233, 368, 386, 364, 238, 238, 237,
+ 237, 237, 238, 2173, 2172, 1247, 238, 237, 238, 239,
+ 239, 237, 238, 250, 241, 238, 246, 239, 239, 368,
+ 239, 364, 239, 241, 384, 2154, 241, 368, 241, 244,
+
+ 241, 241, 244, 244, 2142, 241, 244, 244, 250, 247,
+ 244, 246, 364, 244, 244, 250, 246, 244, 244, 384,
+ 246, 2141, 2140, 246, 384, 250, 457, 250, 457, 250,
+ 246, 457, 246, 246, 247, 2139, 252, 252, 247, 2136,
+ 2135, 252, 247, 256, 252, 252, 247, 252, 257, 252,
+ 254, 254, 254, 259, 406, 410, 247, 247, 247, 254,
+ 254, 255, 254, 258, 254, 255, 650, 379, 256, 255,
+ 2134, 650, 322, 257, 256, 322, 255, 650, 259, 406,
+ 410, 1705, 256, 262, 257, 367, 256, 322, 258, 256,
+ 322, 266, 379, 1705, 259, 257, 259, 257, 260, 260,
+
+ 379, 259, 374, 258, 258, 258, 260, 260, 262, 260,
+ 367, 260, 262, 262, 264, 258, 266, 264, 264, 270,
+ 266, 413, 269, 269, 266, 1707, 262, 374, 2133, 264,
+ 269, 269, 264, 269, 367, 269, 274, 1707, 266, 266,
+ 266, 2132, 273, 273, 270, 374, 413, 279, 270, 2131,
+ 273, 273, 270, 273, 388, 273, 277, 388, 2130, 2129,
+ 2128, 274, 276, 276, 2127, 274, 270, 270, 270, 274,
+ 276, 276, 279, 276, 278, 276, 279, 278, 2126, 388,
+ 279, 277, 375, 274, 274, 274, 277, 2125, 278, 278,
+ 277, 2124, 278, 277, 279, 279, 279, 281, 280, 284,
+
+ 277, 280, 277, 277, 2123, 372, 290, 375, 1838, 2122,
+ 387, 372, 280, 280, 290, 2121, 280, 290, 372, 2085,
+ 1838, 372, 281, 290, 284, 285, 291, 281, 290, 284,
+ 375, 281, 390, 284, 281, 387, 284, 293, 306, 376,
+ 293, 2084, 387, 281, 281, 284, 284, 2083, 284, 2080,
+ 285, 291, 293, 294, 285, 293, 293, 390, 285, 291,
+ 291, 297, 301, 306, 376, 301, 391, 412, 301, 291,
+ 2079, 301, 285, 285, 285, 291, 301, 306, 294, 2076,
+ 390, 306, 306, 376, 306, 377, 294, 294, 297, 297,
+ 297, 391, 412, 2075, 297, 399, 294, 300, 297, 391,
+
+ 297, 302, 294, 305, 297, 297, 300, 297, 298, 298,
+ 377, 300, 300, 300, 300, 412, 298, 298, 300, 298,
+ 399, 298, 298, 2073, 298, 393, 302, 377, 305, 399,
+ 302, 302, 309, 309, 302, 307, 305, 305, 314, 307,
+ 309, 309, 307, 309, 302, 309, 305, 313, 313, 319,
+ 393, 394, 305, 307, 307, 313, 313, 2072, 313, 313,
+ 313, 318, 2070, 314, 318, 423, 1840, 393, 2069, 314,
+ 318, 314, 2067, 318, 319, 318, 394, 1841, 1840, 2065,
+ 381, 314, 319, 2064, 314, 2063, 314, 394, 319, 1841,
+ 423, 383, 319, 403, 385, 319, 336, 336, 336, 336,
+
+ 336, 336, 336, 336, 337, 381, 337, 337, 337, 337,
+ 337, 337, 337, 337, 337, 396, 383, 366, 403, 385,
+ 337, 337, 403, 385, 381, 2027, 1845, 2017, 383, 337,
+ 337, 337, 337, 337, 337, 383, 337, 385, 1845, 383,
+ 396, 337, 366, 385, 444, 456, 2016, 337, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 2015, 366, 366,
+ 2011, 396, 341, 341, 2010, 2008, 366, 2007, 2006, 444,
+ 456, 341, 341, 341, 341, 341, 341, 342, 342, 342,
+ 342, 342, 342, 342, 342, 343, 343, 343, 343, 343,
+ 343, 343, 343, 344, 344, 344, 344, 344, 344, 344,
+
+ 344, 458, 460, 458, 460, 1846, 458, 460, 2005, 2004,
+ 438, 451, 408, 470, 2003, 2002, 2001, 1846, 2000, 1999,
+ 405, 400, 1998, 397, 389, 1997, 343, 346, 346, 346,
+ 346, 346, 346, 346, 346, 438, 451, 408, 470, 438,
+ 451, 346, 346, 395, 398, 405, 400, 408, 397, 389,
+ 346, 346, 346, 346, 346, 346, 352, 352, 352, 352,
+ 352, 352, 352, 352, 397, 400, 389, 405, 395, 398,
+ 352, 352, 389, 401, 404, 402, 407, 409, 414, 352,
+ 352, 352, 352, 352, 352, 398, 395, 402, 1942, 411,
+ 1941, 416, 395, 417, 418, 1940, 1943, 1937, 401, 404,
+
+ 402, 407, 409, 414, 401, 401, 401, 415, 1943, 419,
+ 1936, 1935, 420, 409, 411, 404, 416, 407, 417, 418,
+ 401, 401, 402, 407, 1932, 414, 421, 422, 424, 425,
+ 427, 426, 415, 411, 419, 411, 411, 420, 429, 416,
+ 428, 417, 418, 430, 433, 1931, 1929, 1944, 1928, 415,
+ 419, 421, 422, 424, 425, 427, 426, 431, 420, 1944,
+ 421, 422, 424, 429, 432, 428, 1926, 427, 430, 433,
+ 432, 426, 432, 428, 434, 430, 435, 425, 426, 436,
+ 429, 430, 431, 428, 433, 430, 437, 430, 439, 432,
+ 430, 430, 440, 431, 1924, 432, 1945, 1923, 441, 434,
+
+ 442, 435, 443, 1946, 436, 1922, 445, 435, 1945, 446,
+ 1844, 437, 447, 439, 1837, 1946, 448, 440, 449, 439,
+ 450, 437, 434, 441, 435, 442, 453, 443, 440, 452,
+ 442, 445, 454, 436, 446, 437, 455, 447, 1836, 441,
+ 441, 448, 464, 449, 465, 450, 443, 445, 466, 468,
+ 449, 453, 450, 467, 452, 446, 447, 454, 452, 469,
+ 448, 455, 471, 453, 472, 473, 1835, 464, 474, 465,
+ 475, 476, 454, 466, 468, 464, 480, 1832, 467, 477,
+ 481, 466, 455, 478, 469, 1831, 467, 471, 1828, 472,
+ 473, 469, 1827, 474, 479, 475, 476, 465, 482, 472,
+
+ 483, 480, 468, 1947, 477, 481, 1826, 484, 478, 474,
+ 474, 485, 477, 473, 476, 1947, 475, 474, 486, 479,
+ 478, 487, 488, 482, 481, 483, 1950, 478, 482, 489,
+ 1825, 478, 484, 490, 479, 491, 485, 483, 1950, 492,
+ 484, 496, 485, 486, 1951, 482, 487, 488, 493, 1824,
+ 494, 488, 1823, 487, 489, 486, 1951, 1822, 490, 487,
+ 491, 486, 497, 487, 492, 487, 496, 1821, 487, 487,
+ 498, 489, 491, 493, 490, 494, 499, 493, 491, 500,
+ 502, 493, 494, 1820, 1819, 492, 501, 497, 1698, 496,
+ 503, 494, 494, 1697, 1696, 498, 507, 1694, 1693, 494,
+
+ 505, 499, 1692, 506, 500, 502, 497, 1514, 497, 497,
+ 500, 501, 508, 502, 497, 503, 501, 1514, 501, 498,
+ 509, 507, 499, 502, 500, 505, 510, 500, 506, 1514,
+ 511, 505, 506, 512, 513, 514, 515, 508, 503, 516,
+ 517, 1689, 507, 518, 520, 509, 519, 1688, 505, 1686,
+ 2018, 510, 521, 522, 508, 511, 509, 1684, 512, 513,
+ 514, 515, 2018, 511, 516, 517, 509, 511, 518, 520,
+ 1683, 519, 523, 511, 510, 519, 513, 521, 522, 512,
+ 517, 524, 515, 518, 525, 526, 522, 520, 520, 519,
+ 522, 527, 528, 520, 530, 519, 529, 523, 1682, 531,
+
+ 521, 534, 559, 1681, 521, 559, 524, 1510, 559, 525,
+ 526, 532, 535, 538, 524, 559, 527, 528, 559, 530,
+ 523, 529, 523, 528, 531, 533, 534, 526, 537, 529,
+ 525, 540, 526, 527, 2020, 530, 532, 535, 538, 527,
+ 528, 535, 530, 532, 534, 531, 2020, 538, 542, 1509,
+ 533, 543, 1508, 537, 533, 544, 540, 1507, 533, 532,
+ 545, 550, 546, 547, 548, 1505, 544, 1504, 551, 537,
+ 537, 540, 2021, 542, 533, 552, 543, 537, 1500, 553,
+ 544, 1499, 542, 1498, 2021, 545, 550, 546, 547, 548,
+ 542, 549, 554, 551, 561, 543, 550, 543, 543, 551,
+
+ 552, 555, 556, 543, 553, 552, 547, 547, 545, 546,
+ 2023, 547, 548, 1497, 1496, 560, 549, 554, 557, 561,
+ 553, 562, 2023, 549, 563, 554, 555, 556, 564, 549,
+ 565, 566, 1494, 549, 1265, 549, 555, 561, 549, 549,
+ 560, 567, 554, 557, 556, 568, 562, 557, 570, 563,
+ 562, 569, 575, 564, 1264, 565, 566, 564, 571, 560,
+ 566, 1263, 572, 573, 563, 1261, 567, 1256, 574, 1254,
+ 568, 565, 565, 570, 566, 576, 569, 575, 578, 565,
+ 566, 577, 575, 571, 567, 1252, 568, 572, 573, 579,
+ 567, 571, 568, 574, 573, 569, 570, 569, 569, 580,
+
+ 576, 571, 572, 578, 1246, 581, 577, 578, 582, 574,
+ 574, 573, 577, 583, 579, 576, 665, 584, 585, 588,
+ 2024, 595, 594, 2028, 580, 2029, 579, 2086, 981, 577,
+ 581, 586, 2024, 582, 980, 2028, 580, 2029, 583, 2086,
+ 587, 665, 584, 585, 588, 583, 595, 594, 580, 584,
+ 582, 583, 585, 581, 582, 583, 586, 583, 589, 584,
+ 583, 583, 586, 594, 586, 587, 591, 588, 595, 596,
+ 590, 587, 587, 587, 979, 976, 592, 2087, 971, 586,
+ 2088, 2089, 970, 589, 597, 601, 598, 587, 587, 2087,
+ 589, 591, 2088, 2089, 596, 590, 589, 591, 591, 591,
+
+ 589, 592, 589, 589, 603, 589, 589, 590, 599, 597,
+ 601, 598, 590, 591, 591, 969, 600, 598, 596, 605,
+ 592, 598, 604, 606, 609, 611, 2090, 610, 617, 603,
+ 614, 601, 597, 599, 598, 603, 597, 964, 2090, 963,
+ 599, 600, 613, 612, 605, 825, 600, 604, 606, 609,
+ 611, 600, 610, 617, 611, 614, 816, 615, 616, 617,
+ 605, 618, 599, 604, 604, 604, 787, 613, 612, 606,
+ 609, 604, 619, 610, 612, 612, 612, 613, 614, 621,
+ 612, 614, 615, 616, 2091, 620, 618, 622, 623, 624,
+ 612, 612, 618, 613, 625, 616, 2091, 619, 615, 627,
+
+ 785, 626, 679, 628, 621, 629, 618, 630, 631, 618,
+ 620, 678, 622, 623, 624, 663, 661, 632, 633, 625,
+ 634, 619, 635, 625, 627, 621, 626, 620, 628, 622,
+ 629, 636, 630, 631, 623, 660, 628, 631, 657, 624,
+ 630, 626, 632, 633, 637, 634, 628, 635, 627, 639,
+ 630, 638, 640, 641, 655, 629, 636, 632, 666, 2092,
+ 634, 667, 669, 635, 633, 645, 634, 634, 608, 637,
+ 675, 2092, 602, 2094, 639, 593, 638, 640, 641, 636,
+ 639, 558, 541, 666, 641, 2094, 667, 669, 637, 504,
+ 637, 637, 461, 640, 669, 675, 637, 643, 638, 643,
+
+ 643, 643, 643, 643, 643, 643, 643, 644, 459, 644,
+ 644, 644, 644, 644, 644, 644, 644, 644, 647, 647,
+ 647, 668, 673, 644, 644, 378, 371, 370, 2095, 2143,
+ 647, 647, 644, 644, 644, 644, 644, 644, 670, 644,
+ 2095, 2143, 647, 671, 644, 357, 668, 673, 677, 356,
+ 644, 646, 646, 646, 646, 646, 646, 646, 646, 646,
+ 354, 1515, 2098, 670, 668, 646, 646, 353, 671, 673,
+ 673, 1515, 2098, 677, 646, 646, 646, 646, 646, 646,
+ 671, 670, 345, 1515, 2098, 647, 651, 651, 651, 651,
+ 651, 651, 651, 651, 652, 652, 652, 652, 652, 652,
+
+ 652, 652, 654, 654, 654, 654, 654, 654, 654, 654,
+ 2145, 674, 339, 338, 682, 335, 2146, 331, 2148, 329,
+ 2149, 651, 2145, 327, 680, 685, 326, 651, 2146, 652,
+ 2148, 676, 2149, 683, 684, 652, 674, 654, 656, 682,
+ 656, 656, 656, 656, 656, 656, 656, 656, 656, 680,
+ 685, 682, 323, 674, 656, 656, 676, 680, 683, 684,
+ 676, 320, 686, 656, 656, 656, 656, 656, 656, 659,
+ 659, 659, 659, 659, 659, 659, 659, 659, 684, 2151,
+ 317, 683, 688, 659, 659, 681, 672, 686, 303, 690,
+ 687, 2151, 659, 659, 659, 659, 659, 659, 662, 662,
+
+ 662, 662, 662, 662, 662, 662, 689, 688, 288, 691,
+ 681, 672, 662, 662, 690, 687, 681, 287, 662, 687,
+ 692, 662, 662, 662, 662, 662, 662, 672, 693, 695,
+ 672, 689, 694, 681, 691, 696, 697, 698, 699, 700,
+ 2152, 701, 691, 283, 702, 692, 282, 689, 271, 703,
+ 704, 705, 2152, 693, 695, 707, 706, 694, 708, 236,
+ 696, 697, 698, 699, 700, 693, 701, 692, 694, 702,
+ 696, 693, 229, 699, 703, 704, 705, 702, 701, 709,
+ 707, 706, 710, 708, 698, 711, 712, 697, 706, 714,
+ 716, 713, 717, 704, 222, 715, 720, 708, 201, 705,
+
+ 185, 176, 722, 718, 709, 171, 723, 710, 145, 719,
+ 711, 712, 721, 724, 714, 716, 713, 717, 725, 710,
+ 715, 720, 726, 716, 710, 709, 713, 722, 718, 711,
+ 712, 723, 714, 713, 719, 715, 718, 721, 724, 713,
+ 717, 727, 719, 725, 728, 721, 729, 726, 730, 722,
+ 723, 731, 733, 732, 734, 725, 140, 135, 735, 736,
+ 737, 724, 2155, 738, 742, 132, 727, 739, 740, 728,
+ 726, 729, 741, 730, 2155, 743, 731, 733, 732, 734,
+ 118, 728, 732, 735, 736, 737, 732, 730, 738, 742,
+ 735, 734, 739, 740, 744, 117, 731, 741, 738, 733,
+
+ 743, 745, 746, 747, 739, 736, 737, 741, 740, 739,
+ 748, 749, 755, 116, 741, 751, 750, 752, 115, 744,
+ 741, 2156, 753, 743, 113, 757, 745, 746, 747, 756,
+ 754, 744, 758, 2156, 759, 748, 749, 755, 745, 760,
+ 751, 750, 752, 749, 761, 746, 752, 753, 751, 750,
+ 757, 762, 747, 750, 756, 754, 763, 758, 748, 759,
+ 764, 755, 753, 754, 760, 765, 756, 111, 109, 761,
+ 766, 767, 760, 768, 759, 769, 762, 2197, 770, 771,
+ 772, 763, 2198, 773, 774, 764, 775, 2199, 761, 2197,
+ 765, 776, 762, 764, 2198, 766, 767, 777, 768, 2199,
+
+ 769, 778, 765, 770, 771, 772, 779, 766, 773, 774,
+ 99, 775, 768, 780, 770, 781, 776, 774, 782, 767,
+ 772, 783, 777, 771, 776, 97, 778, 784, 788, 775,
+ 65, 779, 789, 790, 778, 779, 791, 777, 780, 792,
+ 781, 793, 794, 782, 795, 0, 783, 796, 0, 797,
+ 783, 0, 784, 788, 0, 780, 798, 789, 790, 781,
+ 800, 791, 799, 801, 792, 802, 793, 794, 0, 795,
+ 788, 804, 796, 793, 797, 803, 789, 795, 791, 790,
+ 805, 798, 797, 792, 806, 800, 794, 799, 801, 796,
+ 802, 807, 808, 800, 809, 810, 804, 800, 0, 812,
+
+ 803, 0, 798, 800, 799, 805, 804, 801, 803, 806,
+ 811, 802, 813, 814, 0, 815, 807, 808, 0, 809,
+ 810, 817, 2200, 806, 812, 819, 805, 818, 810, 0,
+ 818, 820, 808, 821, 2200, 811, 822, 813, 814, 807,
+ 815, 823, 809, 811, 814, 824, 817, 812, 815, 826,
+ 819, 827, 818, 829, 817, 828, 820, 0, 821, 813,
+ 820, 822, 830, 0, 831, 0, 823, 833, 822, 832,
+ 824, 834, 835, 836, 826, 837, 827, 839, 829, 838,
+ 828, 840, 821, 0, 841, 842, 827, 830, 829, 831,
+ 823, 0, 833, 826, 832, 828, 834, 835, 836, 843,
+
+ 837, 831, 839, 832, 838, 844, 840, 0, 830, 841,
+ 842, 845, 846, 0, 840, 847, 841, 834, 850, 838,
+ 849, 848, 836, 2201, 843, 839, 837, 0, 851, 2202,
+ 844, 852, 842, 0, 853, 2201, 845, 846, 844, 855,
+ 847, 2202, 854, 850, 856, 849, 848, 857, 843, 0,
+ 858, 846, 845, 851, 845, 848, 852, 849, 847, 853,
+ 850, 859, 0, 860, 855, 861, 852, 854, 862, 856,
+ 863, 864, 857, 855, 851, 858, 865, 866, 867, 869,
+ 868, 853, 870, 874, 854, 0, 859, 856, 860, 0,
+ 861, 0, 871, 862, 873, 863, 864, 872, 858, 862,
+
+ 0, 865, 866, 867, 869, 868, 875, 870, 874, 859,
+ 860, 867, 861, 0, 866, 864, 868, 871, 869, 873,
+ 876, 877, 872, 873, 878, 871, 879, 874, 872, 880,
+ 870, 875, 881, 882, 883, 884, 885, 886, 875, 888,
+ 887, 889, 0, 0, 890, 876, 877, 0, 892, 878,
+ 0, 879, 0, 891, 880, 893, 894, 881, 882, 883,
+ 884, 885, 886, 897, 888, 887, 889, 876, 888, 890,
+ 882, 880, 888, 892, 886, 885, 883, 890, 891, 895,
+ 893, 894, 896, 898, 899, 900, 884, 887, 897, 889,
+ 901, 902, 903, 0, 891, 892, 894, 904, 0, 893,
+
+ 905, 906, 907, 908, 895, 909, 910, 896, 898, 899,
+ 900, 911, 895, 896, 0, 901, 902, 903, 900, 912,
+ 913, 899, 904, 901, 0, 905, 906, 907, 908, 904,
+ 909, 910, 903, 914, 909, 916, 911, 915, 906, 903,
+ 915, 917, 0, 908, 912, 913, 911, 918, 919, 910,
+ 920, 907, 921, 922, 923, 924, 922, 925, 914, 0,
+ 916, 926, 915, 927, 928, 0, 917, 912, 0, 0,
+ 929, 933, 918, 919, 930, 920, 934, 921, 922, 923,
+ 924, 914, 925, 935, 924, 0, 926, 936, 927, 928,
+ 925, 921, 937, 920, 919, 929, 933, 931, 918, 930,
+
+ 931, 934, 932, 933, 926, 932, 938, 930, 935, 939,
+ 928, 940, 936, 941, 927, 934, 942, 937, 929, 943,
+ 944, 2203, 931, 945, 946, 935, 0, 932, 947, 0,
+ 948, 938, 0, 2203, 939, 936, 940, 932, 941, 938,
+ 949, 942, 950, 951, 943, 944, 941, 0, 945, 946,
+ 952, 943, 2204, 947, 940, 948, 953, 946, 942, 954,
+ 955, 944, 956, 957, 2204, 949, 0, 950, 951, 0,
+ 958, 966, 945, 1262, 948, 952, 0, 947, 948, 0,
+ 949, 953, 0, 1262, 954, 955, 0, 956, 957, 950,
+ 1262, 951, 953, 966, 952, 958, 957, 0, 966, 958,
+
+ 0, 956, 0, 1262, 966, 0, 954, 960, 960, 960,
+ 960, 960, 960, 960, 960, 961, 962, 961, 961, 961,
+ 961, 961, 961, 961, 961, 965, 965, 965, 965, 965,
+ 965, 965, 965, 965, 962, 968, 968, 968, 962, 972,
+ 990, 2205, 978, 962, 0, 0, 2206, 968, 968, 962,
+ 2207, 2244, 2246, 2205, 972, 0, 978, 972, 2206, 968,
+ 0, 972, 2207, 2244, 2246, 990, 972, 978, 987, 988,
+ 972, 987, 972, 973, 973, 973, 973, 973, 973, 973,
+ 973, 983, 990, 983, 983, 983, 983, 983, 983, 983,
+ 983, 991, 992, 987, 988, 0, 997, 989, 994, 0,
+
+ 993, 986, 968, 974, 988, 974, 974, 974, 974, 974,
+ 974, 974, 974, 974, 0, 986, 991, 992, 0, 974,
+ 974, 997, 989, 994, 991, 993, 986, 995, 974, 974,
+ 974, 974, 974, 974, 982, 994, 982, 982, 982, 982,
+ 982, 982, 982, 982, 982, 986, 989, 996, 993, 998,
+ 982, 982, 995, 999, 1000, 1002, 982, 1001, 1003, 982,
+ 982, 982, 982, 982, 982, 1004, 0, 1005, 1007, 1006,
+ 0, 1008, 996, 1011, 998, 995, 0, 2247, 999, 1000,
+ 1002, 1009, 1001, 1003, 1010, 1012, 1002, 1013, 1014, 2247,
+ 1004, 998, 1005, 1007, 1006, 996, 1008, 1015, 1011, 0,
+
+ 1000, 999, 1006, 1001, 1016, 1011, 1009, 0, 1005, 1010,
+ 1012, 1017, 1013, 1014, 1007, 1018, 1019, 1020, 1021, 1008,
+ 0, 0, 1015, 1022, 1014, 1023, 1024, 1009, 1025, 1016,
+ 1010, 1026, 1012, 1027, 1028, 1013, 1017, 1029, 1250, 1030,
+ 1018, 1019, 1020, 1021, 0, 1019, 1016, 1031, 1022, 1032,
+ 1023, 1024, 1033, 1025, 0, 1024, 1026, 1020, 1027, 1028,
+ 1250, 1017, 1029, 1028, 1030, 1250, 1034, 1035, 1036, 1023,
+ 1037, 1250, 1031, 1038, 1032, 1039, 2249, 1033, 1025, 1027,
+ 1040, 0, 1041, 1042, 1043, 1030, 1044, 0, 2249, 1045,
+ 1029, 1034, 1035, 1036, 1046, 1037, 1031, 1047, 1038, 1036,
+
+ 1039, 1032, 1048, 2250, 1049, 1040, 1037, 1041, 1042, 1043,
+ 0, 1044, 1034, 1035, 1045, 2250, 1050, 1042, 1051, 1046,
+ 0, 1052, 1047, 1053, 1054, 0, 1055, 1048, 1040, 1049,
+ 1056, 1057, 1058, 1059, 1047, 1044, 1061, 1049, 1063, 1060,
+ 1046, 1050, 0, 1051, 0, 1050, 1052, 1051, 1053, 1054,
+ 1048, 1055, 1062, 1054, 1052, 1056, 1057, 1058, 1059, 0,
+ 1057, 1061, 1064, 1063, 1060, 1065, 0, 1053, 1066, 1055,
+ 1060, 1063, 1067, 0, 1068, 1069, 1056, 1062, 1070, 1071,
+ 0, 1073, 0, 0, 1061, 1058, 1059, 1064, 1072, 1075,
+ 1065, 1064, 1074, 1066, 1076, 1077, 0, 1067, 1062, 1068,
+
+ 1069, 1078, 1066, 1070, 1071, 1068, 1073, 1070, 1065, 0,
+ 1079, 0, 1080, 1072, 1075, 1073, 1069, 1074, 1067, 1076,
+ 1077, 1074, 1081, 1082, 1077, 1083, 1078, 1071, 1084, 0,
+ 1085, 0, 1086, 1087, 1072, 1079, 1075, 1080, 0, 1088,
+ 1089, 1091, 1079, 1092, 1080, 1090, 1093, 1081, 1082, 0,
+ 1083, 1094, 0, 1084, 1083, 1085, 1082, 1086, 1087, 1095,
+ 0, 1096, 1097, 1085, 1088, 1089, 1091, 1098, 1092, 1099,
+ 1090, 1093, 1101, 1095, 1084, 1086, 1094, 1089, 1100, 1090,
+ 0, 1102, 1088, 1103, 1095, 1087, 1096, 1097, 1104, 1091,
+ 1105, 1106, 1098, 1094, 1099, 1097, 1098, 1101, 1107, 1109,
+
+ 1108, 1110, 1112, 1100, 1111, 1095, 1102, 1113, 1103, 0,
+ 1114, 1100, 1116, 1104, 0, 1105, 1106, 0, 1101, 0,
+ 1102, 1105, 0, 1107, 1109, 1108, 1110, 1112, 1115, 1111,
+ 1103, 1108, 1113, 1117, 1110, 1114, 1104, 1116, 1118, 1106,
+ 1119, 1120, 1112, 1122, 1113, 1109, 1107, 1111, 1121, 1123,
+ 1124, 1127, 1126, 1115, 1128, 1116, 1125, 1129, 1117, 1130,
+ 1131, 1115, 1117, 1118, 1132, 1119, 1120, 1133, 1122, 1134,
+ 1125, 1118, 1134, 1121, 1123, 1124, 1127, 1126, 0, 1128,
+ 1122, 1125, 1129, 1127, 1130, 1131, 1117, 1118, 1123, 1132,
+ 1129, 1121, 1133, 1135, 1134, 1128, 1136, 1137, 1138, 1139,
+
+ 1140, 0, 1125, 1126, 1131, 1130, 1141, 1142, 1143, 1146,
+ 1144, 0, 1145, 1147, 0, 1148, 0, 1149, 1135, 0,
+ 0, 1136, 1137, 1138, 1139, 1140, 1135, 1150, 1151, 1152,
+ 0, 1141, 1142, 1143, 1146, 1144, 1139, 1145, 1147, 1141,
+ 1148, 1138, 1149, 1153, 1136, 1143, 1144, 1142, 1154, 1156,
+ 0, 1155, 1150, 1151, 1152, 1142, 1157, 1159, 1145, 1158,
+ 1160, 1147, 1161, 1148, 1162, 0, 1163, 0, 1153, 1150,
+ 1164, 1165, 0, 1154, 1156, 1152, 1155, 1166, 0, 1167,
+ 0, 1157, 1159, 0, 1158, 1160, 1153, 1161, 1154, 1162,
+ 1155, 1163, 1158, 1168, 1169, 1164, 1165, 1156, 1170, 1172,
+
+ 1173, 1175, 1166, 1164, 1167, 1159, 1171, 1162, 1165, 1171,
+ 1174, 0, 1171, 1171, 1171, 1171, 0, 0, 1168, 1169,
+ 1176, 1166, 0, 1170, 1172, 1173, 1175, 0, 1177, 1178,
+ 1179, 1171, 1180, 1181, 1182, 1174, 1168, 1183, 1184, 1185,
+ 1169, 1175, 1169, 1173, 1186, 1176, 1170, 1173, 1187, 2252,
+ 1188, 0, 1172, 1177, 1178, 1179, 1174, 1180, 1181, 1182,
+ 1189, 2252, 1183, 1184, 1185, 0, 1190, 1191, 1176, 1186,
+ 1192, 1177, 0, 1187, 1180, 1188, 1178, 1187, 0, 1193,
+ 1195, 1181, 1182, 1194, 1183, 1189, 1184, 1197, 0, 1189,
+ 1186, 1190, 1191, 1196, 1198, 1192, 1196, 1188, 2253, 1199,
+
+ 1200, 0, 0, 1192, 1193, 1195, 1201, 0, 1194, 1202,
+ 2253, 1203, 1197, 1191, 1204, 1205, 1194, 1204, 1196, 1198,
+ 1207, 1206, 0, 1195, 1199, 1200, 1193, 1198, 1208, 1209,
+ 1210, 1201, 1200, 1197, 1202, 1197, 1203, 0, 1211, 1204,
+ 1205, 1212, 0, 1213, 1214, 1207, 1206, 1201, 1215, 1216,
+ 0, 1205, 2255, 1208, 1209, 1210, 1202, 1218, 1219, 1220,
+ 1203, 1206, 1207, 1211, 2255, 0, 1212, 1210, 1213, 1214,
+ 1221, 1209, 0, 1215, 1216, 1217, 1208, 1215, 1217, 0,
+ 1222, 1223, 1218, 1219, 1220, 1224, 1211, 2256, 1226, 1219,
+ 1214, 1220, 0, 1225, 1220, 1221, 1220, 1216, 1227, 2256,
+
+ 1217, 1228, 1220, 1229, 1218, 1222, 1223, 1231, 1230, 0,
+ 1224, 1233, 1217, 1226, 0, 1232, 1234, 1224, 1225, 2258,
+ 1235, 1236, 1225, 1227, 1223, 1237, 1228, 1238, 1229, 1239,
+ 0, 2258, 1231, 1230, 1229, 1240, 1233, 1226, 1227, 1230,
+ 1232, 1234, 1242, 0, 1233, 1235, 1236, 1243, 1228, 1274,
+ 1237, 1231, 1238, 1276, 1239, 1232, 1234, 2259, 1236, 1241,
+ 1240, 1289, 1241, 2291, 2293, 0, 0, 1242, 1240, 2259,
+ 0, 2295, 1243, 1235, 1274, 2291, 2293, 1238, 1276, 1238,
+ 0, 0, 1274, 2295, 1241, 1242, 1289, 1243, 1245, 1242,
+ 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1248, 1248,
+
+ 1248, 1248, 1248, 1248, 1248, 1248, 1249, 1249, 1249, 1251,
+ 1251, 1251, 2297, 2299, 0, 2301, 2302, 2326, 1249, 1249,
+ 0, 1251, 1251, 0, 2297, 2299, 1272, 2301, 2302, 2326,
+ 1249, 0, 1258, 1251, 1258, 1258, 1258, 1258, 1258, 1258,
+ 1258, 1258, 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
+ 1270, 1272, 1270, 1270, 1270, 1270, 1270, 1270, 1270, 1270,
+ 0, 0, 0, 2328, 1294, 1275, 2330, 1273, 0, 0,
+ 1277, 1278, 1279, 1249, 1272, 2328, 1251, 1268, 2330, 1268,
+ 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1268, 1280, 1294,
+ 1275, 1281, 1273, 1268, 1268, 1277, 1278, 1279, 1282, 1268,
+
+ 1278, 1283, 1268, 1268, 1268, 1268, 1268, 1268, 1273, 1275,
+ 1284, 1285, 1277, 1280, 1279, 1286, 1281, 1288, 1287, 1290,
+ 1291, 1280, 0, 1282, 1281, 1292, 1283, 1295, 0, 2332,
+ 0, 1282, 1293, 1296, 1283, 1284, 1285, 1297, 1298, 1299,
+ 1286, 2332, 1288, 1287, 1290, 1291, 0, 1284, 1286, 1300,
+ 1292, 1301, 1295, 1291, 1285, 1287, 1295, 1293, 1296, 1288,
+ 0, 1302, 1297, 1298, 1299, 1303, 1290, 1304, 1305, 0,
+ 1306, 1298, 1307, 1292, 1300, 1308, 1301, 1303, 1293, 1309,
+ 1310, 1311, 1300, 1299, 0, 1297, 1302, 1312, 1313, 0,
+ 1303, 1314, 1304, 1305, 1301, 1306, 1315, 1307, 1317, 1316,
+
+ 1308, 1318, 1302, 0, 1309, 1310, 1311, 1308, 1319, 1305,
+ 1304, 1320, 1312, 1313, 1306, 1321, 1314, 1322, 0, 0,
+ 1307, 1315, 1323, 1317, 1316, 1324, 1318, 1326, 1310, 1325,
+ 1327, 1311, 1316, 1319, 1328, 1329, 1320, 1330, 1331, 0,
+ 1321, 1332, 1322, 1318, 1315, 0, 1321, 1323, 1322, 1333,
+ 1324, 1319, 1326, 0, 1325, 1327, 1326, 1334, 1335, 1328,
+ 1329, 1320, 1330, 1331, 1323, 1336, 1332, 1337, 1324, 1338,
+ 1325, 1339, 1340, 1327, 1333, 1328, 1341, 0, 1332, 1329,
+ 0, 1330, 1334, 1335, 1342, 1343, 1333, 1344, 1346, 1345,
+ 1336, 1331, 1337, 1347, 1338, 1348, 1339, 1340, 1349, 1350,
+
+ 1352, 1341, 1338, 1351, 1337, 1340, 1336, 1341, 1353, 1342,
+ 1343, 0, 1344, 1346, 1345, 1354, 1355, 1356, 1347, 1339,
+ 1348, 1346, 0, 1349, 1350, 1352, 0, 1343, 1351, 1357,
+ 1358, 1360, 1359, 1353, 1361, 1344, 1345, 1362, 1363, 1347,
+ 1354, 1355, 1356, 1352, 0, 1364, 1365, 1350, 1366, 1367,
+ 1351, 1356, 0, 1369, 1357, 1358, 1360, 1359, 1368, 1361,
+ 1370, 0, 1362, 1363, 1354, 1359, 0, 1358, 1371, 1355,
+ 1364, 1365, 1372, 1366, 1367, 1373, 0, 1357, 1369, 0,
+ 1374, 1375, 1376, 1368, 1378, 1370, 1363, 1379, 1377, 1380,
+ 1379, 1368, 1381, 1371, 1382, 0, 1366, 1372, 1385, 1384,
+
+ 1373, 1369, 1383, 1386, 1373, 1374, 1375, 1376, 1373, 1378,
+ 1387, 1388, 1379, 1377, 1380, 1390, 0, 1381, 1379, 1382,
+ 1372, 1391, 1389, 1385, 1384, 1389, 1374, 1383, 1386, 1375,
+ 1377, 1392, 1378, 1383, 1393, 1387, 1388, 1394, 1395, 1387,
+ 1390, 1382, 1384, 1396, 1388, 1385, 1391, 1389, 1397, 0,
+ 1398, 1399, 0, 1400, 0, 0, 1392, 1390, 1401, 1393,
+ 0, 1402, 1394, 1395, 1403, 0, 1404, 1406, 1396, 0,
+ 1405, 1407, 1408, 1397, 1395, 1398, 1399, 1393, 1400, 1394,
+ 1399, 1409, 1410, 1401, 1411, 1396, 1402, 1413, 1412, 1403,
+ 1401, 1404, 1406, 1414, 1400, 1405, 1407, 1408, 1415, 1404,
+
+ 1397, 1416, 1405, 0, 0, 1417, 1409, 1410, 0, 1411,
+ 1418, 1419, 1413, 1412, 1420, 1421, 1422, 1407, 1414, 1423,
+ 1406, 1412, 0, 1415, 1424, 1425, 1416, 1426, 1414, 1411,
+ 1417, 1413, 1427, 1415, 1428, 1418, 1419, 1429, 1430, 1420,
+ 1421, 1422, 1431, 1432, 1423, 1433, 1435, 1417, 1434, 1424,
+ 1425, 1436, 1426, 2334, 0, 1437, 1438, 1427, 1420, 1428,
+ 1418, 1439, 1429, 1430, 0, 2334, 1440, 1431, 1432, 1425,
+ 1433, 1435, 1441, 1434, 1442, 1426, 1436, 1434, 1433, 1431,
+ 1437, 1438, 1444, 1429, 1443, 1445, 1439, 0, 1446, 1430,
+ 1432, 1440, 0, 1447, 1439, 1449, 0, 1441, 1436, 1442,
+
+ 1448, 1450, 1437, 1438, 1451, 1452, 1453, 1444, 1455, 1443,
+ 1445, 1457, 1440, 1446, 0, 1441, 2336, 1443, 1447, 1459,
+ 1449, 1442, 1446, 0, 1454, 1448, 1450, 1445, 2336, 1451,
+ 1452, 1453, 1456, 1455, 1458, 1460, 1457, 1461, 1462, 1453,
+ 1463, 1455, 0, 1447, 1459, 0, 1464, 1465, 1448, 1454,
+ 0, 1451, 1459, 1452, 1466, 1467, 1454, 1456, 1468, 1458,
+ 1460, 1469, 1461, 1462, 1456, 1463, 1470, 1454, 1458, 0,
+ 1463, 1464, 1465, 1471, 1472, 1464, 1465, 0, 1473, 1466,
+ 1467, 1475, 1460, 1468, 1462, 1474, 1469, 1476, 1477, 1478,
+ 1469, 1470, 1479, 0, 1464, 1480, 0, 0, 1471, 1472,
+
+ 0, 0, 1466, 1473, 1467, 1481, 1475, 1468, 1470, 1483,
+ 1474, 1485, 1476, 1477, 1478, 1486, 1482, 1479, 1478, 1482,
+ 1480, 1473, 1471, 1488, 1484, 1475, 1474, 1484, 1487, 1489,
+ 1481, 1490, 1477, 2359, 1483, 1479, 1485, 1518, 0, 0,
+ 1486, 1482, 1483, 0, 0, 2359, 0, 0, 1488, 1484,
+ 0, 0, 0, 1487, 1489, 0, 1490, 0, 1485, 0,
+ 0, 0, 1518, 1487, 1490, 0, 0, 1488, 1491, 1491,
+ 1491, 1491, 1491, 1491, 1491, 1491, 1492, 1489, 1492, 1492,
+ 1492, 1492, 1492, 1492, 1492, 1492, 1493, 1493, 1493, 1495,
+ 1495, 1495, 0, 0, 0, 0, 0, 0, 1493, 1493,
+
+ 0, 1495, 1495, 0, 0, 0, 0, 0, 0, 0,
+ 1493, 0, 0, 1495, 1502, 1502, 1502, 1502, 1502, 1502,
+ 1502, 1502, 1503, 1520, 1503, 1503, 1503, 1503, 1503, 1503,
+ 1503, 1503, 1513, 1517, 1513, 1513, 1513, 1513, 1513, 1513,
+ 1513, 1513, 1519, 1517, 1521, 1522, 1523, 1524, 1520, 1525,
+ 1517, 1526, 1527, 1493, 1528, 1517, 1495, 1529, 1530, 1531,
+ 1532, 1533, 0, 1517, 1534, 1535, 0, 1519, 0, 1521,
+ 1522, 1523, 1524, 1536, 1525, 1519, 1526, 1527, 1537, 1528,
+ 1538, 0, 1529, 1530, 1531, 1532, 1533, 1529, 1523, 1534,
+ 1535, 1532, 1539, 1522, 1540, 1525, 1524, 1541, 1536, 1542,
+
+ 0, 1543, 1544, 1537, 1545, 1538, 1531, 1546, 1547, 1533,
+ 1538, 1530, 1535, 1548, 1549, 1550, 0, 1539, 1551, 1540,
+ 1552, 0, 1541, 0, 1542, 1539, 1543, 1544, 1553, 1545,
+ 1554, 0, 1546, 1547, 1555, 1544, 1556, 1557, 1548, 1549,
+ 1550, 1547, 1558, 1551, 0, 1552, 1548, 1543, 1550, 1552,
+ 0, 0, 1559, 1553, 1560, 1554, 1546, 0, 1561, 1555,
+ 1562, 1556, 1557, 1563, 1564, 1565, 0, 1558, 0, 1555,
+ 0, 1568, 1566, 0, 1567, 1558, 1554, 1559, 1569, 1560,
+ 0, 1570, 1556, 1561, 1571, 1562, 1572, 1573, 1563, 1564,
+ 1565, 1559, 1574, 1562, 1575, 1563, 1568, 1566, 1565, 1567,
+
+ 1576, 1577, 1578, 1569, 1561, 1566, 1570, 1567, 0, 1571,
+ 1579, 1572, 1573, 1564, 1580, 1581, 1582, 1574, 1573, 1575,
+ 1583, 1569, 1584, 1585, 1586, 1576, 1577, 1578, 1572, 1570,
+ 1587, 0, 0, 1576, 1588, 1579, 1589, 0, 1590, 1580,
+ 1581, 1582, 0, 1591, 1592, 1583, 0, 1584, 1585, 1586,
+ 1593, 1595, 1594, 0, 1581, 1587, 1583, 1579, 1596, 1588,
+ 1597, 1589, 1580, 1590, 1598, 1599, 1600, 1588, 1591, 1592,
+ 1602, 1585, 1601, 0, 1584, 1593, 1595, 1594, 1589, 1603,
+ 1591, 1594, 1604, 1596, 1605, 1597, 1606, 1593, 0, 1598,
+ 1599, 1600, 1607, 1598, 1608, 1602, 0, 1601, 1600, 1595,
+
+ 0, 0, 1611, 1597, 1603, 1596, 0, 1604, 1609, 1605,
+ 1610, 1606, 1599, 1600, 1612, 1601, 1613, 1607, 1614, 1608,
+ 0, 1603, 1615, 0, 1616, 1608, 1606, 1611, 1617, 1618,
+ 1619, 1604, 1620, 1609, 0, 1610, 1607, 1605, 1621, 1612,
+ 1623, 1613, 1609, 1614, 1622, 1610, 1624, 1615, 1614, 1616,
+ 1625, 1626, 0, 1617, 1618, 1619, 1627, 1620, 1628, 1615,
+ 1630, 1612, 1631, 1621, 0, 1623, 0, 1629, 1632, 1622,
+ 1616, 1624, 0, 1620, 1633, 1625, 1626, 1622, 1634, 1635,
+ 1636, 1627, 1637, 1628, 1626, 1630, 1638, 1631, 1639, 1627,
+ 1640, 1628, 1629, 1632, 1641, 1642, 1629, 1625, 1643, 1633,
+
+ 1632, 1644, 0, 1634, 1635, 1636, 1645, 1637, 1646, 1635,
+ 1647, 1638, 1648, 1639, 1649, 1640, 1650, 0, 1651, 1641,
+ 1642, 1654, 1652, 1643, 1634, 1652, 1644, 1639, 1655, 0,
+ 1657, 1645, 1656, 1646, 1644, 1647, 0, 1648, 0, 1649,
+ 0, 1650, 1640, 1651, 1643, 1653, 1654, 1652, 1653, 1658,
+ 1650, 1659, 1661, 1655, 1648, 1657, 1660, 1656, 1649, 1660,
+ 1655, 1657, 1662, 1654, 1663, 1656, 0, 1664, 0, 1665,
+ 1653, 1666, 0, 1667, 1658, 1668, 1659, 1661, 1658, 1671,
+ 1669, 1660, 1670, 0, 0, 1672, 1674, 1662, 1673, 1663,
+ 1675, 1659, 1664, 1661, 1665, 1676, 1666, 1664, 1667, 1679,
+
+ 1668, 1677, 1678, 0, 1671, 1669, 1662, 1670, 1663, 1669,
+ 1672, 1674, 1709, 1673, 0, 1675, 0, 1665, 0, 0,
+ 1676, 0, 1666, 1708, 1679, 1668, 1677, 1678, 1670, 1671,
+ 1673, 1678, 1674, 1672, 1677, 0, 0, 1709, 1675, 1680,
+ 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1691, 1708, 1691,
+ 1691, 1691, 1691, 1691, 1691, 1691, 1691, 1695, 1695, 1695,
+ 1695, 1695, 1695, 1695, 1695, 0, 0, 0, 0, 1708,
+ 1710, 1695, 1695, 0, 0, 0, 0, 0, 0, 1711,
+ 1695, 1695, 1695, 1695, 1695, 1695, 1702, 1702, 1702, 1702,
+ 1702, 1702, 1702, 1702, 1703, 1710, 1703, 1703, 1703, 1703,
+
+ 1703, 1703, 1703, 1703, 1711, 1712, 1713, 1714, 1715, 1716,
+ 1717, 1718, 1711, 1719, 0, 1720, 1721, 1722, 1710, 1723,
+ 1724, 1725, 1726, 1728, 1729, 1727, 1730, 0, 0, 1731,
+ 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1732, 1719, 1713,
+ 1720, 1721, 1722, 1733, 1723, 1724, 1725, 1726, 1728, 1729,
+ 1727, 1730, 1728, 1719, 1731, 1734, 1735, 1717, 1736, 1737,
+ 1738, 1720, 1732, 1723, 1721, 1727, 0, 1739, 1733, 1740,
+ 1741, 1742, 1743, 1744, 1746, 1745, 1747, 0, 1748, 0,
+ 1734, 1735, 1749, 1736, 1737, 1738, 0, 0, 1750, 1751,
+ 1753, 1733, 1739, 1752, 1740, 1741, 1742, 1743, 1744, 1746,
+
+ 1745, 1747, 1736, 1748, 1742, 1754, 1755, 1749, 0, 1756,
+ 0, 1740, 1745, 1750, 1751, 1753, 1757, 1758, 1752, 1759,
+ 1743, 0, 1760, 1741, 1761, 1763, 1752, 1762, 1764, 0,
+ 1754, 1755, 1766, 1753, 1756, 1749, 1765, 1767, 1768, 1769,
+ 0, 1757, 1758, 1771, 1759, 1770, 1756, 1760, 1754, 1761,
+ 1763, 1772, 1762, 1764, 1755, 1773, 1774, 1766, 1775, 1759,
+ 1776, 1765, 1767, 1768, 1769, 1763, 1767, 1777, 1771, 1778,
+ 1770, 1761, 1769, 1762, 1779, 1780, 1772, 1765, 1781, 1770,
+ 1773, 1774, 1782, 1775, 1768, 1776, 1783, 1784, 1773, 1776,
+ 1785, 1771, 1777, 1786, 1778, 1787, 0, 1788, 0, 1779,
+
+ 1780, 0, 1790, 1781, 1774, 0, 1779, 1782, 1791, 1777,
+ 1789, 1783, 1784, 1792, 1793, 1785, 1794, 0, 1786, 1798,
+ 1787, 1780, 1788, 1782, 0, 0, 1788, 1790, 1795, 1796,
+ 1785, 1795, 1796, 1791, 1784, 1789, 0, 1797, 1792, 1793,
+ 1786, 1794, 1789, 1793, 1798, 1794, 1799, 1801, 1787, 1794,
+ 1790, 1805, 1800, 1795, 1796, 1800, 0, 1802, 1798, 1807,
+ 1802, 1792, 1797, 1806, 1803, 1804, 1797, 1803, 1804, 0,
+ 0, 1799, 1801, 1809, 1810, 1808, 1805, 1800, 1811, 1812,
+ 1813, 1799, 1802, 1808, 1807, 1814, 1816, 1815, 1806, 1803,
+ 1804, 1849, 1817, 1806, 1805, 1801, 0, 0, 1809, 1810,
+
+ 1808, 1807, 0, 1811, 1812, 1813, 1810, 0, 0, 0,
+ 1814, 1816, 1815, 0, 1814, 1812, 1849, 1817, 1848, 1809,
+ 1815, 1818, 1818, 1818, 1818, 1818, 1818, 1818, 1818, 0,
+ 0, 0, 1816, 1817, 1829, 1829, 1829, 1829, 1829, 1829,
+ 1829, 1829, 1830, 1848, 1830, 1830, 1830, 1830, 1830, 1830,
+ 1830, 1830, 1834, 1848, 1834, 1834, 1834, 1834, 1834, 1834,
+ 1834, 1834, 1834, 0, 0, 0, 0, 0, 1834, 1834,
+ 0, 0, 0, 0, 0, 0, 1850, 1834, 1834, 1834,
+ 1834, 1834, 1834, 1843, 1851, 1843, 1843, 1843, 1843, 1843,
+ 1843, 1843, 1843, 1847, 1847, 1847, 1847, 1847, 1847, 1847,
+
+ 1847, 1850, 1852, 1853, 1854, 1855, 1856, 1847, 1847, 1851,
+ 1857, 0, 1858, 1859, 1860, 1861, 1847, 1847, 1847, 1847,
+ 1847, 1847, 1862, 1863, 1864, 1865, 1866, 1852, 1853, 1854,
+ 1855, 1856, 0, 1867, 1868, 1857, 1853, 1858, 1859, 1860,
+ 1861, 1869, 1870, 1871, 1858, 1872, 1873, 1862, 1863, 1864,
+ 1865, 1866, 1875, 1874, 1854, 1876, 1877, 1865, 1867, 1868,
+ 1878, 0, 1879, 1880, 1881, 1882, 1869, 1870, 1871, 0,
+ 1872, 1873, 1883, 1884, 1885, 0, 1868, 1875, 1874, 1870,
+ 1876, 1877, 1886, 1869, 1874, 1878, 1871, 1879, 1880, 1881,
+ 1882, 1887, 1888, 1889, 1873, 1890, 1891, 1883, 1884, 1885,
+
+ 1881, 1892, 1893, 1878, 1894, 1882, 1895, 1886, 1896, 1877,
+ 1897, 0, 1894, 1898, 1899, 1884, 1887, 1888, 1889, 0,
+ 1890, 1891, 1900, 0, 1901, 1902, 1892, 1893, 1890, 1894,
+ 1903, 1895, 1887, 1896, 1904, 1897, 1888, 1893, 1898, 1899,
+ 1905, 1897, 1906, 1907, 1898, 1899, 1908, 1900, 1892, 1901,
+ 1902, 1900, 1895, 1909, 1910, 1903, 1911, 0, 1912, 1904,
+ 1913, 1912, 1914, 0, 0, 1905, 0, 1906, 1907, 0,
+ 0, 1908, 1901, 1902, 0, 1915, 1916, 1917, 1909, 1910,
+ 1919, 1911, 1909, 1912, 1918, 1913, 1920, 1914, 1905, 1906,
+ 1954, 1907, 1955, 1958, 1908, 1914, 0, 0, 0, 1911,
+
+ 1915, 1916, 1917, 1910, 1959, 1919, 0, 0, 0, 1918,
+ 0, 1920, 0, 0, 0, 1954, 0, 1955, 1958, 1917,
+ 0, 1919, 1916, 1954, 0, 0, 1918, 0, 0, 1959,
+ 1920, 1934, 1934, 1934, 1934, 1934, 1934, 1934, 1934, 1938,
+ 1938, 1938, 1938, 1938, 1938, 1938, 1938, 1939, 0, 1939,
+ 1939, 1939, 1939, 1939, 1939, 1939, 1939, 1939, 0, 0,
+ 0, 0, 1960, 1939, 1939, 0, 0, 0, 0, 0,
+ 0, 0, 1939, 1939, 1939, 1939, 1939, 1939, 1948, 1948,
+ 1948, 1948, 1948, 1948, 1948, 1948, 1949, 1960, 1949, 1949,
+ 1949, 1949, 1949, 1949, 1949, 1949, 1953, 0, 1953, 1953,
+
+ 1953, 1953, 1953, 1953, 1953, 1953, 1953, 1956, 1957, 1961,
+ 1963, 0, 1953, 1953, 1962, 1964, 0, 1965, 1953, 1966,
+ 1967, 1953, 1953, 1953, 1953, 1953, 1953, 0, 1968, 1969,
+ 1970, 0, 1956, 1957, 1961, 1963, 1956, 1971, 1972, 1962,
+ 1964, 1957, 1965, 1973, 1966, 1967, 1974, 1975, 1976, 1966,
+ 1977, 1978, 1961, 1968, 1969, 1970, 1962, 1979, 1981, 1983,
+ 1969, 1980, 1971, 1972, 0, 0, 1982, 1970, 1973, 1982,
+ 1984, 1974, 1975, 1976, 1985, 1977, 1978, 1986, 1987, 1989,
+ 0, 0, 1979, 1981, 1983, 1972, 1980, 1974, 1988, 1977,
+ 1978, 1982, 1980, 1979, 1990, 1984, 0, 1991, 0, 1985,
+
+ 0, 1976, 1986, 1987, 1989, 1981, 1983, 1992, 1994, 1987,
+ 1993, 1995, 1984, 1988, 0, 0, 1996, 0, 2032, 1990,
+ 2034, 1985, 1991, 1990, 1986, 1990, 2033, 2036, 1989, 2040,
+ 1988, 0, 1992, 1994, 0, 1993, 1995, 0, 0, 1991,
+ 1992, 1996, 1993, 2032, 0, 2034, 0, 0, 1995, 0,
+ 0, 2033, 2036, 0, 2040, 0, 1994, 2009, 2009, 2009,
+ 2009, 2009, 2009, 2009, 2009, 2013, 2033, 2013, 2013, 2013,
+ 2013, 2013, 2013, 2013, 2013, 2026, 2026, 2026, 2026, 2026,
+ 2026, 2026, 2026, 2030, 2030, 2030, 2030, 2030, 2030, 2030,
+ 2030, 2035, 2037, 0, 2038, 2026, 2031, 0, 2031, 2031,
+
+ 2031, 2031, 2031, 2031, 2031, 2031, 2031, 0, 0, 2039,
+ 2041, 2042, 2031, 2031, 2043, 2044, 2035, 2037, 2031, 2038,
+ 2045, 2031, 2031, 2031, 2031, 2031, 2031, 2038, 2046, 2047,
+ 2048, 2049, 2037, 2035, 2039, 2041, 2042, 2050, 0, 2043,
+ 2044, 2051, 0, 2041, 2052, 2045, 0, 2054, 0, 2053,
+ 2055, 2056, 2057, 2046, 2047, 2048, 2049, 2039, 0, 2048,
+ 2058, 0, 2050, 2045, 2059, 2061, 2051, 2046, 2062, 2052,
+ 0, 2047, 2054, 2049, 2053, 2055, 2056, 2057, 2060, 2054,
+ 2099, 2100, 2056, 2051, 2101, 2058, 2052, 2102, 2053, 2059,
+ 2061, 0, 2055, 2062, 2105, 2057, 0, 0, 0, 0,
+
+ 0, 0, 0, 2060, 0, 2099, 2100, 0, 2058, 2101,
+ 0, 2059, 2102, 0, 0, 0, 2062, 2101, 0, 2105,
+ 0, 2060, 2081, 2081, 2081, 2081, 2081, 2081, 2081, 2081,
+ 2082, 0, 2082, 2082, 2082, 2082, 2082, 2082, 2082, 2082,
+ 2093, 2093, 2093, 2093, 2093, 2093, 2093, 2093, 2097, 2103,
+ 2097, 2097, 2097, 2097, 2097, 2097, 2097, 2097, 2104, 2106,
+ 2093, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 0, 2112,
+ 2113, 2114, 0, 2116, 2103, 0, 2115, 2117, 0, 2119,
+ 2118, 2120, 2163, 2104, 2106, 2160, 2107, 2108, 2109, 2110,
+ 2111, 2112, 2113, 2108, 0, 0, 2114, 2103, 2116, 0,
+
+ 2104, 2115, 2117, 2114, 2119, 2118, 2120, 2163, 0, 0,
+ 2160, 0, 2111, 0, 2116, 2115, 2118, 0, 2160, 2138,
+ 2119, 2138, 2138, 2138, 2138, 2138, 2138, 2138, 2138, 2120,
+ 2157, 2157, 2157, 2157, 2157, 2157, 2157, 2157, 2158, 2159,
+ 2158, 2158, 2158, 2158, 2158, 2158, 2158, 2158, 2161, 2162,
+ 2165, 2164, 2166, 2167, 2168, 2166, 0, 2169, 2170, 2171,
+ 2211, 2212, 2214, 0, 2159, 2192, 2192, 2192, 2192, 2192,
+ 2192, 2192, 2192, 2161, 2162, 2165, 2164, 2166, 2167, 2168,
+ 2159, 2164, 2169, 2170, 2171, 2211, 2212, 2214, 2162, 0,
+ 0, 0, 2171, 2212, 2213, 2215, 2161, 2165, 2168, 2193,
+
+ 2169, 2193, 2193, 2193, 2193, 2193, 2193, 2193, 2193, 2209,
+ 0, 2209, 2209, 2209, 2209, 2209, 2209, 2209, 2209, 2213,
+ 2215, 2216, 2218, 2217, 2219, 2220, 2239, 2239, 2239, 2239,
+ 2239, 2239, 2239, 2239, 2262, 2215, 2263, 0, 2269, 0,
+ 2310, 2213, 2266, 2265, 0, 0, 2216, 2218, 2217, 2219,
+ 2220, 0, 0, 0, 0, 2264, 0, 2220, 0, 2262,
+ 0, 2263, 2218, 2269, 2219, 2310, 2267, 2266, 2265, 2216,
+ 2217, 2260, 2260, 2260, 2260, 2260, 2260, 2260, 2260, 2261,
+ 2264, 2261, 2261, 2261, 2261, 2261, 2261, 2261, 2261, 2265,
+ 2266, 2267, 2268, 2307, 2306, 2308, 2309, 0, 2264, 2267,
+
+ 2286, 2286, 2286, 2286, 2286, 2286, 2286, 2286, 2304, 2304,
+ 2304, 2304, 2304, 2304, 2304, 2304, 0, 2268, 2307, 2306,
+ 2308, 2309, 2339, 2340, 2268, 2306, 2307, 0, 2304, 2338,
+ 2338, 2338, 2338, 2338, 2338, 2338, 2338, 2341, 2342, 2362,
+ 2363, 2308, 2365, 2364, 2309, 0, 0, 2339, 2340, 2338,
+ 2375, 2376, 2340, 2377, 2379, 2380, 0, 2381, 0, 0,
+ 0, 2339, 2341, 2342, 2362, 2363, 0, 2365, 2364, 0,
+ 2341, 2342, 2364, 0, 0, 2375, 2376, 0, 2377, 2379,
+ 2380, 2363, 2381, 0, 0, 0, 2362, 0, 0, 0,
+ 0, 0, 0, 0, 2377, 0, 0, 0, 2376, 0,
+
+ 0, 0, 2380, 2383, 2383, 2383, 2383, 2383, 2383, 2383,
+ 2383, 2383, 2383, 2383, 2383, 2383, 2384, 2384, 2384, 2384,
+ 2384, 2384, 2384, 2384, 2384, 2384, 2384, 2384, 2384, 2385,
+ 2385, 2385, 2385, 2385, 0, 2385, 2385, 0, 2385, 2385,
+ 2386, 2386, 2386, 0, 0, 2386, 2387, 2387, 2387, 2387,
+ 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2388,
+ 2388, 2388, 0, 0, 2388, 2389, 2389, 2389, 0, 0,
+ 2389, 2390, 0, 2390, 0, 0, 2390, 2391, 2391, 2391,
+ 0, 0, 2391, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
+ 2392, 2392, 2392, 2392, 2392, 2392, 2393, 0, 0, 0,
+
+ 2393, 2393, 0, 2393, 2393, 2394, 2394, 2394, 0, 0,
+ 2394, 2395, 0, 2395, 0, 0, 2395, 2395, 2395, 0,
+ 0, 2395, 2396, 0, 2396, 0, 0, 2396, 2397, 2397,
+ 2397, 0, 0, 2397, 2398, 2398, 2398, 0, 0, 2398,
+ 2399, 2399, 2399, 0, 0, 2399, 2400, 2400, 2400, 2400,
+ 0, 2400, 2400, 0, 2400, 2400, 2401, 2401, 0, 0,
+ 0, 2401, 2401, 2402, 2402, 2402, 0, 0, 2402, 2403,
+ 2403, 0, 0, 0, 0, 2403, 2404, 0, 2404, 0,
+ 0, 2404, 2404, 2404, 0, 0, 2404, 2405, 2405, 2405,
+ 0, 0, 2405, 2406, 2406, 2406, 0, 0, 2406, 2407,
+
+ 0, 2407, 0, 0, 2407, 2408, 2408, 2408, 0, 0,
+ 2408, 2409, 2409, 2409, 0, 0, 2409, 2410, 2410, 2410,
+ 0, 0, 2410, 2411, 0, 2411, 0, 2411, 2411, 2412,
+ 0, 2412, 0, 0, 2412, 2412, 2412, 0, 0, 2412,
+ 2413, 0, 2413, 0, 0, 2413, 2413, 2413, 0, 0,
+ 2413, 2414, 2414, 2414, 0, 0, 2414, 2415, 0, 2415,
+ 0, 0, 2415, 2416, 2416, 2416, 0, 0, 2416, 2417,
+ 0, 2417, 0, 0, 2417, 2418, 0, 2418, 2418, 2418,
+ 0, 0, 2418, 2419, 2419, 2419, 0, 0, 2419, 2420,
+ 2420, 2420, 0, 0, 2420, 2421, 2421, 2421, 0, 0,
+
+ 2421, 2422, 2422, 2422, 0, 2422, 2422, 2423, 0, 2423,
+ 0, 0, 2423, 2424, 0, 2424, 0, 0, 2424, 2424,
+ 2424, 0, 0, 2424, 2425, 2425, 2425, 0, 0, 2425,
+ 2426, 2426, 2426, 0, 0, 2426, 2427, 2427, 2427, 0,
+ 0, 2427, 2428, 2428, 2428, 0, 0, 2428, 2429, 2429,
+ 2429, 0, 0, 2429, 2430, 2430, 2430, 0, 0, 2430,
+ 2431, 2431, 2431, 0, 0, 2431, 2432, 0, 2432, 0,
+ 0, 2432, 2433, 2433, 2433, 0, 0, 2433, 2434, 2434,
+ 2434, 0, 0, 2434, 2435, 0, 2435, 0, 2435, 2435,
+ 2436, 2436, 2436, 0, 2436, 2436, 2437, 0, 2437, 0,
+
+ 0, 2437, 2438, 0, 2438, 2438, 2438, 0, 2438, 2438,
+ 2439, 2439, 2439, 0, 2439, 2439, 2440, 2440, 2440, 0,
+ 0, 2440, 2441, 2441, 2441, 0, 0, 2441, 2442, 2442,
+ 2442, 0, 0, 2442, 2443, 0, 2443, 0, 0, 2443,
+ 2444, 2444, 2444, 0, 0, 2444, 2445, 0, 2445, 0,
+ 0, 2445, 2446, 2446, 2446, 0, 0, 2446, 2447, 0,
+ 2447, 0, 0, 2447, 2448, 2448, 2448, 0, 0, 2448,
+ 2449, 2449, 2449, 0, 0, 2449, 2450, 2450, 2450, 0,
+ 0, 2450, 2451, 2451, 2451, 0, 0, 2451, 2452, 2452,
+ 2452, 0, 2452, 2452, 2453, 2453, 2453, 0, 2453, 2453,
+
+ 2454, 2454, 2454, 0, 2454, 2454, 2455, 2455, 2455, 0,
+ 2455, 2455, 2456, 0, 2456, 0, 0, 2456, 2457, 2457,
+ 2457, 0, 0, 2457, 2458, 2458, 2458, 0, 0, 2458,
+ 2459, 2459, 2459, 0, 0, 2459, 2460, 2460, 2460, 0,
+ 0, 2460, 2461, 2461, 2461, 0, 0, 2461, 2462, 2462,
+ 2462, 0, 0, 2462, 2463, 2463, 2463, 0, 0, 2463,
+ 2464, 2464, 2464, 0, 0, 2464, 2465, 2465, 2465, 0,
+ 0, 2465, 2466, 2466, 2466, 0, 0, 2466, 2467, 0,
+ 2467, 0, 0, 2467, 2468, 2468, 2468, 0, 0, 2468,
+ 2469, 2469, 2469, 0, 0, 2469, 2470, 0, 2470, 0,
+
+ 2470, 2470, 2471, 2471, 2471, 0, 2471, 2471, 2472, 0,
+ 2472, 0, 0, 2472, 2473, 2473, 2473, 0, 2473, 2473,
+ 2474, 0, 2474, 0, 0, 2474, 2475, 2475, 2475, 0,
+ 2475, 2475, 2476, 2476, 2476, 0, 2476, 2476, 2477, 2477,
+ 2477, 0, 0, 2477, 2478, 2478, 2478, 0, 0, 2478,
+ 2479, 2479, 2479, 0, 0, 2479, 2480, 0, 2480, 0,
+ 0, 2480, 2481, 2481, 2481, 0, 0, 2481, 2482, 0,
+ 2482, 0, 0, 2482, 2483, 2483, 2483, 0, 0, 2483,
+ 2484, 0, 2484, 0, 0, 2484, 2485, 2485, 2485, 0,
+ 0, 2485, 2486, 0, 2486, 0, 0, 2486, 2487, 2487,
+
+ 2487, 0, 0, 2487, 2488, 2488, 2488, 0, 0, 2488,
+ 2489, 2489, 2489, 0, 0, 2489, 2490, 2490, 2490, 0,
+ 0, 2490, 2491, 2491, 2491, 0, 2491, 2491, 2492, 2492,
+ 2492, 0, 2492, 2492, 2493, 2493, 2493, 0, 2493, 2493,
+ 2494, 2494, 2494, 0, 2494, 2494, 2495, 2495, 2495, 0,
+ 2495, 2495, 2496, 2496, 2496, 0, 2496, 2496, 2497, 0,
+ 2497, 0, 0, 2497, 2498, 2498, 2498, 0, 0, 2498,
+ 2499, 2499, 2499, 0, 0, 2499, 2500, 2500, 2500, 0,
+ 0, 2500, 2501, 2501, 2501, 0, 0, 2501, 2502, 2502,
+ 2502, 0, 0, 2502, 2503, 2503, 2503, 0, 0, 2503,
+
+ 2504, 2504, 2504, 0, 0, 2504, 2505, 2505, 2505, 0,
+ 0, 2505, 2506, 2506, 2506, 0, 0, 2506, 2507, 2507,
+ 2507, 0, 0, 2507, 2508, 2508, 2508, 0, 0, 2508,
+ 2509, 2509, 2509, 0, 0, 2509, 2510, 0, 2510, 0,
+ 0, 2510, 2511, 0, 2511, 2511, 2511, 0, 0, 2511,
+ 2512, 2512, 2512, 0, 0, 2512, 2513, 2513, 2513, 0,
+ 0, 2513, 2514, 0, 2514, 0, 2514, 2514, 2515, 2515,
+ 2515, 0, 2515, 2515, 2516, 0, 2516, 0, 0, 2516,
+ 2517, 2517, 2517, 0, 2517, 2517, 2518, 0, 2518, 0,
+ 0, 2518, 2519, 2519, 2519, 0, 2519, 2519, 2520, 0,
+
+ 2520, 0, 0, 2520, 2521, 2521, 2521, 0, 2521, 2521,
+ 2522, 2522, 2522, 0, 2522, 2522, 2523, 2523, 2523, 0,
+ 0, 2523, 2524, 2524, 2524, 0, 0, 2524, 2525, 2525,
+ 2525, 0, 0, 2525, 2526, 0, 2526, 0, 0, 2526,
+ 2527, 2527, 2527, 0, 0, 2527, 2528, 0, 2528, 0,
+ 0, 2528, 2529, 2529, 2529, 0, 0, 2529, 2530, 0,
+ 2530, 0, 0, 2530, 2531, 2531, 2531, 0, 0, 2531,
+ 2532, 0, 2532, 0, 0, 2532, 2533, 2533, 2533, 0,
+ 0, 2533, 2534, 0, 2534, 0, 0, 2534, 2535, 2535,
+ 2535, 0, 0, 2535, 2536, 2536, 2536, 0, 0, 2536,
+
+ 2537, 2537, 2537, 0, 0, 2537, 2538, 2538, 2538, 0,
+ 0, 2538, 2539, 2539, 2539, 0, 2539, 2539, 2540, 2540,
+ 2540, 0, 2540, 2540, 2541, 2541, 2541, 0, 2541, 2541,
+ 2542, 2542, 2542, 0, 2542, 2542, 2543, 2543, 2543, 0,
+ 2543, 2543, 2544, 2544, 2544, 0, 2544, 2544, 2545, 2545,
+ 2545, 0, 2545, 2545, 2546, 2546, 2546, 0, 2546, 2546,
+ 2547, 0, 2547, 0, 0, 2547, 2548, 0, 2548, 2548,
+ 2548, 0, 2548, 2548, 2549, 2549, 2549, 0, 0, 2549,
+ 2550, 2550, 2550, 0, 0, 2550, 2551, 2551, 2551, 0,
+ 0, 2551, 2552, 2552, 2552, 0, 0, 2552, 2553, 2553,
+
+ 2553, 0, 0, 2553, 2554, 2554, 2554, 0, 0, 2554,
+ 2555, 2555, 2555, 0, 0, 2555, 2556, 2556, 2556, 0,
+ 0, 2556, 2557, 2557, 2557, 0, 0, 2557, 2558, 2558,
+ 2558, 0, 0, 2558, 2559, 2559, 2559, 0, 0, 2559,
+ 2560, 2560, 2560, 0, 0, 2560, 2561, 2561, 2561, 0,
+ 0, 2561, 2562, 2562, 2562, 0, 0, 2562, 2563, 0,
+ 2563, 0, 0, 2563, 2564, 2564, 2564, 0, 0, 2564,
+ 2565, 2565, 2565, 0, 0, 2565, 2566, 0, 2566, 0,
+ 2566, 2566, 2567, 2567, 2567, 0, 2567, 2567, 2568, 0,
+ 2568, 0, 0, 2568, 2569, 2569, 2569, 0, 2569, 2569,
+
+ 2570, 0, 2570, 0, 0, 2570, 2571, 2571, 2571, 0,
+ 2571, 2571, 2572, 0, 2572, 0, 0, 2572, 2573, 2573,
+ 2573, 0, 2573, 2573, 2574, 0, 2574, 0, 0, 2574,
+ 2575, 2575, 2575, 0, 2575, 2575, 2576, 2576, 2576, 0,
+ 2576, 2576, 2577, 2577, 2577, 2577, 2577, 0, 2577, 2577,
+ 0, 2577, 2577, 2578, 2578, 2578, 0, 0, 2578, 2579,
+ 2579, 2579, 0, 0, 2579, 2580, 2580, 2580, 0, 0,
+ 2580, 2581, 0, 2581, 0, 0, 2581, 2582, 2582, 2582,
+ 0, 0, 2582, 2583, 0, 2583, 0, 0, 2583, 2584,
+ 2584, 2584, 0, 0, 2584, 2585, 0, 2585, 0, 0,
+
+ 2585, 2586, 2586, 2586, 0, 0, 2586, 2587, 0, 2587,
+ 0, 0, 2587, 2588, 2588, 2588, 0, 0, 2588, 2589,
+ 0, 2589, 0, 0, 2589, 2590, 2590, 2590, 0, 0,
+ 2590, 2591, 0, 2591, 0, 0, 2591, 2592, 2592, 2592,
+ 0, 0, 2592, 2593, 2593, 2593, 0, 0, 2593, 2594,
+ 2594, 2594, 0, 0, 2594, 2595, 2595, 2595, 0, 0,
+ 2595, 2596, 2596, 2596, 0, 2596, 2596, 2597, 2597, 2597,
+ 0, 2597, 2597, 2598, 2598, 2598, 0, 2598, 2598, 2599,
+ 2599, 2599, 0, 2599, 2599, 2600, 2600, 2600, 0, 2600,
+ 2600, 2601, 2601, 2601, 0, 2601, 2601, 2602, 2602, 2602,
+
+ 0, 2602, 2602, 2603, 2603, 2603, 0, 2603, 2603, 2604,
+ 2604, 2604, 0, 2604, 2604, 2605, 2605, 2605, 0, 2605,
+ 2605, 2606, 0, 2606, 0, 0, 2606, 2607, 2607, 2607,
+ 2607, 2607, 0, 2607, 2607, 0, 2607, 2607, 2608, 2608,
+ 2608, 0, 0, 2608, 2609, 2609, 2609, 0, 0, 2609,
+ 2610, 2610, 2610, 0, 0, 2610, 2611, 0, 2611, 0,
+ 0, 2611, 2612, 2612, 2612, 0, 0, 2612, 2613, 0,
+ 2613, 0, 0, 2613, 2614, 2614, 2614, 0, 0, 2614,
+ 2615, 0, 2615, 0, 0, 2615, 2616, 2616, 2616, 0,
+ 0, 2616, 2617, 0, 2617, 0, 0, 2617, 2618, 2618,
+
+ 2618, 0, 0, 2618, 2619, 0, 2619, 0, 0, 2619,
+ 2620, 2620, 2620, 0, 0, 2620, 2621, 0, 2621, 0,
+ 0, 2621, 2622, 2622, 2622, 0, 0, 2622, 2623, 0,
+ 2623, 0, 0, 2623, 2624, 2624, 2624, 0, 0, 2624,
+ 2625, 2625, 2625, 0, 0, 2625, 2626, 0, 2626, 0,
+ 2626, 2626, 2627, 2627, 2627, 0, 2627, 2627, 2628, 0,
+ 2628, 0, 0, 2628, 2629, 2629, 2629, 0, 2629, 2629,
+ 2630, 0, 2630, 0, 0, 2630, 2631, 2631, 2631, 0,
+ 2631, 2631, 2632, 0, 2632, 0, 0, 2632, 2633, 2633,
+ 2633, 0, 2633, 2633, 2634, 0, 2634, 0, 0, 2634,
+
+ 2635, 2635, 2635, 0, 2635, 2635, 2636, 0, 2636, 0,
+ 0, 2636, 2637, 2637, 2637, 0, 2637, 2637, 2638, 2638,
+ 2638, 0, 2638, 2638, 2639, 2639, 2639, 2639, 2639, 0,
+ 2639, 2639, 0, 2639, 2639, 2640, 2640, 2640, 0, 0,
+ 2640, 2641, 0, 2641, 0, 0, 2641, 2642, 0, 2642,
+ 0, 0, 2642, 2643, 0, 2643, 0, 0, 2643, 2644,
+ 0, 2644, 0, 0, 2644, 2645, 0, 2645, 0, 0,
+ 2645, 2646, 0, 2646, 0, 0, 2646, 2647, 0, 2647,
+ 0, 0, 2647, 2648, 2648, 2648, 0, 0, 2648, 2649,
+ 0, 2649, 0, 0, 2649, 2650, 2650, 2650, 0, 0,
+
+ 2650, 2651, 2651, 2651, 0, 0, 2651, 2652, 0, 2652,
+ 0, 2652, 2652, 2653, 2653, 2653, 0, 2653, 2653, 2654,
+ 0, 2654, 0, 2654, 2654, 2655, 2655, 2655, 0, 2655,
+ 2655, 2656, 0, 2656, 0, 2656, 2656, 2657, 2657, 2657,
+ 0, 2657, 2657, 2658, 0, 2658, 0, 2658, 2658, 2659,
+ 2659, 2659, 0, 2659, 2659, 2660, 0, 2660, 0, 2660,
+ 2660, 2661, 2661, 2661, 0, 2661, 2661, 2662, 0, 2662,
+ 0, 2662, 2662, 2663, 2663, 2663, 0, 2663, 2663, 2664,
+ 0, 2664, 0, 0, 2664, 2665, 0, 2665, 0, 0,
+ 2665, 2666, 0, 2666, 0, 0, 2666, 2667, 0, 2667,
+
+ 0, 0, 2667, 2668, 0, 2668, 0, 0, 2668, 2669,
+ 0, 2669, 0, 0, 2669, 2670, 0, 2670, 0, 0,
+ 2670, 2671, 0, 2671, 0, 0, 2671, 2672, 0, 2672,
+ 0, 0, 2672, 2673, 2673, 2673, 0, 0, 2673, 2674,
+ 0, 2674, 0, 2674, 2674, 2675, 0, 2675, 0, 2675,
+ 2675, 2676, 0, 2676, 0, 2676, 2676, 2677, 0, 2677,
+ 0, 2677, 2677, 2678, 0, 2678, 0, 2678, 2678, 2679,
+ 0, 2679, 0, 2679, 2679, 2680, 0, 2680, 0, 2680,
+ 2680, 2681, 2681, 2681, 0, 2681, 2681, 2682, 0, 2682,
+ 0, 2682, 2682, 2683, 0, 2683, 0, 0, 2683, 2684,
+
+ 0, 2684, 0, 0, 2684, 2685, 0, 2685, 0, 2685,
+ 2685, 2686, 0, 2686, 0, 2686, 2686, 2687, 0, 2687,
+ 0, 2687, 2687, 2688, 0, 2688, 0, 2688, 2688, 2689,
+ 0, 2689, 0, 2689, 2689, 2690, 0, 2690, 0, 2690,
+ 2690, 2691, 0, 2691, 0, 2691, 2691, 2692, 0, 2692,
+ 0, 2692, 2692, 2693, 0, 2693, 0, 2693, 2693, 2694,
+ 0, 2694, 0, 2694, 2694, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382, 2382,
+ 2382, 2382, 2382, 2382, 2382
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static const flex_int32_t yy_rule_can_match_eol[413] =
+ { 0,
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, };
+
+static const flex_int16_t yy_rule_linenum[412] =
+ { 0,
+ 260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 275, 276, 277, 278, 279,
+ 280, 281, 282, 283, 284, 285, 286, 287, 288, 289,
+ 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
+ 300, 302, 304, 305, 306, 307, 309, 312, 313, 314,
+ 317, 318, 320, 321, 322, 323, 324, 325, 326, 327,
+ 328, 329, 330, 331, 333, 335, 336, 337, 338, 340,
+ 342, 343, 344, 345, 346, 347, 348, 350, 351, 353,
+ 354, 355, 356, 357, 358, 359, 360, 361, 362, 363,
+ 364, 365, 366, 367, 370, 371, 372, 374, 375, 376,
+
+ 377, 378, 379, 380, 381, 383, 384, 386, 387, 390,
+ 391, 392, 395, 396, 397, 398, 399, 400, 401, 404,
+ 405, 406, 407, 409, 411, 415, 416, 417, 420, 421,
+ 423, 424, 425, 426, 429, 431, 432, 433, 435, 437,
+ 438, 441, 442, 443, 445, 447, 449, 452, 454, 455,
+ 457, 459, 460, 463, 464, 465, 466, 467, 469, 470,
+ 471, 475, 476, 478, 480, 482, 484, 485, 487, 488,
+ 490, 491, 493, 494, 495, 497, 498, 500, 502, 503,
+ 504, 505, 506, 509, 511, 514, 517, 519, 520, 522,
+ 525, 527, 529, 533, 534, 535, 536, 538, 539, 541,
+
+ 542, 547, 548, 549, 550, 553, 554, 555, 556, 557,
+ 558, 559, 560, 561, 562, 563, 564, 565, 566, 567,
+ 568, 569, 572, 573, 574, 575, 576, 577, 579, 580,
+ 582, 584, 585, 587, 588, 589, 590, 591, 592, 593,
+ 596, 599, 601, 602, 605, 606, 608, 609, 612, 615,
+ 617, 619, 621, 623, 625, 627, 629, 630, 632, 635,
+ 638, 641, 644, 645, 647, 649, 650, 652, 654, 656,
+ 659, 660, 664, 665, 666, 667, 668, 669, 670, 671,
+ 672, 673, 674, 675, 676, 677, 678, 679, 680, 682,
+ 683, 684, 685, 686, 687, 688, 689, 690, 691, 692,
+
+ 693, 694, 695, 696, 697, 700, 701, 702, 703, 704,
+ 706, 708, 710, 711, 714, 716, 718, 719, 720, 721,
+ 722, 723, 724, 725, 726, 727, 728, 729, 730, 731,
+ 732, 733, 734, 735, 736, 737, 738, 741, 742, 743,
+ 744, 745, 746, 749, 752, 754, 755, 756, 757, 758,
+ 759, 760, 761, 762, 763, 764, 765, 766, 767, 768,
+ 769, 770, 773, 775, 778, 779, 782, 785, 786, 788,
+ 789, 791, 793, 795, 797, 798, 799, 800, 801, 802,
+ 805, 807, 810, 811, 812, 815, 816, 818, 820, 822,
+ 823, 825, 826, 829, 831, 833, 838, 844, 849, 859,
+
+ 872, 877, 883, 888, 893, 897, 902, 903, 904, 907,
+ 916
+ } ;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "scanner.l"
+/*
+ * Copyright (c) 2007-2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+#line 12 "scanner.l"
+
+#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>
+#include <rule.h>
+#include <parser.h>
+#include "parser_bison.h"
+
+#define YY_NO_INPUT
+
+/*
+ * Work around flex behaviour when reaching the end of buffer: normally, flex
+ * regexes are greedy, when reaching the end of buffer however it tries to
+ * match whatever is left in the buffer and only backs up in case it doesn't
+ * match *any* pattern. Since we accept unquoted strings, this means any partial
+ * token will be recognized as string.
+ *
+ * Make sure to only pass input to flex linewise to avoid this.
+ */
+#define YY_INPUT(buf,result,max_size) \
+{ \
+ result = 0; \
+ errno = 0; \
+ \
+ while (result < max_size) { \
+ int chr = fgetc(yyin); \
+ \
+ if (chr != EOF) { \
+ buf[result++] = chr; \
+ if (chr == '\n' || chr == ' ') \
+ break; \
+ continue; \
+ } \
+ \
+ if (ferror(yyin)) { \
+ if (errno != EINTR) { \
+ YY_FATAL_ERROR("input in flex scanner failed"); \
+ break; \
+ } \
+ errno = 0; \
+ clearerr(yyin); \
+ } \
+ break; \
+ } \
+}
+
+static void scanner_pop_buffer(yyscan_t scanner);
+
+
+static void init_pos(struct input_descriptor *indesc)
+{
+ indesc->lineno = 1;
+ indesc->column = 1;
+ indesc->token_offset = 0;
+ indesc->line_offset = 0;
+}
+
+static void update_pos(struct parser_state *state, struct location *loc,
+ int len)
+{
+ loc->indesc = state->indesc;
+ loc->first_line = state->indesc->lineno;
+ loc->last_line = state->indesc->lineno;
+ loc->first_column = state->indesc->column;
+ loc->last_column = state->indesc->column + len - 1;
+ state->indesc->column += len;
+}
+
+static void update_offset(struct parser_state *state, struct location *loc,
+ unsigned int len)
+{
+ state->indesc->token_offset += len;
+ loc->token_offset = state->indesc->token_offset;
+ loc->line_offset = state->indesc->line_offset;
+}
+
+static void reset_pos(struct parser_state *state, struct location *loc)
+{
+ state->indesc->line_offset = state->indesc->token_offset;
+ state->indesc->lineno += 1;
+ state->indesc->column = 1;
+}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type);
+
+#define YY_USER_ACTION { \
+ update_pos(yyget_extra(yyscanner), yylloc, yyleng); \
+ update_offset(yyget_extra(yyscanner), yylloc, yyleng); \
+}
+
+/* avoid warnings with -Wmissing-prototypes */
+extern int yyget_column(yyscan_t);
+extern void yyset_column(int, yyscan_t);
+
+#line 3986 "scanner.c"
+
+#line 3988 "scanner.c"
+
+#define INITIAL 0
+#define SCANSTATE_ARP 1
+#define SCANSTATE_AT 2
+#define SCANSTATE_CT 3
+#define SCANSTATE_COUNTER 4
+#define SCANSTATE_ETH 5
+#define SCANSTATE_GRE 6
+#define SCANSTATE_ICMP 7
+#define SCANSTATE_IGMP 8
+#define SCANSTATE_IP 9
+#define SCANSTATE_IP6 10
+#define SCANSTATE_LAST 11
+#define SCANSTATE_LIMIT 12
+#define SCANSTATE_META 13
+#define SCANSTATE_POLICY 14
+#define SCANSTATE_QUOTA 15
+#define SCANSTATE_SCTP 16
+#define SCANSTATE_SECMARK 17
+#define SCANSTATE_TCP 18
+#define SCANSTATE_TYPE 19
+#define SCANSTATE_VLAN 20
+#define SCANSTATE_XT 21
+#define SCANSTATE_CMD_DESTROY 22
+#define SCANSTATE_CMD_EXPORT 23
+#define SCANSTATE_CMD_IMPORT 24
+#define SCANSTATE_CMD_LIST 25
+#define SCANSTATE_CMD_MONITOR 26
+#define SCANSTATE_CMD_RESET 27
+#define SCANSTATE_EXPR_AH 28
+#define SCANSTATE_EXPR_COMP 29
+#define SCANSTATE_EXPR_DCCP 30
+#define SCANSTATE_EXPR_DST 31
+#define SCANSTATE_EXPR_ESP 32
+#define SCANSTATE_EXPR_FIB 33
+#define SCANSTATE_EXPR_FRAG 34
+#define SCANSTATE_EXPR_HASH 35
+#define SCANSTATE_EXPR_HBH 36
+#define SCANSTATE_EXPR_IPSEC 37
+#define SCANSTATE_EXPR_MH 38
+#define SCANSTATE_EXPR_NUMGEN 39
+#define SCANSTATE_EXPR_OSF 40
+#define SCANSTATE_EXPR_QUEUE 41
+#define SCANSTATE_EXPR_RT 42
+#define SCANSTATE_EXPR_SCTP_CHUNK 43
+#define SCANSTATE_EXPR_SOCKET 44
+#define SCANSTATE_EXPR_TH 45
+#define SCANSTATE_EXPR_UDP 46
+#define SCANSTATE_EXPR_UDPLITE 47
+#define SCANSTATE_STMT_DUP 48
+#define SCANSTATE_STMT_FWD 49
+#define SCANSTATE_STMT_LOG 50
+#define SCANSTATE_STMT_NAT 51
+#define SCANSTATE_STMT_REJECT 52
+#define SCANSTATE_STMT_SYNPROXY 53
+#define SCANSTATE_STMT_TPROXY 54
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+/* %if-c-only */
+#include <unistd.h>
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+/* %if-c-only Reentrant structure and macros (non-C++). */
+/* %if-reentrant */
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ YYSTYPE * yylval_r;
+
+ YYLTYPE * yylloc_r;
+
+ }; /* end struct yyguts_t */
+
+/* %if-c-only */
+
+static int yy_init_globals ( yyscan_t yyscanner );
+
+/* %endif */
+
+/* %if-reentrant */
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+ # define yylloc yyg->yylloc_r
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
+
+/* %endif */
+
+/* %endif End reentrant structures and macros. */
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy ( yyscan_t yyscanner );
+
+int yyget_debug ( yyscan_t yyscanner );
+
+void yyset_debug ( int debug_flag , yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
+
+void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
+
+FILE *yyget_in ( yyscan_t yyscanner );
+
+void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
+
+FILE *yyget_out ( yyscan_t yyscanner );
+
+void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
+
+ int yyget_leng ( yyscan_t yyscanner );
+
+char *yyget_text ( yyscan_t yyscanner );
+
+int yyget_lineno ( yyscan_t yyscanner );
+
+void yyset_lineno ( int _line_number , yyscan_t yyscanner );
+
+int yyget_column ( yyscan_t yyscanner );
+
+void yyset_column ( int _column_no , yyscan_t yyscanner );
+
+/* %if-bison-bridge */
+
+YYSTYPE * yyget_lval ( yyscan_t yyscanner );
+
+void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner );
+
+ YYLTYPE *yyget_lloc ( yyscan_t yyscanner );
+
+ void yyset_lloc ( YYLTYPE * yylloc_param , yyscan_t yyscanner );
+
+/* %endif */
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap ( yyscan_t yyscanner );
+#else
+extern int yywrap ( yyscan_t yyscanner );
+#endif
+#endif
+
+/* %not-for-header */
+#ifndef YY_NO_UNPUT
+
+#endif
+/* %ok-for-header */
+
+/* %endif */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+/* %if-c-only Standard (non-C++) definition */
+/* %not-for-header */
+#ifdef __cplusplus
+static int yyinput ( yyscan_t yyscanner );
+#else
+static int input ( yyscan_t yyscanner );
+#endif
+/* %ok-for-header */
+
+/* %endif */
+#endif
+
+/* %if-c-only */
+
+ static void yy_push_state ( int _new_state , yyscan_t yyscanner);
+
+ static void yy_pop_state ( yyscan_t yyscanner );
+
+ static int yy_top_state ( yyscan_t yyscanner );
+
+/* %endif */
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* %if-c-only Standard (non-C++) definition */
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0)
+/* %endif */
+/* %if-c++-only C++ definition */
+/* %endif */
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+/* %% [5.0] fread()/read() definition of YY_INPUT goes here unless we're doing C++ \ */\
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+/* %if-c++-only C++ definition \ */\
+/* %endif */
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+/* %if-c-only */
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+#endif
+
+/* %if-tables-serialization structures and prototypes */
+/* %not-for-header */
+/* %ok-for-header */
+
+/* %not-for-header */
+/* %tables-yydmap generated elements */
+/* %endif */
+/* end tables serialization structures and prototypes */
+
+/* %ok-for-header */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+/* %if-c-only Standard (non-C++) definition */
+
+extern int yylex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner);
+
+#define YY_DECL int yylex \
+ (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only C++ definition */
+/* %endif */
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK /*LINTED*/break;
+#endif
+
+/* %% [6.0] YY_RULE_SETUP definition goes here */
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+/* %not-for-header */
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ yy_state_type yy_current_state;
+ char *yy_cp, *yy_bp;
+ int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yylval = yylval_param;
+
+ yylloc = yylloc_param;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+/* %if-c-only */
+ yyin = stdin;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+ if ( ! yyout )
+/* %if-c-only */
+ yyout = stdout;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_load_buffer_state( yyscanner );
+ }
+
+ {
+/* %% [7.0] user's declarations go here */
+#line 258 "scanner.l"
+
+
+#line 4404 "scanner.c"
+
+ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
+ {
+/* %% [8.0] yymore()-related code goes here */
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+/* %% [9.0] code to set up and find next match goes here */
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 2383 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 9866 );
+
+yy_find_action:
+/* %% [10.0] code to find the action number goes here */
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+/* %% [11.0] code for yylineno update goes here */
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+/* %% [12.0] debug code goes here */
+ if ( yy_flex_debug )
+ {
+ if ( yy_act == 0 )
+ fprintf( stderr, "--scanner backing up\n" );
+ else if ( yy_act < 412 )
+ fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
+ (long)yy_rule_linenum[yy_act], yytext );
+ else if ( yy_act == 412 )
+ fprintf( stderr, "--accepting default rule (\"%s\")\n",
+ yytext );
+ else if ( yy_act == 413 )
+ fprintf( stderr, "--(end of buffer or a NUL)\n" );
+ else
+ fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
+ }
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+/* %% [13.0] actions go here */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 260 "scanner.l"
+{ return EQ; }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 261 "scanner.l"
+{ return EQ; }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 262 "scanner.l"
+{ return NEQ; }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 263 "scanner.l"
+{ return NEQ; }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 264 "scanner.l"
+{ return LTE; }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 265 "scanner.l"
+{ return LTE; }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 266 "scanner.l"
+{ return LT; }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 267 "scanner.l"
+{ return LT; }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 268 "scanner.l"
+{ return GTE; }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 269 "scanner.l"
+{ return GTE; }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 270 "scanner.l"
+{ return GT; }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 271 "scanner.l"
+{ return GT; }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 272 "scanner.l"
+{ return COMMA; }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 273 "scanner.l"
+{ return DOT; }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 274 "scanner.l"
+{ return COLON; }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 275 "scanner.l"
+{ return SEMICOLON; }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 276 "scanner.l"
+{ return '{'; }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 277 "scanner.l"
+{ return '}'; }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 278 "scanner.l"
+{ return '['; }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 279 "scanner.l"
+{ return ']'; }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 280 "scanner.l"
+{ return '('; }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 281 "scanner.l"
+{ return ')'; }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 282 "scanner.l"
+{ return LSHIFT; }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 283 "scanner.l"
+{ return LSHIFT; }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 284 "scanner.l"
+{ return RSHIFT; }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 285 "scanner.l"
+{ return RSHIFT; }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 286 "scanner.l"
+{ return CARET; }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 287 "scanner.l"
+{ return CARET; }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 288 "scanner.l"
+{ return AMPERSAND; }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 289 "scanner.l"
+{ return AMPERSAND; }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 290 "scanner.l"
+{ return '|'; }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 291 "scanner.l"
+{ return '|'; }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 292 "scanner.l"
+{ return NOT; }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 293 "scanner.l"
+{ return NOT; }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 294 "scanner.l"
+{ return SLASH; }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 295 "scanner.l"
+{ return DASH; }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 296 "scanner.l"
+{ return ASTERISK; }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 297 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_AT); return AT; }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 298 "scanner.l"
+{ return '$'; }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 299 "scanner.l"
+{ return '='; }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 300 "scanner.l"
+{ return VMAP; }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 302 "scanner.l"
+{ return PLUS; }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 304 "scanner.l"
+{ return INCLUDE; }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 305 "scanner.l"
+{ return DEFINE; }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 306 "scanner.l"
+{ return REDEFINE; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 307 "scanner.l"
+{ return UNDEFINE; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 309 "scanner.l"
+{ return DESCRIBE; }
+ YY_BREAK
+
+case 48:
+YY_RULE_SETUP
+#line 312 "scanner.l"
+{ return CHAINS; }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 313 "scanner.l"
+{ return SETS; }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 314 "scanner.l"
+{ return TABLES; }
+ YY_BREAK
+
+
+case 51:
+YY_RULE_SETUP
+#line 317 "scanner.l"
+{ return RULES; }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 318 "scanner.l"
+{ return TRACE; }
+ YY_BREAK
+
+case 53:
+YY_RULE_SETUP
+#line 320 "scanner.l"
+{ return HOOK; }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 321 "scanner.l"
+{ return DEVICE; }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 322 "scanner.l"
+{ return DEVICES; }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 323 "scanner.l"
+{ return TABLE; }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 324 "scanner.l"
+{ return CHAIN; }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 325 "scanner.l"
+{ return RULE; }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 326 "scanner.l"
+{ return SET; }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 327 "scanner.l"
+{ return ELEMENT; }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 328 "scanner.l"
+{ return MAP; }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 329 "scanner.l"
+{ return FLOWTABLE; }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 330 "scanner.l"
+{ return HANDLE; }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 331 "scanner.l"
+{ return RULESET; }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 333 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SOCKET); return SOCKET; }
+ YY_BREAK
+
+case 66:
+YY_RULE_SETUP
+#line 335 "scanner.l"
+{ return TRANSPARENT; }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 336 "scanner.l"
+{ return WILDCARD; }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 337 "scanner.l"
+{ return CGROUPV2; }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 338 "scanner.l"
+{ return LEVEL; }
+ YY_BREAK
+
+case 70:
+YY_RULE_SETUP
+#line 340 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_TPROXY); return TPROXY; }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 342 "scanner.l"
+{ return ACCEPT; }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 343 "scanner.l"
+{ return DROP; }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 344 "scanner.l"
+{ return CONTINUE; }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 345 "scanner.l"
+{ return JUMP; }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 346 "scanner.l"
+{ return GOTO; }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 347 "scanner.l"
+{ return RETURN; }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 348 "scanner.l"
+{ return TO; } /* XXX: SCANSTATE_IP is a workaround */
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 350 "scanner.l"
+{ return INET; }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 351 "scanner.l"
+{ return NETDEV; }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 353 "scanner.l"
+{ return ADD; }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 354 "scanner.l"
+{ return REPLACE; }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 355 "scanner.l"
+{ return UPDATE; }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 356 "scanner.l"
+{ return CREATE; }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 357 "scanner.l"
+{ return INSERT; }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 358 "scanner.l"
+{ return DELETE; }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 359 "scanner.l"
+{ return GET; }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 360 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_CMD_LIST); return LIST; }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 361 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_CMD_RESET); return RESET; }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 362 "scanner.l"
+{ return FLUSH; }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 363 "scanner.l"
+{ return RENAME; }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 364 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_CMD_IMPORT); return IMPORT; }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 365 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_CMD_EXPORT); return EXPORT; }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 366 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_CMD_MONITOR); return MONITOR; }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 367 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_CMD_DESTROY); return DESTROY; }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 370 "scanner.l"
+{ return POSITION; }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 371 "scanner.l"
+{ return INDEX; }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 372 "scanner.l"
+{ return COMMENT; }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 374 "scanner.l"
+{ return CONSTANT; }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 375 "scanner.l"
+{ return INTERVAL; }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 376 "scanner.l"
+{ return DYNAMIC; }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 377 "scanner.l"
+{ return AUTOMERGE; }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 378 "scanner.l"
+{ return TIMEOUT; }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 379 "scanner.l"
+{ return GC_INTERVAL; }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 380 "scanner.l"
+{ return ELEMENTS; }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 381 "scanner.l"
+{ return EXPIRES; }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 383 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_POLICY); return POLICY; }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 384 "scanner.l"
+{ return SIZE; }
+ YY_BREAK
+
+case 108:
+YY_RULE_SETUP
+#line 386 "scanner.l"
+{ return PERFORMANCE; }
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 387 "scanner.l"
+{ return MEMORY; }
+ YY_BREAK
+
+case 110:
+YY_RULE_SETUP
+#line 390 "scanner.l"
+{ return FLOW; }
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 391 "scanner.l"
+{ return OFFLOAD; }
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 392 "scanner.l"
+{ return METER; }
+ YY_BREAK
+
+case 113:
+YY_RULE_SETUP
+#line 395 "scanner.l"
+{ return METERS; }
+ YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 396 "scanner.l"
+{ return FLOWTABLES; }
+ YY_BREAK
+case 115:
+YY_RULE_SETUP
+#line 397 "scanner.l"
+{ return LIMITS; }
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 398 "scanner.l"
+{ return MAPS; }
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 399 "scanner.l"
+{ return SECMARKS; }
+ YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 400 "scanner.l"
+{ return SYNPROXYS; }
+ YY_BREAK
+case 119:
+YY_RULE_SETUP
+#line 401 "scanner.l"
+{ return HOOKS; }
+ YY_BREAK
+
+case 120:
+YY_RULE_SETUP
+#line 404 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_COUNTER); return COUNTER; }
+ YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 405 "scanner.l"
+{ return NAME; }
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 406 "scanner.l"
+{ return PACKETS; }
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 407 "scanner.l"
+{ return BYTES; }
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 409 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_LAST); return LAST; }
+ YY_BREAK
+
+case 125:
+YY_RULE_SETUP
+#line 411 "scanner.l"
+{ return NEVER; }
+ YY_BREAK
+
+
+case 126:
+YY_RULE_SETUP
+#line 415 "scanner.l"
+{ return COUNTERS; }
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 416 "scanner.l"
+{ return QUOTAS; }
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 417 "scanner.l"
+{ return RULES; }
+ YY_BREAK
+
+case 129:
+YY_RULE_SETUP
+#line 420 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_LOG); return LOG; }
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 421 "scanner.l"
+{ return PREFIX; }
+ YY_BREAK
+
+case 131:
+YY_RULE_SETUP
+#line 423 "scanner.l"
+{ return SNAPLEN; }
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 424 "scanner.l"
+{ return QUEUE_THRESHOLD; }
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 425 "scanner.l"
+{ return LEVEL; }
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 426 "scanner.l"
+{ return GROUP; }
+ YY_BREAK
+
+case 135:
+YY_RULE_SETUP
+#line 429 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_QUEUE); return QUEUE;}
+ YY_BREAK
+
+case 136:
+YY_RULE_SETUP
+#line 431 "scanner.l"
+{ return QUEUENUM;}
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 432 "scanner.l"
+{ return BYPASS;}
+ YY_BREAK
+case 138:
+YY_RULE_SETUP
+#line 433 "scanner.l"
+{ return FANOUT;}
+ YY_BREAK
+
+case 139:
+YY_RULE_SETUP
+#line 435 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_LIMIT); return LIMIT; }
+ YY_BREAK
+
+case 140:
+YY_RULE_SETUP
+#line 437 "scanner.l"
+{ return RATE; }
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+#line 438 "scanner.l"
+{ return BURST; }
+ YY_BREAK
+/* time_unit */
+case 142:
+YY_RULE_SETUP
+#line 441 "scanner.l"
+{ return SECOND; }
+ YY_BREAK
+case 143:
+YY_RULE_SETUP
+#line 442 "scanner.l"
+{ return MINUTE; }
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+#line 443 "scanner.l"
+{ return WEEK; }
+ YY_BREAK
+
+case 145:
+YY_RULE_SETUP
+#line 445 "scanner.l"
+{ return OVER; }
+ YY_BREAK
+case 146:
+YY_RULE_SETUP
+#line 447 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_QUOTA); return QUOTA; }
+ YY_BREAK
+
+case 147:
+YY_RULE_SETUP
+#line 449 "scanner.l"
+{ return UNTIL; }
+ YY_BREAK
+
+case 148:
+YY_RULE_SETUP
+#line 452 "scanner.l"
+{ return USED; }
+ YY_BREAK
+case 149:
+YY_RULE_SETUP
+#line 454 "scanner.l"
+{ return HOUR; }
+ YY_BREAK
+case 150:
+YY_RULE_SETUP
+#line 455 "scanner.l"
+{ return DAY; }
+ YY_BREAK
+case 151:
+YY_RULE_SETUP
+#line 457 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_REJECT); return _REJECT; }
+ YY_BREAK
+
+case 152:
+YY_RULE_SETUP
+#line 459 "scanner.l"
+{ return WITH; }
+ YY_BREAK
+case 153:
+YY_RULE_SETUP
+#line 460 "scanner.l"
+{ return ICMPX; }
+ YY_BREAK
+
+case 154:
+YY_RULE_SETUP
+#line 463 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; }
+ YY_BREAK
+case 155:
+YY_RULE_SETUP
+#line 464 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; }
+ YY_BREAK
+case 156:
+YY_RULE_SETUP
+#line 465 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; }
+ YY_BREAK
+case 157:
+YY_RULE_SETUP
+#line 466 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return REDIRECT; }
+ YY_BREAK
+case 158:
+YY_RULE_SETUP
+#line 467 "scanner.l"
+{ return RANDOM; }
+ YY_BREAK
+
+case 159:
+YY_RULE_SETUP
+#line 469 "scanner.l"
+{ return FULLY_RANDOM; }
+ YY_BREAK
+case 160:
+YY_RULE_SETUP
+#line 470 "scanner.l"
+{ return PERSISTENT; }
+ YY_BREAK
+case 161:
+YY_RULE_SETUP
+#line 471 "scanner.l"
+{ return PORT; }
+ YY_BREAK
+
+
+case 162:
+YY_RULE_SETUP
+#line 475 "scanner.l"
+{ return LL_HDR; }
+ YY_BREAK
+case 163:
+YY_RULE_SETUP
+#line 476 "scanner.l"
+{ return NETWORK_HDR; }
+ YY_BREAK
+
+case 164:
+YY_RULE_SETUP
+#line 478 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_TH); return TRANSPORT_HDR; }
+ YY_BREAK
+case 165:
+YY_RULE_SETUP
+#line 480 "scanner.l"
+{ return BRIDGE; }
+ YY_BREAK
+case 166:
+YY_RULE_SETUP
+#line 482 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_ETH); return ETHER; }
+ YY_BREAK
+
+case 167:
+YY_RULE_SETUP
+#line 484 "scanner.l"
+{ return SADDR; }
+ YY_BREAK
+case 168:
+YY_RULE_SETUP
+#line 485 "scanner.l"
+{ return DADDR; }
+ YY_BREAK
+
+case 169:
+YY_RULE_SETUP
+#line 487 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_TYPE); return TYPE; }
+ YY_BREAK
+case 170:
+YY_RULE_SETUP
+#line 488 "scanner.l"
+{ return TYPEOF; }
+ YY_BREAK
+case 171:
+YY_RULE_SETUP
+#line 490 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_VLAN); return VLAN; }
+ YY_BREAK
+case 172:
+YY_RULE_SETUP
+#line 491 "scanner.l"
+{ return ID; }
+ YY_BREAK
+
+case 173:
+YY_RULE_SETUP
+#line 493 "scanner.l"
+{ return CFI; }
+ YY_BREAK
+case 174:
+YY_RULE_SETUP
+#line 494 "scanner.l"
+{ return DEI; }
+ YY_BREAK
+case 175:
+YY_RULE_SETUP
+#line 495 "scanner.l"
+{ return PCP; }
+ YY_BREAK
+
+case 176:
+YY_RULE_SETUP
+#line 497 "scanner.l"
+{ yylval->string = xstrdup(yytext); return STRING; }
+ YY_BREAK
+case 177:
+YY_RULE_SETUP
+#line 498 "scanner.l"
+{ yylval->string = xstrdup(yytext); return STRING; }
+ YY_BREAK
+case 178:
+YY_RULE_SETUP
+#line 500 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_ARP); return ARP; }
+ YY_BREAK
+
+case 179:
+YY_RULE_SETUP
+#line 502 "scanner.l"
+{ return HTYPE; }
+ YY_BREAK
+case 180:
+YY_RULE_SETUP
+#line 503 "scanner.l"
+{ return PTYPE; }
+ YY_BREAK
+case 181:
+YY_RULE_SETUP
+#line 504 "scanner.l"
+{ return HLEN; }
+ YY_BREAK
+case 182:
+YY_RULE_SETUP
+#line 505 "scanner.l"
+{ return PLEN; }
+ YY_BREAK
+case 183:
+YY_RULE_SETUP
+#line 506 "scanner.l"
+{ return OPERATION; }
+ YY_BREAK
+
+case 184:
+YY_RULE_SETUP
+#line 509 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_IP); return IP; }
+ YY_BREAK
+
+case 185:
+YY_RULE_SETUP
+#line 511 "scanner.l"
+{ return HDRVERSION; }
+ YY_BREAK
+
+
+case 186:
+YY_RULE_SETUP
+#line 514 "scanner.l"
+{ return HDRLENGTH; }
+ YY_BREAK
+
+
+case 187:
+YY_RULE_SETUP
+#line 517 "scanner.l"
+{ return DSCP; }
+ YY_BREAK
+
+case 188:
+YY_RULE_SETUP
+#line 519 "scanner.l"
+{ return ECN; }
+ YY_BREAK
+case 189:
+YY_RULE_SETUP
+#line 520 "scanner.l"
+{ return LENGTH; }
+ YY_BREAK
+
+case 190:
+YY_RULE_SETUP
+#line 522 "scanner.l"
+{ return FRAG_OFF; }
+ YY_BREAK
+
+
+case 191:
+YY_RULE_SETUP
+#line 525 "scanner.l"
+{ return TTL; }
+ YY_BREAK
+
+case 192:
+YY_RULE_SETUP
+#line 527 "scanner.l"
+{ return PROTOCOL; }
+ YY_BREAK
+
+case 193:
+YY_RULE_SETUP
+#line 529 "scanner.l"
+{ return CHECKSUM; }
+ YY_BREAK
+
+
+case 194:
+YY_RULE_SETUP
+#line 533 "scanner.l"
+{ return LSRR; }
+ YY_BREAK
+case 195:
+YY_RULE_SETUP
+#line 534 "scanner.l"
+{ return RR; }
+ YY_BREAK
+case 196:
+YY_RULE_SETUP
+#line 535 "scanner.l"
+{ return SSRR; }
+ YY_BREAK
+case 197:
+YY_RULE_SETUP
+#line 536 "scanner.l"
+{ return RA; }
+ YY_BREAK
+case 198:
+YY_RULE_SETUP
+#line 538 "scanner.l"
+{ return PTR; }
+ YY_BREAK
+case 199:
+YY_RULE_SETUP
+#line 539 "scanner.l"
+{ return VALUE; }
+ YY_BREAK
+case 200:
+YY_RULE_SETUP
+#line 541 "scanner.l"
+{ return OPTION; }
+ YY_BREAK
+case 201:
+YY_RULE_SETUP
+#line 542 "scanner.l"
+{ return OPTIONS; }
+ YY_BREAK
+
+
+/* tcp header fields */
+case 202:
+YY_RULE_SETUP
+#line 547 "scanner.l"
+{ return ACKSEQ; }
+ YY_BREAK
+case 203:
+YY_RULE_SETUP
+#line 548 "scanner.l"
+{ return DOFF; }
+ YY_BREAK
+case 204:
+YY_RULE_SETUP
+#line 549 "scanner.l"
+{ return WINDOW; }
+ YY_BREAK
+case 205:
+YY_RULE_SETUP
+#line 550 "scanner.l"
+{ return URGPTR; }
+ YY_BREAK
+/* tcp option types */
+case 206:
+YY_RULE_SETUP
+#line 553 "scanner.l"
+{ return ECHO; }
+ YY_BREAK
+case 207:
+YY_RULE_SETUP
+#line 554 "scanner.l"
+{ return EOL; }
+ YY_BREAK
+case 208:
+YY_RULE_SETUP
+#line 555 "scanner.l"
+{ return MSS; }
+ YY_BREAK
+case 209:
+YY_RULE_SETUP
+#line 556 "scanner.l"
+{ return MSS; }
+ YY_BREAK
+case 210:
+YY_RULE_SETUP
+#line 557 "scanner.l"
+{ return NOP; }
+ YY_BREAK
+case 211:
+YY_RULE_SETUP
+#line 558 "scanner.l"
+{ return NOP; }
+ YY_BREAK
+case 212:
+YY_RULE_SETUP
+#line 559 "scanner.l"
+{ return SACK; }
+ YY_BREAK
+case 213:
+YY_RULE_SETUP
+#line 560 "scanner.l"
+{ return SACK0; }
+ YY_BREAK
+case 214:
+YY_RULE_SETUP
+#line 561 "scanner.l"
+{ return SACK1; }
+ YY_BREAK
+case 215:
+YY_RULE_SETUP
+#line 562 "scanner.l"
+{ return SACK2; }
+ YY_BREAK
+case 216:
+YY_RULE_SETUP
+#line 563 "scanner.l"
+{ return SACK3; }
+ YY_BREAK
+case 217:
+YY_RULE_SETUP
+#line 564 "scanner.l"
+{ return SACK_PERM; }
+ YY_BREAK
+case 218:
+YY_RULE_SETUP
+#line 565 "scanner.l"
+{ return SACK_PERM; }
+ YY_BREAK
+case 219:
+YY_RULE_SETUP
+#line 566 "scanner.l"
+{ return TIMESTAMP; }
+ YY_BREAK
+case 220:
+YY_RULE_SETUP
+#line 567 "scanner.l"
+{ return FASTOPEN; }
+ YY_BREAK
+case 221:
+YY_RULE_SETUP
+#line 568 "scanner.l"
+{ return MPTCP; }
+ YY_BREAK
+case 222:
+YY_RULE_SETUP
+#line 569 "scanner.l"
+{ return MD5SIG; }
+ YY_BREAK
+/* tcp option fields */
+case 223:
+YY_RULE_SETUP
+#line 572 "scanner.l"
+{ return LEFT; }
+ YY_BREAK
+case 224:
+YY_RULE_SETUP
+#line 573 "scanner.l"
+{ return RIGHT; }
+ YY_BREAK
+case 225:
+YY_RULE_SETUP
+#line 574 "scanner.l"
+{ return COUNT; }
+ YY_BREAK
+case 226:
+YY_RULE_SETUP
+#line 575 "scanner.l"
+{ return TSVAL; }
+ YY_BREAK
+case 227:
+YY_RULE_SETUP
+#line 576 "scanner.l"
+{ return TSECR; }
+ YY_BREAK
+case 228:
+YY_RULE_SETUP
+#line 577 "scanner.l"
+{ return SUBTYPE; }
+ YY_BREAK
+case 229:
+YY_RULE_SETUP
+#line 579 "scanner.l"
+{ return OPTIONS; }
+ YY_BREAK
+case 230:
+YY_RULE_SETUP
+#line 580 "scanner.l"
+{ return OPTION; }
+ YY_BREAK
+
+case 231:
+YY_RULE_SETUP
+#line 582 "scanner.l"
+{ return TIME; }
+ YY_BREAK
+case 232:
+YY_RULE_SETUP
+#line 584 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP; }
+ YY_BREAK
+case 233:
+YY_RULE_SETUP
+#line 585 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP6; }
+ YY_BREAK
+
+case 234:
+YY_RULE_SETUP
+#line 587 "scanner.l"
+{ return GATEWAY; }
+ YY_BREAK
+case 235:
+YY_RULE_SETUP
+#line 588 "scanner.l"
+{ return CODE; }
+ YY_BREAK
+case 236:
+YY_RULE_SETUP
+#line 589 "scanner.l"
+{ return PPTR; }
+ YY_BREAK
+case 237:
+YY_RULE_SETUP
+#line 590 "scanner.l"
+{ return MAXDELAY; }
+ YY_BREAK
+case 238:
+YY_RULE_SETUP
+#line 591 "scanner.l"
+{ return MTU; }
+ YY_BREAK
+case 239:
+YY_RULE_SETUP
+#line 592 "scanner.l"
+{ return TADDR; }
+ YY_BREAK
+case 240:
+YY_RULE_SETUP
+#line 593 "scanner.l"
+{ return DADDR; }
+ YY_BREAK
+
+
+case 241:
+YY_RULE_SETUP
+#line 596 "scanner.l"
+{ return SEQUENCE; }
+ YY_BREAK
+
+case 242:
+YY_RULE_SETUP
+#line 599 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_IGMP); return IGMP; }
+ YY_BREAK
+
+case 243:
+YY_RULE_SETUP
+#line 601 "scanner.l"
+{ return MRT; }
+ YY_BREAK
+case 244:
+YY_RULE_SETUP
+#line 602 "scanner.l"
+{ return GROUP; }
+ YY_BREAK
+
+case 245:
+YY_RULE_SETUP
+#line 605 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_IP6); return IP6; }
+ YY_BREAK
+case 246:
+YY_RULE_SETUP
+#line 606 "scanner.l"
+{ return PRIORITY; }
+ YY_BREAK
+
+case 247:
+YY_RULE_SETUP
+#line 608 "scanner.l"
+{ return FLOWLABEL; }
+ YY_BREAK
+case 248:
+YY_RULE_SETUP
+#line 609 "scanner.l"
+{ return HOPLIMIT; }
+ YY_BREAK
+
+
+case 249:
+YY_RULE_SETUP
+#line 612 "scanner.l"
+{ return NEXTHDR; }
+ YY_BREAK
+
+case 250:
+YY_RULE_SETUP
+#line 615 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_AH); return AH; }
+ YY_BREAK
+
+case 251:
+YY_RULE_SETUP
+#line 617 "scanner.l"
+{ return RESERVED; }
+ YY_BREAK
+
+case 252:
+YY_RULE_SETUP
+#line 619 "scanner.l"
+{ return SPI; }
+ YY_BREAK
+case 253:
+YY_RULE_SETUP
+#line 621 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_ESP); return ESP; }
+ YY_BREAK
+case 254:
+YY_RULE_SETUP
+#line 623 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_COMP); return COMP; }
+ YY_BREAK
+
+case 255:
+YY_RULE_SETUP
+#line 625 "scanner.l"
+{ return CPI; }
+ YY_BREAK
+
+case 256:
+YY_RULE_SETUP
+#line 627 "scanner.l"
+{ return FLAGS; }
+ YY_BREAK
+case 257:
+YY_RULE_SETUP
+#line 629 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDP); return UDP; }
+ YY_BREAK
+case 258:
+YY_RULE_SETUP
+#line 630 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDPLITE); return UDPLITE; }
+ YY_BREAK
+
+case 259:
+YY_RULE_SETUP
+#line 632 "scanner.l"
+{ return CSUMCOV; }
+ YY_BREAK
+
+
+case 260:
+YY_RULE_SETUP
+#line 635 "scanner.l"
+{ return SPORT; }
+ YY_BREAK
+
+
+case 261:
+YY_RULE_SETUP
+#line 638 "scanner.l"
+{ return DPORT; }
+ YY_BREAK
+
+
+case 262:
+YY_RULE_SETUP
+#line 641 "scanner.l"
+{ return OPTION; }
+ YY_BREAK
+
+case 263:
+YY_RULE_SETUP
+#line 644 "scanner.l"
+{ return VXLAN; }
+ YY_BREAK
+case 264:
+YY_RULE_SETUP
+#line 645 "scanner.l"
+{ return VNI; }
+ YY_BREAK
+case 265:
+YY_RULE_SETUP
+#line 647 "scanner.l"
+{ return GENEVE; }
+ YY_BREAK
+case 266:
+YY_RULE_SETUP
+#line 649 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRE; }
+ YY_BREAK
+case 267:
+YY_RULE_SETUP
+#line 650 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRETAP; }
+ YY_BREAK
+case 268:
+YY_RULE_SETUP
+#line 652 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; }
+ YY_BREAK
+case 269:
+YY_RULE_SETUP
+#line 654 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DCCP); return DCCP; }
+ YY_BREAK
+case 270:
+YY_RULE_SETUP
+#line 656 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; }
+ YY_BREAK
+
+case 271:
+YY_RULE_SETUP
+#line 659 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SCTP_CHUNK); return CHUNK; }
+ YY_BREAK
+case 272:
+YY_RULE_SETUP
+#line 660 "scanner.l"
+{ return VTAG; }
+ YY_BREAK
+
+
+case 273:
+YY_RULE_SETUP
+#line 664 "scanner.l"
+{ return DATA; }
+ YY_BREAK
+case 274:
+YY_RULE_SETUP
+#line 665 "scanner.l"
+{ return INIT; }
+ YY_BREAK
+case 275:
+YY_RULE_SETUP
+#line 666 "scanner.l"
+{ return INIT_ACK; }
+ YY_BREAK
+case 276:
+YY_RULE_SETUP
+#line 667 "scanner.l"
+{ return HEARTBEAT; }
+ YY_BREAK
+case 277:
+YY_RULE_SETUP
+#line 668 "scanner.l"
+{ return HEARTBEAT_ACK; }
+ YY_BREAK
+case 278:
+YY_RULE_SETUP
+#line 669 "scanner.l"
+{ return ABORT; }
+ YY_BREAK
+case 279:
+YY_RULE_SETUP
+#line 670 "scanner.l"
+{ return SHUTDOWN; }
+ YY_BREAK
+case 280:
+YY_RULE_SETUP
+#line 671 "scanner.l"
+{ return SHUTDOWN_ACK; }
+ YY_BREAK
+case 281:
+YY_RULE_SETUP
+#line 672 "scanner.l"
+{ return ERROR; }
+ YY_BREAK
+case 282:
+YY_RULE_SETUP
+#line 673 "scanner.l"
+{ return COOKIE_ECHO; }
+ YY_BREAK
+case 283:
+YY_RULE_SETUP
+#line 674 "scanner.l"
+{ return COOKIE_ACK; }
+ YY_BREAK
+case 284:
+YY_RULE_SETUP
+#line 675 "scanner.l"
+{ return ECNE; }
+ YY_BREAK
+case 285:
+YY_RULE_SETUP
+#line 676 "scanner.l"
+{ return CWR; }
+ YY_BREAK
+case 286:
+YY_RULE_SETUP
+#line 677 "scanner.l"
+{ return SHUTDOWN_COMPLETE; }
+ YY_BREAK
+case 287:
+YY_RULE_SETUP
+#line 678 "scanner.l"
+{ return ASCONF_ACK; }
+ YY_BREAK
+case 288:
+YY_RULE_SETUP
+#line 679 "scanner.l"
+{ return FORWARD_TSN; }
+ YY_BREAK
+case 289:
+YY_RULE_SETUP
+#line 680 "scanner.l"
+{ return ASCONF; }
+ YY_BREAK
+case 290:
+YY_RULE_SETUP
+#line 682 "scanner.l"
+{ return TSN; }
+ YY_BREAK
+case 291:
+YY_RULE_SETUP
+#line 683 "scanner.l"
+{ return SACK; }
+ YY_BREAK
+case 292:
+YY_RULE_SETUP
+#line 684 "scanner.l"
+{ return STREAM; }
+ YY_BREAK
+case 293:
+YY_RULE_SETUP
+#line 685 "scanner.l"
+{ return SSN; }
+ YY_BREAK
+case 294:
+YY_RULE_SETUP
+#line 686 "scanner.l"
+{ return PPID; }
+ YY_BREAK
+case 295:
+YY_RULE_SETUP
+#line 687 "scanner.l"
+{ return INIT_TAG; }
+ YY_BREAK
+case 296:
+YY_RULE_SETUP
+#line 688 "scanner.l"
+{ return A_RWND; }
+ YY_BREAK
+case 297:
+YY_RULE_SETUP
+#line 689 "scanner.l"
+{ return NUM_OSTREAMS; }
+ YY_BREAK
+case 298:
+YY_RULE_SETUP
+#line 690 "scanner.l"
+{ return NUM_ISTREAMS; }
+ YY_BREAK
+case 299:
+YY_RULE_SETUP
+#line 691 "scanner.l"
+{ return INIT_TSN; }
+ YY_BREAK
+case 300:
+YY_RULE_SETUP
+#line 692 "scanner.l"
+{ return CUM_TSN_ACK; }
+ YY_BREAK
+case 301:
+YY_RULE_SETUP
+#line 693 "scanner.l"
+{ return NUM_GACK_BLOCKS; }
+ YY_BREAK
+case 302:
+YY_RULE_SETUP
+#line 694 "scanner.l"
+{ return NUM_DUP_TSNS; }
+ YY_BREAK
+case 303:
+YY_RULE_SETUP
+#line 695 "scanner.l"
+{ return LOWEST_TSN; }
+ YY_BREAK
+case 304:
+YY_RULE_SETUP
+#line 696 "scanner.l"
+{ return SEQNO; }
+ YY_BREAK
+case 305:
+YY_RULE_SETUP
+#line 697 "scanner.l"
+{ return NEW_CUM_TSN; }
+ YY_BREAK
+
+case 306:
+YY_RULE_SETUP
+#line 700 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT; }
+ YY_BREAK
+case 307:
+YY_RULE_SETUP
+#line 701 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT0; }
+ YY_BREAK
+case 308:
+YY_RULE_SETUP
+#line 702 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT2; }
+ YY_BREAK
+case 309:
+YY_RULE_SETUP
+#line 703 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT4; }
+ YY_BREAK
+case 310:
+YY_RULE_SETUP
+#line 704 "scanner.l"
+{ return ADDR; }
+ YY_BREAK
+case 311:
+YY_RULE_SETUP
+#line 706 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HBH); return HBH; }
+ YY_BREAK
+case 312:
+YY_RULE_SETUP
+#line 708 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FRAG); return FRAG; }
+ YY_BREAK
+
+case 313:
+YY_RULE_SETUP
+#line 710 "scanner.l"
+{ return RESERVED2; }
+ YY_BREAK
+case 314:
+YY_RULE_SETUP
+#line 711 "scanner.l"
+{ return MORE_FRAGMENTS; }
+ YY_BREAK
+
+case 315:
+YY_RULE_SETUP
+#line 714 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DST); return DST; }
+ YY_BREAK
+case 316:
+YY_RULE_SETUP
+#line 716 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_MH); return MH; }
+ YY_BREAK
+case 317:
+YY_RULE_SETUP
+#line 718 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_META); return META; }
+ YY_BREAK
+case 318:
+YY_RULE_SETUP
+#line 719 "scanner.l"
+{ return MARK; }
+ YY_BREAK
+case 319:
+YY_RULE_SETUP
+#line 720 "scanner.l"
+{ return IIF; }
+ YY_BREAK
+case 320:
+YY_RULE_SETUP
+#line 721 "scanner.l"
+{ return IIFNAME; }
+ YY_BREAK
+case 321:
+YY_RULE_SETUP
+#line 722 "scanner.l"
+{ return IIFTYPE; }
+ YY_BREAK
+case 322:
+YY_RULE_SETUP
+#line 723 "scanner.l"
+{ return OIF; }
+ YY_BREAK
+case 323:
+YY_RULE_SETUP
+#line 724 "scanner.l"
+{ return OIFNAME; }
+ YY_BREAK
+case 324:
+YY_RULE_SETUP
+#line 725 "scanner.l"
+{ return OIFTYPE; }
+ YY_BREAK
+case 325:
+YY_RULE_SETUP
+#line 726 "scanner.l"
+{ return SKUID; }
+ YY_BREAK
+case 326:
+YY_RULE_SETUP
+#line 727 "scanner.l"
+{ return SKGID; }
+ YY_BREAK
+case 327:
+YY_RULE_SETUP
+#line 728 "scanner.l"
+{ return NFTRACE; }
+ YY_BREAK
+case 328:
+YY_RULE_SETUP
+#line 729 "scanner.l"
+{ return RTCLASSID; }
+ YY_BREAK
+case 329:
+YY_RULE_SETUP
+#line 730 "scanner.l"
+{ return IBRIPORT; }
+ YY_BREAK
+case 330:
+YY_RULE_SETUP
+#line 731 "scanner.l"
+{ return IBRIDGENAME; }
+ YY_BREAK
+case 331:
+YY_RULE_SETUP
+#line 732 "scanner.l"
+{ return OBRIPORT; }
+ YY_BREAK
+case 332:
+YY_RULE_SETUP
+#line 733 "scanner.l"
+{ return OBRIDGENAME; }
+ YY_BREAK
+case 333:
+YY_RULE_SETUP
+#line 734 "scanner.l"
+{ return PKTTYPE; }
+ YY_BREAK
+case 334:
+YY_RULE_SETUP
+#line 735 "scanner.l"
+{ return CPU; }
+ YY_BREAK
+case 335:
+YY_RULE_SETUP
+#line 736 "scanner.l"
+{ return IIFGROUP; }
+ YY_BREAK
+case 336:
+YY_RULE_SETUP
+#line 737 "scanner.l"
+{ return OIFGROUP; }
+ YY_BREAK
+case 337:
+YY_RULE_SETUP
+#line 738 "scanner.l"
+{ return CGROUP; }
+ YY_BREAK
+
+case 338:
+YY_RULE_SETUP
+#line 741 "scanner.l"
+{ return NEXTHOP; }
+ YY_BREAK
+case 339:
+YY_RULE_SETUP
+#line 742 "scanner.l"
+{ return SEG_LEFT; }
+ YY_BREAK
+case 340:
+YY_RULE_SETUP
+#line 743 "scanner.l"
+{ return MTU; }
+ YY_BREAK
+case 341:
+YY_RULE_SETUP
+#line 744 "scanner.l"
+{ return LAST_ENT; }
+ YY_BREAK
+case 342:
+YY_RULE_SETUP
+#line 745 "scanner.l"
+{ return TAG; }
+ YY_BREAK
+case 343:
+YY_RULE_SETUP
+#line 746 "scanner.l"
+{ return SID; }
+ YY_BREAK
+
+
+case 344:
+YY_RULE_SETUP
+#line 749 "scanner.l"
+{ return CLASSID; }
+ YY_BREAK
+
+case 345:
+YY_RULE_SETUP
+#line 752 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_CT); return CT; }
+ YY_BREAK
+
+case 346:
+YY_RULE_SETUP
+#line 754 "scanner.l"
+{ return AVGPKT; }
+ YY_BREAK
+case 347:
+YY_RULE_SETUP
+#line 755 "scanner.l"
+{ return L3PROTOCOL; }
+ YY_BREAK
+case 348:
+YY_RULE_SETUP
+#line 756 "scanner.l"
+{ return PROTO_SRC; }
+ YY_BREAK
+case 349:
+YY_RULE_SETUP
+#line 757 "scanner.l"
+{ return PROTO_DST; }
+ YY_BREAK
+case 350:
+YY_RULE_SETUP
+#line 758 "scanner.l"
+{ return ZONE; }
+ YY_BREAK
+case 351:
+YY_RULE_SETUP
+#line 759 "scanner.l"
+{ return ORIGINAL; }
+ YY_BREAK
+case 352:
+YY_RULE_SETUP
+#line 760 "scanner.l"
+{ return REPLY; }
+ YY_BREAK
+case 353:
+YY_RULE_SETUP
+#line 761 "scanner.l"
+{ return DIRECTION; }
+ YY_BREAK
+case 354:
+YY_RULE_SETUP
+#line 762 "scanner.l"
+{ return EVENT; }
+ YY_BREAK
+case 355:
+YY_RULE_SETUP
+#line 763 "scanner.l"
+{ return EXPECTATION; }
+ YY_BREAK
+case 356:
+YY_RULE_SETUP
+#line 764 "scanner.l"
+{ return EXPIRATION; }
+ YY_BREAK
+case 357:
+YY_RULE_SETUP
+#line 765 "scanner.l"
+{ return HELPER; }
+ YY_BREAK
+case 358:
+YY_RULE_SETUP
+#line 766 "scanner.l"
+{ return HELPERS; }
+ YY_BREAK
+case 359:
+YY_RULE_SETUP
+#line 767 "scanner.l"
+{ return LABEL; }
+ YY_BREAK
+case 360:
+YY_RULE_SETUP
+#line 768 "scanner.l"
+{ return STATE; }
+ YY_BREAK
+case 361:
+YY_RULE_SETUP
+#line 769 "scanner.l"
+{ return STATUS; }
+ YY_BREAK
+case 362:
+YY_RULE_SETUP
+#line 770 "scanner.l"
+{ return COUNT; }
+ YY_BREAK
+
+case 363:
+YY_RULE_SETUP
+#line 773 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_NUMGEN); return NUMGEN; }
+ YY_BREAK
+
+case 364:
+YY_RULE_SETUP
+#line 775 "scanner.l"
+{ return INC; }
+ YY_BREAK
+
+case 365:
+YY_RULE_SETUP
+#line 778 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return JHASH; }
+ YY_BREAK
+case 366:
+YY_RULE_SETUP
+#line 779 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return SYMHASH; }
+ YY_BREAK
+
+case 367:
+YY_RULE_SETUP
+#line 782 "scanner.l"
+{ return SEED; }
+ YY_BREAK
+
+
+case 368:
+YY_RULE_SETUP
+#line 785 "scanner.l"
+{ return MOD; }
+ YY_BREAK
+case 369:
+YY_RULE_SETUP
+#line 786 "scanner.l"
+{ return OFFSET; }
+ YY_BREAK
+
+case 370:
+YY_RULE_SETUP
+#line 788 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_DUP); return DUP; }
+ YY_BREAK
+case 371:
+YY_RULE_SETUP
+#line 789 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_FWD); return FWD; }
+ YY_BREAK
+case 372:
+YY_RULE_SETUP
+#line 791 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FIB); return FIB; }
+ YY_BREAK
+case 373:
+YY_RULE_SETUP
+#line 793 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_OSF); return OSF; }
+ YY_BREAK
+case 374:
+YY_RULE_SETUP
+#line 795 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_STMT_SYNPROXY); return SYNPROXY; }
+ YY_BREAK
+
+case 375:
+YY_RULE_SETUP
+#line 797 "scanner.l"
+{ return WSCALE; }
+ YY_BREAK
+case 376:
+YY_RULE_SETUP
+#line 798 "scanner.l"
+{ return MSS; }
+ YY_BREAK
+case 377:
+YY_RULE_SETUP
+#line 799 "scanner.l"
+{ return MSS; }
+ YY_BREAK
+case 378:
+YY_RULE_SETUP
+#line 800 "scanner.l"
+{ return TIMESTAMP; }
+ YY_BREAK
+case 379:
+YY_RULE_SETUP
+#line 801 "scanner.l"
+{ return SACK_PERM; }
+ YY_BREAK
+case 380:
+YY_RULE_SETUP
+#line 802 "scanner.l"
+{ return SACK_PERM; }
+ YY_BREAK
+
+case 381:
+YY_RULE_SETUP
+#line 805 "scanner.l"
+{ return NOTRACK; }
+ YY_BREAK
+case 382:
+YY_RULE_SETUP
+#line 807 "scanner.l"
+{ return ALL; }
+ YY_BREAK
+
+case 383:
+YY_RULE_SETUP
+#line 810 "scanner.l"
+{ return XML; }
+ YY_BREAK
+case 384:
+YY_RULE_SETUP
+#line 811 "scanner.l"
+{ return JSON; }
+ YY_BREAK
+case 385:
+YY_RULE_SETUP
+#line 812 "scanner.l"
+{ return VM; }
+ YY_BREAK
+
+case 386:
+YY_RULE_SETUP
+#line 815 "scanner.l"
+{ return EXISTS; }
+ YY_BREAK
+case 387:
+YY_RULE_SETUP
+#line 816 "scanner.l"
+{ return MISSING; }
+ YY_BREAK
+case 388:
+YY_RULE_SETUP
+#line 818 "scanner.l"
+{ return EXTHDR; }
+ YY_BREAK
+case 389:
+YY_RULE_SETUP
+#line 820 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_IPSEC); return IPSEC; }
+ YY_BREAK
+
+case 390:
+YY_RULE_SETUP
+#line 822 "scanner.l"
+{ return REQID; }
+ YY_BREAK
+case 391:
+YY_RULE_SETUP
+#line 823 "scanner.l"
+{ return SPNUM; }
+ YY_BREAK
+case 392:
+YY_RULE_SETUP
+#line 825 "scanner.l"
+{ return IN; }
+ YY_BREAK
+case 393:
+YY_RULE_SETUP
+#line 826 "scanner.l"
+{ return OUT; }
+ YY_BREAK
+
+case 394:
+YY_RULE_SETUP
+#line 829 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_SECMARK); return SECMARK; }
+ YY_BREAK
+case 395:
+YY_RULE_SETUP
+#line 831 "scanner.l"
+{ scanner_push_start_cond(yyscanner, SCANSTATE_XT); return XT; }
+ YY_BREAK
+case 396:
+YY_RULE_SETUP
+#line 833 "scanner.l"
+{
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ YY_BREAK
+case 397:
+YY_RULE_SETUP
+#line 838 "scanner.l"
+{
+ yytext[yyleng - 1] = '\0';
+ yylval->string = xstrdup(yytext + 1);
+ return STRING;
+ }
+ YY_BREAK
+case 398:
+YY_RULE_SETUP
+#line 844 "scanner.l"
+{
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ YY_BREAK
+case 399:
+YY_RULE_SETUP
+#line 849 "scanner.l"
+{
+ errno = 0;
+ yylval->val = strtoull(yytext, NULL, 16);
+ if (errno != 0) {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ return NUM;
+ }
+ YY_BREAK
+case 400:
+YY_RULE_SETUP
+#line 859 "scanner.l"
+{
+ 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;
+ }
+ YY_BREAK
+case 401:
+/* rule 401 can match eol */
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+YY_LINENO_REWIND_TO(yy_cp - 1);
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 872 "scanner.l"
+{
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ YY_BREAK
+case 402:
+/* rule 402 can match eol */
+YY_RULE_SETUP
+#line 877 "scanner.l"
+{
+ yytext[yyleng - 1] = '\0';
+ yylval->string = xstrdup(yytext + 1);
+ return QUOTED_STRING;
+ }
+ YY_BREAK
+case 403:
+YY_RULE_SETUP
+#line 883 "scanner.l"
+{
+ yylval->string = xstrdup(yytext);
+ return ASTERISK_STRING;
+ }
+ YY_BREAK
+case 404:
+YY_RULE_SETUP
+#line 888 "scanner.l"
+{
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ YY_BREAK
+case 405:
+/* rule 405 can match eol */
+YY_RULE_SETUP
+#line 893 "scanner.l"
+{
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
+ YY_BREAK
+case 406:
+/* rule 406 can match eol */
+YY_RULE_SETUP
+#line 897 "scanner.l"
+{
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ return NEWLINE;
+ }
+ YY_BREAK
+case 407:
+YY_RULE_SETUP
+#line 902 "scanner.l"
+
+ YY_BREAK
+case 408:
+YY_RULE_SETUP
+#line 903 "scanner.l"
+
+ YY_BREAK
+case 409:
+/* rule 409 can match eol */
+YY_RULE_SETUP
+#line 904 "scanner.l"
+{
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
+ YY_BREAK
+case 410:
+*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */
+yyg->yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 907 "scanner.l"
+
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(SCANSTATE_ARP):
+case YY_STATE_EOF(SCANSTATE_AT):
+case YY_STATE_EOF(SCANSTATE_CT):
+case YY_STATE_EOF(SCANSTATE_COUNTER):
+case YY_STATE_EOF(SCANSTATE_ETH):
+case YY_STATE_EOF(SCANSTATE_GRE):
+case YY_STATE_EOF(SCANSTATE_ICMP):
+case YY_STATE_EOF(SCANSTATE_IGMP):
+case YY_STATE_EOF(SCANSTATE_IP):
+case YY_STATE_EOF(SCANSTATE_IP6):
+case YY_STATE_EOF(SCANSTATE_LAST):
+case YY_STATE_EOF(SCANSTATE_LIMIT):
+case YY_STATE_EOF(SCANSTATE_META):
+case YY_STATE_EOF(SCANSTATE_POLICY):
+case YY_STATE_EOF(SCANSTATE_QUOTA):
+case YY_STATE_EOF(SCANSTATE_SCTP):
+case YY_STATE_EOF(SCANSTATE_SECMARK):
+case YY_STATE_EOF(SCANSTATE_TCP):
+case YY_STATE_EOF(SCANSTATE_TYPE):
+case YY_STATE_EOF(SCANSTATE_VLAN):
+case YY_STATE_EOF(SCANSTATE_XT):
+case YY_STATE_EOF(SCANSTATE_CMD_DESTROY):
+case YY_STATE_EOF(SCANSTATE_CMD_EXPORT):
+case YY_STATE_EOF(SCANSTATE_CMD_IMPORT):
+case YY_STATE_EOF(SCANSTATE_CMD_LIST):
+case YY_STATE_EOF(SCANSTATE_CMD_MONITOR):
+case YY_STATE_EOF(SCANSTATE_CMD_RESET):
+case YY_STATE_EOF(SCANSTATE_EXPR_AH):
+case YY_STATE_EOF(SCANSTATE_EXPR_COMP):
+case YY_STATE_EOF(SCANSTATE_EXPR_DCCP):
+case YY_STATE_EOF(SCANSTATE_EXPR_DST):
+case YY_STATE_EOF(SCANSTATE_EXPR_ESP):
+case YY_STATE_EOF(SCANSTATE_EXPR_FIB):
+case YY_STATE_EOF(SCANSTATE_EXPR_FRAG):
+case YY_STATE_EOF(SCANSTATE_EXPR_HASH):
+case YY_STATE_EOF(SCANSTATE_EXPR_HBH):
+case YY_STATE_EOF(SCANSTATE_EXPR_IPSEC):
+case YY_STATE_EOF(SCANSTATE_EXPR_MH):
+case YY_STATE_EOF(SCANSTATE_EXPR_NUMGEN):
+case YY_STATE_EOF(SCANSTATE_EXPR_OSF):
+case YY_STATE_EOF(SCANSTATE_EXPR_QUEUE):
+case YY_STATE_EOF(SCANSTATE_EXPR_RT):
+case YY_STATE_EOF(SCANSTATE_EXPR_SCTP_CHUNK):
+case YY_STATE_EOF(SCANSTATE_EXPR_SOCKET):
+case YY_STATE_EOF(SCANSTATE_EXPR_TH):
+case YY_STATE_EOF(SCANSTATE_EXPR_UDP):
+case YY_STATE_EOF(SCANSTATE_EXPR_UDPLITE):
+case YY_STATE_EOF(SCANSTATE_STMT_DUP):
+case YY_STATE_EOF(SCANSTATE_STMT_FWD):
+case YY_STATE_EOF(SCANSTATE_STMT_LOG):
+case YY_STATE_EOF(SCANSTATE_STMT_NAT):
+case YY_STATE_EOF(SCANSTATE_STMT_REJECT):
+case YY_STATE_EOF(SCANSTATE_STMT_SYNPROXY):
+case YY_STATE_EOF(SCANSTATE_STMT_TPROXY):
+#line 909 "scanner.l"
+{
+ update_pos(yyget_extra(yyscanner), yylloc, 1);
+ scanner_pop_buffer(yyscanner);
+ if (YY_CURRENT_BUFFER == NULL)
+ return TOKEN_EOF;
+ }
+ YY_BREAK
+case 411:
+YY_RULE_SETUP
+#line 916 "scanner.l"
+{ return JUNK; }
+ YY_BREAK
+case 412:
+YY_RULE_SETUP
+#line 918 "scanner.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+#line 6781 "scanner.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+/* %if-c-only */
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */
+ yy_cp = yyg->yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap( yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+/* %ok-for-header */
+
+/* %if-c++-only */
+/* %not-for-header */
+/* %ok-for-header */
+
+/* %endif */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+/* %if-c-only */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ char *source = yyg->yytext_ptr;
+ int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1);
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc( (void *) b->yy_ch_buf,
+ (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = NULL;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin , yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc(
+ (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ /* "- 2" to take care of EOB's */
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2);
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+/* %if-c-only */
+/* %not-for-header */
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ yy_state_type yy_current_state;
+ char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+/* %% [15.0] code to get the start state into yy_current_state goes here */
+ yy_current_state = yyg->yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+/* %% [16.0] code to find the next state goes here */
+ YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 2383 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+/* %if-c-only */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+/* %% [17.0] code to find the next state, and perhaps do backing up, goes here */
+ char *yy_cp = yyg->yy_c_buf_p;
+
+ YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 2383 )
+ yy_c = yy_meta[yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 2382);
+
+ (void)yyg;
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_UNPUT
+/* %if-c-only */
+
+/* %endif */
+#endif
+
+/* %if-c-only */
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr);
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin , yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( yyscanner ) )
+ return 0;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+/* %% [19.0] update BOL and yylineno */
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n');
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+/* %if-c-only */
+#endif /* ifndef YY_NO_INPUT */
+/* %endif */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+/* %if-c-only */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner);
+ }
+
+ yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner);
+ yy_load_buffer_state( yyscanner );
+}
+
+/* %if-c++-only */
+/* %endif */
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+/* %if-c-only */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/* %if-c-only */
+static void yy_load_buffer_state (yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+/* %if-c-only */
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+/* %if-c-only */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file , yyscanner);
+
+ return b;
+}
+
+/* %if-c++-only */
+/* %endif */
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+/* %if-c-only */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree( (void *) b->yy_ch_buf , yyscanner );
+
+ yyfree( (void *) b , yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+/* %if-c-only */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer( b , yyscanner);
+
+/* %if-c-only */
+ b->yy_input_file = file;
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+/* %if-c-only */
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+/* %if-c-only */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( yyscanner );
+}
+
+/* %if-c-or-c++ */
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+/* %if-c-only */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+/* %endif */
+
+/* %if-c-or-c++ */
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+/* %if-c-only */
+void yypop_buffer_state (yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+/* %endif */
+
+/* %if-c-or-c++ */
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+/* %if-c-only */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ yy_size_t num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ yy_size_t grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return NULL;
+
+ b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = NULL;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b , yyscanner );
+
+ return b;
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner);
+}
+/* %endif */
+
+/* %if-c-only */
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = (yy_size_t) (_yybytes_len + 2);
+ buf = (char *) yyalloc( n , yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n , yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+/* %endif */
+
+/* %if-c-only */
+ static void yy_push_state (int _new_state , yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yyg->yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = (yy_size_t) yyg->yy_start_stack_depth * sizeof( int );
+
+ if ( ! yyg->yy_start_stack )
+ yyg->yy_start_stack = (int *) yyalloc( new_size , yyscanner );
+
+ else
+ yyg->yy_start_stack = (int *) yyrealloc(
+ (void *) yyg->yy_start_stack, new_size , yyscanner );
+
+ if ( ! yyg->yy_start_stack )
+ YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
+ }
+
+ yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(_new_state);
+}
+
+/* %if-c-only */
+ static void yy_pop_state (yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( --yyg->yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]);
+}
+
+/* %if-c-only */
+ static int yy_top_state (yyscan_t yyscanner)
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1];
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+/* %if-c-only */
+static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+/* %endif */
+/* %if-c++-only */
+/* %endif */
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/* %if-c-only */
+/* %if-reentrant */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/* %endif */
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/* %if-reentrant */
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/* %endif */
+
+/** Set the current line number.
+ * @param _line_number line number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int _line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_lineno called with no buffer" );
+
+ yylineno = _line_number;
+}
+
+/** Set the current column.
+ * @param _column_no column number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int _column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ YY_FATAL_ERROR( "yyset_column called with no buffer" );
+
+ yycolumn = _column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param _in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * _in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = _in_str ;
+}
+
+void yyset_out (FILE * _out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = _out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int _bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = _bdebug ;
+}
+
+/* %endif */
+
+/* %if-reentrant */
+/* Accessor methods for yylval and yylloc */
+
+/* %if-bison-bridge */
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+YYLTYPE *yyget_lloc (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylloc;
+}
+
+void yyset_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylloc = yylloc_param;
+}
+
+/* %endif */
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+int yylex_init(yyscan_t* ptr_yy_globals)
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals )
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* %endif if-c-only */
+
+/* %if-c-only */
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = NULL;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = NULL;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = NULL;
+ yyout = NULL;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+/* %endif */
+
+/* %if-c-only SNIP! this currently causes conflicts with the c++ scanner */
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack , yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree( yyg->yy_start_stack , yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+/* %if-reentrant */
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+/* %endif */
+ return 0;
+}
+/* %endif */
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (const char * s , yyscan_t yyscanner)
+{
+ int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ return malloc(size);
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return realloc(ptr, size);
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ (void)yyg;
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+/* %if-tables-serialization definitions */
+/* %define-yytables The name for this specific scanner's tables. */
+#define YYTABLES_NAME "yytables"
+/* %endif */
+
+/* %ok-for-header */
+
+#line 918 "scanner.l"
+
+
+static void scanner_push_indesc(struct parser_state *state,
+ struct input_descriptor *indesc)
+{
+ if (!state->indesc)
+ list_add_tail(&indesc->list, &state->indesc_list);
+ else
+ list_add(&indesc->list, &state->indesc->list);
+
+ state->indesc = indesc;
+}
+
+static void scanner_pop_indesc(struct parser_state *state)
+{
+ if (!list_is_first(&state->indesc->list, &state->indesc_list)) {
+ state->indesc = list_entry(state->indesc->list.prev,
+ struct input_descriptor, list);
+ } else {
+ state->indesc = NULL;
+ }
+}
+
+static void scanner_pop_buffer(yyscan_t scanner)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ yypop_buffer_state(scanner);
+ scanner_pop_indesc(state);
+}
+
+static void scanner_push_file(struct nft_ctx *nft, void *scanner,
+ FILE *f, const char *filename,
+ const struct location *loc,
+ const struct input_descriptor *parent_indesc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *indesc;
+ YY_BUFFER_STATE b;
+
+ b = yy_create_buffer(f, YY_BUF_SIZE, scanner);
+ yypush_buffer_state(b, scanner);
+
+ indesc = xzalloc(sizeof(struct input_descriptor));
+
+ if (loc != NULL)
+ indesc->location = *loc;
+ indesc->type = INDESC_FILE;
+ indesc->name = xstrdup(filename);
+ indesc->f = f;
+ if (!parent_indesc) {
+ indesc->depth = 1;
+ } else {
+ indesc->depth = parent_indesc->depth + 1;
+ }
+ init_pos(indesc);
+
+ 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,
+ enum nft_include_type includetype)
+
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct error_record *erec;
+ FILE *f;
+
+ if (parent_indesc && parent_indesc->depth == MAX_INCLUDE_DEPTH) {
+ erec = error(loc, "Include nested too deeply, max %u levels",
+ MAX_INCLUDE_DEPTH);
+ goto err;
+ }
+
+ if (includetype == NFT_INCLUDE && !filename_is_useable(filename)) {
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+ goto err;
+ }
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ erec = error(loc, "Could not open file \"%s\": %s\n",
+ filename, strerror(errno));
+ goto err;
+ }
+
+ if (!fp_is_useable(f, includetype)) {
+ fclose(f);
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+ goto err;
+ }
+
+ scanner_push_file(nft, scanner, f, filename, loc, parent_indesc);
+ return 0;
+err:
+ erec_queue(erec, state->msgs);
+ return -1;
+}
+
+static int include_glob(struct nft_ctx *nft, void *scanner, const char *pattern,
+ const struct location *loc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *indesc = state->indesc;
+ struct error_record *erec = NULL;
+ bool wildcard = false;
+ glob_t glob_data;
+ unsigned int i;
+ int flags = 0;
+ int ret;
+ char *p;
+
+ /* This function can return four meaningful values:
+ *
+ * -1 means that there was an error.
+ * 0 means that a single non-wildcard match was done.
+ * 1 means that there are no wildcards in the pattern and the
+ * search can continue.
+ * 2 means that there are wildcards in the pattern and the search
+ * can continue.
+ *
+ * The diffrence is needed, because there is a semantic difference
+ * between patterns with wildcards and no wildcards. Not finding a
+ * non-wildcard file is an error but not finding any matches for a
+ * wildcard pattern is not.
+ */
+
+ /* There shouldn't be a need to use escape characters in include paths.
+ */
+ flags |= GLOB_NOESCAPE;
+
+ /* Mark directories so we can filter them out (also links). */
+ flags |= GLOB_MARK;
+
+ /* If there is no match, glob() doesn't set GLOB_MAGCHAR even if there
+ * are wildcard characters in the pattern. We need to look for (luckily
+ * well-known and not likely to change) magic characters ourselves. In a
+ * perfect world, we could use glob() itself to figure out if there are
+ * wildcards in the pattern.
+ */
+ p = (char *)pattern;
+ while (*p) {
+ if (*p == '*' || *p == '?' || *p == '[') {
+ wildcard = true;
+ break;
+ }
+ p++;
+ }
+
+ ret = glob(pattern, flags, NULL, &glob_data);
+ if (ret == 0) {
+ char *path;
+ int len;
+
+ /* reverse alphabetical order due to stack */
+ for (i = glob_data.gl_pathc; i > 0; i--) {
+
+ path = glob_data.gl_pathv[i-1];
+
+ /* ignore directories */
+ len = strlen(path);
+ if (len == 0 || path[len - 1] == '/')
+ continue;
+
+ ret = include_file(nft, scanner, path, loc, indesc, NFT_INCLUDE);
+ if (ret != 0)
+ goto err;
+ }
+
+ globfree(&glob_data);
+
+ /* If no wildcards and we found the file, stop the search (with
+ * 0). In case of wildcards we need to still continue the
+ * search, because other matches might be in other include
+ * directories. We handled the case with a non-wildcard pattern
+ * and no matches already before.
+ */
+ return wildcard ? 2 : 0;
+ } else if (ret == GLOB_NOMATCH) {
+ globfree(&glob_data);
+
+ /* We need to tell the caller whether wildcards were used in
+ * case of no match, because the semantics for handling the
+ * cases are different.
+ */
+ return wildcard ? 2 : 1;
+ }
+
+ erec = error(loc, "Failed to glob the pattern %s", pattern);
+
+ /* intentional fall through */
+err:
+ if (erec)
+ erec_queue(erec, state->msgs);
+ globfree(&glob_data);
+ return -1;
+}
+
+int scanner_read_file(struct nft_ctx *nft, const char *filename,
+ const struct location *loc)
+{
+ return include_file(nft, nft->scanner, filename, loc, NULL, NFT_CMDLINE);
+}
+
+static bool search_in_include_path(const char *filename)
+{
+ return (strncmp(filename, "./", strlen("./")) != 0 &&
+ strncmp(filename, "../", strlen("../")) != 0 &&
+ filename[0] != '/');
+}
+
+int scanner_include_file(struct nft_ctx *nft, void *scanner,
+ const char *filename, const struct location *loc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct error_record *erec;
+ char buf[PATH_MAX];
+ unsigned int i;
+ int ret = -1;
+
+ if (search_in_include_path(filename)) {
+ for (i = 0; i < nft->num_include_paths; i++) {
+ ret = snprintf(buf, sizeof(buf), "%s/%s",
+ nft->include_paths[i], filename);
+ if (ret < 0 || ret >= PATH_MAX) {
+ erec = error(loc, "Too long file path \"%s/%s\"\n",
+ nft->include_paths[i], filename);
+ erec_queue(erec, state->msgs);
+ return -1;
+ }
+
+ ret = include_glob(nft, scanner, buf, loc);
+
+ /* error was already handled */
+ if (ret == -1)
+ return -1;
+ /* no wildcards and file was processed: break early. */
+ if (ret == 0)
+ return 0;
+
+ /* else 1 (no wildcards) or 2 (wildcards): keep
+ * searching.
+ */
+ }
+ } else {
+ /* an absolute path (starts with '/') */
+ ret = include_glob(nft, scanner, filename, loc);
+ }
+
+ /* handle the case where no file was found */
+ if (ret == -1)
+ return -1;
+ else if (ret == 0 || ret == 2)
+ return 0;
+
+ /* 1 means an error, because there are no more include directories to
+ * search, and the pattern does not have wildcard characters.
+ */
+ erec = error(loc, "File not found: %s", filename);
+ erec_queue(erec, state->msgs);
+ return -1;
+}
+
+void scanner_push_buffer(void *scanner, const struct input_descriptor *indesc,
+ const char *buffer)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *new_indesc;
+ YY_BUFFER_STATE b;
+
+ new_indesc = xzalloc(sizeof(struct input_descriptor));
+ memcpy(new_indesc, indesc, sizeof(*new_indesc));
+ new_indesc->data = buffer;
+ new_indesc->name = xstrdup(indesc->name);
+ scanner_push_indesc(state, new_indesc);
+
+ b = yy_scan_string(buffer, scanner);
+ assert(b != NULL);
+ init_pos(state->indesc);
+}
+
+void *scanner_init(struct parser_state *state)
+{
+ yyscan_t scanner;
+
+ 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);
+}
+
+static void input_descriptor_list_destroy(struct parser_state *state)
+{
+ struct input_descriptor *indesc, *next;
+
+ list_for_each_entry_safe(indesc, next, &state->indesc_list, list) {
+ if (indesc->f) {
+ fclose(indesc->f);
+ indesc->f = NULL;
+ }
+ list_del(&indesc->list);
+ input_descriptor_destroy(indesc);
+ }
+}
+
+void scanner_destroy(struct nft_ctx *nft)
+{
+ struct parser_state *state = yyget_extra(nft->scanner);
+
+ input_descriptor_list_destroy(state);
+ xfree(state->startcond_active);
+
+ yylex_destroy(nft->scanner);
+}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_type = type;
+ state->startcond_active[type]++;
+
+ yy_push_state((int)type, scanner);
+}
+
+void scanner_pop_start_cond(void *scanner, enum startcond_type t)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_active[t]--;
+
+ if (state->startcond_type != t) {
+ state->flex_state_pop++;
+ return; /* Can't pop just yet! */
+ }
+
+ while (state->flex_state_pop) {
+ state->flex_state_pop--;
+ state->startcond_type = yy_top_state(scanner);
+ yy_pop_state(scanner);
+
+ t = state->startcond_type;
+ if (state->startcond_active[t])
+ return;
+ }
+
+ state->startcond_type = yy_top_state(scanner);
+
+ yy_pop_state(scanner);
+}
+
diff --git a/src/scanner.l b/src/scanner.l
new file mode 100644
index 0000000..88376b7
--- /dev/null
+++ b/src/scanner.l
@@ -0,0 +1,1326 @@
+/*
+ * Copyright (c) 2007-2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+%{
+
+#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>
+#include <rule.h>
+#include <parser.h>
+#include "parser_bison.h"
+
+#define YY_NO_INPUT
+
+/*
+ * Work around flex behaviour when reaching the end of buffer: normally, flex
+ * regexes are greedy, when reaching the end of buffer however it tries to
+ * match whatever is left in the buffer and only backs up in case it doesn't
+ * match *any* pattern. Since we accept unquoted strings, this means any partial
+ * token will be recognized as string.
+ *
+ * Make sure to only pass input to flex linewise to avoid this.
+ */
+#define YY_INPUT(buf,result,max_size) \
+{ \
+ result = 0; \
+ errno = 0; \
+ \
+ while (result < max_size) { \
+ int chr = fgetc(yyin); \
+ \
+ if (chr != EOF) { \
+ buf[result++] = chr; \
+ if (chr == '\n' || chr == ' ') \
+ break; \
+ continue; \
+ } \
+ \
+ if (ferror(yyin)) { \
+ if (errno != EINTR) { \
+ YY_FATAL_ERROR("input in flex scanner failed"); \
+ break; \
+ } \
+ errno = 0; \
+ clearerr(yyin); \
+ } \
+ break; \
+ } \
+}
+
+static void scanner_pop_buffer(yyscan_t scanner);
+
+
+static void init_pos(struct input_descriptor *indesc)
+{
+ indesc->lineno = 1;
+ indesc->column = 1;
+ indesc->token_offset = 0;
+ indesc->line_offset = 0;
+}
+
+static void update_pos(struct parser_state *state, struct location *loc,
+ int len)
+{
+ loc->indesc = state->indesc;
+ loc->first_line = state->indesc->lineno;
+ loc->last_line = state->indesc->lineno;
+ loc->first_column = state->indesc->column;
+ loc->last_column = state->indesc->column + len - 1;
+ state->indesc->column += len;
+}
+
+static void update_offset(struct parser_state *state, struct location *loc,
+ unsigned int len)
+{
+ state->indesc->token_offset += len;
+ loc->token_offset = state->indesc->token_offset;
+ loc->line_offset = state->indesc->line_offset;
+}
+
+static void reset_pos(struct parser_state *state, struct location *loc)
+{
+ state->indesc->line_offset = state->indesc->token_offset;
+ state->indesc->lineno += 1;
+ state->indesc->column = 1;
+}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type);
+
+#define YY_USER_ACTION { \
+ update_pos(yyget_extra(yyscanner), yylloc, yyleng); \
+ update_offset(yyget_extra(yyscanner), yylloc, yyleng); \
+}
+
+/* avoid warnings with -Wmissing-prototypes */
+extern int yyget_column(yyscan_t);
+extern void yyset_column(int, yyscan_t);
+
+%}
+
+space [ ]
+tab \t
+newline \n
+digit [0-9]
+hexdigit [0-9a-fA-F]
+decstring {digit}+
+hexstring 0[xX]{hexdigit}+
+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)?
+
+hex4 ([[:xdigit:]]{1,4})
+v680 (({hex4}:){7}{hex4})
+v670 ((:)((:{hex4}){7}))
+v671 ((({hex4}:){1})((:{hex4}){6}))
+v672 ((({hex4}:){2})((:{hex4}){5}))
+v673 ((({hex4}:){3})((:{hex4}){4}))
+v674 ((({hex4}:){4})((:{hex4}){3}))
+v675 ((({hex4}:){5})((:{hex4}){2}))
+v676 ((({hex4}:){6})(:{hex4}{1}))
+v677 ((({hex4}:){7})(:))
+v67 ({v670}|{v671}|{v672}|{v673}|{v674}|{v675}|{v676}|{v677})
+v660 ((:)((:{hex4}){6}))
+v661 ((({hex4}:){1})((:{hex4}){5}))
+v662 ((({hex4}:){2})((:{hex4}){4}))
+v663 ((({hex4}:){3})((:{hex4}){3}))
+v664 ((({hex4}:){4})((:{hex4}){2}))
+v665 ((({hex4}:){5})((:{hex4}){1}))
+v666 ((({hex4}:){6})(:))
+v66 ({v660}|{v661}|{v662}|{v663}|{v664}|{v665}|{v666})
+v650 ((:)((:{hex4}){5}))
+v651 ((({hex4}:){1})((:{hex4}){4}))
+v652 ((({hex4}:){2})((:{hex4}){3}))
+v653 ((({hex4}:){3})((:{hex4}){2}))
+v654 ((({hex4}:){4})(:{hex4}{1}))
+v655 ((({hex4}:){5})(:))
+v65 ({v650}|{v651}|{v652}|{v653}|{v654}|{v655})
+v640 ((:)((:{hex4}){4}))
+v641 ((({hex4}:){1})((:{hex4}){3}))
+v642 ((({hex4}:){2})((:{hex4}){2}))
+v643 ((({hex4}:){3})((:{hex4}){1}))
+v644 ((({hex4}:){4})(:))
+v64 ({v640}|{v641}|{v642}|{v643}|{v644})
+v630 ((:)((:{hex4}){3}))
+v631 ((({hex4}:){1})((:{hex4}){2}))
+v632 ((({hex4}:){2})((:{hex4}){1}))
+v633 ((({hex4}:){3})(:))
+v63 ({v630}|{v631}|{v632}|{v633})
+v620 ((:)((:{hex4}){2}))
+v620_rfc4291 ((:)(:{ip4addr}))
+v621 ((({hex4}:){1})((:{hex4}){1}))
+v622 ((({hex4}:){2})(:))
+v62_rfc4291 ((:)(:[fF]{4})(:{ip4addr}))
+v62 ({v620}|{v621}|{v622}|{v62_rfc4291}|{v620_rfc4291})
+v610 ((:)(:{hex4}{1}))
+v611 ((({hex4}:){1})(:))
+v61 ({v610}|{v611})
+v60 (::)
+
+macaddr (([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2})
+ip4addr (([[:digit:]]{1,3}"."){3}([[:digit:]]{1,3}))
+ip6addr ({v680}|{v67}|{v66}|{v65}|{v64}|{v63}|{v62}|{v61}|{v60})
+ip6addr_rfc2732 (\[{ip6addr}\])
+
+classid ({hexdigit}{1,4}:{hexdigit}{1,4})
+addrstring ({macaddr}|{ip4addr}|{ip6addr})
+
+%option prefix="nft_"
+%option outfile="lex.yy.c"
+%option reentrant
+%option noyywrap
+%option nounput
+%option bison-bridge
+%option bison-locations
+%option debug
+%option yylineno
+%option nodefault
+%option warn
+%option stack
+%s SCANSTATE_ARP
+%s SCANSTATE_AT
+%s SCANSTATE_CT
+%s SCANSTATE_COUNTER
+%s SCANSTATE_ETH
+%s SCANSTATE_GRE
+%s SCANSTATE_ICMP
+%s SCANSTATE_IGMP
+%s SCANSTATE_IP
+%s SCANSTATE_IP6
+%s SCANSTATE_LAST
+%s SCANSTATE_LIMIT
+%s SCANSTATE_META
+%s SCANSTATE_POLICY
+%s SCANSTATE_QUOTA
+%s SCANSTATE_SCTP
+%s SCANSTATE_SECMARK
+%s SCANSTATE_TCP
+%s SCANSTATE_TYPE
+%s SCANSTATE_VLAN
+%s SCANSTATE_XT
+%s SCANSTATE_CMD_DESTROY
+%s SCANSTATE_CMD_EXPORT
+%s SCANSTATE_CMD_IMPORT
+%s SCANSTATE_CMD_LIST
+%s SCANSTATE_CMD_MONITOR
+%s SCANSTATE_CMD_RESET
+%s SCANSTATE_EXPR_AH
+%s SCANSTATE_EXPR_COMP
+%s SCANSTATE_EXPR_DCCP
+%s SCANSTATE_EXPR_DST
+%s SCANSTATE_EXPR_ESP
+%s SCANSTATE_EXPR_FIB
+%s SCANSTATE_EXPR_FRAG
+%s SCANSTATE_EXPR_HASH
+%s SCANSTATE_EXPR_HBH
+%s SCANSTATE_EXPR_IPSEC
+%s SCANSTATE_EXPR_MH
+%s SCANSTATE_EXPR_NUMGEN
+%s SCANSTATE_EXPR_OSF
+%s SCANSTATE_EXPR_QUEUE
+%s SCANSTATE_EXPR_RT
+%s SCANSTATE_EXPR_SCTP_CHUNK
+%s SCANSTATE_EXPR_SOCKET
+%s SCANSTATE_EXPR_TH
+%s SCANSTATE_EXPR_UDP
+%s SCANSTATE_EXPR_UDPLITE
+
+%s SCANSTATE_STMT_DUP
+%s SCANSTATE_STMT_FWD
+%s SCANSTATE_STMT_LOG
+%s SCANSTATE_STMT_NAT
+%s SCANSTATE_STMT_REJECT
+%s SCANSTATE_STMT_SYNPROXY
+%s SCANSTATE_STMT_TPROXY
+
+%%
+
+"==" { return EQ; }
+"eq" { return EQ; }
+"!=" { return NEQ; }
+"ne" { return NEQ; }
+"<=" { return LTE; }
+"le" { return LTE; }
+"<" { return LT; }
+"lt" { return LT; }
+">=" { return GTE; }
+"ge" { return GTE; }
+">" { return GT; }
+"gt" { return GT; }
+"," { return COMMA; }
+"." { return DOT; }
+":" { return COLON; }
+";" { return SEMICOLON; }
+"{" { return '{'; }
+"}" { return '}'; }
+"[" { return '['; }
+"]" { return ']'; }
+"(" { return '('; }
+")" { return ')'; }
+"<<" { return LSHIFT; }
+"lshift" { return LSHIFT; }
+">>" { return RSHIFT; }
+"rshift" { return RSHIFT; }
+"^" { return CARET; }
+"xor" { return CARET; }
+"&" { return AMPERSAND; }
+"and" { return AMPERSAND; }
+"|" { return '|'; }
+"or" { return '|'; }
+"!" { return NOT; }
+"not" { return NOT; }
+"/" { return SLASH; }
+"-" { return DASH; }
+"*" { return ASTERISK; }
+"@" { scanner_push_start_cond(yyscanner, SCANSTATE_AT); return AT; }
+"$" { return '$'; }
+"=" { return '='; }
+"vmap" { return VMAP; }
+
+"+" { return PLUS; }
+
+"include" { return INCLUDE; }
+"define" { return DEFINE; }
+"redefine" { return REDEFINE; }
+"undefine" { return UNDEFINE; }
+
+"describe" { return DESCRIBE; }
+
+<SCANSTATE_CMD_LIST,SCANSTATE_CMD_MONITOR>{
+ "chains" { return CHAINS; }
+ "sets" { return SETS; }
+ "tables" { return TABLES; }
+}
+<SCANSTATE_CMD_MONITOR>{
+ "rules" { return RULES; }
+ "trace" { return TRACE; }
+}
+"hook" { return HOOK; }
+"device" { return DEVICE; }
+"devices" { return DEVICES; }
+"table" { return TABLE; }
+"chain" { return CHAIN; }
+"rule" { return RULE; }
+"set" { return SET; }
+"element" { return ELEMENT; }
+"map" { return MAP; }
+"flowtable" { return FLOWTABLE; }
+"handle" { return HANDLE; }
+"ruleset" { return RULESET; }
+
+"socket" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SOCKET); return SOCKET; }
+<SCANSTATE_EXPR_SOCKET>{
+ "transparent" { return TRANSPARENT; }
+ "wildcard" { return WILDCARD; }
+ "cgroupv2" { return CGROUPV2; }
+ "level" { return LEVEL; }
+}
+"tproxy" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_TPROXY); return TPROXY; }
+
+"accept" { return ACCEPT; }
+"drop" { return DROP; }
+"continue" { return CONTINUE; }
+"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_IP,SCANSTATE_IP6>"to" { return TO; } /* XXX: SCANSTATE_IP is a workaround */
+
+"inet" { return INET; }
+"netdev" { return NETDEV; }
+
+"add" { return ADD; }
+"replace" { return REPLACE; }
+"update" { return UPDATE; }
+"create" { return CREATE; }
+"insert" { return INSERT; }
+"delete" { return DELETE; }
+"get" { return GET; }
+"list" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_LIST); return LIST; }
+"reset" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_RESET); return RESET; }
+"flush" { return FLUSH; }
+"rename" { return RENAME; }
+"import" { 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; }
+
+"constant" { return CONSTANT; }
+"interval" { return INTERVAL; }
+"dynamic" { return DYNAMIC; }
+"auto-merge" { return AUTOMERGE; }
+"timeout" { return TIMEOUT; }
+"gc-interval" { return GC_INTERVAL; }
+"elements" { return ELEMENTS; }
+"expires" { return EXPIRES; }
+
+"policy" { scanner_push_start_cond(yyscanner, SCANSTATE_POLICY); return POLICY; }
+"size" { return SIZE; }
+<SCANSTATE_POLICY>{
+ "performance" { return PERFORMANCE; }
+ "memory" { return MEMORY; }
+}
+
+"flow" { return FLOW; }
+"offload" { return OFFLOAD; }
+"meter" { return METER; }
+
+<SCANSTATE_CMD_LIST>{
+ "meters" { return METERS; }
+ "flowtables" { return FLOWTABLES; }
+ "limits" { return LIMITS; }
+ "maps" { return MAPS; }
+ "secmarks" { return SECMARKS; }
+ "synproxys" { return SYNPROXYS; }
+ "hooks" { return HOOKS; }
+}
+
+"counter" { scanner_push_start_cond(yyscanner, SCANSTATE_COUNTER); return COUNTER; }
+<SCANSTATE_COUNTER,SCANSTATE_LIMIT,SCANSTATE_QUOTA,SCANSTATE_STMT_SYNPROXY,SCANSTATE_EXPR_OSF>"name" { return NAME; }
+<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT>"packets" { return PACKETS; }
+<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT,SCANSTATE_QUOTA>"bytes" { return BYTES; }
+
+"last" { scanner_push_start_cond(yyscanner, SCANSTATE_LAST); return LAST; }
+<SCANSTATE_LAST>{
+ "never" { return NEVER; }
+}
+
+<SCANSTATE_CMD_LIST,SCANSTATE_CMD_RESET>{
+ "counters" { return COUNTERS; }
+ "quotas" { return QUOTAS; }
+ "rules" { return RULES; }
+}
+
+"log" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_LOG); return LOG; }
+<SCANSTATE_STMT_LOG,SCANSTATE_STMT_NAT,SCANSTATE_IP,SCANSTATE_IP6>"prefix" { return PREFIX; }
+<SCANSTATE_STMT_LOG>{
+ "snaplen" { return SNAPLEN; }
+ "queue-threshold" { return QUEUE_THRESHOLD; }
+ "level" { return LEVEL; }
+ "group" { return GROUP; }
+}
+
+"queue" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_QUEUE); return QUEUE;}
+<SCANSTATE_EXPR_QUEUE>{
+ "num" { return QUEUENUM;}
+ "bypass" { return BYPASS;}
+ "fanout" { return FANOUT;}
+}
+"limit" { scanner_push_start_cond(yyscanner, SCANSTATE_LIMIT); return LIMIT; }
+<SCANSTATE_LIMIT>{
+ "rate" { return RATE; }
+ "burst" { return BURST; }
+
+ /* time_unit */
+ "second" { return SECOND; }
+ "minute" { return MINUTE; }
+ "week" { return WEEK; }
+}
+<SCANSTATE_CT,SCANSTATE_LIMIT,SCANSTATE_QUOTA>"over" { return OVER; }
+
+"quota" { scanner_push_start_cond(yyscanner, SCANSTATE_QUOTA); return QUOTA; }
+<SCANSTATE_QUOTA>{
+ "until" { return UNTIL; }
+}
+
+<SCANSTATE_QUOTA,SCANSTATE_LAST>"used" { return USED; }
+
+"hour" { return HOUR; }
+"day" { return DAY; }
+
+"reject" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_REJECT); return _REJECT; }
+<SCANSTATE_STMT_REJECT>{
+ "with" { return WITH; }
+ "icmpx" { return ICMPX; }
+}
+
+"snat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; }
+"dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; }
+"masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; }
+"redirect" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return REDIRECT; }
+"random" { return RANDOM; }
+<SCANSTATE_STMT_NAT>{
+ "fully-random" { return FULLY_RANDOM; }
+ "persistent" { return PERSISTENT; }
+ "port" { return PORT; }
+}
+
+<SCANSTATE_AT>{
+ "ll" { return LL_HDR; }
+ "nh" { return NETWORK_HDR; }
+}
+"th" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_TH); return TRANSPORT_HDR; }
+
+"bridge" { return BRIDGE; }
+
+"ether" { scanner_push_start_cond(yyscanner, SCANSTATE_ETH); return ETHER; }
+<SCANSTATE_ARP,SCANSTATE_CT,SCANSTATE_ETH,SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_EXPR_FIB,SCANSTATE_EXPR_IPSEC>{
+ "saddr" { return SADDR; }
+ "daddr" { return DADDR; }
+}
+"type" { scanner_push_start_cond(yyscanner, SCANSTATE_TYPE); return TYPE; }
+"typeof" { return TYPEOF; }
+
+"vlan" { scanner_push_start_cond(yyscanner, SCANSTATE_VLAN); return VLAN; }
+<SCANSTATE_CT,SCANSTATE_EXPR_FRAG,SCANSTATE_VLAN,SCANSTATE_IP,SCANSTATE_ICMP>"id" { return ID; }
+<SCANSTATE_VLAN>{
+ "cfi" { return CFI; }
+ "dei" { return DEI; }
+ "pcp" { return PCP; }
+}
+"8021ad" { yylval->string = xstrdup(yytext); return STRING; }
+"8021q" { yylval->string = xstrdup(yytext); return STRING; }
+
+"arp" { scanner_push_start_cond(yyscanner, SCANSTATE_ARP); return ARP; }
+<SCANSTATE_ARP>{
+ "htype" { return HTYPE; }
+ "ptype" { return PTYPE; }
+ "hlen" { return HLEN; }
+ "plen" { return PLEN; }
+ "operation" { return OPERATION; }
+}
+
+"ip" { scanner_push_start_cond(yyscanner, SCANSTATE_IP); return IP; }
+<SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_EXPR_OSF,SCANSTATE_GRE>{
+ "version" { return HDRVERSION; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_DST,SCANSTATE_EXPR_HBH,SCANSTATE_EXPR_MH,SCANSTATE_EXPR_RT,SCANSTATE_IP>{
+ "hdrlength" { return HDRLENGTH; }
+}
+<SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_TYPE>{
+ "dscp" { return DSCP; }
+}
+"ecn" { return ECN; }
+<SCANSTATE_EXPR_UDP,SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_META,SCANSTATE_TCP,SCANSTATE_SCTP,SCANSTATE_EXPR_SCTP_CHUNK>"length" { return LENGTH; }
+<SCANSTATE_EXPR_FRAG,SCANSTATE_IP>{
+ "frag-off" { return FRAG_OFF; }
+}
+<SCANSTATE_EXPR_OSF,SCANSTATE_IP>{
+ "ttl" { return TTL; }
+}
+<SCANSTATE_CT,SCANSTATE_IP,SCANSTATE_META,SCANSTATE_TYPE,SCANSTATE_GRE>"protocol" { return PROTOCOL; }
+<SCANSTATE_EXPR_MH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE,SCANSTATE_ICMP,SCANSTATE_IGMP,SCANSTATE_IP,SCANSTATE_SCTP,SCANSTATE_TCP>{
+ "checksum" { return CHECKSUM; }
+}
+
+<SCANSTATE_IP>{
+ "lsrr" { return LSRR; }
+ "rr" { return RR; }
+ "ssrr" { return SSRR; }
+ "ra" { return RA; }
+
+ "ptr" { return PTR; }
+ "value" { return VALUE; }
+
+ "option" { return OPTION; }
+ "options" { return OPTIONS; }
+}
+
+<SCANSTATE_TCP>{
+ /* tcp header fields */
+ "ackseq" { return ACKSEQ; }
+ "doff" { return DOFF; }
+ "window" { return WINDOW; }
+ "urgptr" { return URGPTR; }
+
+ /* tcp option types */
+ "echo" { return ECHO; }
+ "eol" { return EOL; }
+ "maxseg" { return MSS; }
+ "mss" { return MSS; }
+ "nop" { return NOP; }
+ "noop" { return NOP; }
+ "sack" { return SACK; }
+ "sack0" { return SACK0; }
+ "sack1" { return SACK1; }
+ "sack2" { return SACK2; }
+ "sack3" { return SACK3; }
+ "sack-permitted" { return SACK_PERM; }
+ "sack-perm" { return SACK_PERM; }
+ "timestamp" { return TIMESTAMP; }
+ "fastopen" { return FASTOPEN; }
+ "mptcp" { return MPTCP; }
+ "md5sig" { return MD5SIG; }
+
+ /* tcp option fields */
+ "left" { return LEFT; }
+ "right" { return RIGHT; }
+ "count" { return COUNT; }
+ "tsval" { return TSVAL; }
+ "tsecr" { return TSECR; }
+ "subtype" { return SUBTYPE; }
+
+ "options" { return OPTIONS; }
+ "option" { return OPTION; }
+}
+"time" { return TIME; }
+
+"icmp" { scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP; }
+"icmpv6" { scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP6; }
+<SCANSTATE_ICMP>{
+ "gateway" { return GATEWAY; }
+ "code" { return CODE; }
+ "param-problem" { return PPTR; }
+ "max-delay" { return MAXDELAY; }
+ "mtu" { return MTU; }
+ "taddr" { return TADDR; }
+ "daddr" { return DADDR; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_ESP,SCANSTATE_ICMP,SCANSTATE_TCP>{
+ "sequence" { return SEQUENCE; }
+}
+
+"igmp" { scanner_push_start_cond(yyscanner, SCANSTATE_IGMP); return IGMP; }
+<SCANSTATE_IGMP>{
+ "mrt" { return MRT; }
+ "group" { return GROUP; }
+}
+
+"ip6" { scanner_push_start_cond(yyscanner, SCANSTATE_IP6); return IP6; }
+"priority" { return PRIORITY; }
+<SCANSTATE_IP6>{
+ "flowlabel" { return FLOWLABEL; }
+ "hoplimit" { return HOPLIMIT; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_COMP,SCANSTATE_EXPR_DST,SCANSTATE_EXPR_FRAG,SCANSTATE_EXPR_HBH,SCANSTATE_EXPR_MH,SCANSTATE_EXPR_RT,SCANSTATE_IP6>{
+ "nexthdr" { return NEXTHDR; }
+}
+
+"ah" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_AH); return AH; }
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_FRAG,SCANSTATE_EXPR_MH,SCANSTATE_TCP>{
+ "reserved" { return RESERVED; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_ESP,SCANSTATE_EXPR_IPSEC>"spi" { return SPI; }
+
+"esp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_ESP); return ESP; }
+
+"comp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_COMP); return COMP; }
+<SCANSTATE_EXPR_COMP>{
+ "cpi" { return CPI; }
+}
+"flags" { return FLAGS; }
+
+"udp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDP); return UDP; }
+"udplite" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDPLITE); return UDPLITE; }
+<SCANSTATE_EXPR_UDPLITE>{
+ "csumcov" { return CSUMCOV; }
+}
+<SCANSTATE_EXPR_DCCP,SCANSTATE_SCTP,SCANSTATE_TCP,SCANSTATE_EXPR_TH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE>{
+ "sport" { return SPORT; }
+}
+<SCANSTATE_CT,SCANSTATE_EXPR_DCCP,SCANSTATE_SCTP,SCANSTATE_TCP,SCANSTATE_EXPR_TH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE>{
+ "dport" { return DPORT; }
+}
+<SCANSTATE_EXPR_DCCP>{
+ "option" { return OPTION; }
+}
+
+"vxlan" { return VXLAN; }
+"vni" { return VNI; }
+
+"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; }
+
+"dccp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DCCP); return DCCP; }
+
+"sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; }
+
+<SCANSTATE_SCTP>{
+ "chunk" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SCTP_CHUNK); return CHUNK; }
+ "vtag" { return VTAG; }
+}
+
+<SCANSTATE_EXPR_SCTP_CHUNK>{
+ "data" { return DATA; }
+ "init" { return INIT; }
+ "init-ack" { return INIT_ACK; }
+ "heartbeat" { return HEARTBEAT; }
+ "heartbeat-ack" { return HEARTBEAT_ACK; }
+ "abort" { return ABORT; }
+ "shutdown" { return SHUTDOWN; }
+ "shutdown-ack" { return SHUTDOWN_ACK; }
+ "error" { return ERROR; }
+ "cookie-echo" { return COOKIE_ECHO; }
+ "cookie-ack" { return COOKIE_ACK; }
+ "ecne" { return ECNE; }
+ "cwr" { return CWR; }
+ "shutdown-complete" { return SHUTDOWN_COMPLETE; }
+ "asconf-ack" { return ASCONF_ACK; }
+ "forward-tsn" { return FORWARD_TSN; }
+ "asconf" { return ASCONF; }
+
+ "tsn" { return TSN; }
+ "sack" { return SACK; }
+ "stream" { return STREAM; }
+ "ssn" { return SSN; }
+ "ppid" { return PPID; }
+ "init-tag" { return INIT_TAG; }
+ "a-rwnd" { return A_RWND; }
+ "num-outbound-streams" { return NUM_OSTREAMS; }
+ "num-inbound-streams" { return NUM_ISTREAMS; }
+ "initial-tsn" { return INIT_TSN; }
+ "cum-tsn-ack" { return CUM_TSN_ACK; }
+ "num-gap-ack-blocks" { return NUM_GACK_BLOCKS; }
+ "num-dup-tsns" { return NUM_DUP_TSNS; }
+ "lowest-tsn" { return LOWEST_TSN; }
+ "seqno" { return SEQNO; }
+ "new-cum-tsn" { return NEW_CUM_TSN; }
+}
+
+"rt" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT; }
+"rt0" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT0; }
+"rt2" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT2; }
+"srh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT4; }
+<SCANSTATE_EXPR_RT,SCANSTATE_STMT_NAT,SCANSTATE_IP,SCANSTATE_IP6>"addr" { return ADDR; }
+
+"hbh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HBH); return HBH; }
+
+"frag" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FRAG); return FRAG; }
+<SCANSTATE_EXPR_FRAG>{
+ "reserved2" { return RESERVED2; }
+ "more-fragments" { return MORE_FRAGMENTS; }
+}
+
+"dst" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DST); return DST; }
+
+"mh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_MH); return MH; }
+
+"meta" { scanner_push_start_cond(yyscanner, SCANSTATE_META); return META; }
+"mark" { return MARK; }
+"iif" { return IIF; }
+"iifname" { return IIFNAME; }
+"iiftype" { return IIFTYPE; }
+"oif" { return OIF; }
+"oifname" { return OIFNAME; }
+"oiftype" { return OIFTYPE; }
+"skuid" { return SKUID; }
+"skgid" { return SKGID; }
+"nftrace" { return NFTRACE; }
+"rtclassid" { return RTCLASSID; }
+"ibriport" { return IBRIPORT; }
+"ibrname" { return IBRIDGENAME; }
+"obriport" { return OBRIPORT; }
+"obrname" { return OBRIDGENAME; }
+"pkttype" { return PKTTYPE; }
+"cpu" { return CPU; }
+"iifgroup" { return IIFGROUP; }
+"oifgroup" { return OIFGROUP; }
+"cgroup" { return CGROUP; }
+
+<SCANSTATE_EXPR_RT>{
+ "nexthop" { return NEXTHOP; }
+ "seg-left" { return SEG_LEFT; }
+ "mtu" { return MTU; }
+ "last-entry" { return LAST_ENT; }
+ "tag" { return TAG; }
+ "sid" { return SID; }
+}
+<SCANSTATE_EXPR_RT,SCANSTATE_TYPE>{
+ "classid" { return CLASSID; }
+}
+
+"ct" { scanner_push_start_cond(yyscanner, SCANSTATE_CT); return CT; }
+<SCANSTATE_CT>{
+ "avgpkt" { return AVGPKT; }
+ "l3proto" { return L3PROTOCOL; }
+ "proto-src" { return PROTO_SRC; }
+ "proto-dst" { return PROTO_DST; }
+ "zone" { return ZONE; }
+ "original" { return ORIGINAL; }
+ "reply" { return REPLY; }
+ "direction" { return DIRECTION; }
+ "event" { return EVENT; }
+ "expectation" { return EXPECTATION; }
+ "expiration" { return EXPIRATION; }
+ "helper" { return HELPER; }
+ "helpers" { return HELPERS; }
+ "label" { return LABEL; }
+ "state" { return STATE; }
+ "status" { return STATUS; }
+ "count" { return COUNT; }
+}
+
+"numgen" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_NUMGEN); return NUMGEN; }
+<SCANSTATE_EXPR_NUMGEN>{
+ "inc" { return INC; }
+}
+
+"jhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return JHASH; }
+"symhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return SYMHASH; }
+
+<SCANSTATE_EXPR_HASH>{
+ "seed" { return SEED; }
+}
+<SCANSTATE_EXPR_HASH,SCANSTATE_EXPR_NUMGEN>{
+ "mod" { return MOD; }
+ "offset" { return OFFSET; }
+}
+"dup" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_DUP); return DUP; }
+"fwd" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_FWD); return FWD; }
+
+"fib" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FIB); return FIB; }
+
+"osf" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_OSF); return OSF; }
+
+"synproxy" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_SYNPROXY); return SYNPROXY; }
+<SCANSTATE_STMT_SYNPROXY>{
+ "wscale" { return WSCALE; }
+ "maxseg" { return MSS; }
+ "mss" { return MSS; }
+ "timestamp" { return TIMESTAMP; }
+ "sack-permitted" { return SACK_PERM; }
+ "sack-perm" { return SACK_PERM; }
+}
+
+"notrack" { return NOTRACK; }
+
+"all" { return ALL; }
+
+<SCANSTATE_CMD_EXPORT,SCANSTATE_CMD_IMPORT,SCANSTATE_CMD_MONITOR>{
+ "xml" { return XML; }
+ "json" { return JSON; }
+ "vm" { return VM; }
+}
+
+"exists" { return EXISTS; }
+"missing" { return MISSING; }
+
+"exthdr" { return EXTHDR; }
+
+"ipsec" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_IPSEC); return IPSEC; }
+<SCANSTATE_EXPR_IPSEC>{
+ "reqid" { return REQID; }
+ "spnum" { return SPNUM; }
+
+ "in" { return IN; }
+ "out" { return OUT; }
+}
+
+"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;
+ }
+
+{ip6addr_rfc2732} {
+ yytext[yyleng - 1] = '\0';
+ yylval->string = xstrdup(yytext + 1);
+ return STRING;
+ }
+
+{timestring} {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+
+{hexstring} {
+ errno = 0;
+ yylval->val = strtoull(yytext, NULL, 16);
+ if (errno != 0) {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ 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;
+ }
+
+{quotedstring} {
+ yytext[yyleng - 1] = '\0';
+ yylval->string = xstrdup(yytext + 1);
+ return QUOTED_STRING;
+ }
+
+{asteriskstring} {
+ yylval->string = xstrdup(yytext);
+ return ASTERISK_STRING;
+ }
+
+{string} {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+
+\\{newline} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
+
+{newline} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ return NEWLINE;
+ }
+
+{tab}+
+{space}+
+{comment_line} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
+{comment}
+
+<<EOF>> {
+ update_pos(yyget_extra(yyscanner), yylloc, 1);
+ scanner_pop_buffer(yyscanner);
+ if (YY_CURRENT_BUFFER == NULL)
+ return TOKEN_EOF;
+ }
+
+. { return JUNK; }
+
+%%
+
+static void scanner_push_indesc(struct parser_state *state,
+ struct input_descriptor *indesc)
+{
+ if (!state->indesc)
+ list_add_tail(&indesc->list, &state->indesc_list);
+ else
+ list_add(&indesc->list, &state->indesc->list);
+
+ state->indesc = indesc;
+}
+
+static void scanner_pop_indesc(struct parser_state *state)
+{
+ if (!list_is_first(&state->indesc->list, &state->indesc_list)) {
+ state->indesc = list_entry(state->indesc->list.prev,
+ struct input_descriptor, list);
+ } else {
+ state->indesc = NULL;
+ }
+}
+
+static void scanner_pop_buffer(yyscan_t scanner)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ yypop_buffer_state(scanner);
+ scanner_pop_indesc(state);
+}
+
+static void scanner_push_file(struct nft_ctx *nft, void *scanner,
+ FILE *f, const char *filename,
+ const struct location *loc,
+ const struct input_descriptor *parent_indesc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *indesc;
+ YY_BUFFER_STATE b;
+
+ b = yy_create_buffer(f, YY_BUF_SIZE, scanner);
+ yypush_buffer_state(b, scanner);
+
+ indesc = xzalloc(sizeof(struct input_descriptor));
+
+ if (loc != NULL)
+ indesc->location = *loc;
+ indesc->type = INDESC_FILE;
+ indesc->name = xstrdup(filename);
+ indesc->f = f;
+ if (!parent_indesc) {
+ indesc->depth = 1;
+ } else {
+ indesc->depth = parent_indesc->depth + 1;
+ }
+ init_pos(indesc);
+
+ 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,
+ enum nft_include_type includetype)
+
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct error_record *erec;
+ FILE *f;
+
+ if (parent_indesc && parent_indesc->depth == MAX_INCLUDE_DEPTH) {
+ erec = error(loc, "Include nested too deeply, max %u levels",
+ MAX_INCLUDE_DEPTH);
+ goto err;
+ }
+
+ if (includetype == NFT_INCLUDE && !filename_is_useable(filename)) {
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+ goto err;
+ }
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ erec = error(loc, "Could not open file \"%s\": %s\n",
+ filename, strerror(errno));
+ goto err;
+ }
+
+ if (!fp_is_useable(f, includetype)) {
+ fclose(f);
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+ goto err;
+ }
+
+ scanner_push_file(nft, scanner, f, filename, loc, parent_indesc);
+ return 0;
+err:
+ erec_queue(erec, state->msgs);
+ return -1;
+}
+
+static int include_glob(struct nft_ctx *nft, void *scanner, const char *pattern,
+ const struct location *loc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *indesc = state->indesc;
+ struct error_record *erec = NULL;
+ bool wildcard = false;
+ glob_t glob_data;
+ unsigned int i;
+ int flags = 0;
+ int ret;
+ char *p;
+
+ /* This function can return four meaningful values:
+ *
+ * -1 means that there was an error.
+ * 0 means that a single non-wildcard match was done.
+ * 1 means that there are no wildcards in the pattern and the
+ * search can continue.
+ * 2 means that there are wildcards in the pattern and the search
+ * can continue.
+ *
+ * The diffrence is needed, because there is a semantic difference
+ * between patterns with wildcards and no wildcards. Not finding a
+ * non-wildcard file is an error but not finding any matches for a
+ * wildcard pattern is not.
+ */
+
+ /* There shouldn't be a need to use escape characters in include paths.
+ */
+ flags |= GLOB_NOESCAPE;
+
+ /* Mark directories so we can filter them out (also links). */
+ flags |= GLOB_MARK;
+
+ /* If there is no match, glob() doesn't set GLOB_MAGCHAR even if there
+ * are wildcard characters in the pattern. We need to look for (luckily
+ * well-known and not likely to change) magic characters ourselves. In a
+ * perfect world, we could use glob() itself to figure out if there are
+ * wildcards in the pattern.
+ */
+ p = (char *)pattern;
+ while (*p) {
+ if (*p == '*' || *p == '?' || *p == '[') {
+ wildcard = true;
+ break;
+ }
+ p++;
+ }
+
+ ret = glob(pattern, flags, NULL, &glob_data);
+ if (ret == 0) {
+ char *path;
+ int len;
+
+ /* reverse alphabetical order due to stack */
+ for (i = glob_data.gl_pathc; i > 0; i--) {
+
+ path = glob_data.gl_pathv[i-1];
+
+ /* ignore directories */
+ len = strlen(path);
+ if (len == 0 || path[len - 1] == '/')
+ continue;
+
+ ret = include_file(nft, scanner, path, loc, indesc, NFT_INCLUDE);
+ if (ret != 0)
+ goto err;
+ }
+
+ globfree(&glob_data);
+
+ /* If no wildcards and we found the file, stop the search (with
+ * 0). In case of wildcards we need to still continue the
+ * search, because other matches might be in other include
+ * directories. We handled the case with a non-wildcard pattern
+ * and no matches already before.
+ */
+ return wildcard ? 2 : 0;
+ } else if (ret == GLOB_NOMATCH) {
+ globfree(&glob_data);
+
+ /* We need to tell the caller whether wildcards were used in
+ * case of no match, because the semantics for handling the
+ * cases are different.
+ */
+ return wildcard ? 2 : 1;
+ }
+
+ erec = error(loc, "Failed to glob the pattern %s", pattern);
+
+ /* intentional fall through */
+err:
+ if (erec)
+ erec_queue(erec, state->msgs);
+ globfree(&glob_data);
+ return -1;
+}
+
+int scanner_read_file(struct nft_ctx *nft, const char *filename,
+ const struct location *loc)
+{
+ return include_file(nft, nft->scanner, filename, loc, NULL, NFT_CMDLINE);
+}
+
+static bool search_in_include_path(const char *filename)
+{
+ return (strncmp(filename, "./", strlen("./")) != 0 &&
+ strncmp(filename, "../", strlen("../")) != 0 &&
+ filename[0] != '/');
+}
+
+int scanner_include_file(struct nft_ctx *nft, void *scanner,
+ const char *filename, const struct location *loc)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct error_record *erec;
+ char buf[PATH_MAX];
+ unsigned int i;
+ int ret = -1;
+
+ if (search_in_include_path(filename)) {
+ for (i = 0; i < nft->num_include_paths; i++) {
+ ret = snprintf(buf, sizeof(buf), "%s/%s",
+ nft->include_paths[i], filename);
+ if (ret < 0 || ret >= PATH_MAX) {
+ erec = error(loc, "Too long file path \"%s/%s\"\n",
+ nft->include_paths[i], filename);
+ erec_queue(erec, state->msgs);
+ return -1;
+ }
+
+ ret = include_glob(nft, scanner, buf, loc);
+
+ /* error was already handled */
+ if (ret == -1)
+ return -1;
+ /* no wildcards and file was processed: break early. */
+ if (ret == 0)
+ return 0;
+
+ /* else 1 (no wildcards) or 2 (wildcards): keep
+ * searching.
+ */
+ }
+ } else {
+ /* an absolute path (starts with '/') */
+ ret = include_glob(nft, scanner, filename, loc);
+ }
+
+ /* handle the case where no file was found */
+ if (ret == -1)
+ return -1;
+ else if (ret == 0 || ret == 2)
+ return 0;
+
+ /* 1 means an error, because there are no more include directories to
+ * search, and the pattern does not have wildcard characters.
+ */
+ erec = error(loc, "File not found: %s", filename);
+ erec_queue(erec, state->msgs);
+ return -1;
+}
+
+void scanner_push_buffer(void *scanner, const struct input_descriptor *indesc,
+ const char *buffer)
+{
+ struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *new_indesc;
+ YY_BUFFER_STATE b;
+
+ new_indesc = xzalloc(sizeof(struct input_descriptor));
+ memcpy(new_indesc, indesc, sizeof(*new_indesc));
+ new_indesc->data = buffer;
+ new_indesc->name = xstrdup(indesc->name);
+ scanner_push_indesc(state, new_indesc);
+
+ b = yy_scan_string(buffer, scanner);
+ assert(b != NULL);
+ init_pos(state->indesc);
+}
+
+void *scanner_init(struct parser_state *state)
+{
+ yyscan_t scanner;
+
+ 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);
+}
+
+static void input_descriptor_list_destroy(struct parser_state *state)
+{
+ struct input_descriptor *indesc, *next;
+
+ list_for_each_entry_safe(indesc, next, &state->indesc_list, list) {
+ if (indesc->f) {
+ fclose(indesc->f);
+ indesc->f = NULL;
+ }
+ list_del(&indesc->list);
+ input_descriptor_destroy(indesc);
+ }
+}
+
+void scanner_destroy(struct nft_ctx *nft)
+{
+ struct parser_state *state = yyget_extra(nft->scanner);
+
+ input_descriptor_list_destroy(state);
+ xfree(state->startcond_active);
+
+ yylex_destroy(nft->scanner);
+}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_type = type;
+ state->startcond_active[type]++;
+
+ yy_push_state((int)type, scanner);
+}
+
+void scanner_pop_start_cond(void *scanner, enum startcond_type t)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_active[t]--;
+
+ if (state->startcond_type != t) {
+ state->flex_state_pop++;
+ return; /* Can't pop just yet! */
+ }
+
+ while (state->flex_state_pop) {
+ state->flex_state_pop--;
+ state->startcond_type = yy_top_state(scanner);
+ yy_pop_state(scanner);
+
+ t = state->startcond_type;
+ if (state->startcond_active[t])
+ return;
+ }
+
+ state->startcond_type = yy_top_state(scanner);
+
+ yy_pop_state(scanner);
+}
diff --git a/src/sctp_chunk.c b/src/sctp_chunk.c
new file mode 100644
index 0000000..24a07e2
--- /dev/null
+++ b/src/sctp_chunk.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright Red Hat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <exthdr.h>
+#include <sctp_chunk.h>
+
+
+#define PHT(__token, __offset, __len) \
+ PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
+ __offset, __len)
+
+static const struct exthdr_desc sctp_chunk_data = {
+ .name = "data",
+ .type = SCTP_CHUNK_TYPE_DATA,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_DATA_TSN] = PHT("tsn", 32, 32),
+ [SCTP_CHUNK_DATA_STREAM] = PHT("stream", 64, 16),
+ [SCTP_CHUNK_DATA_SSN] = PHT("ssn", 80, 16),
+ [SCTP_CHUNK_DATA_PPID] = PHT("ppid", 96, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_init = {
+ .name = "init",
+ .type = SCTP_CHUNK_TYPE_INIT,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32),
+ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32),
+ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16),
+ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16),
+ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_init_ack = {
+ .name = "init-ack",
+ .type = SCTP_CHUNK_TYPE_INIT_ACK,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32),
+ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32),
+ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16),
+ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16),
+ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_sack = {
+ .name = "sack",
+ .type = SCTP_CHUNK_TYPE_SACK,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_SACK_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32),
+ [SCTP_CHUNK_SACK_RWND] = PHT("a-rwnd", 64, 32),
+ [SCTP_CHUNK_SACK_GACK_BLOCKS] = PHT("num-gap-ack-blocks", 96, 16),
+ [SCTP_CHUNK_SACK_DUP_TSNS] = PHT("num-dup-tsns", 112, 16),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_shutdown = {
+ .name = "shutdown",
+ .type = SCTP_CHUNK_TYPE_SHUTDOWN,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_SHUTDOWN_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_ecne = {
+ .name = "ecne",
+ .type = SCTP_CHUNK_TYPE_ECNE,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_cwr = {
+ .name = "cwr",
+ .type = SCTP_CHUNK_TYPE_CWR,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_asconf_ack = {
+ .name = "asconf-ack",
+ .type = SCTP_CHUNK_TYPE_ASCONF_ACK,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_forward_tsn = {
+ .name = "forward-tsn",
+ .type = SCTP_CHUNK_TYPE_FORWARD_TSN,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_FORWARD_TSN_NCTSN] = PHT("new-cum-tsn", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_asconf = {
+ .name = "asconf",
+ .type = SCTP_CHUNK_TYPE_ASCONF,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32),
+ },
+};
+
+#define SCTP_CHUNK_DESC_GENERATOR(descname, hname, desctype) \
+static const struct exthdr_desc sctp_chunk_##descname = { \
+ .name = #hname, \
+ .type = SCTP_CHUNK_TYPE_##desctype, \
+ .templates = { \
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), \
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), \
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),\
+ }, \
+};
+
+SCTP_CHUNK_DESC_GENERATOR(heartbeat, heartbeat, HEARTBEAT)
+SCTP_CHUNK_DESC_GENERATOR(heartbeat_ack, heartbeat-ack, HEARTBEAT_ACK)
+SCTP_CHUNK_DESC_GENERATOR(abort, abort, ABORT)
+SCTP_CHUNK_DESC_GENERATOR(shutdown_ack, shutdown-ack, SHUTDOWN_ACK)
+SCTP_CHUNK_DESC_GENERATOR(error, error, ERROR)
+SCTP_CHUNK_DESC_GENERATOR(cookie_echo, cookie-echo, COOKIE_ECHO)
+SCTP_CHUNK_DESC_GENERATOR(cookie_ack, cookie-ack, COOKIE_ACK)
+SCTP_CHUNK_DESC_GENERATOR(shutdown_complete, shutdown-complete, SHUTDOWN_COMPLETE)
+
+#undef SCTP_CHUNK_DESC_GENERATOR
+
+static const struct exthdr_desc *sctp_chunk_protocols[] = {
+ [SCTP_CHUNK_TYPE_DATA] = &sctp_chunk_data,
+ [SCTP_CHUNK_TYPE_INIT] = &sctp_chunk_init,
+ [SCTP_CHUNK_TYPE_INIT_ACK] = &sctp_chunk_init_ack,
+ [SCTP_CHUNK_TYPE_SACK] = &sctp_chunk_sack,
+ [SCTP_CHUNK_TYPE_HEARTBEAT] = &sctp_chunk_heartbeat,
+ [SCTP_CHUNK_TYPE_HEARTBEAT_ACK] = &sctp_chunk_heartbeat_ack,
+ [SCTP_CHUNK_TYPE_ABORT] = &sctp_chunk_abort,
+ [SCTP_CHUNK_TYPE_SHUTDOWN] = &sctp_chunk_shutdown,
+ [SCTP_CHUNK_TYPE_SHUTDOWN_ACK] = &sctp_chunk_shutdown_ack,
+ [SCTP_CHUNK_TYPE_ERROR] = &sctp_chunk_error,
+ [SCTP_CHUNK_TYPE_COOKIE_ECHO] = &sctp_chunk_cookie_echo,
+ [SCTP_CHUNK_TYPE_COOKIE_ACK] = &sctp_chunk_cookie_ack,
+ [SCTP_CHUNK_TYPE_ECNE] = &sctp_chunk_ecne,
+ [SCTP_CHUNK_TYPE_CWR] = &sctp_chunk_cwr,
+ [SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE] = &sctp_chunk_shutdown_complete,
+ [SCTP_CHUNK_TYPE_ASCONF_ACK] = &sctp_chunk_asconf_ack,
+ [SCTP_CHUNK_TYPE_FORWARD_TSN] = &sctp_chunk_forward_tsn,
+ [SCTP_CHUNK_TYPE_ASCONF] = &sctp_chunk_asconf,
+};
+
+const struct exthdr_desc *sctp_chunk_protocol_find(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(sctp_chunk_protocols); i++) {
+ if (sctp_chunk_protocols[i] &&
+ !strcmp(sctp_chunk_protocols[i]->name, name))
+ return sctp_chunk_protocols[i];
+ }
+ return NULL;
+}
+
+struct expr *sctp_chunk_expr_alloc(const struct location *loc,
+ unsigned int type, unsigned int field)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct exthdr_desc *desc = NULL;
+ struct expr *expr;
+
+ if (type < array_size(sctp_chunk_protocols))
+ desc = sctp_chunk_protocols[type];
+
+ if (!desc)
+ return NULL;
+
+ tmpl = &desc->templates[field];
+ if (!tmpl)
+ return NULL;
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+ BYTEORDER_BIG_ENDIAN, tmpl->len);
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.op = NFT_EXTHDR_OP_SCTP;
+ expr->exthdr.raw_type = desc->type;
+ expr->exthdr.offset = tmpl->offset;
+
+ return expr;
+}
+
+void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off,
+ unsigned int len, uint32_t flags)
+{
+ const struct proto_hdr_template *tmpl;
+ unsigned int i;
+
+ assert(expr->etype == EXPR_EXTHDR);
+
+ expr->len = len;
+ expr->exthdr.flags = flags;
+ expr->exthdr.offset = off;
+ expr->exthdr.op = NFT_EXTHDR_OP_SCTP;
+
+ if (flags & NFT_EXTHDR_F_PRESENT)
+ datatype_set(expr, &boolean_type);
+ else
+ datatype_set(expr, &integer_type);
+
+ if (type >= array_size(sctp_chunk_protocols))
+ return;
+
+ expr->exthdr.desc = sctp_chunk_protocols[type];
+ expr->exthdr.flags = flags;
+ assert(expr->exthdr.desc != NULL);
+
+ for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
+ tmpl = &expr->exthdr.desc->templates[i];
+ if (tmpl->offset != off || tmpl->len != len)
+ continue;
+
+ if ((flags & NFT_EXTHDR_F_PRESENT) == 0)
+ datatype_set(expr, tmpl->dtype);
+
+ expr->exthdr.tmpl = tmpl;
+ break;
+ }
+}
diff --git a/src/segtree.c b/src/segtree.c
new file mode 100644
index 0000000..28172b3
--- /dev/null
+++ b/src/segtree.c
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 2008-2012 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <inttypes.h>
+#include <arpa/inet.h>
+
+#include <libnftnl/udata.h>
+
+#include <rule.h>
+#include <expression.h>
+#include <gmputil.h>
+#include <utils.h>
+
+static enum byteorder get_key_byteorder(const struct expr *e)
+{
+ enum datatypes basetype = expr_basetype(e)->type;
+
+ switch (basetype) {
+ case TYPE_INTEGER:
+ /* For ranges, integers MUST be in BYTEORDER_BIG_ENDIAN.
+ * If the LHS (lookup key, e.g. 'meta mark', is host endian,
+ * a byteorder expression is injected to convert the register
+ * content before lookup.
+ */
+ return BYTEORDER_BIG_ENDIAN;
+ case TYPE_STRING:
+ return BYTEORDER_HOST_ENDIAN;
+ default:
+ break;
+ }
+
+ return BYTEORDER_INVALID;
+}
+
+static void interval_expr_copy(struct expr *dst, struct expr *src)
+{
+ if (src->comment)
+ dst->comment = xstrdup(src->comment);
+ if (src->timeout)
+ dst->timeout = src->timeout;
+ if (src->expiration)
+ dst->expiration = src->expiration;
+
+ list_splice_init(&src->stmt_list, &dst->stmt_list);
+}
+
+static void set_elem_add(const struct set *set, struct expr *init, mpz_t value,
+ uint32_t flags, enum byteorder byteorder)
+{
+ struct expr *expr;
+
+ expr = constant_expr_alloc(&internal_location, set->key->dtype,
+ byteorder, set->key->len, NULL);
+ mpz_set(expr->value, value);
+ expr = set_elem_expr_alloc(&internal_location, expr);
+ expr->flags = flags;
+
+ compound_expr_add(init, expr);
+}
+
+struct expr *get_set_intervals(const struct set *set, const struct expr *init)
+{
+ enum byteorder byteorder = get_key_byteorder(set->key);
+ struct expr *new_init;
+ mpz_t low, high;
+ struct expr *i;
+
+ mpz_init2(low, set->key->len);
+ mpz_init2(high, set->key->len);
+
+ new_init = list_expr_alloc(&internal_location);
+
+ list_for_each_entry(i, &init->expressions, list) {
+ switch (i->key->etype) {
+ case EXPR_VALUE:
+ set_elem_add(set, new_init, i->key->value,
+ i->flags, byteorder);
+ break;
+ case EXPR_CONCAT:
+ compound_expr_add(new_init, expr_clone(i));
+ i->flags |= EXPR_F_INTERVAL_END;
+ compound_expr_add(new_init, expr_clone(i));
+ break;
+ case EXPR_SET_ELEM_CATCHALL:
+ compound_expr_add(new_init, expr_clone(i));
+ break;
+ default:
+ range_expr_value_low(low, i);
+ set_elem_add(set, new_init, low, 0, i->byteorder);
+ range_expr_value_high(high, i);
+ mpz_add_ui(high, high, 1);
+ set_elem_add(set, new_init, high,
+ EXPR_F_INTERVAL_END, i->byteorder);
+ break;
+ }
+ }
+
+ mpz_clear(low);
+ mpz_clear(high);
+
+ return new_init;
+}
+
+static struct expr *get_set_interval_find(const struct set *cache_set,
+ struct expr *left,
+ struct expr *right)
+{
+ const struct set *set = cache_set;
+ struct expr *range = NULL;
+ struct expr *i;
+ mpz_t val;
+
+ mpz_init2(val, set->key->len);
+
+ list_for_each_entry(i, &set->init->expressions, list) {
+ switch (i->key->etype) {
+ case EXPR_VALUE:
+ if (expr_basetype(i->key)->type != TYPE_STRING)
+ break;
+ /* string type, check if its a range (wildcard). */
+ /* fall-through */
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ range_expr_value_low(val, i);
+ if (left && mpz_cmp(left->key->value, val))
+ break;
+
+ range_expr_value_high(val, i);
+ if (right && mpz_cmp(right->key->value, val))
+ break;
+
+ range = expr_clone(i->key);
+ goto out;
+ default:
+ break;
+ }
+ }
+out:
+ mpz_clear(val);
+
+ return range;
+}
+
+static struct expr *expr_value(struct expr *expr)
+{
+ switch (expr->etype) {
+ case EXPR_MAPPING:
+ return expr->left->key;
+ case EXPR_SET_ELEM:
+ return expr->key;
+ case EXPR_VALUE:
+ return expr;
+ default:
+ BUG("invalid expression type %s\n", expr_name(expr));
+ }
+}
+
+static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr)
+{
+ struct expr *elem = set_elem_expr_alloc(&low->location, expr);
+
+ if (low->etype == EXPR_MAPPING) {
+ interval_expr_copy(elem, low->left);
+
+ elem = mapping_expr_alloc(&low->location, elem,
+ expr_clone(low->right));
+ } else {
+ interval_expr_copy(elem, low);
+ }
+ elem->flags |= EXPR_F_KERNEL;
+
+ return elem;
+}
+
+static struct expr *expr_to_set_elem(struct expr *e)
+{
+ unsigned int len = div_round_up(e->len, BITS_PER_BYTE);
+ unsigned int str_len;
+ char data[len + 1];
+ struct expr *expr;
+
+ if (expr_basetype(expr_value(e))->type != TYPE_STRING)
+ return expr_clone(e);
+
+ mpz_export_data(data, expr_value(e)->value, BYTEORDER_BIG_ENDIAN, len);
+
+ str_len = strnlen(data, len);
+ if (str_len >= len || str_len == 0)
+ return expr_clone(e);
+
+ data[str_len] = '*';
+
+ expr = constant_expr_alloc(&e->location, e->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (str_len + 1) * BITS_PER_BYTE, data);
+
+ return __expr_to_set_elem(e, expr);
+}
+
+int get_set_decompose(struct set *cache_set, struct set *set)
+{
+ struct expr *i, *next, *range;
+ struct expr *left = NULL;
+ struct expr *new_init;
+
+ new_init = set_expr_alloc(&internal_location, set);
+
+ list_for_each_entry_safe(i, next, &set->init->expressions, list) {
+ if (i->flags & EXPR_F_INTERVAL_END && left) {
+ list_del(&left->list);
+ list_del(&i->list);
+ mpz_sub_ui(i->key->value, i->key->value, 1);
+ range = get_set_interval_find(cache_set, left, i);
+ if (!range) {
+ expr_free(left);
+ expr_free(i);
+ expr_free(new_init);
+ errno = ENOENT;
+ return -1;
+ }
+ expr_free(left);
+ expr_free(i);
+
+ compound_expr_add(new_init, range);
+ left = NULL;
+ } else {
+ if (left) {
+ range = get_set_interval_find(cache_set,
+ left, NULL);
+ if (range)
+ compound_expr_add(new_init, range);
+ else
+ compound_expr_add(new_init,
+ expr_to_set_elem(left));
+ }
+ left = i;
+ }
+ }
+ if (left) {
+ range = get_set_interval_find(cache_set, left, NULL);
+ if (range)
+ compound_expr_add(new_init, range);
+ else
+ compound_expr_add(new_init, expr_to_set_elem(left));
+ }
+
+ expr_free(set->init);
+ set->init = new_init;
+
+ return 0;
+}
+
+static bool range_is_prefix(const mpz_t range)
+{
+ mpz_t tmp;
+ bool ret;
+
+ mpz_init_set(tmp, range);
+ mpz_add_ui(tmp, tmp, 1);
+ mpz_and(tmp, range, tmp);
+ ret = !mpz_cmp_ui(tmp, 0);
+ mpz_clear(tmp);
+ return ret;
+}
+
+static int expr_value_cmp(const void *p1, const void *p2)
+{
+ struct expr *e1 = *(void * const *)p1;
+ struct expr *e2 = *(void * const *)p2;
+ int ret;
+
+ if (expr_value(e1)->etype == EXPR_CONCAT)
+ return -1;
+
+ ret = mpz_cmp(expr_value(e1)->value, expr_value(e2)->value);
+ if (ret == 0) {
+ if (e1->flags & EXPR_F_INTERVAL_END)
+ return -1;
+ else if (e2->flags & EXPR_F_INTERVAL_END)
+ return 1;
+ }
+
+ return ret;
+}
+
+/* Given start and end elements of a range, check if it can be represented as
+ * a single netmask, and if so, how long, by returning zero or a positive value.
+ */
+static int range_mask_len(const mpz_t start, const mpz_t end, unsigned int len)
+{
+ mpz_t tmp_start, tmp_end;
+ int ret;
+
+ mpz_init_set(tmp_start, start);
+ mpz_init_set(tmp_end, end);
+
+ while (mpz_cmp(tmp_start, tmp_end) <= 0 &&
+ !mpz_tstbit(tmp_start, 0) && mpz_tstbit(tmp_end, 0) &&
+ len--) {
+ mpz_fdiv_q_2exp(tmp_start, tmp_start, 1);
+ mpz_fdiv_q_2exp(tmp_end, tmp_end, 1);
+ }
+
+ ret = !mpz_cmp(tmp_start, tmp_end) ? (int)len : -1;
+
+ mpz_clear(tmp_start);
+ mpz_clear(tmp_end);
+
+ return ret;
+}
+
+/* Given a set with two elements (start and end), transform them into a
+ * concatenation of ranges. That is, from a list of start expressions and a list
+ * of end expressions, form a list of start - end expressions.
+ */
+void concat_range_aggregate(struct expr *set)
+{
+ struct expr *i, *start = NULL, *end, *r1, *r2, *next, *r1_next, *tmp;
+ struct list_head *r2_next;
+ int prefix_len, free_r1;
+ mpz_t range, p;
+
+ list_for_each_entry_safe(i, next, &set->expressions, list) {
+ if (!start) {
+ start = i;
+ continue;
+ }
+ end = i;
+
+ /* Walk over r1 (start expression) and r2 (end) in parallel,
+ * form ranges between corresponding r1 and r2 expressions,
+ * store them by replacing r2 expressions, and free r1
+ * expressions.
+ */
+ r2 = list_first_entry(&expr_value(end)->expressions,
+ struct expr, list);
+ list_for_each_entry_safe(r1, r1_next,
+ &expr_value(start)->expressions,
+ list) {
+ bool string_type = false;
+
+ mpz_init(range);
+ mpz_init(p);
+
+ r2_next = r2->list.next;
+ free_r1 = 0;
+
+ if (!mpz_cmp(r1->value, r2->value)) {
+ free_r1 = 1;
+ goto next;
+ }
+
+ if (expr_basetype(r1)->type == TYPE_STRING &&
+ expr_basetype(r2)->type == TYPE_STRING) {
+ string_type = true;
+ mpz_switch_byteorder(r1->value, r1->len / BITS_PER_BYTE);
+ mpz_switch_byteorder(r2->value, r2->len / BITS_PER_BYTE);
+ }
+
+ mpz_sub(range, r2->value, r1->value);
+ mpz_sub_ui(range, range, 1);
+ mpz_and(p, r1->value, range);
+
+ /* Check if we are forced, or if it's anyway preferable,
+ * to express the range as a wildcard string, or two points
+ * instead of a netmask.
+ */
+ prefix_len = range_mask_len(r1->value, r2->value,
+ r1->len);
+ if (string_type) {
+ mpz_switch_byteorder(r1->value, r1->len / BITS_PER_BYTE);
+ mpz_switch_byteorder(r2->value, r2->len / BITS_PER_BYTE);
+ }
+
+ if (prefix_len >= 0 &&
+ (prefix_len % BITS_PER_BYTE) == 0 &&
+ string_type) {
+ unsigned int str_len = prefix_len / BITS_PER_BYTE;
+ char data[str_len + 2];
+
+ mpz_export_data(data, r1->value, BYTEORDER_HOST_ENDIAN, str_len);
+ data[str_len] = '*';
+
+ tmp = constant_expr_alloc(&r1->location, r1->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (str_len + 1) * BITS_PER_BYTE, data);
+ tmp->len = r2->len;
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ expr_free(r2);
+ free_r1 = 1;
+ goto next;
+ }
+
+ if (prefix_len < 0 ||
+ !(r1->dtype->flags & DTYPE_F_PREFIX)) {
+ tmp = range_expr_alloc(&r1->location, r1,
+ r2);
+
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ } else {
+ tmp = prefix_expr_alloc(&r1->location, r1,
+ prefix_len);
+ tmp->len = r2->len;
+
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ expr_free(r2);
+ }
+
+next:
+ mpz_clear(p);
+ mpz_clear(range);
+
+ r2 = list_entry(r2_next, typeof(*r2), list);
+ compound_expr_remove(start, r1);
+
+ if (free_r1)
+ expr_free(r1);
+ }
+
+ compound_expr_remove(set, start);
+ expr_free(start);
+ start = NULL;
+ }
+}
+
+static struct expr *interval_to_prefix(struct expr *low, struct expr *i, const mpz_t range)
+{
+ unsigned int prefix_len;
+ struct expr *prefix;
+
+ prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
+ prefix = prefix_expr_alloc(&low->location,
+ expr_clone(expr_value(low)),
+ prefix_len);
+ prefix->len = expr_value(i)->len;
+
+ return __expr_to_set_elem(low, prefix);
+}
+
+static struct expr *interval_to_string(struct expr *low, struct expr *i, const mpz_t range)
+{
+ unsigned int len = div_round_up(i->len, BITS_PER_BYTE);
+ unsigned int prefix_len, str_len;
+ char data[len + 2];
+ struct expr *expr;
+
+ prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
+
+ if (prefix_len > i->len || prefix_len % BITS_PER_BYTE)
+ return interval_to_prefix(low, i, range);
+
+ mpz_export_data(data, expr_value(low)->value, BYTEORDER_BIG_ENDIAN, len);
+
+ str_len = strnlen(data, len);
+ if (str_len >= len || str_len == 0)
+ return interval_to_prefix(low, i, range);
+
+ data[str_len] = '*';
+
+ expr = constant_expr_alloc(&low->location, low->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (str_len + 1) * BITS_PER_BYTE, data);
+
+ return __expr_to_set_elem(low, expr);
+}
+
+static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t range)
+{
+ struct expr *tmp;
+
+ tmp = constant_expr_alloc(&low->location, low->dtype,
+ low->byteorder, expr_value(low)->len,
+ NULL);
+
+ mpz_add(range, range, expr_value(low)->value);
+ mpz_set(tmp->value, range);
+
+ tmp = range_expr_alloc(&low->location,
+ expr_clone(expr_value(low)),
+ tmp);
+
+ return __expr_to_set_elem(low, tmp);
+}
+
+static void
+add_interval(struct expr *set, struct expr *low, struct expr *i)
+{
+ struct expr *expr;
+ mpz_t range, p;
+
+ mpz_init(range);
+ mpz_init(p);
+
+ mpz_sub(range, expr_value(i)->value, expr_value(low)->value);
+ if (i->etype != EXPR_VALUE)
+ mpz_sub_ui(range, range, 1);
+
+ mpz_and(p, expr_value(low)->value, range);
+
+ if (!mpz_cmp_ui(range, 0)) {
+ if (expr_basetype(low)->type == TYPE_STRING)
+ mpz_switch_byteorder(expr_value(low)->value,
+ expr_value(low)->len / BITS_PER_BYTE);
+ low->flags |= EXPR_F_KERNEL;
+ expr = expr_get(low);
+ } else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) {
+
+ if (i->dtype->flags & DTYPE_F_PREFIX)
+ expr = interval_to_prefix(low, i, range);
+ else if (expr_basetype(i)->type == TYPE_STRING)
+ expr = interval_to_string(low, i, range);
+ else
+ expr = interval_to_range(low, i, range);
+ } else
+ expr = interval_to_range(low, i, range);
+
+ compound_expr_add(set, expr);
+
+ mpz_clear(range);
+ mpz_clear(p);
+}
+
+void interval_map_decompose(struct expr *set)
+{
+ struct expr *i, *next, *low = NULL, *end, *catchall = NULL, *key;
+ struct expr **elements, **ranges;
+ unsigned int n, m, size;
+ bool interval;
+
+ if (set->size == 0)
+ return;
+
+ elements = xmalloc_array(set->size, sizeof(struct expr *));
+ ranges = xmalloc_array(set->size * 2, sizeof(struct expr *));
+
+ /* Sort elements */
+ n = 0;
+ list_for_each_entry_safe(i, next, &set->expressions, list) {
+ key = NULL;
+ if (i->etype == EXPR_SET_ELEM)
+ key = i->key;
+ else if (i->etype == EXPR_MAPPING)
+ key = i->left->key;
+
+ if (key && key->etype == EXPR_SET_ELEM_CATCHALL) {
+ list_del(&i->list);
+ catchall = i;
+ continue;
+ }
+ compound_expr_remove(set, i);
+ elements[n++] = i;
+ }
+ qsort(elements, n, sizeof(elements[0]), expr_value_cmp);
+ size = n;
+
+ /* Transform points (single values) into half-closed intervals */
+ n = 0;
+ interval = false;
+ for (m = 0; m < size; m++) {
+ i = elements[m];
+
+ if (i->flags & EXPR_F_INTERVAL_END)
+ interval = false;
+ else if (interval) {
+ end = expr_clone(i);
+ end->flags |= EXPR_F_INTERVAL_END;
+ ranges[n++] = end;
+ } else
+ interval = true;
+
+ ranges[n++] = i;
+ }
+ size = n;
+
+ for (n = 0; n < size; n++) {
+ i = ranges[n];
+
+ if (low == NULL) {
+ if (i->flags & EXPR_F_INTERVAL_END) {
+ /*
+ * End of interval mark
+ */
+ expr_free(i);
+ continue;
+ } else {
+ /*
+ * Start a new interval
+ */
+ low = i;
+ continue;
+ }
+ }
+
+ add_interval(set, low, i);
+
+ if (i->flags & EXPR_F_INTERVAL_END) {
+ expr_free(low);
+ low = NULL;
+ }
+ expr_free(i);
+ }
+
+ if (!low) /* no unclosed interval at end */
+ goto out;
+
+ i = constant_expr_alloc(&low->location, low->dtype,
+ low->byteorder, expr_value(low)->len, NULL);
+ mpz_bitmask(i->value, i->len);
+
+ if (!mpz_cmp(i->value, expr_value(low)->value)) {
+ compound_expr_add(set, low);
+ } else {
+ add_interval(set, low, i);
+ expr_free(low);
+ }
+
+ expr_free(i);
+
+out:
+ if (catchall)
+ compound_expr_add(set, catchall);
+
+ xfree(ranges);
+ xfree(elements);
+}
diff --git a/src/socket.c b/src/socket.c
new file mode 100644
index 0000000..8a149e6
--- /dev/null
+++ b/src/socket.c
@@ -0,0 +1,136 @@
+/*
+ * Socket expression/statement related definition and types.
+ *
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <nftables.h>
+#include <expression.h>
+#include <socket.h>
+#include <json.h>
+
+const struct socket_template socket_templates[] = {
+ [NFT_SOCKET_TRANSPARENT] = {
+ .token = "transparent",
+ .dtype = &integer_type,
+ .len = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ },
+ [NFT_SOCKET_MARK] = {
+ .token = "mark",
+ .dtype = &mark_type,
+ .len = 4 * BITS_PER_BYTE,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ },
+ [NFT_SOCKET_WILDCARD] = {
+ .token = "wildcard",
+ .dtype = &integer_type,
+ .len = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ },
+ [NFT_SOCKET_CGROUPV2] = {
+ .token = "cgroupv2",
+ .dtype = &cgroupv2_type,
+ .len = 8 * BITS_PER_BYTE,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ },
+};
+
+static void socket_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_print(octx, "socket %s", socket_templates[expr->socket.key].token);
+ if (expr->socket.key == NFT_SOCKET_CGROUPV2)
+ nft_print(octx, " level %u", expr->socket.level);
+}
+
+static bool socket_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->socket.key == e2->socket.key &&
+ e1->socket.level == e2->socket.level;
+}
+
+static void socket_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->socket.key = expr->socket.key;
+ new->socket.level = expr->socket.level;
+}
+
+#define NFTNL_UDATA_SOCKET_KEY 0
+#define NFTNL_UDATA_SOCKET_MAX 1
+
+static int socket_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SOCKET_KEY, expr->socket.key);
+
+ return 0;
+}
+
+static int socket_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SOCKET_KEY:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *socket_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SOCKET_MAX + 1] = {};
+ uint32_t key;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ socket_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_SOCKET_KEY])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_SOCKET_KEY]);
+
+ return socket_expr_alloc(&internal_location, key, 0);
+}
+
+const struct expr_ops socket_expr_ops = {
+ .type = EXPR_SOCKET,
+ .name = "socket",
+ .print = socket_expr_print,
+ .json = socket_expr_json,
+ .cmp = socket_expr_cmp,
+ .clone = socket_expr_clone,
+ .build_udata = socket_expr_build_udata,
+ .parse_udata = socket_expr_parse_udata,
+};
+
+struct expr *socket_expr_alloc(const struct location *loc,
+ enum nft_socket_keys key, uint32_t level)
+{
+ const struct socket_template *tmpl = &socket_templates[key];
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_SOCKET, tmpl->dtype,
+ tmpl->byteorder, tmpl->len);
+ expr->socket.key = key;
+ expr->socket.level = level;
+
+ return expr;
+}
diff --git a/src/statement.c b/src/statement.c
new file mode 100644
index 0000000..4756116
--- /dev/null
+++ b/src/statement.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <syslog.h>
+#include <rule.h>
+
+#include <arpa/inet.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_log.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
+#include <statement.h>
+#include <tcpopt.h>
+#include <utils.h>
+#include <list.h>
+#include <xt.h>
+#include <json.h>
+
+#include <netinet/in.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_log.h>
+#include <linux/netfilter/nf_synproxy.h>
+
+struct stmt *stmt_alloc(const struct location *loc,
+ const struct stmt_ops *ops)
+{
+ struct stmt *stmt;
+
+ stmt = xzalloc(sizeof(*stmt));
+ init_list_head(&stmt->list);
+ stmt->location = *loc;
+ stmt->ops = ops;
+ return stmt;
+}
+
+void stmt_free(struct stmt *stmt)
+{
+ if (stmt == NULL)
+ return;
+ if (stmt->ops->destroy)
+ stmt->ops->destroy(stmt);
+ xfree(stmt);
+}
+
+void stmt_list_free(struct list_head *list)
+{
+ struct stmt *i, *next;
+
+ list_for_each_entry_safe(i, next, list, list) {
+ list_del(&i->list);
+ stmt_free(i);
+ }
+}
+
+void stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ stmt->ops->print(stmt, octx);
+}
+
+static void expr_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ expr_print(stmt->expr, octx);
+}
+
+static void expr_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->expr);
+}
+
+static const struct stmt_ops expr_stmt_ops = {
+ .type = STMT_EXPRESSION,
+ .name = "expression",
+ .print = expr_stmt_print,
+ .json = expr_stmt_json,
+ .destroy = expr_stmt_destroy,
+};
+
+struct stmt *expr_stmt_alloc(const struct location *loc, struct expr *expr)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &expr_stmt_ops);
+ stmt->expr = expr;
+ return stmt;
+}
+
+static const struct stmt_ops verdict_stmt_ops = {
+ .type = STMT_VERDICT,
+ .name = "verdict",
+ .print = expr_stmt_print,
+ .json = verdict_stmt_json,
+ .destroy = expr_stmt_destroy,
+};
+
+struct stmt *verdict_stmt_alloc(const struct location *loc, struct expr *expr)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &verdict_stmt_ops);
+ stmt->expr = expr;
+ return stmt;
+}
+
+static const char *chain_verdict(const struct expr *expr)
+{
+ switch (expr->verdict) {
+ case NFT_JUMP:
+ return "jump";
+ case NFT_GOTO:
+ return "goto";
+ default:
+ BUG("unknown chain verdict");
+ }
+}
+
+static void chain_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "%s {\n", chain_verdict(stmt->chain.expr));
+ chain_rules_print(stmt->chain.chain, octx, "\t");
+ nft_print(octx, "\t\t}");
+}
+
+static void chain_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->chain.expr);
+}
+
+static const struct stmt_ops chain_stmt_ops = {
+ .type = STMT_CHAIN,
+ .name = "chain",
+ .print = chain_stmt_print,
+ .destroy = chain_stmt_destroy,
+};
+
+struct stmt *chain_stmt_alloc(const struct location *loc, struct chain *chain,
+ enum nft_verdicts verdict)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &chain_stmt_ops);
+ stmt->chain.chain = chain;
+ stmt->chain.expr = verdict_expr_alloc(loc, verdict, NULL);
+ stmt->chain.expr->chain_id = chain->handle.chain_id;
+
+ return stmt;
+}
+
+static void meter_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ unsigned int flags = octx->flags;
+
+ nft_print(octx, "meter ");
+ if (stmt->meter.set) {
+ expr_print(stmt->meter.set, octx);
+ nft_print(octx, " ");
+ }
+ nft_print(octx, "size %u { ", stmt->meter.size);
+ expr_print(stmt->meter.key, octx);
+ nft_print(octx, " ");
+
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ stmt_print(stmt->meter.stmt, octx);
+ octx->flags = flags;
+
+ nft_print(octx, " }");
+
+}
+
+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);
+}
+
+static const struct stmt_ops meter_stmt_ops = {
+ .type = STMT_METER,
+ .name = "meter",
+ .print = meter_stmt_print,
+ .json = meter_stmt_json,
+ .destroy = meter_stmt_destroy,
+};
+
+struct stmt *meter_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &meter_stmt_ops);
+}
+
+static void connlimit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "ct count %s%u",
+ stmt->connlimit.flags ? "over " : "", stmt->connlimit.count);
+}
+
+static const struct stmt_ops connlimit_stmt_ops = {
+ .type = STMT_CONNLIMIT,
+ .name = "connlimit",
+ .print = connlimit_stmt_print,
+ .json = connlimit_stmt_json,
+};
+
+struct stmt *connlimit_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &connlimit_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ return stmt;
+}
+
+static void counter_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "counter");
+
+ if (nft_output_stateless(octx))
+ return;
+
+ nft_print(octx, " packets %" PRIu64 " bytes %" PRIu64,
+ stmt->counter.packets, stmt->counter.bytes);
+}
+
+static const struct stmt_ops counter_stmt_ops = {
+ .type = STMT_COUNTER,
+ .name = "counter",
+ .print = counter_stmt_print,
+ .json = counter_stmt_json,
+};
+
+struct stmt *counter_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &counter_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ 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",
+ [NFT_OBJECT_CT_HELPER] = "ct helper",
+ [NFT_OBJECT_LIMIT] = "limit",
+ [NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
+ [NFT_OBJECT_SECMARK] = "secmark",
+ [NFT_OBJECT_SYNPROXY] = "synproxy",
+ [NFT_OBJECT_CT_EXPECT] = "ct expectation",
+};
+
+const char *objref_type_name(uint32_t type)
+{
+ if (type > NFT_OBJECT_MAX)
+ return "unknown";
+
+ return objref_type[type];
+}
+
+static void objref_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ switch (stmt->objref.type) {
+ case NFT_OBJECT_CT_HELPER:
+ nft_print(octx, "ct helper set ");
+ break;
+ case NFT_OBJECT_CT_TIMEOUT:
+ nft_print(octx, "ct timeout set ");
+ break;
+ case NFT_OBJECT_CT_EXPECT:
+ nft_print(octx, "ct expectation set ");
+ break;
+ case NFT_OBJECT_SECMARK:
+ nft_print(octx, "meta secmark set ");
+ break;
+ default:
+ nft_print(octx, "%s name ",
+ objref_type_name(stmt->objref.type));
+ break;
+ }
+ expr_print(stmt->objref.expr, octx);
+}
+
+static void objref_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->objref.expr);
+}
+
+static const struct stmt_ops objref_stmt_ops = {
+ .type = STMT_OBJREF,
+ .name = "objref",
+ .print = objref_stmt_print,
+ .json = objref_stmt_json,
+ .destroy = objref_stmt_destroy,
+};
+
+struct stmt *objref_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &objref_stmt_ops);
+ return stmt;
+}
+
+static const char *syslog_level[NFT_LOGLEVEL_MAX + 1] = {
+ [NFT_LOGLEVEL_EMERG] = "emerg",
+ [NFT_LOGLEVEL_ALERT] = "alert",
+ [NFT_LOGLEVEL_CRIT] = "crit",
+ [NFT_LOGLEVEL_ERR] = "err",
+ [NFT_LOGLEVEL_WARNING] = "warn",
+ [NFT_LOGLEVEL_NOTICE] = "notice",
+ [NFT_LOGLEVEL_INFO] = "info",
+ [NFT_LOGLEVEL_DEBUG] = "debug",
+ [NFT_LOGLEVEL_AUDIT] = "audit"
+};
+
+const char *log_level(uint32_t level)
+{
+ if (level > NFT_LOGLEVEL_MAX)
+ return "unknown";
+
+ return syslog_level[level];
+}
+
+int log_level_parse(const char *level)
+{
+ int i;
+
+ for (i = 0; i <= NFT_LOGLEVEL_MAX; i++) {
+ if (syslog_level[i] &&
+ !strcmp(level, syslog_level[i]))
+ return i;
+ }
+ return -1;
+}
+
+static void log_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "log");
+ if (stmt->log.flags & STMT_LOG_PREFIX) {
+ char prefix[NF_LOG_PREFIXLEN] = {};
+
+ expr_to_string(stmt->log.prefix, prefix);
+ nft_print(octx, " prefix \"%s\"", prefix);
+ }
+ if (stmt->log.flags & STMT_LOG_GROUP)
+ nft_print(octx, " group %u", stmt->log.group);
+ if (stmt->log.flags & STMT_LOG_SNAPLEN)
+ nft_print(octx, " snaplen %u", stmt->log.snaplen);
+ if (stmt->log.flags & STMT_LOG_QTHRESHOLD)
+ nft_print(octx, " queue-threshold %u", stmt->log.qthreshold);
+ if ((stmt->log.flags & STMT_LOG_LEVEL) &&
+ stmt->log.level != LOG_WARNING)
+ nft_print(octx, " level %s", log_level(stmt->log.level));
+
+ if ((stmt->log.logflags & NF_LOG_MASK) == NF_LOG_MASK) {
+ nft_print(octx, " flags all");
+ } else {
+ if (stmt->log.logflags & (NF_LOG_TCPSEQ | NF_LOG_TCPOPT)) {
+ const char *delim = " ";
+
+ nft_print(octx, " flags tcp");
+ if (stmt->log.logflags & NF_LOG_TCPSEQ) {
+ nft_print(octx, " sequence");
+ delim = ",";
+ }
+ if (stmt->log.logflags & NF_LOG_TCPOPT)
+ nft_print(octx, "%soptions",
+ delim);
+ }
+ if (stmt->log.logflags & NF_LOG_IPOPT)
+ nft_print(octx, " flags ip options");
+ if (stmt->log.logflags & NF_LOG_UID)
+ nft_print(octx, " flags skuid");
+ if (stmt->log.logflags & NF_LOG_MACDECODE)
+ nft_print(octx, " flags ether");
+ }
+}
+
+static void log_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->log.prefix);
+}
+
+static const struct stmt_ops log_stmt_ops = {
+ .type = STMT_LOG,
+ .name = "log",
+ .print = log_stmt_print,
+ .json = log_stmt_json,
+ .destroy = log_stmt_destroy,
+};
+
+struct stmt *log_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &log_stmt_ops);
+}
+
+const char *get_unit(uint64_t u)
+{
+ switch (u) {
+ case 1: return "second";
+ case 60: return "minute";
+ case 60 * 60: return "hour";
+ case 60 * 60 * 24: return "day";
+ case 60 * 60 * 24 * 7: return "week";
+ }
+
+ return "error";
+}
+
+static const char * const data_unit[] = {
+ "bytes",
+ "kbytes",
+ "mbytes",
+ NULL
+};
+
+const char *get_rate(uint64_t byte_rate, uint64_t *rate)
+{
+ int i;
+
+ if (!byte_rate) {
+ *rate = 0;
+ return data_unit[0];
+ }
+
+ for (i = 0; data_unit[i + 1] != NULL; i++) {
+ if (byte_rate % 1024)
+ break;
+ byte_rate /= 1024;
+ }
+
+ *rate = byte_rate;
+ return data_unit[i];
+}
+
+static void limit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ bool inv = stmt->limit.flags & NFT_LIMIT_F_INV;
+ const char *data_unit;
+ uint64_t rate;
+
+ switch (stmt->limit.type) {
+ case NFT_LIMIT_PKTS:
+ nft_print(octx, "limit rate %s%" PRIu64 "/%s",
+ inv ? "over " : "", stmt->limit.rate,
+ get_unit(stmt->limit.unit));
+ nft_print(octx, " burst %u packets", stmt->limit.burst);
+ break;
+ case NFT_LIMIT_PKT_BYTES:
+ data_unit = get_rate(stmt->limit.rate, &rate);
+
+ nft_print(octx, "limit rate %s%" PRIu64 " %s/%s",
+ inv ? "over " : "", rate, data_unit,
+ get_unit(stmt->limit.unit));
+ if (stmt->limit.burst != 0) {
+ uint64_t burst;
+
+ data_unit = get_rate(stmt->limit.burst, &burst);
+ nft_print(octx, " burst %" PRIu64 " %s", burst,
+ data_unit);
+ }
+ break;
+ }
+}
+
+static const struct stmt_ops limit_stmt_ops = {
+ .type = STMT_LIMIT,
+ .name = "limit",
+ .print = limit_stmt_print,
+ .json = limit_stmt_json,
+};
+
+struct stmt *limit_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &limit_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ return stmt;
+}
+
+static void queue_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ struct expr *e = stmt->queue.queue;
+ const char *delim = " flags ";
+
+ nft_print(octx, "queue");
+
+ if (stmt->queue.flags & NFT_QUEUE_FLAG_BYPASS) {
+ nft_print(octx, "%sbypass", delim);
+ delim = ",";
+ }
+
+ if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT)
+ nft_print(octx, "%sfanout", delim);
+
+ if (e) {
+ nft_print(octx, " to ");
+ expr_print(stmt->queue.queue, octx);
+ } else {
+ nft_print(octx, " to 0");
+ }
+}
+
+static void queue_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->queue.queue);
+}
+
+static const struct stmt_ops queue_stmt_ops = {
+ .type = STMT_QUEUE,
+ .name = "queue",
+ .print = queue_stmt_print,
+ .json = queue_stmt_json,
+ .destroy = queue_stmt_destroy,
+};
+
+struct stmt *queue_stmt_alloc(const struct location *loc, struct expr *e, uint16_t flags)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &queue_stmt_ops);
+ stmt->queue.queue = e;
+ stmt->queue.flags = flags;
+
+ return stmt;
+}
+
+static void quota_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ bool inv = stmt->quota.flags & NFT_QUOTA_F_INV;
+ const char *data_unit;
+ uint64_t bytes, used;
+
+ data_unit = get_rate(stmt->quota.bytes, &bytes);
+ nft_print(octx, "quota %s%" PRIu64 " %s",
+ inv ? "over " : "", bytes, data_unit);
+
+ if (!nft_output_stateless(octx) && stmt->quota.used) {
+ data_unit = get_rate(stmt->quota.used, &used);
+ nft_print(octx, " used %" PRIu64 " %s", used, data_unit);
+ }
+}
+
+static const struct stmt_ops quota_stmt_ops = {
+ .type = STMT_QUOTA,
+ .name = "quota",
+ .print = quota_stmt_print,
+ .json = quota_stmt_json,
+};
+
+struct stmt *quota_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &quota_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ return stmt;
+}
+
+static void reject_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "reject");
+ switch (stmt->reject.type) {
+ case NFT_REJECT_TCP_RST:
+ nft_print(octx, " with tcp reset");
+ break;
+ case NFT_REJECT_ICMPX_UNREACH:
+ if (stmt->reject.icmp_code == NFT_REJECT_ICMPX_PORT_UNREACH)
+ break;
+ nft_print(octx, " with icmpx ");
+ expr_print(stmt->reject.expr, octx);
+ break;
+ case NFT_REJECT_ICMP_UNREACH:
+ switch (stmt->reject.family) {
+ case NFPROTO_IPV4:
+ if (!stmt->reject.verbose_print &&
+ stmt->reject.icmp_code == ICMP_PORT_UNREACH)
+ break;
+ nft_print(octx, " with icmp ");
+ expr_print(stmt->reject.expr, octx);
+ break;
+ case NFPROTO_IPV6:
+ if (!stmt->reject.verbose_print &&
+ stmt->reject.icmp_code == ICMP6_DST_UNREACH_NOPORT)
+ break;
+ nft_print(octx, " with icmpv6 ");
+ expr_print(stmt->reject.expr, octx);
+ break;
+ }
+ break;
+ }
+}
+
+static void reject_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->reject.expr);
+}
+
+static const struct stmt_ops reject_stmt_ops = {
+ .type = STMT_REJECT,
+ .name = "reject",
+ .print = reject_stmt_print,
+ .json = reject_stmt_json,
+ .destroy = reject_stmt_destroy,
+};
+
+struct stmt *reject_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &reject_stmt_ops);
+}
+
+static void print_nf_nat_flags(uint32_t flags, struct output_ctx *octx)
+{
+ const char *delim = " ";
+
+ if (flags == 0)
+ return;
+
+ if (flags & NF_NAT_RANGE_PROTO_RANDOM) {
+ nft_print(octx, "%srandom", delim);
+ delim = ",";
+ }
+
+ if (flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+ nft_print(octx, "%sfully-random", delim);
+ delim = ",";
+ }
+
+ if (flags & NF_NAT_RANGE_PERSISTENT)
+ nft_print(octx, "%spersistent", delim);
+}
+
+const char *nat_etype2str(enum nft_nat_etypes type)
+{
+ static const char * const nat_types[] = {
+ [NFT_NAT_SNAT] = "snat",
+ [NFT_NAT_DNAT] = "dnat",
+ [NFT_NAT_MASQ] = "masquerade",
+ [NFT_NAT_REDIR] = "redirect",
+ };
+
+ return nat_types[type];
+}
+
+static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "%s", nat_etype2str(stmt->nat.type));
+ if (stmt->nat.addr || stmt->nat.proto) {
+ switch (stmt->nat.family) {
+ case NFPROTO_IPV4:
+ nft_print(octx, " ip");
+ break;
+ case NFPROTO_IPV6:
+ nft_print(octx, " ip6");
+ break;
+ }
+
+ if (stmt->nat.type_flags & STMT_NAT_F_PREFIX)
+ nft_print(octx, " prefix");
+
+ nft_print(octx, " to");
+ }
+
+ if (stmt->nat.addr) {
+ nft_print(octx, " ");
+ if (stmt->nat.proto) {
+ if (stmt->nat.addr->etype == EXPR_VALUE &&
+ stmt->nat.addr->dtype->type == TYPE_IP6ADDR) {
+ nft_print(octx, "[");
+ expr_print(stmt->nat.addr, octx);
+ nft_print(octx, "]");
+ } else if (stmt->nat.addr->etype == EXPR_RANGE &&
+ stmt->nat.addr->left->dtype->type == TYPE_IP6ADDR) {
+ nft_print(octx, "[");
+ expr_print(stmt->nat.addr->left, octx);
+ nft_print(octx, "]-[");
+ expr_print(stmt->nat.addr->right, octx);
+ nft_print(octx, "]");
+ } else {
+ expr_print(stmt->nat.addr, octx);
+ }
+ } else {
+ expr_print(stmt->nat.addr, octx);
+ }
+ }
+
+ if (stmt->nat.proto) {
+ if (!stmt->nat.addr)
+ nft_print(octx, " ");
+ nft_print(octx, ":");
+ expr_print(stmt->nat.proto, octx);
+ }
+
+ print_nf_nat_flags(stmt->nat.flags, octx);
+}
+
+static void nat_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->nat.addr);
+ expr_free(stmt->nat.proto);
+}
+
+static const struct stmt_ops nat_stmt_ops = {
+ .type = STMT_NAT,
+ .name = "nat",
+ .print = nat_stmt_print,
+ .json = nat_stmt_json,
+ .destroy = nat_stmt_destroy,
+};
+
+struct stmt *nat_stmt_alloc(const struct location *loc,
+ enum nft_nat_etypes type)
+{
+ struct stmt *stmt = stmt_alloc(loc, &nat_stmt_ops);
+
+ stmt->nat.type = type;
+ return stmt;
+}
+
+const char * const set_stmt_op_names[] = {
+ [NFT_DYNSET_OP_ADD] = "add",
+ [NFT_DYNSET_OP_UPDATE] = "update",
+ [NFT_DYNSET_OP_DELETE] = "delete",
+};
+
+static void set_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ unsigned int flags = octx->flags;
+ struct stmt *this;
+
+ nft_print(octx, "%s ", set_stmt_op_names[stmt->set.op]);
+ expr_print(stmt->set.set, octx);
+ nft_print(octx, " { ");
+ expr_print(stmt->set.key, octx);
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ nft_print(octx, " ");
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ stmt_print(this, octx);
+ octx->flags = flags;
+ }
+ nft_print(octx, " }");
+}
+
+static void set_stmt_destroy(struct stmt *stmt)
+{
+ struct stmt *this, *next;
+
+ expr_free(stmt->set.key);
+ expr_free(stmt->set.set);
+ list_for_each_entry_safe(this, next, &stmt->set.stmt_list, list)
+ stmt_free(this);
+}
+
+static const struct stmt_ops set_stmt_ops = {
+ .type = STMT_SET,
+ .name = "set",
+ .print = set_stmt_print,
+ .json = set_stmt_json,
+ .destroy = set_stmt_destroy,
+};
+
+struct stmt *set_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &set_stmt_ops);
+ init_list_head(&stmt->set.stmt_list);
+
+ return stmt;
+}
+
+static void map_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ unsigned int flags = octx->flags;
+ struct stmt *this;
+
+ nft_print(octx, "%s ", set_stmt_op_names[stmt->map.op]);
+ expr_print(stmt->map.set, octx);
+ nft_print(octx, " { ");
+ expr_print(stmt->map.key, octx);
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ nft_print(octx, " ");
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ stmt_print(this, octx);
+ octx->flags = flags;
+ }
+ nft_print(octx, " : ");
+ expr_print(stmt->map.data, octx);
+ nft_print(octx, " }");
+}
+
+static void map_stmt_destroy(struct stmt *stmt)
+{
+ struct stmt *this, *next;
+
+ expr_free(stmt->map.key);
+ expr_free(stmt->map.data);
+ expr_free(stmt->map.set);
+ list_for_each_entry_safe(this, next, &stmt->map.stmt_list, list)
+ stmt_free(this);
+}
+
+static const struct stmt_ops map_stmt_ops = {
+ .type = STMT_MAP,
+ .name = "map",
+ .print = map_stmt_print,
+ .destroy = map_stmt_destroy,
+ .json = map_stmt_json,
+};
+
+struct stmt *map_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &map_stmt_ops);
+ init_list_head(&stmt->map.stmt_list);
+
+ return stmt;
+}
+
+static void dup_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "dup");
+ if (stmt->dup.to != NULL) {
+ nft_print(octx, " to ");
+ expr_print(stmt->dup.to, octx);
+
+ if (stmt->dup.dev != NULL) {
+ nft_print(octx, " device ");
+ expr_print(stmt->dup.dev, octx);
+ }
+ }
+}
+
+static void dup_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->dup.to);
+ expr_free(stmt->dup.dev);
+}
+
+static const struct stmt_ops dup_stmt_ops = {
+ .type = STMT_DUP,
+ .name = "dup",
+ .print = dup_stmt_print,
+ .json = dup_stmt_json,
+ .destroy = dup_stmt_destroy,
+};
+
+struct stmt *dup_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &dup_stmt_ops);
+}
+
+static const char * const nfproto_family_name_array[NFPROTO_NUMPROTO] = {
+ [NFPROTO_IPV4] = "ip",
+ [NFPROTO_IPV6] = "ip6",
+};
+
+static const char *nfproto_family_name(uint8_t nfproto)
+{
+ if (nfproto >= NFPROTO_NUMPROTO || !nfproto_family_name_array[nfproto])
+ return "unknown";
+
+ return nfproto_family_name_array[nfproto];
+}
+
+static void fwd_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ if (stmt->fwd.addr) {
+ nft_print(octx, "fwd %s to ",
+ nfproto_family_name(stmt->fwd.family));
+ expr_print(stmt->fwd.addr, octx);
+ nft_print(octx, " device ");
+ expr_print(stmt->fwd.dev, octx);
+ } else {
+ nft_print(octx, "fwd to ");
+ expr_print(stmt->fwd.dev, octx);
+ }
+}
+
+static void fwd_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->fwd.addr);
+ expr_free(stmt->fwd.dev);
+}
+
+static const struct stmt_ops fwd_stmt_ops = {
+ .type = STMT_FWD,
+ .name = "fwd",
+ .print = fwd_stmt_print,
+ .json = fwd_stmt_json,
+ .destroy = fwd_stmt_destroy,
+};
+
+struct stmt *fwd_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &fwd_stmt_ops);
+}
+
+static void optstrip_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ const struct expr *expr = stmt->optstrip.expr;
+
+ nft_print(octx, "reset ");
+ expr_print(expr, octx);
+}
+
+static void optstrip_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->optstrip.expr);
+}
+
+static const struct stmt_ops optstrip_stmt_ops = {
+ .type = STMT_OPTSTRIP,
+ .name = "optstrip",
+ .print = optstrip_stmt_print,
+ .json = optstrip_stmt_json,
+ .destroy = optstrip_stmt_destroy,
+};
+
+struct stmt *optstrip_stmt_alloc(const struct location *loc, struct expr *e)
+{
+ struct stmt *stmt = stmt_alloc(loc, &optstrip_stmt_ops);
+
+ e->exthdr.flags |= NFT_EXTHDR_F_PRESENT;
+ stmt->optstrip.expr = e;
+
+ return stmt;
+}
+
+static void tproxy_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "tproxy");
+
+ if (stmt->tproxy.table_family == NFPROTO_INET &&
+ stmt->tproxy.family != NFPROTO_UNSPEC)
+ nft_print(octx, " %s", nfproto_family_name(stmt->tproxy.family));
+ nft_print(octx, " to");
+ if (stmt->tproxy.addr) {
+ nft_print(octx, " ");
+ if (stmt->tproxy.addr->etype == EXPR_VALUE &&
+ stmt->tproxy.addr->dtype->type == TYPE_IP6ADDR) {
+ nft_print(octx, "[");
+ expr_print(stmt->tproxy.addr, octx);
+ nft_print(octx, "]");
+ } else {
+ expr_print(stmt->tproxy.addr, octx);
+ }
+ }
+ if (stmt->tproxy.port && stmt->tproxy.port->etype == EXPR_VALUE) {
+ if (!stmt->tproxy.addr)
+ nft_print(octx, " ");
+ nft_print(octx, ":");
+ expr_print(stmt->tproxy.port, octx);
+ }
+}
+
+static void tproxy_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->tproxy.addr);
+ expr_free(stmt->tproxy.port);
+}
+
+static const struct stmt_ops tproxy_stmt_ops = {
+ .type = STMT_TPROXY,
+ .name = "tproxy",
+ .print = tproxy_stmt_print,
+ .json = tproxy_stmt_json,
+ .destroy = tproxy_stmt_destroy,
+};
+
+struct stmt *tproxy_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &tproxy_stmt_ops);
+}
+
+static void xt_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ xt_stmt_xlate(stmt, octx);
+}
+
+static const struct stmt_ops xt_stmt_ops = {
+ .type = STMT_XT,
+ .name = "xt",
+ .print = xt_stmt_print,
+ .destroy = xt_stmt_destroy,
+ .json = xt_stmt_json,
+};
+
+struct stmt *xt_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &xt_stmt_ops);
+}
+
+static const char *synproxy_sack_to_str(const uint32_t flags)
+{
+ if (flags & NF_SYNPROXY_OPT_SACK_PERM)
+ return " sack-perm";
+
+ return "";
+}
+
+static const char *synproxy_timestamp_to_str(const uint32_t flags)
+{
+ if (flags & NF_SYNPROXY_OPT_TIMESTAMP)
+ return " timestamp";
+
+ return "";
+}
+
+static void synproxy_stmt_print(const struct stmt *stmt,
+ struct output_ctx *octx)
+{
+ uint32_t flags = stmt->synproxy.flags;
+ const char *ts_str = synproxy_timestamp_to_str(flags);
+ const char *sack_str = synproxy_sack_to_str(flags);
+
+ if (flags & (NF_SYNPROXY_OPT_MSS | NF_SYNPROXY_OPT_WSCALE))
+ nft_print(octx, "synproxy mss %u wscale %u%s%s",
+ stmt->synproxy.mss, stmt->synproxy.wscale,
+ ts_str, sack_str);
+ else if (flags & NF_SYNPROXY_OPT_MSS)
+ nft_print(octx, "synproxy mss %u%s%s", stmt->synproxy.mss,
+ ts_str, sack_str);
+ else if (flags & NF_SYNPROXY_OPT_WSCALE)
+ nft_print(octx, "synproxy wscale %u%s%s", stmt->synproxy.wscale,
+ ts_str, sack_str);
+ else
+ nft_print(octx, "synproxy%s%s", ts_str, sack_str);
+
+}
+
+static const struct stmt_ops synproxy_stmt_ops = {
+ .type = STMT_SYNPROXY,
+ .name = "synproxy",
+ .print = synproxy_stmt_print,
+ .json = synproxy_stmt_json,
+};
+
+struct stmt *synproxy_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &synproxy_stmt_ops);
+}
diff --git a/src/tcpopt.c b/src/tcpopt.c
new file mode 100644
index 0000000..3fcb273
--- /dev/null
+++ b/src/tcpopt.c
@@ -0,0 +1,266 @@
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+
+#include <utils.h>
+#include <headers.h>
+#include <expression.h>
+#include <tcpopt.h>
+
+static const struct proto_hdr_template tcpopt_unknown_template =
+ PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
+
+#define PHT(__token, __offset, __len) \
+ PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
+ __offset, __len)
+static const struct exthdr_desc tcpopt_eol = {
+ .name = "eol",
+ .type = TCPOPT_KIND_EOL,
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ },
+};
+
+static const struct exthdr_desc tcpopt_nop = {
+ .name = "nop",
+ .type = TCPOPT_KIND_NOP,
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ },
+};
+
+static const struct exthdr_desc tcptopt_maxseg = {
+ .name = "maxseg",
+ .type = TCPOPT_KIND_MAXSEG,
+ .templates = {
+ [TCPOPT_MAXSEG_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_MAXSEG_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_MAXSEG_SIZE] = PHT("size", 16, 16),
+ },
+};
+
+static const struct exthdr_desc tcpopt_window = {
+ .name = "window",
+ .type = TCPOPT_KIND_WINDOW,
+ .templates = {
+ [TCPOPT_WINDOW_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_WINDOW_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_WINDOW_COUNT] = PHT("count", 16, 8),
+ },
+};
+
+static const struct exthdr_desc tcpopt_sack_permitted = {
+ .name = "sack-perm",
+ .type = TCPOPT_KIND_SACK_PERMITTED,
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
+ },
+};
+
+static const struct exthdr_desc tcpopt_sack = {
+ .name = "sack",
+ .type = TCPOPT_KIND_SACK,
+ .templates = {
+ [TCPOPT_SACK_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_SACK_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_SACK_LEFT] = PHT("left", 16, 32),
+ [TCPOPT_SACK_RIGHT] = PHT("right", 48, 32),
+ [TCPOPT_SACK_LEFT1] = PHT("left", 80, 32),
+ [TCPOPT_SACK_RIGHT1] = PHT("right", 112, 32),
+ [TCPOPT_SACK_LEFT2] = PHT("left", 144, 32),
+ [TCPOPT_SACK_RIGHT2] = PHT("right", 176, 32),
+ [TCPOPT_SACK_LEFT3] = PHT("left", 208, 32),
+ [TCPOPT_SACK_RIGHT3] = PHT("right", 240, 32),
+ },
+};
+
+static const struct exthdr_desc tcpopt_timestamp = {
+ .name = "timestamp",
+ .type = TCPOPT_KIND_TIMESTAMP,
+ .templates = {
+ [TCPOPT_TS_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_TS_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_TS_TSVAL] = PHT("tsval", 16, 32),
+ [TCPOPT_TS_TSECR] = PHT("tsecr", 48, 32),
+ },
+};
+
+static const struct exthdr_desc tcpopt_fastopen = {
+ .name = "fastopen",
+ .type = TCPOPT_KIND_FASTOPEN,
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
+ },
+};
+
+static const struct exthdr_desc tcpopt_md5sig = {
+ .name = "md5sig",
+ .type = TCPOPT_KIND_MD5SIG,
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
+ },
+};
+
+
+static const struct exthdr_desc tcpopt_mptcp = {
+ .name = "mptcp",
+ .type = TCPOPT_KIND_MPTCP,
+ .templates = {
+ [TCPOPT_MPTCP_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_MPTCP_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_MPTCP_SUBTYPE] = PHT("subtype", 16, 4),
+ },
+};
+#undef PHT
+
+const struct exthdr_desc *tcpopt_protocols[] = {
+ [TCPOPT_KIND_EOL] = &tcpopt_eol,
+ [TCPOPT_KIND_NOP] = &tcpopt_nop,
+ [TCPOPT_KIND_MAXSEG] = &tcptopt_maxseg,
+ [TCPOPT_KIND_WINDOW] = &tcpopt_window,
+ [TCPOPT_KIND_SACK_PERMITTED] = &tcpopt_sack_permitted,
+ [TCPOPT_KIND_SACK] = &tcpopt_sack,
+ [TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp,
+ [TCPOPT_KIND_MD5SIG] = &tcpopt_md5sig,
+ [TCPOPT_KIND_MPTCP] = &tcpopt_mptcp,
+ [TCPOPT_KIND_FASTOPEN] = &tcpopt_fastopen,
+};
+
+/**
+ * tcpopt_expr_alloc - allocate tcp option extension expression
+ *
+ * @loc: location from parser
+ * @kind: raw tcp option value to find in packet
+ * @field: highlevel field to find in the option if @kind is present in packet
+ *
+ * Allocate a new tcp option expression.
+ * @kind is the raw option value to find in the packet.
+ * Exception: SACK may use extra OOB data that is mangled here.
+ *
+ * @field is the optional field to extract from the @type option.
+ */
+struct expr *tcpopt_expr_alloc(const struct location *loc,
+ unsigned int kind,
+ unsigned int field)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct exthdr_desc *desc = NULL;
+ struct expr *expr;
+
+ switch (kind) {
+ case TCPOPT_KIND_SACK1:
+ kind = TCPOPT_KIND_SACK;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT1;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT1;
+ break;
+ case TCPOPT_KIND_SACK2:
+ kind = TCPOPT_KIND_SACK;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT2;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT2;
+ break;
+ case TCPOPT_KIND_SACK3:
+ kind = TCPOPT_KIND_SACK;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT3;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT3;
+ break;
+ }
+
+ if (kind < array_size(tcpopt_protocols))
+ desc = tcpopt_protocols[kind];
+
+ if (!desc) {
+ if (field != TCPOPT_COMMON_KIND || kind > 255)
+ return NULL;
+
+ 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;
+ return expr;
+ }
+
+ tmpl = &desc->templates[field];
+ if (!tmpl)
+ return NULL;
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+ BYTEORDER_BIG_ENDIAN, tmpl->len);
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+ expr->exthdr.raw_type = desc->type;
+ expr->exthdr.offset = tmpl->offset;
+
+ return expr;
+}
+
+void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
+ unsigned int len, uint32_t flags)
+{
+ const struct proto_hdr_template *tmpl;
+ unsigned int i;
+
+ assert(expr->etype == EXPR_EXTHDR);
+
+ expr->len = len;
+ expr->exthdr.flags = flags;
+ expr->exthdr.offset = off;
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+ expr->exthdr.tmpl = &tcpopt_unknown_template;
+
+ if (flags & NFT_EXTHDR_F_PRESENT)
+ datatype_set(expr, &boolean_type);
+ else
+ datatype_set(expr, &integer_type);
+
+ if (type >= array_size(tcpopt_protocols) ||
+ !tcpopt_protocols[type])
+ return;
+
+ expr->exthdr.desc = tcpopt_protocols[type];
+ expr->exthdr.flags = flags;
+ assert(expr->exthdr.desc != NULL);
+
+ for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
+ tmpl = &expr->exthdr.desc->templates[i];
+ if (tmpl->offset != off || tmpl->len != len)
+ continue;
+
+ if ((flags & NFT_EXTHDR_F_PRESENT) == 0)
+ datatype_set(expr, tmpl->dtype);
+
+ expr->exthdr.tmpl = tmpl;
+ break;
+ }
+}
+
+bool tcpopt_find_template(struct expr *expr, unsigned int offset, unsigned int len)
+{
+ if (expr->exthdr.tmpl != &tcpopt_unknown_template)
+ return false;
+
+ tcpopt_init_raw(expr, expr->exthdr.desc->type, offset, len, 0);
+
+ if (expr->exthdr.tmpl == &tcpopt_unknown_template)
+ return false;
+
+ return true;
+}
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..e6ad8b8
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2008 Patrick McHardy <kaber@trash.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 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <nft.h>
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nftables.h>
+#include <utils.h>
+
+void __noreturn __memory_allocation_error(const char *filename, uint32_t line)
+{
+ fprintf(stderr, "%s:%u: Memory allocation failure\n", filename, line);
+ exit(NFT_EXIT_NOMEM);
+}
+
+void xfree(const void *ptr)
+{
+ free((void *)ptr);
+}
+
+void *xmalloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr == NULL)
+ memory_allocation_error();
+ return ptr;
+}
+
+void *xmalloc_array(size_t nmemb, size_t size)
+{
+ assert(size != 0);
+ assert(nmemb != 0);
+
+ if (nmemb > SIZE_MAX / size)
+ memory_allocation_error();
+
+ return xmalloc(nmemb * size);
+}
+
+void *xzalloc_array(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ ptr = xmalloc_array(nmemb, size);
+ memset(ptr, 0, nmemb * size);
+
+ return ptr;
+}
+
+void *xrealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL && size != 0)
+ memory_allocation_error();
+ return ptr;
+}
+
+void *xzalloc(size_t size)
+{
+ void *ptr;
+
+ ptr = xmalloc(size);
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+char *xstrdup(const char *s)
+{
+ char *res;
+
+ assert(s != NULL);
+ res = strdup(s);
+ if (res == NULL)
+ memory_allocation_error();
+ return res;
+}
+
+void xstrunescape(const char *in, char *out)
+{
+ unsigned int i, k = 0;
+
+ for (i = 0; i < strlen(in); i++) {
+ if (in[i] == '\\')
+ continue;
+
+ out[k++] = in[i];
+ }
+ 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
new file mode 100644
index 0000000..b32b2a1
--- /dev/null
+++ b/src/xfrm.c
@@ -0,0 +1,184 @@
+/*
+ * 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 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <nftables.h>
+#include <erec.h>
+#include <expression.h>
+#include <xfrm.h>
+#include <datatype.h>
+#include <gmputil.h>
+#include <utils.h>
+
+#include <netinet/ip.h>
+#include <linux/netfilter.h>
+#include <linux/xfrm.h>
+
+#define XFRM_TEMPLATE_BE(__token, __dtype, __len) { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .len = (__len), \
+ .byteorder = BYTEORDER_BIG_ENDIAN, \
+}
+
+#define XFRM_TEMPLATE_HE(__token, __dtype, __len) { \
+ .token = (__token), \
+ .dtype = (__dtype), \
+ .len = (__len), \
+ .byteorder = BYTEORDER_HOST_ENDIAN, \
+}
+
+const struct xfrm_template xfrm_templates[] = {
+ [NFT_XFRM_KEY_DADDR_IP4] = XFRM_TEMPLATE_BE("daddr", &ipaddr_type, 4 * BITS_PER_BYTE),
+ [NFT_XFRM_KEY_SADDR_IP4] = XFRM_TEMPLATE_BE("saddr", &ipaddr_type, 4 * BITS_PER_BYTE),
+ [NFT_XFRM_KEY_DADDR_IP6] = XFRM_TEMPLATE_BE("daddr", &ip6addr_type, 16 * BITS_PER_BYTE),
+ [NFT_XFRM_KEY_SADDR_IP6] = XFRM_TEMPLATE_BE("saddr", &ip6addr_type, 16 * BITS_PER_BYTE),
+ [NFT_XFRM_KEY_REQID] = XFRM_TEMPLATE_HE("reqid", &integer_type, 4 * BITS_PER_BYTE),
+ [NFT_XFRM_KEY_SPI] = XFRM_TEMPLATE_BE("spi", &integer_type, 4 * BITS_PER_BYTE),
+};
+
+static void xfrm_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ switch (expr->xfrm.direction) {
+ case XFRM_POLICY_IN:
+ nft_print(octx, "ipsec in");
+ break;
+ case XFRM_POLICY_OUT:
+ nft_print(octx, "ipsec out");
+ break;
+ default:
+ nft_print(octx, "ipsec (unknown dir %d)", expr->xfrm.direction);
+ break;
+ }
+
+ if (expr->xfrm.spnum)
+ nft_print(octx, " spnum %u", expr->xfrm.spnum);
+
+ switch (expr->xfrm.key) {
+ case NFT_XFRM_KEY_DADDR_IP4:
+ case NFT_XFRM_KEY_SADDR_IP4:
+ nft_print(octx, " ip");
+ break;
+ case NFT_XFRM_KEY_DADDR_IP6:
+ case NFT_XFRM_KEY_SADDR_IP6:
+ nft_print(octx, " ip6");
+ break;
+ case NFT_XFRM_KEY_REQID:
+ case NFT_XFRM_KEY_SPI:
+ break;
+ default:
+ nft_print(octx, " (unknown key 0x%x)", expr->xfrm.key);
+ return;
+ }
+
+ nft_print(octx, " %s", xfrm_templates[expr->xfrm.key].token);
+}
+
+static bool xfrm_expr_cmp(const struct expr *e1, const struct expr *e2)
+{
+ return e1->xfrm.key == e2->xfrm.key &&
+ e1->xfrm.direction == e2->xfrm.direction &&
+ e1->xfrm.spnum == e2->xfrm.spnum;
+}
+
+static void xfrm_expr_clone(struct expr *new, const struct expr *expr)
+{
+ memcpy(&new->xfrm, &expr->xfrm, sizeof(new->xfrm));
+}
+
+#define NFTNL_UDATA_XFRM_KEY 0
+#define NFTNL_UDATA_XFRM_SPNUM 1
+#define NFTNL_UDATA_XFRM_DIR 2
+#define NFTNL_UDATA_XFRM_MAX 3
+
+static int xfrm_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_XFRM_KEY, expr->xfrm.key);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_XFRM_SPNUM, expr->xfrm.spnum);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_XFRM_DIR, expr->xfrm.direction);
+
+ return 0;
+}
+
+static int xfrm_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_XFRM_KEY:
+ case NFTNL_UDATA_XFRM_SPNUM:
+ case NFTNL_UDATA_XFRM_DIR:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *xfrm_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_XFRM_MAX + 1] = {};
+ uint32_t key, dir, spnum;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ xfrm_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_XFRM_KEY] ||
+ !ud[NFTNL_UDATA_XFRM_DIR] ||
+ !ud[NFTNL_UDATA_XFRM_SPNUM])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_XFRM_KEY]);
+ dir = nftnl_udata_get_u32(ud[NFTNL_UDATA_XFRM_DIR]);
+ spnum = nftnl_udata_get_u32(ud[NFTNL_UDATA_XFRM_SPNUM]);
+
+ return xfrm_expr_alloc(&internal_location, dir, spnum, key);
+}
+
+const struct expr_ops xfrm_expr_ops = {
+ .type = EXPR_XFRM,
+ .name = "xfrm",
+ .print = xfrm_expr_print,
+ .json = xfrm_expr_json,
+ .cmp = xfrm_expr_cmp,
+ .clone = xfrm_expr_clone,
+ .parse_udata = xfrm_expr_parse_udata,
+ .build_udata = xfrm_expr_build_udata,
+};
+
+struct expr *xfrm_expr_alloc(const struct location *loc,
+ uint8_t direction,
+ uint8_t spnum,
+ enum nft_xfrm_keys key)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_XFRM,
+ xfrm_templates[key].dtype,
+ xfrm_templates[key].byteorder,
+ xfrm_templates[key].len);
+
+ expr->xfrm.direction = direction;
+ expr->xfrm.spnum = spnum;
+ expr->xfrm.key = key;
+
+ return expr;
+}
diff --git a/src/xt.c b/src/xt.c
new file mode 100644
index 0000000..3cb5f02
--- /dev/null
+++ b/src/xt.c
@@ -0,0 +1,377 @@
+/*
+ * 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 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 <time.h>
+#include <net/if.h>
+#include <getopt.h>
+#include <ctype.h> /* for isspace */
+#include <statement.h>
+#include <netlink.h>
+#include <xt.h>
+#include <erec.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables_compat.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_arp/arp_tables.h>
+#include <linux/netfilter_bridge/ebtables.h>
+
+#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:
+ 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 = entry,
+ .match = m,
+ .numeric = 1,
+ };
+
+ rc = mt->xlate(xl, &params);
+ }
+ xfree(m);
+ break;
+ case NFT_XT_WATCHER:
+ case NFT_XT_TARGET:
+ 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 = entry,
+ .target = t,
+ .numeric = 1,
+ };
+
+ rc = tg->xlate(xl, &params);
+ }
+ xfree(t);
+ break;
+ }
+
+ if (rc == 1)
+ nft_print(octx, "%s", xt_xlate_get(xl));
+ xt_xlate_free(xl);
+ xfree(entry);
+#endif
+ if (!rc)
+ nft_print(octx, "xt %s \"%s\"",
+ typename[stmt->xt.type], stmt->xt.name);
+}
+
+void xt_stmt_destroy(struct stmt *stmt)
+{
+ xfree(stmt->xt.name);
+ xfree(stmt->xt.info);
+}
+
+#ifdef HAVE_LIBXTABLES
+static void *xt_entry_alloc(const struct xt_stmt *xt, uint32_t af)
+{
+ union nft_entry {
+ struct ipt_entry ipt;
+ struct ip6t_entry ip6t;
+ struct arpt_entry arpt;
+ struct ebt_entry ebt;
+ } *entry;
+
+ entry = xmalloc(sizeof(union nft_entry));
+
+ switch (af) {
+ case NFPROTO_IPV4:
+ entry->ipt.ip.proto = xt->proto;
+ break;
+ case NFPROTO_IPV6:
+ entry->ip6t.ipv6.proto = xt->proto;
+ break;
+ case NFPROTO_BRIDGE:
+ entry->ebt.ethproto = xt->proto;
+ break;
+ case NFPROTO_ARP:
+ entry->arpt.arp.arhln_mask = 0xff;
+ entry->arpt.arp.arhln = 6;
+ break;
+ default:
+ break;
+ }
+
+ return entry;
+}
+
+static uint32_t xt_proto(const struct proto_ctx *pctx)
+{
+ const struct proto_desc *desc = NULL;
+
+ if (pctx->family == NFPROTO_BRIDGE) {
+ desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc == NULL)
+ return 0;
+ if (strcmp(desc->name, "ip") == 0)
+ return __constant_htons(ETH_P_IP);
+ if (strcmp(desc->name, "ip6") == 0)
+ return __constant_htons(ETH_P_IPV6);
+ return 0;
+ }
+
+ desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+ if (desc == NULL)
+ return 0;
+ if (strcmp(desc->name, "tcp") == 0)
+ return IPPROTO_TCP;
+ else if (strcmp(desc->name, "udp") == 0)
+ return IPPROTO_UDP;
+ else if (strcmp(desc->name, "udplite") == 0)
+ return IPPROTO_UDPLITE;
+ else if (strcmp(desc->name, "sctp") == 0)
+ return IPPROTO_SCTP;
+ else if (strcmp(desc->name, "dccp") == 0)
+ return IPPROTO_DCCP;
+ else if (strcmp(desc->name, "esp") == 0)
+ return IPPROTO_ESP;
+ else if (strcmp(desc->name, "ah") == 0)
+ return IPPROTO_AH;
+
+ return 0;
+}
+#endif
+
+/*
+ * Delinearization
+ */
+
+void netlink_parse_match(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ const char *mtinfo;
+ struct stmt *stmt;
+ uint32_t mt_len;
+
+ mtinfo = nftnl_expr_get(nle, NFTNL_EXPR_MT_INFO, &mt_len);
+
+ stmt = xt_stmt_alloc(loc);
+ stmt->xt.name = strdup(nftnl_expr_get_str(nle, NFTNL_EXPR_MT_NAME));
+ stmt->xt.type = NFT_XT_MATCH;
+ stmt->xt.rev = nftnl_expr_get_u32(nle, NFTNL_EXPR_MT_REV);
+ stmt->xt.family = ctx->table->handle.family;
+
+ stmt->xt.infolen = mt_len;
+ stmt->xt.info = xmalloc(mt_len);
+ memcpy(stmt->xt.info, mtinfo, mt_len);
+
+ ctx->table->has_xt_stmts = true;
+ rule_stmt_append(ctx->rule, stmt);
+}
+
+void netlink_parse_target(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ const void *tginfo;
+ struct stmt *stmt;
+ uint32_t tg_len;
+
+ tginfo = nftnl_expr_get(nle, NFTNL_EXPR_TG_INFO, &tg_len);
+
+ stmt = xt_stmt_alloc(loc);
+ stmt->xt.name = strdup(nftnl_expr_get_str(nle, NFTNL_EXPR_TG_NAME));
+ stmt->xt.type = NFT_XT_TARGET;
+ stmt->xt.rev = nftnl_expr_get_u32(nle, NFTNL_EXPR_TG_REV);
+ stmt->xt.family = ctx->table->handle.family;
+
+ stmt->xt.infolen = tg_len;
+ stmt->xt.info = xmalloc(tg_len);
+ memcpy(stmt->xt.info, tginfo, tg_len);
+
+ ctx->table->has_xt_stmts = true;
+ rule_stmt_append(ctx->rule, stmt);
+}
+
+#ifdef HAVE_LIBXTABLES
+static bool is_watcher(uint32_t family, struct stmt *stmt)
+{
+ if (family != NFPROTO_BRIDGE ||
+ stmt->xt.type != NFT_XT_TARGET)
+ return false;
+
+ /* this has to be hardcoded :-( */
+ if (strcmp(stmt->xt.name, "log") == 0)
+ return true;
+ else if (strcmp(stmt->xt.name, "nflog") == 0)
+ return true;
+
+ return false;
+}
+
+void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt,
+ struct rule *rule)
+{
+ 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(&dl->pctx);
+}
+
+static int nft_xt_compatible_revision(const char *name, uint8_t rev, int opt)
+{
+ struct mnl_socket *nl;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t portid, seq, type, family;
+ struct nfgenmsg *nfg;
+ int ret = 0;
+
+ switch (opt) {
+ case IPT_SO_GET_REVISION_MATCH:
+ family = NFPROTO_IPV4;
+ type = 0;
+ break;
+ case IPT_SO_GET_REVISION_TARGET:
+ family = NFPROTO_IPV4;
+ type = 1;
+ break;
+ case IP6T_SO_GET_REVISION_MATCH:
+ family = NFPROTO_IPV6;
+ type = 0;
+ break;
+ case IP6T_SO_GET_REVISION_TARGET:
+ family = NFPROTO_IPV6;
+ type = 1;
+ break;
+ default: /* No revision support, assume ok */
+ return 1;
+ }
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlh->nlmsg_seq = seq = time(NULL);
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = family;
+ nfg->version = NFNETLINK_V0;
+ nfg->res_id = 0;
+
+ mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name);
+ mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev));
+ mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type));
+
+ nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (nl == NULL)
+ return 0;
+
+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
+ goto err;
+
+ portid = mnl_socket_get_portid(nl);
+
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+ goto err;
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ if (ret == -1)
+ goto err;
+
+ ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
+ if (ret == -1)
+ goto err;
+
+err:
+ mnl_socket_close(nl);
+
+ return ret < 0 ? 0 : 1;
+}
+
+static struct option original_opts[] = {
+ { },
+};
+
+static struct xtables_globals xt_nft_globals = {
+ .program_name = "nft",
+ .program_version = PACKAGE_VERSION,
+ .orig_opts = original_opts,
+ .compat_rev = nft_xt_compatible_revision,
+};
+
+void xt_init(void)
+{
+ 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/README b/tests/build/README
new file mode 100644
index 0000000..c365b88
--- /dev/null
+++ b/tests/build/README
@@ -0,0 +1,12 @@
+Testsuite for NFT compile options.
+
+In this testsuite, automated testing is done for following nft compile options:
+
+ cli support
+ enable debugging symbols
+ use mini-gmp
+ enable man page
+ libxtables support
+
+Run the test script 'run-tests.sh' as root user: ./run-tests.sh
+Any error encountered on compiling is saved in tests/build/tests.log file.
diff --git a/tests/build/run-tests.sh b/tests/build/run-tests.sh
new file mode 100755
index 0000000..916df2e
--- /dev/null
+++ b/tests/build/run-tests.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+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"
+
+tmpdir=$(mktemp -d)
+if [ ! -w "$tmpdir" ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+git clone "$dir" "$tmpdir" &>>"$log_file"
+cd "$tmpdir" || exit
+
+if ! autoreconf -fi &>>"$log_file" ; then
+ echo "Something went wrong. Check the log '${log_file}' for details."
+ exit 1
+fi
+
+if ! ./configure &>>"$log_file" ; then
+ echo "Something went wrong. Check the log '${log_file}' for details."
+ exit 1
+fi
+
+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
+
+echo -en "\033[1A\033[K"
+echo "Build works. Now, testing compile options"
+
+for var in "${argument[@]}" ; do
+ echo "[EXECUTING] Testing compile option $var"
+ ./configure "$var" &>>"$log_file"
+ make -j 8 &>>"$log_file"
+ rt=$?
+ echo -en "\033[1A\033[K" # clean the [EXECUTING] foobar line
+
+ if [ $rt -eq 0 ] ; then
+ echo "[OK] Compile option $var works."
+ ((ok++))
+ else
+ echo "[FAILED] Compile option $var does not work. Check log for details."
+ ((failed++))
+ fi
+done
+
+rm -rf "$tmpdir"
+
+echo "results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
+[ "$failed" -eq 0 ]
diff --git a/tests/build/tests.log b/tests/build/tests.log
new file mode 100644
index 0000000..efbb5de
--- /dev/null
+++ b/tests/build/tests.log
@@ -0,0 +1,3597 @@
+Clonando en '/tmp/tmp.nspSLnT0EN'...
+hecho.
+libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
+libtoolize: copying file 'build-aux/ltmain.sh'
+libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
+libtoolize: copying file 'm4/libtool.m4'
+libtoolize: copying file 'm4/ltoptions.m4'
+libtoolize: copying file 'm4/ltsugar.m4'
+libtoolize: copying file 'm4/ltversion.m4'
+libtoolize: copying file 'm4/lt~obsolete.m4'
+configure.ac:48: installing 'build-aux/ar-lib'
+configure.ac:25: installing 'build-aux/compile'
+configure.ac:49: installing 'build-aux/config.guess'
+configure.ac:49: installing 'build-aux/config.sub'
+configure.ac:6: installing 'build-aux/install-sh'
+configure.ac:6: installing 'build-aux/missing'
+examples/Makefile.am: installing 'build-aux/depcomp'
+configure.ac: installing 'build-aux/ylwrap'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for readline in -ledit... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: no
+ json output support: no
+make dist-xz am__post_remove_distdir='@:'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make distdir-am
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+if test -d "nftables-1.0.8"; then find "nftables-1.0.8" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "nftables-1.0.8" || { sleep 5 && rm -rf "nftables-1.0.8"; }; else :; fi
+test -d "nftables-1.0.8" || mkdir "nftables-1.0.8"
+ (cd src && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/src \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ YACC parser_bison.c
+/tmp/tmp.nspSLnT0EN/src/parser_bison.y:187.1-19: aviso: directiva no válida: «%name-prefix "nft_"», use «%define api.prefix {nft_}» [-Wdeprecated]
+ 187 | %name-prefix "nft_"
+ | ^~~~~~~~~~~~~~~~~~~
+ | %define api.prefix {nft_}
+/tmp/tmp.nspSLnT0EN/src/parser_bison.y: aviso: fix-its can be applied. Rerun with option '--update'. [-Wother]
+updating parser_bison.h
+make distdir-am
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ LEX scanner.c
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+ (cd include && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/include \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make distdir-am
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+ (cd linux && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/include/linux \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make distdir-am
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+ (cd netfilter && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make distdir-am
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+ (cd netfilter_arp && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_arp \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make distdir-am
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+ (cd netfilter_bridge && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_bridge \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make distdir-am
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+ (cd netfilter_ipv4 && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_ipv4 \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make distdir-am
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+ (cd netfilter_ipv6 && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_ipv6 \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make distdir-am
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+ (cd nftables && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/include/nftables \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make distdir-am
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+ (cd files && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/files \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make distdir-am
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+ (cd nftables && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/files/nftables \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make distdir-am
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+ (cd examples && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/files/examples \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make distdir-am
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+ (cd osf && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/files/osf \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make distdir-am
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+ (cd doc && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/doc \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make distdir-am
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+ GEN nft.8
+ GEN libnftables-json.5
+ GEN libnftables.3
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+ (cd examples && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/examples \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make distdir-am
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+ (cd py && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/py \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make distdir-am
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+test -n "" \
+|| find "nftables-1.0.8" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec /bin/bash /tmp/tmp.nspSLnT0EN/build-aux/install-sh -c -m a+r {} {} \; \
+|| chmod -R a+r "nftables-1.0.8"
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+tardir=nftables-1.0.8 && tar --format=posix -chf - "$tardir" | XZ_OPT=${XZ_OPT--e} xz -c >nftables-1.0.8.tar.xz
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+if test -d "nftables-1.0.8"; then find "nftables-1.0.8" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "nftables-1.0.8" || { sleep 5 && rm -rf "nftables-1.0.8"; }; else :; fi
+case 'nftables-1.0.8.tar.xz' in \
+*.tar.gz*) \
+ eval GZIP= gzip --best -dc nftables-1.0.8.tar.gz | tar -xf - ;;\
+*.tar.bz2*) \
+ bzip2 -dc nftables-1.0.8.tar.bz2 | tar -xf - ;;\
+*.tar.lz*) \
+ lzip -dc nftables-1.0.8.tar.lz | tar -xf - ;;\
+*.tar.xz*) \
+ xz -dc nftables-1.0.8.tar.xz | tar -xf - ;;\
+*.tar.Z*) \
+ uncompress -c nftables-1.0.8.tar.Z | tar -xf - ;;\
+*.shar.gz*) \
+ eval GZIP= gzip --best -dc nftables-1.0.8.shar.gz | unshar ;;\
+*.zip*) \
+ unzip nftables-1.0.8.zip ;;\
+*.tar.zst*) \
+ zstd -dc nftables-1.0.8.tar.zst | tar -xf - ;;\
+esac
+chmod -R a-w nftables-1.0.8
+chmod u+w nftables-1.0.8
+mkdir nftables-1.0.8/_build nftables-1.0.8/_build/sub nftables-1.0.8/_inst
+chmod a-w nftables-1.0.8
+test -d nftables-1.0.8/_build || exit 0; \
+dc_install_base=`CDPATH="${ZSH_VERSION+.}:" && cd nftables-1.0.8/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="${TMPDIR-/tmp}/am-dc-$$/" \
+ && am__cwd=`pwd` \
+ && CDPATH="${ZSH_VERSION+.}:" && cd nftables-1.0.8/_build/sub \
+ && ../../configure \
+ \
+ \
+ --srcdir=../.. --prefix="$dc_install_base" \
+ && make \
+ && make dvi \
+ && make check \
+ && make install \
+ && make installcheck \
+ && make uninstall \
+ && make distuninstallcheck_dir="$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$dc_destdir") \
+ && make DESTDIR="$dc_destdir" install \
+ && make DESTDIR="$dc_destdir" uninstall \
+ && make DESTDIR="$dc_destdir" \
+ distuninstallcheck_dir="$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$dc_destdir"; exit 1; }) \
+ && rm -rf "$dc_destdir" \
+ && make dist \
+ && rm -rf nftables-1.0.8.tar.xz \
+ && make distcleancheck \
+ && cd "$am__cwd" \
+ || exit 1
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for readline in -ledit... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: no
+ json output support: no
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make all-recursive
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making all in src
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make all-am
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+ CC main.o
+ CC cli.o
+ CC rule.lo
+ CC statement.lo
+ CC cache.lo
+ CC cmd.lo
+ CC datatype.lo
+ CC expression.lo
+ CC evaluate.lo
+ CC proto.lo
+ CC payload.lo
+ CC exthdr.lo
+ CC fib.lo
+ CC hash.lo
+ CC intervals.lo
+ CC ipopt.lo
+ CC meta.lo
+ CC rt.lo
+ CC numgen.lo
+ CC ct.lo
+ CC xfrm.lo
+ CC netlink.lo
+ CC netlink_linearize.lo
+ CC netlink_delinearize.lo
+ CC misspell.lo
+ CC monitor.lo
+ CC owner.lo
+ CC segtree.lo
+ CC gmputil.lo
+ CC utils.lo
+ CC nftutils.lo
+ CC erec.lo
+ CC mnl.lo
+ CC iface.lo
+ CC mergesort.lo
+ CC optimize.lo
+ CC osf.lo
+ CC nfnl_osf.lo
+ CC tcpopt.lo
+ CC socket.lo
+ CC print.lo
+ CC sctp_chunk.lo
+ CC dccpopt.lo
+ CC libnftables.lo
+ CC xt.lo
+ CC libparser_la-parser_bison.lo
+ CC libparser_la-scanner.lo
+ CCLD libparser.la
+ CCLD libnftables.la
+ CCLD nft
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making all in include
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making all in linux
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making all in netfilter
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[5]: No se hace nada para 'all'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making all in netfilter_arp
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[5]: No se hace nada para 'all'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[5]: No se hace nada para 'all'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[5]: No se hace nada para 'all'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[5]: No se hace nada para 'all'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[5]: No se hace nada para 'all-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making all in nftables
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making all in files
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making all in nftables
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making all in examples
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making all in osf
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making all in doc
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making all in py
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making dvi in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[2]: No se hace nada para 'dvi'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making dvi in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making dvi in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making dvi in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[4]: No se hace nada para 'dvi'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making dvi in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'dvi'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making dvi in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'dvi'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making dvi in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'dvi'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making dvi in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'dvi'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: No se hace nada para 'dvi-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making dvi in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: No se hace nada para 'dvi'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: No se hace nada para 'dvi-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making dvi in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making dvi in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[3]: No se hace nada para 'dvi'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making dvi in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[3]: No se hace nada para 'dvi'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making dvi in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: No se hace nada para 'dvi'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: No se hace nada para 'dvi-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making dvi in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[2]: No se hace nada para 'dvi'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making dvi in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[2]: No se hace nada para 'dvi'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making dvi in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: No se hace nada para 'dvi'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[2]: No se hace nada para 'dvi-am'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making check in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make check-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[3]: No se hace nada para 'check-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making check in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making check in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making check in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[4]: No se hace nada para 'check'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making check in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'check'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making check in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'check'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making check in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'check'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making check in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'check'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: No se hace nada para 'check-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making check in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: No se hace nada para 'check'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: No se hace nada para 'check-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making check in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making check in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[3]: No se hace nada para 'check'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making check in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[3]: No se hace nada para 'check'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making check in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: No se hace nada para 'check'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: No se hace nada para 'check-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making check in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[2]: No se hace nada para 'check'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making check in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make nft-buffer nft-json-file
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+ CC nft-buffer.o
+ CCLD nft-buffer
+ CC nft-json-file.o
+ CCLD nft-json-file
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making check in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: No se hace nada para 'check'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making install in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make install-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib'
+ /bin/bash ../libtool --mode=install /usr/bin/install -c libnftables.la '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib'
+libtool: install: /usr/bin/install -c .libs/libnftables.so.1.1.0 /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so.1.1.0
+libtool: install: (cd /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib && { ln -s -f libnftables.so.1.1.0 libnftables.so.1 || { rm -f libnftables.so.1 && ln -s libnftables.so.1.1.0 libnftables.so.1; }; })
+libtool: install: (cd /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib && { ln -s -f libnftables.so.1.1.0 libnftables.so || { rm -f libnftables.so && ln -s libnftables.so.1.1.0 libnftables.so; }; })
+libtool: install: /usr/bin/install -c .libs/libnftables.lai /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.la
+libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/sbin" ldconfig -n /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib
+----------------------------------------------------------------------
+Libraries have been installed in:
+ /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib
+
+If you ever happen to want to link against installed libraries
+in a given directory, LIBDIR, you must either use libtool, and
+specify the full pathname of the library, or use the '-LLIBDIR'
+flag during linking and do at least one of the following:
+ - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
+ during execution
+ - add LIBDIR to the 'LD_RUN_PATH' environment variable
+ during linking
+ - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
+ - have your system administrator add LIBDIR to '/etc/ld.so.conf'
+
+See any operating system documentation about shared libraries for
+more information, such as the ld(1) and ld.so(8) manual pages.
+----------------------------------------------------------------------
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin'
+ /bin/bash ../libtool --mode=install /usr/bin/install -c nft '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin'
+libtool: install: /usr/bin/install -c .libs/nft /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin/nft
+make[4]: No se hace nada para 'install-data-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making install in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making install in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making install in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making install in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making install in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making install in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making install in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making install in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/include/nftables'
+ /usr/bin/install -c -m 644 ../../../../include/nftables/libnftables.h '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/include/nftables'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[4]: No se hace nada para 'install-exec-am'.
+make[4]: No se hace nada para 'install-data-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making install in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making install in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/nftables'
+ /usr/bin/install -c -m 644 ../../../../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 '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/nftables'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making install in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/doc/nftables/examples'
+ /usr/bin/install -c ../../../../files/examples/ct_helpers.nft ../../../../files/examples/load_balancing.nft ../../../../files/examples/secmark.nft ../../../../files/examples/sets_and_maps.nft '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/doc/nftables/examples'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making install in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/etc/nftables/osf'
+ /usr/bin/install -c -m 644 ../../../../files/osf/pf.os '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/etc/nftables/osf'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[4]: No se hace nada para 'install-exec-am'.
+make[4]: No se hace nada para 'install-data-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making install in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[3]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man3'
+ /usr/bin/install -c -m 644 ../../../doc/libnftables.3 '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man3'
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man5'
+ /usr/bin/install -c -m 644 ../../../doc/libnftables-json.5 '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man5'
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man8'
+ /usr/bin/install -c -m 644 ../../../doc/nft.8 '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man8'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making install in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[3]: No se hace nada para 'install-exec-am'.
+make[3]: No se hace nada para 'install-data-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making install in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[3]: No se hace nada para 'install-exec-am'.
+make[3]: No se hace nada para 'install-data-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[3]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/pkgconfig'
+ /usr/bin/install -c -m 644 libnftables.pc '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/pkgconfig'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making installcheck in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[2]: No se hace nada para 'installcheck'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making installcheck in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making installcheck in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making installcheck in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[4]: No se hace nada para 'installcheck'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making installcheck in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'installcheck'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making installcheck in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'installcheck'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making installcheck in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'installcheck'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making installcheck in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'installcheck'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: No se hace nada para 'installcheck-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making installcheck in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: No se hace nada para 'installcheck'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: No se hace nada para 'installcheck-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making installcheck in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making installcheck in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[3]: No se hace nada para 'installcheck'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making installcheck in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[3]: No se hace nada para 'installcheck'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making installcheck in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: No se hace nada para 'installcheck'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: No se hace nada para 'installcheck-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making installcheck in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[2]: No se hace nada para 'installcheck'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making installcheck in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[2]: No se hace nada para 'installcheck'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making installcheck in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: No se hace nada para 'installcheck'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[2]: No se hace nada para 'installcheck-am'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making uninstall in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+ /bin/bash ../libtool --mode=uninstall rm -f '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.la'
+libtool: uninstall: rm -f /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.la /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so.1.1.0 /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so.1 /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin' && rm -f nft )
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making uninstall in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making uninstall in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making uninstall in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making uninstall in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making uninstall in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making uninstall in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making uninstall in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: No se hace nada para 'uninstall-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making uninstall in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/include/nftables' && rm -f libnftables.h )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: No se hace nada para 'uninstall-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making uninstall in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making uninstall in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/nftables' && rm -f 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 )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making uninstall in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/doc/nftables/examples' && rm -f ct_helpers.nft load_balancing.nft secmark.nft sets_and_maps.nft )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making uninstall in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/etc/nftables/osf' && rm -f pf.os )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: No se hace nada para 'uninstall-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making uninstall in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man3' && rm -f libnftables.3 )
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man5' && rm -f libnftables-json.5 )
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man8' && rm -f nft.8 )
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making uninstall in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[2]: No se hace nada para 'uninstall'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making uninstall in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: No se hace nada para 'uninstall'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+ ( cd '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/pkgconfig' && rm -f libnftables.pc )
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making install in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make install-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib'
+ /bin/bash ../libtool --mode=install /usr/bin/install -c libnftables.la '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib'
+libtool: install: /usr/bin/install -c .libs/libnftables.so.1.1.0 /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so.1.1.0
+libtool: install: (cd /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib && { ln -s -f libnftables.so.1.1.0 libnftables.so.1 || { rm -f libnftables.so.1 && ln -s libnftables.so.1.1.0 libnftables.so.1; }; })
+libtool: install: (cd /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib && { ln -s -f libnftables.so.1.1.0 libnftables.so || { rm -f libnftables.so && ln -s libnftables.so.1.1.0 libnftables.so; }; })
+libtool: install: /usr/bin/install -c .libs/libnftables.lai /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.la
+libtool: warning: remember to run 'libtool --finish /tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib'
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin'
+ /bin/bash ../libtool --mode=install /usr/bin/install -c nft '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin'
+libtool: warning: 'libnftables.la' has not been installed in '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib'
+libtool: install: /usr/bin/install -c .libs/nft /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin/nft
+make[4]: No se hace nada para 'install-data-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making install in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making install in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making install in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making install in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making install in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making install in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making install in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[5]: No se hace nada para 'install-exec-am'.
+make[5]: No se hace nada para 'install-data-am'.
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making install in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/include/nftables'
+ /usr/bin/install -c -m 644 ../../../../include/nftables/libnftables.h '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/include/nftables'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[4]: No se hace nada para 'install-exec-am'.
+make[4]: No se hace nada para 'install-data-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making install in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making install in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/nftables'
+ /usr/bin/install -c -m 644 ../../../../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 '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/nftables'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making install in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/doc/nftables/examples'
+ /usr/bin/install -c ../../../../files/examples/ct_helpers.nft ../../../../files/examples/load_balancing.nft ../../../../files/examples/secmark.nft ../../../../files/examples/sets_and_maps.nft '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/doc/nftables/examples'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making install in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[4]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/etc/nftables/osf'
+ /usr/bin/install -c -m 644 ../../../../files/osf/pf.os '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/etc/nftables/osf'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[4]: No se hace nada para 'install-exec-am'.
+make[4]: No se hace nada para 'install-data-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making install in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[3]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man3'
+ /usr/bin/install -c -m 644 ../../../doc/libnftables.3 '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man3'
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man5'
+ /usr/bin/install -c -m 644 ../../../doc/libnftables-json.5 '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man5'
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man8'
+ /usr/bin/install -c -m 644 ../../../doc/nft.8 '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man8'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making install in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[3]: No se hace nada para 'install-exec-am'.
+make[3]: No se hace nada para 'install-data-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making install in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[3]: No se hace nada para 'install-exec-am'.
+make[3]: No se hace nada para 'install-data-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[3]: No se hace nada para 'install-exec-am'.
+ /usr/bin/mkdir -p '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/pkgconfig'
+ /usr/bin/install -c -m 644 libnftables.pc '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/pkgconfig'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making uninstall in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+ /bin/bash ../libtool --mode=uninstall rm -f '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.la'
+libtool: uninstall: rm -f /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.la /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so.1.1.0 /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so.1 /tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/libnftables.so
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/sbin' && rm -f nft )
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making uninstall in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making uninstall in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making uninstall in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making uninstall in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making uninstall in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making uninstall in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making uninstall in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'uninstall'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[4]: No se hace nada para 'uninstall-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making uninstall in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/include/nftables' && rm -f libnftables.h )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[3]: No se hace nada para 'uninstall-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making uninstall in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making uninstall in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/nftables' && rm -f 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 )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making uninstall in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/doc/nftables/examples' && rm -f ct_helpers.nft load_balancing.nft secmark.nft sets_and_maps.nft )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making uninstall in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/etc/nftables/osf' && rm -f pf.os )
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[3]: No se hace nada para 'uninstall-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making uninstall in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man3' && rm -f libnftables.3 )
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man5' && rm -f libnftables-json.5 )
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/share/man/man8' && rm -f nft.8 )
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making uninstall in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[2]: No se hace nada para 'uninstall'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making uninstall in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: No se hace nada para 'uninstall'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+ ( cd '/tmp/am-dc-9318//tmp/tmp.nspSLnT0EN/nftables-1.0.8/_inst/lib/pkgconfig' && rm -f libnftables.pc )
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make dist-xz am__post_remove_distdir='@:'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make distdir-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+if test -d "nftables-1.0.8"; then find "nftables-1.0.8" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "nftables-1.0.8" || { sleep 5 && rm -rf "nftables-1.0.8"; }; else :; fi
+test -d "nftables-1.0.8" || mkdir "nftables-1.0.8"
+ (cd src && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/src \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make distdir-am
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+ (cd include && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/include \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make distdir-am
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+ (cd linux && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/include/linux \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make distdir-am
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+ (cd netfilter && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make distdir-am
+make[9]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[9]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+ (cd netfilter_arp && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_arp \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make distdir-am
+make[9]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[9]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+ (cd netfilter_bridge && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_bridge \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make distdir-am
+make[9]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[9]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+ (cd netfilter_ipv4 && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_ipv4 \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make distdir-am
+make[9]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[9]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+ (cd netfilter_ipv6 && make top_distdir=../../../nftables-1.0.8 distdir=../../../nftables-1.0.8/include/linux/netfilter_ipv6 \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[8]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make distdir-am
+make[9]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[9]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[8]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+ (cd nftables && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/include/nftables \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make distdir-am
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+ (cd files && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/files \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make distdir-am
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+ (cd nftables && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/files/nftables \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make distdir-am
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+ (cd examples && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/files/examples \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make distdir-am
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+ (cd osf && make top_distdir=../../nftables-1.0.8 distdir=../../nftables-1.0.8/files/osf \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[6]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make distdir-am
+make[7]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[7]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[6]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+ (cd doc && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/doc \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make distdir-am
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+ (cd examples && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/examples \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make distdir-am
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+ (cd py && make top_distdir=../nftables-1.0.8 distdir=../nftables-1.0.8/py \
+ am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make distdir-am
+make[5]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[5]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+test -n "" \
+|| find "nftables-1.0.8" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec /bin/bash /tmp/tmp.nspSLnT0EN/nftables-1.0.8/build-aux/install-sh -c -m a+r {} {} \; \
+|| chmod -R a+r "nftables-1.0.8"
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+tardir=nftables-1.0.8 && tar --format=posix -chf - "$tardir" | XZ_OPT=${XZ_OPT--e} xz -c >nftables-1.0.8.tar.xz
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+if test -d "nftables-1.0.8"; then find "nftables-1.0.8" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "nftables-1.0.8" || { sleep 5 && rm -rf "nftables-1.0.8"; }; else :; fi
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+Making distclean in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+test -z "libnftables.la" || rm -f libnftables.la
+rm -f ./so_locations
+rm -rf .libs _libs
+test -z "libparser.la " || rm -f libparser.la
+rm -f ./so_locations
+ rm -f nft
+rm -f *.o
+rm -f *.lo
+rm -f *.tab.c
+test -z "" || rm -f
+test . = "../../../src" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f ./.deps/cache.Plo
+rm -f ./.deps/cli.Po
+rm -f ./.deps/cmd.Plo
+rm -f ./.deps/ct.Plo
+rm -f ./.deps/datatype.Plo
+rm -f ./.deps/dccpopt.Plo
+rm -f ./.deps/erec.Plo
+rm -f ./.deps/evaluate.Plo
+rm -f ./.deps/expression.Plo
+rm -f ./.deps/exthdr.Plo
+rm -f ./.deps/fib.Plo
+rm -f ./.deps/gmputil.Plo
+rm -f ./.deps/hash.Plo
+rm -f ./.deps/iface.Plo
+rm -f ./.deps/intervals.Plo
+rm -f ./.deps/ipopt.Plo
+rm -f ./.deps/json.Plo
+rm -f ./.deps/libminigmp_la-mini-gmp.Plo
+rm -f ./.deps/libnftables.Plo
+rm -f ./.deps/libparser_la-parser_bison.Plo
+rm -f ./.deps/libparser_la-scanner.Plo
+rm -f ./.deps/main.Po
+rm -f ./.deps/mergesort.Plo
+rm -f ./.deps/meta.Plo
+rm -f ./.deps/misspell.Plo
+rm -f ./.deps/mnl.Plo
+rm -f ./.deps/monitor.Plo
+rm -f ./.deps/netlink.Plo
+rm -f ./.deps/netlink_delinearize.Plo
+rm -f ./.deps/netlink_linearize.Plo
+rm -f ./.deps/nfnl_osf.Plo
+rm -f ./.deps/nftutils.Plo
+rm -f ./.deps/numgen.Plo
+rm -f ./.deps/optimize.Plo
+rm -f ./.deps/osf.Plo
+rm -f ./.deps/owner.Plo
+rm -f ./.deps/parser_json.Plo
+rm -f ./.deps/payload.Plo
+rm -f ./.deps/print.Plo
+rm -f ./.deps/proto.Plo
+rm -f ./.deps/rt.Plo
+rm -f ./.deps/rule.Plo
+rm -f ./.deps/sctp_chunk.Plo
+rm -f ./.deps/segtree.Plo
+rm -f ./.deps/socket.Plo
+rm -f ./.deps/statement.Plo
+rm -f ./.deps/tcpopt.Plo
+rm -f ./.deps/utils.Plo
+rm -f ./.deps/xfrm.Plo
+rm -f ./.deps/xt.Plo
+rm -f Makefile
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/src'
+Making distclean in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making distclean in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making distclean in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../../include/linux/netfilter" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f Makefile
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter'
+Making distclean in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../../include/linux/netfilter_arp" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f Makefile
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_arp'
+Making distclean in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../../include/linux/netfilter_bridge" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f Makefile
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_bridge'
+Making distclean in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../../include/linux/netfilter_ipv4" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f Makefile
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv4'
+Making distclean in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../../include/linux/netfilter_ipv6" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f Makefile
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../include/linux" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+rm -f Makefile
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/linux'
+Making distclean in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../include/nftables" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f Makefile
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../include" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+rm -f Makefile
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/include'
+Making distclean in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making distclean in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../files/nftables" || test -z "" || rm -f
+rm -f Makefile
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/nftables'
+Making distclean in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../files/examples" || test -z "" || rm -f
+rm -f Makefile
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/examples'
+Making distclean in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../../files/osf" || test -z "" || rm -f
+rm -f Makefile
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../files" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+rm -f Makefile
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/files'
+Making distclean in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+test -z "*~" || rm -f *~
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../doc" || test -z "" || rm -f
+rm -f Makefile
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/doc'
+Making distclean in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+ rm -f nft-buffer nft-json-file
+rm -rf .libs _libs
+rm -f *.o
+rm -f *.lo
+rm -f *.tab.c
+test -z "" || rm -f
+test . = "../../../examples" || test -z "" || rm -f
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f ./.deps/nft-buffer.Po
+rm -f ./.deps/nft-json-file.Po
+rm -f Makefile
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/examples'
+Making distclean in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "" || rm -f
+test . = "../../../py" || test -z "" || rm -f
+rm -f Makefile
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+rm -rf .libs _libs
+rm -f *.lo
+test -z "libnftables.pc" || rm -f libnftables.pc
+test . = "../.." || test -z "" || rm -f
+rm -f config.h stamp-h1
+rm -f libtool config.lt
+rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+rm -f config.status config.cache config.log configure.lineno config.status.lineno
+rm -f Makefile
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN/nftables-1.0.8/_build/sub'
+if test -d "nftables-1.0.8"; then find "nftables-1.0.8" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "nftables-1.0.8" || { sleep 5 && rm -rf "nftables-1.0.8"; }; else :; fi
+================================================
+nftables-1.0.8 archives ready for distribution:
+nftables-1.0.8.tar.xz
+================================================
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: no
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: no
+ json output support: no
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ CC main.o
+ CC rule.lo
+ CC statement.lo
+ CC cache.lo
+ CC cmd.lo
+ CC datatype.lo
+ CC expression.lo
+ CC evaluate.lo
+ CC proto.lo
+ CC payload.lo
+ CC exthdr.lo
+ CC fib.lo
+ CC hash.lo
+ CC intervals.lo
+ CC ipopt.lo
+ CC meta.lo
+ CC rt.lo
+ CC numgen.lo
+ CC ct.lo
+ CC xfrm.lo
+ CC netlink.lo
+ CC netlink_linearize.lo
+ CC netlink_delinearize.lo
+ CC misspell.lo
+ CC monitor.lo
+ CC owner.lo
+ CC segtree.lo
+ CC gmputil.lo
+ CC utils.lo
+ CC nftutils.lo
+ CC erec.lo
+ CC mnl.lo
+ CC iface.lo
+ CC mergesort.lo
+ CC optimize.lo
+ CC osf.lo
+ CC nfnl_osf.lo
+ CC tcpopt.lo
+ CC socket.lo
+ CC print.lo
+ CC sctp_chunk.lo
+ CC dccpopt.lo
+ CC libnftables.lo
+ CC xt.lo
+ CC libparser_la-parser_bison.lo
+ CC libparser_la-scanner.lo
+ CCLD libparser.la
+ CCLD libnftables.la
+ CCLD nft
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for linenoise in -llinenoise... no
+configure: error: No suitable version of linenoise found
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for readline in -ledit... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: no
+ json output support: no
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ CC main.o
+ CC cli.o
+ CC rule.lo
+ CC statement.lo
+ CC cache.lo
+ CC cmd.lo
+ CC datatype.lo
+ CC expression.lo
+ CC evaluate.lo
+ CC proto.lo
+ CC payload.lo
+ CC exthdr.lo
+ CC fib.lo
+ CC hash.lo
+ CC intervals.lo
+ CC ipopt.lo
+ CC meta.lo
+ CC rt.lo
+ CC numgen.lo
+ CC ct.lo
+ CC xfrm.lo
+ CC netlink.lo
+ CC netlink_linearize.lo
+ CC netlink_delinearize.lo
+ CC misspell.lo
+ CC monitor.lo
+ CC owner.lo
+ CC segtree.lo
+ CC gmputil.lo
+ CC utils.lo
+ CC nftutils.lo
+ CC erec.lo
+ CC mnl.lo
+ CC iface.lo
+ CC mergesort.lo
+ CC optimize.lo
+ CC osf.lo
+ CC nfnl_osf.lo
+ CC tcpopt.lo
+ CC socket.lo
+ CC print.lo
+ CC sctp_chunk.lo
+ CC dccpopt.lo
+ CC libnftables.lo
+ CC xt.lo
+ CC libparser_la-parser_bison.lo
+ CC libparser_la-scanner.lo
+ CCLD libparser.la
+ CCLD libnftables.la
+ CCLD nft
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for readline in -ledit... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: config.h is unchanged
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: no
+ json output support: no
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for readline in -ledit... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: yes
+ enable man page: yes
+ libxtables support: no
+ json output support: no
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ CC main.o
+ CC cli.o
+ CC rule.lo
+ CC statement.lo
+ CC cache.lo
+ CC cmd.lo
+ CC datatype.lo
+ CC expression.lo
+ CC evaluate.lo
+ CC proto.lo
+ CC payload.lo
+ CC exthdr.lo
+ CC fib.lo
+ CC hash.lo
+ CC intervals.lo
+ CC ipopt.lo
+ CC meta.lo
+ CC rt.lo
+ CC numgen.lo
+ CC ct.lo
+ CC xfrm.lo
+ CC netlink.lo
+ CC netlink_linearize.lo
+ CC netlink_delinearize.lo
+ CC misspell.lo
+ CC monitor.lo
+ CC owner.lo
+ CC segtree.lo
+ CC gmputil.lo
+ CC utils.lo
+ CC nftutils.lo
+ CC erec.lo
+ CC mnl.lo
+ CC iface.lo
+ CC mergesort.lo
+ CC optimize.lo
+ CC osf.lo
+ CC nfnl_osf.lo
+ CC tcpopt.lo
+ CC socket.lo
+ CC print.lo
+ CC sctp_chunk.lo
+ CC dccpopt.lo
+ CC libnftables.lo
+ CC xt.lo
+ CC libparser_la-parser_bison.lo
+ CC libparser_la-scanner.lo
+ CC libminigmp_la-mini-gmp.lo
+ CCLD libminigmp.la
+ CCLD libparser.la
+ CCLD libnftables.la
+ CCLD nft
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for readline in -ledit... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: no
+ json output support: no
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ CC main.o
+ CC cli.o
+ CC rule.lo
+ CC statement.lo
+ CC cache.lo
+ CC cmd.lo
+ CC datatype.lo
+ CC expression.lo
+ CC evaluate.lo
+ CC proto.lo
+ CC payload.lo
+ CC exthdr.lo
+ CC fib.lo
+ CC hash.lo
+ CC intervals.lo
+ CC ipopt.lo
+ CC meta.lo
+ CC rt.lo
+ CC numgen.lo
+ CC ct.lo
+ CC xfrm.lo
+ CC netlink.lo
+ CC netlink_linearize.lo
+ CC netlink_delinearize.lo
+ CC misspell.lo
+ CC monitor.lo
+ CC owner.lo
+ CC segtree.lo
+ CC gmputil.lo
+ CC utils.lo
+ CC nftutils.lo
+ CC erec.lo
+ CC mnl.lo
+ CC iface.lo
+ CC mergesort.lo
+ CC optimize.lo
+ CC osf.lo
+ CC nfnl_osf.lo
+ CC tcpopt.lo
+ CC socket.lo
+ CC print.lo
+ CC sctp_chunk.lo
+ CC dccpopt.lo
+ CC libnftables.lo
+ CC xt.lo
+ CC libparser_la-parser_bison.lo
+ CC libparser_la-scanner.lo
+ CCLD libparser.la
+ CCLD libnftables.la
+ CCLD nft
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for readline in -ledit... yes
+checking for xtables >= 1.6.1... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: yes
+ json output support: no
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ CC main.o
+ CC cli.o
+ CC rule.lo
+ CC statement.lo
+ CC cache.lo
+ CC cmd.lo
+ CC datatype.lo
+ CC expression.lo
+ CC evaluate.lo
+ CC proto.lo
+ CC payload.lo
+ CC exthdr.lo
+ CC fib.lo
+ CC hash.lo
+ CC intervals.lo
+ CC ipopt.lo
+ CC meta.lo
+ CC rt.lo
+ CC numgen.lo
+ CC ct.lo
+ CC xfrm.lo
+ CC netlink.lo
+ CC netlink_linearize.lo
+ CC netlink_delinearize.lo
+ CC misspell.lo
+ CC monitor.lo
+ CC owner.lo
+ CC segtree.lo
+ CC gmputil.lo
+ CC utils.lo
+ CC nftutils.lo
+ CC erec.lo
+ CC mnl.lo
+ CC iface.lo
+ CC mergesort.lo
+ CC optimize.lo
+ CC osf.lo
+ CC nfnl_osf.lo
+ CC tcpopt.lo
+ CC socket.lo
+ CC print.lo
+ CC sctp_chunk.lo
+ CC dccpopt.lo
+ CC libnftables.lo
+ CC xt.lo
+ CC libparser_la-parser_bison.lo
+ CC libparser_la-scanner.lo
+ CCLD libparser.la
+ CCLD libnftables.la
+ CCLD nft
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+checking for a BSD-compatible install... /usr/bin/install -c
+checking whether build environment is sane... yes
+checking for a thread-safe mkdir -p... /usr/bin/mkdir -p
+checking for gawk... gawk
+checking whether make sets $(MAKE)... yes
+checking whether make supports nested variables... yes
+checking how to create a pax tar archive... gnutar
+checking whether make supports nested variables... (cached) yes
+checking for gcc... gcc
+checking whether the C compiler works... yes
+checking for C compiler default output file name... a.out
+checking for suffix of executables...
+checking whether we are cross compiling... no
+checking for suffix of object files... o
+checking whether we are using the GNU C compiler... yes
+checking whether gcc accepts -g... yes
+checking for gcc option to accept ISO C89... none needed
+checking whether gcc understands -c and -o together... yes
+checking whether make supports the include directive... yes (GNU style)
+checking dependency style of gcc... gcc3
+checking how to run the C preprocessor... gcc -E
+checking for grep that handles long lines and -e... /usr/bin/grep
+checking for egrep... /usr/bin/grep -E
+checking for ANSI C header files... yes
+checking for sys/types.h... yes
+checking for sys/stat.h... yes
+checking for stdlib.h... yes
+checking for string.h... yes
+checking for memory.h... yes
+checking for strings.h... yes
+checking for inttypes.h... yes
+checking for stdint.h... yes
+checking for unistd.h... yes
+checking minix/config.h usability... no
+checking minix/config.h presence... no
+checking for minix/config.h... no
+checking whether it is safe to define __EXTENSIONS__... yes
+checking for a sed that does not truncate output... /usr/bin/sed
+checking for flex... flex
+checking lex output file root... lex.yy
+checking lex library... -lfl
+checking whether yytext is a pointer... yes
+checking for bison... bison -y
+checking for ar... ar
+checking the archiver (ar) interface... ar
+checking build system type... x86_64-pc-linux-gnu
+checking host system type... x86_64-pc-linux-gnu
+checking how to print strings... printf
+checking for a sed that does not truncate output... (cached) /usr/bin/sed
+checking for fgrep... /usr/bin/grep -F
+checking for ld used by gcc... /usr/bin/ld
+checking if the linker (/usr/bin/ld) is GNU ld... yes
+checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
+checking the name lister (/usr/bin/nm -B) interface... BSD nm
+checking whether ln -s works... yes
+checking the maximum length of command line arguments... 1572864
+checking how to convert x86_64-pc-linux-gnu file names to x86_64-pc-linux-gnu format... func_convert_file_noop
+checking how to convert x86_64-pc-linux-gnu file names to toolchain format... func_convert_file_noop
+checking for /usr/bin/ld option to reload object files... -r
+checking for objdump... objdump
+checking how to recognize dependent libraries... pass_all
+checking for dlltool... no
+checking how to associate runtime and link libraries... printf %s\n
+checking for archiver @FILE support... @
+checking for strip... strip
+checking for ranlib... ranlib
+checking command to parse /usr/bin/nm -B output from gcc object... ok
+checking for sysroot... no
+checking for a working dd... /usr/bin/dd
+checking how to truncate binary pipes... /usr/bin/dd bs=4096 count=1
+checking for mt... mt
+checking if mt is a manifest tool... no
+checking for dlfcn.h... yes
+checking for objdir... .libs
+checking if gcc supports -fno-rtti -fno-exceptions... no
+checking for gcc option to produce PIC... -fPIC -DPIC
+checking if gcc PIC flag -fPIC -DPIC works... yes
+checking if gcc static flag -static works... yes
+checking if gcc supports -c -o file.o... yes
+checking if gcc supports -c -o file.o... (cached) yes
+checking whether the gcc linker (/usr/bin/ld -m elf_x86_64) supports shared libraries... yes
+checking whether -lc should be explicitly linked in... no
+checking dynamic linker characteristics... GNU/Linux ld.so
+checking how to hardcode library paths into programs... immediate
+checking whether stripping libraries is possible... yes
+checking if libtool supports shared libraries... yes
+checking whether to build shared libraries... yes
+checking whether to build static libraries... no
+checking whether compiler accepts -fvisibility=hidden... yes
+checking for a2x... a2x
+checking for pkg-config... /usr/bin/pkg-config
+checking pkg-config is at least version 0.9.0... yes
+checking for libmnl >= 1.0.4... yes
+checking for libnftnl >= 1.2.6... yes
+checking for __gmpz_init in -lgmp... yes
+checking for readline in -ledit... yes
+checking for json_object in -ljansson... yes
+checking whether getprotobyname_r is declared... yes
+checking whether getprotobynumber_r is declared... yes
+checking whether getservbyport_r is declared... yes
+checking that generated files are newer than configure... done
+configure: creating ./config.status
+config.status: creating Makefile
+config.status: creating libnftables.pc
+config.status: creating src/Makefile
+config.status: creating include/Makefile
+config.status: creating include/nftables/Makefile
+config.status: creating include/linux/Makefile
+config.status: creating include/linux/netfilter/Makefile
+config.status: creating include/linux/netfilter_arp/Makefile
+config.status: creating include/linux/netfilter_bridge/Makefile
+config.status: creating include/linux/netfilter_ipv4/Makefile
+config.status: creating include/linux/netfilter_ipv6/Makefile
+config.status: creating files/Makefile
+config.status: creating files/examples/Makefile
+config.status: creating files/nftables/Makefile
+config.status: creating files/osf/Makefile
+config.status: creating doc/Makefile
+config.status: creating py/Makefile
+config.status: creating examples/Makefile
+config.status: creating config.h
+config.status: executing depfiles commands
+config.status: executing libtool commands
+
+nft configuration:
+ cli support: editline
+ enable debugging symbols: yes
+ use mini-gmp: no
+ enable man page: yes
+ libxtables support: no
+ json output support: yes
+make all-recursive
+make[1]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+Making all in src
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+make all-am
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/src'
+ CC main.o
+ CC cli.o
+ CC rule.lo
+ CC statement.lo
+ CC cache.lo
+ CC cmd.lo
+ CC datatype.lo
+ CC expression.lo
+ CC evaluate.lo
+ CC proto.lo
+ CC payload.lo
+ CC exthdr.lo
+ CC fib.lo
+ CC hash.lo
+ CC intervals.lo
+ CC ipopt.lo
+ CC meta.lo
+ CC rt.lo
+ CC numgen.lo
+ CC ct.lo
+ CC xfrm.lo
+ CC netlink.lo
+ CC netlink_linearize.lo
+ CC netlink_delinearize.lo
+ CC misspell.lo
+ CC monitor.lo
+ CC owner.lo
+ CC segtree.lo
+ CC gmputil.lo
+ CC utils.lo
+ CC nftutils.lo
+ CC erec.lo
+ CC mnl.lo
+ CC iface.lo
+ CC mergesort.lo
+ CC optimize.lo
+ CC osf.lo
+ CC nfnl_osf.lo
+ CC tcpopt.lo
+ CC socket.lo
+ CC print.lo
+ CC sctp_chunk.lo
+ CC dccpopt.lo
+ CC libnftables.lo
+ CC xt.lo
+ CC json.lo
+ CC parser_json.lo
+ CC libparser_la-parser_bison.lo
+ CC libparser_la-scanner.lo
+ CCLD libparser.la
+ CCLD libnftables.la
+ CCLD nft
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/src'
+Making all in include
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in linux
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in netfilter
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter'
+Making all in netfilter_arp
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_arp'
+Making all in netfilter_bridge
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_bridge'
+Making all in netfilter_ipv4
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv4'
+Making all in netfilter_ipv6
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: No se hace nada para 'all'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux/netfilter_ipv6'
+make[4]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[4]: No se hace nada para 'all-am'.
+make[4]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/linux'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include/nftables'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/include'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/include'
+Making all in files
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in nftables
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/nftables'
+Making all in examples
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/examples'
+Making all in osf
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: No se hace nada para 'all'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files/osf'
+make[3]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/files'
+make[3]: No se hace nada para 'all-am'.
+make[3]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/files'
+Making all in doc
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/doc'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/doc'
+Making all in examples
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/examples'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/examples'
+Making all in py
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: No se hace nada para 'all'.
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN/py'
+make[2]: se entra en el directorio '/tmp/tmp.nspSLnT0EN'
+make[2]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
+make[1]: se sale del directorio '/tmp/tmp.nspSLnT0EN'
diff --git a/tests/json_echo/run-test.py b/tests/json_echo/run-test.py
new file mode 100755
index 0000000..a6bdfc6
--- /dev/null
+++ b/tests/json_echo/run-test.py
@@ -0,0 +1,309 @@
+#!/usr/bin/python
+
+from __future__ import print_function
+import sys
+import os
+import json
+import argparse
+
+TESTS_PATH = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, os.path.join(TESTS_PATH, '../../py/'))
+
+from nftables import Nftables
+
+# Change working directory to repository root
+os.chdir(TESTS_PATH + "/../..")
+
+parser = argparse.ArgumentParser(description='Run JSON echo tests')
+parser.add_argument('-H', '--host', action='store_true',
+ help='Run tests against installed libnftables.so.1')
+parser.add_argument('-l', '--library', default=None,
+ help='Path to libntables.so, overrides --host')
+args = parser.parse_args()
+
+check_lib_path = True
+if args.library is None:
+ if args.host:
+ args.library = 'libnftables.so.1'
+ check_lib_path = False
+ else:
+ args.library = 'src/.libs/libnftables.so.1'
+
+if check_lib_path and not os.path.exists(args.library):
+ print("Library not found at '%s'." % args.library)
+ sys.exit(1)
+
+nftables = Nftables(sofile = args.library)
+nftables.set_echo_output(True)
+
+# various commands to work with
+
+flush_ruleset = { "flush": { "ruleset": None } }
+
+list_ruleset = { "list": { "ruleset": None } }
+
+add_table = { "add": {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ }
+}}
+
+add_chain = { "add": {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c"
+ }
+}}
+
+add_set = { "add": {
+ "set": {
+ "family": "inet",
+ "table": "t",
+ "name": "s",
+ "type": "inet_service"
+ }
+}}
+
+add_rule = { "add": {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "expr": [ { "accept": None } ]
+ }
+}}
+
+add_counter = { "add": {
+ "counter": {
+ "family": "inet",
+ "table": "t",
+ "name": "c"
+ }
+}}
+
+add_quota = { "add": {
+ "quota": {
+ "family": "inet",
+ "table": "t",
+ "name": "q",
+ "bytes": 65536
+ }
+}}
+
+# helper functions
+
+def exit_err(msg):
+ print("Error: %s" %msg, file=sys.stderr)
+ sys.exit(1)
+
+def exit_dump(e, obj):
+ msg = "{}\n".format(e)
+ msg += "Output was:\n"
+ msg += json.dumps(obj, sort_keys = True, indent = 4, separators = (',', ': '))
+ exit_err(msg)
+
+def do_flush():
+ rc, out, err = nftables.json_cmd({ "nftables": [flush_ruleset] })
+ if rc != 0:
+ exit_err("flush ruleset failed: {}".format(err))
+
+def do_command(cmd):
+ if not type(cmd) is list:
+ cmd = [cmd]
+ rc, out, err = nftables.json_cmd({ "nftables": cmd })
+ if rc != 0:
+ exit_err("command failed: {}".format(err))
+ return out
+
+def do_list_ruleset():
+ echo = nftables.get_echo_output()
+ nftables.set_echo_output(False)
+ out = do_command(list_ruleset)
+ nftables.set_echo_output(echo)
+ return out
+
+def get_handle(output, search):
+ try:
+ for item in output["nftables"]:
+ if "add" in item:
+ data = item["add"]
+ elif "insert" in item:
+ data = item["insert"]
+ else:
+ data = item
+
+ k = list(search.keys())[0]
+
+ if not k in data:
+ continue
+ found = True
+ for key in list(search[k].keys()):
+ if key == "handle":
+ continue
+ if not key in data[k] or search[k][key] != data[k][key]:
+ found = False
+ break
+ if not found:
+ continue
+
+ return data[k]["handle"]
+ except Exception as e:
+ exit_dump(e, output)
+
+# single commands first
+
+do_flush()
+
+print("Adding table t")
+out = do_command(add_table)
+handle = get_handle(out, add_table["add"])
+
+out = do_list_ruleset()
+handle_cmp = get_handle(out, add_table["add"])
+
+if handle != handle_cmp:
+ exit_err("handle mismatch!")
+
+add_table["add"]["table"]["handle"] = handle
+
+print("Adding chain c")
+out = do_command(add_chain)
+handle = get_handle(out, add_chain["add"])
+
+out = do_list_ruleset()
+handle_cmp = get_handle(out, add_chain["add"])
+
+if handle != handle_cmp:
+ exit_err("handle mismatch!")
+
+add_chain["add"]["chain"]["handle"] = handle
+
+print("Adding set s")
+out = do_command(add_set)
+handle = get_handle(out, add_set["add"])
+
+out = do_list_ruleset()
+handle_cmp = get_handle(out, add_set["add"])
+
+if handle != handle_cmp:
+ exit_err("handle mismatch!")
+
+add_set["add"]["set"]["handle"] = handle
+
+print("Adding rule")
+out = do_command(add_rule)
+handle = get_handle(out, add_rule["add"])
+
+out = do_list_ruleset()
+handle_cmp = get_handle(out, add_rule["add"])
+
+if handle != handle_cmp:
+ exit_err("handle mismatch!")
+
+add_rule["add"]["rule"]["handle"] = handle
+
+print("Adding counter")
+out = do_command(add_counter)
+handle = get_handle(out, add_counter["add"])
+
+out = do_list_ruleset()
+handle_cmp = get_handle(out, add_counter["add"])
+
+if handle != handle_cmp:
+ exit_err("handle mismatch!")
+
+add_counter["add"]["counter"]["handle"] = handle
+
+print("Adding quota")
+out = do_command(add_quota)
+handle = get_handle(out, add_quota["add"])
+
+out = do_list_ruleset()
+handle_cmp = get_handle(out, add_quota["add"])
+
+if handle != handle_cmp:
+ exit_err("handle mismatch!")
+
+add_quota["add"]["quota"]["handle"] = handle
+
+# adjust names and add items again
+# Note: Handles are per-table, hence add renamed objects to first table
+# to make sure assigned handle differs from first run.
+
+add_table["add"]["table"]["name"] = "t2"
+add_chain["add"]["chain"]["name"] = "c2"
+add_set["add"]["set"]["name"] = "s2"
+add_counter["add"]["counter"]["name"] = "c2"
+add_quota["add"]["quota"]["name"] = "q2"
+
+print("Adding table t2")
+out = do_command(add_table)
+handle = get_handle(out, add_table["add"])
+if handle == add_table["add"]["table"]["handle"]:
+ exit_err("handle not changed in re-added table!")
+
+print("Adding chain c2")
+out = do_command(add_chain)
+handle = get_handle(out, add_chain["add"])
+if handle == add_chain["add"]["chain"]["handle"]:
+ exit_err("handle not changed in re-added chain!")
+
+print("Adding set s2")
+out = do_command(add_set)
+handle = get_handle(out, add_set["add"])
+if handle == add_set["add"]["set"]["handle"]:
+ exit_err("handle not changed in re-added set!")
+
+print("Adding rule again")
+out = do_command(add_rule)
+handle = get_handle(out, add_rule["add"])
+if handle == add_rule["add"]["rule"]["handle"]:
+ exit_err("handle not changed in re-added rule!")
+
+print("Adding counter c2")
+out = do_command(add_counter)
+handle = get_handle(out, add_counter["add"])
+if handle == add_counter["add"]["counter"]["handle"]:
+ exit_err("handle not changed in re-added counter!")
+
+print("Adding quota q2")
+out = do_command(add_quota)
+handle = get_handle(out, add_quota["add"])
+if handle == add_quota["add"]["quota"]["handle"]:
+ exit_err("handle not changed in re-added quota!")
+
+# now multiple commands
+
+# reset name changes again
+add_table["add"]["table"]["name"] = "t"
+add_chain["add"]["chain"]["name"] = "c"
+add_set["add"]["set"]["name"] = "s"
+add_counter["add"]["counter"]["name"] = "c"
+add_quota["add"]["quota"]["name"] = "q"
+
+do_flush()
+
+print("doing multi add")
+add_multi = [ add_table, add_chain, add_set, add_rule ]
+out = do_command(add_multi)
+
+thandle = get_handle(out, add_table["add"])
+chandle = get_handle(out, add_chain["add"])
+shandle = get_handle(out, add_set["add"])
+rhandle = get_handle(out, add_rule["add"])
+
+out = do_list_ruleset()
+
+if thandle != get_handle(out, add_table["add"]):
+ exit_err("table handle mismatch!")
+
+if chandle != get_handle(out, add_chain["add"]):
+ exit_err("chain handle mismatch!")
+
+if shandle != get_handle(out, add_set["add"]):
+ exit_err("set handle mismatch!")
+
+if rhandle != get_handle(out, add_rule["add"]):
+ exit_err("rule handle mismatch!")
diff --git a/tests/monitor/README b/tests/monitor/README
new file mode 100644
index 0000000..39096a7
--- /dev/null
+++ b/tests/monitor/README
@@ -0,0 +1,59 @@
+Simple NFT MONITOR Testsuite
+============================
+
+The purpose of this suite of tests is to assert correct 'nft monitor' output for
+known input. The suite consists of the single shell script 'run-tests.sh' which
+performs the tests and a number of test definition files in 'testcases/'. The
+latter have to be suffixed '.t' in order to be recognized as such.
+
+Test Case Syntax
+----------------
+
+Each testcase defines a number of commands to pass on to 'nft' binary and an
+associated 'nft monitor' output definition. Prerequisites for each command have
+to be established manually, i.e. in order to test monitor output when adding a
+chain, the table containing it has to be created first. In between each
+testcase, rule set is flushed completely.
+
+Input lines are prefixed by 'I'. Multiple consecutive input lines are passed to
+'nft' together, hence lead to a single transaction.
+
+There are two types of output lines: Those for standard syntax, prefixed by 'O'
+and those for JSON output, prefixed by 'J'. For standard syntax output lines,
+there is a shortcut: If a line consists of 'O -' only, the test script uses all
+previous input lines as expected output directly. Of course this is not
+available for JSON output lines.
+
+Empty lines and those starting with '#' are ignored.
+
+Test Script Semantics
+---------------------
+
+The script iterates over all test case files, reading them line by line. It
+assumes that sections of 'I' lines alternate with sections of 'O'/'J' lines.
+After stripping the prefix, each line is appended to a temporary file. There are
+separate files for input and output lines.
+
+If a set of input and output lines is complete (i.e. upon encountering either a
+new input line or end of file), a testrun is performed: 'nft monitor' is run in
+background, redirecting the output into a third file. The input file is passed
+to 'nft -f'. Finally 'nft monitor' is killed and it's output compared to the
+output file created earlier. If the files differ, a unified diff is printed and
+test execution aborts.
+
+After each testrun, input and output files are cleared.
+
+Note: Running 'nft monitor' in background is prone to race conditions. Hence
+an artificial delay is introduced before calling 'nft -f' to allow for 'nft
+monitor' to complete initialization and another one before comparing the output
+to allow for 'nft monitor' to process the netlink events.
+
+By default, only standard syntax is being tested for, i.e. 'J'-prefixed lines
+are simply ignored. If JSON testing was requested (by passing '-j' flag to the
+test script), 'O'-prefixed lines in turn are ignored.
+
+There is one caveat with regards to JSON output: Since it always contains handle
+properties (if the given object possesses such) which is supposed to be
+arbitrary, there is a filter script which normalizes all handle values in
+monitor output to zero before comparison. Therefore expected output must have
+all handle properties present but with a value of zero.
diff --git a/tests/monitor/run-tests.sh b/tests/monitor/run-tests.sh
new file mode 100755
index 0000000..f1ac790
--- /dev/null
+++ b/tests/monitor/run-tests.sh
@@ -0,0 +1,211 @@
+#!/bin/bash
+
+cd $(dirname $0)
+nft=${NFT:-../../src/nft}
+debug=false
+test_json=false
+
+mydiff() {
+ diff -w -I '^# ' "$@"
+}
+
+err() {
+ echo "$*" >&2
+}
+
+die() {
+ err "$*"
+ exit 1
+}
+
+if [ "$(id -u)" != "0" ] ; then
+ die "this requires root!"
+fi
+
+testdir=$(mktemp -d)
+if [ ! -d $testdir ]; then
+ die "Failed to create test directory"
+fi
+trap 'rm -rf $testdir; $nft flush ruleset' EXIT
+
+command_file=$(mktemp -p $testdir)
+output_file=$(mktemp -p $testdir)
+
+cmd_append() {
+ echo "$*" >>$command_file
+}
+monitor_output_append() {
+ [[ "$*" == '-' ]] && {
+ cat $command_file >>$output_file
+ return
+ }
+ echo "$*" >>$output_file
+}
+echo_output_append() {
+ # this is a bit tricky: for replace commands, nft prints a delete
+ # command - so in case there is a replace command in $command_file,
+ # just assume any other commands in the same file are sane
+ grep -q '^replace' $command_file >/dev/null 2>&1 && {
+ monitor_output_append "$*"
+ return
+ }
+ [[ "$*" == '-' ]] && {
+ grep '^\(add\|replace\|insert\)' $command_file >>$output_file
+ return
+ }
+ [[ "$*" =~ ^add|replace|insert ]] && echo "$*" >>$output_file
+}
+json_output_filter() { # (filename)
+ # unify handle values
+ sed -i -e 's/\("handle":\) [0-9][0-9]*/\1 0/g' "$1"
+}
+monitor_run_test() {
+ monitor_output=$(mktemp -p $testdir)
+ monitor_args=""
+ $test_json && monitor_args="vm json"
+ local rc=0
+
+ $nft -nn monitor $monitor_args >$monitor_output &
+ monitor_pid=$!
+
+ sleep 0.5
+
+ $debug && {
+ echo "command file:"
+ cat $command_file
+ }
+ $nft -f - <$command_file || {
+ err "nft command failed!"
+ rc=1
+ }
+ sleep 0.5
+ kill $monitor_pid
+ wait >/dev/null 2>&1
+ $test_json && json_output_filter $monitor_output
+ mydiff -q $monitor_output $output_file >/dev/null 2>&1
+ if [[ $rc == 0 && $? != 0 ]]; then
+ err "monitor output differs!"
+ mydiff -u $output_file $monitor_output >&2
+ rc=1
+ fi
+ rm $command_file
+ rm $output_file
+ touch $command_file
+ touch $output_file
+ return $rc
+}
+
+echo_run_test() {
+ echo_output=$(mktemp -p $testdir)
+ local rc=0
+
+ $debug && {
+ echo "command file:"
+ cat $command_file
+ }
+ $nft -nn -e -f - <$command_file >$echo_output || {
+ err "nft command failed!"
+ rc=1
+ }
+ mydiff -q $echo_output $output_file >/dev/null 2>&1
+ if [[ $rc == 0 && $? != 0 ]]; then
+ err "echo output differs!"
+ mydiff -u $output_file $echo_output >&2
+ rc=1
+ fi
+ rm $command_file
+ rm $output_file
+ touch $command_file
+ touch $output_file
+ return $rc
+}
+
+testcases=""
+while [ -n "$1" ]; do
+ case "$1" in
+ -d|--debug)
+ debug=true
+ shift
+ ;;
+ -j|--json)
+ test_json=true
+ shift
+ ;;
+ -H|--host)
+ nft=nft
+ shift
+ ;;
+ testcases/*.t)
+ testcases+=" $1"
+ shift
+ ;;
+ *)
+ echo "unknown option '$1'"
+ ;&
+ -h|--help)
+ echo "Usage: $(basename $0) [-j|--json] [-d|--debug] [testcase ...]"
+ exit 1
+ ;;
+ esac
+done
+
+if $test_json; then
+ variants="monitor"
+else
+ variants="monitor echo"
+fi
+
+rc=0
+for variant in $variants; do
+ run_test=${variant}_run_test
+ output_append=${variant}_output_append
+
+ for testcase in ${testcases:-testcases/*.t}; do
+ filename=$(basename $testcase)
+ echo "$variant: running tests from file $filename"
+ rc_start=$rc
+
+ # files are like this:
+ #
+ # I add table ip t
+ # O add table ip t
+ # I add chain ip t c
+ # O add chain ip t c
+
+ $nft flush ruleset
+
+ input_complete=false
+ while read dir line; do
+ case $dir in
+ I)
+ $input_complete && {
+ $run_test
+ let "rc += $?"
+ }
+ input_complete=false
+ cmd_append "$line"
+ ;;
+ O)
+ input_complete=true
+ $test_json || $output_append "$line"
+ ;;
+ J)
+ input_complete=true
+ $test_json && $output_append "$line"
+ ;;
+ '#'|'')
+ # ignore comments and empty lines
+ ;;
+ esac
+ done <$testcase
+ $input_complete && {
+ $run_test
+ let "rc += $?"
+ }
+
+ let "rc_diff = rc - rc_start"
+ [[ $rc_diff -ne 0 ]] && \
+ echo "$variant: $rc_diff tests from file $filename failed"
+ done
+done
+exit $rc
diff --git a/tests/monitor/testcases/map-expr.t b/tests/monitor/testcases/map-expr.t
new file mode 100644
index 0000000..8729c0b
--- /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
new file mode 100644
index 0000000..53a9f8c
--- /dev/null
+++ b/tests/monitor/testcases/object.t
@@ -0,0 +1,46 @@
+# first the setup
+I add table ip t
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+
+I add counter ip t c
+O add counter ip t c { packets 0 bytes 0 }
+J {"add": {"counter": {"family": "ip", "name": "c", "table": "t", "handle": 0, "packets": 0, "bytes": 0}}}
+
+I delete counter ip t c
+O -
+J {"delete": {"counter": {"family": "ip", "name": "c", "table": "t", "handle": 0, "packets": 0, "bytes": 0}}}
+
+# FIXME: input/output shouldn't be asynchronous here
+I add quota ip t q 25 mbytes
+O add quota ip t q { 25 mbytes }
+J {"add": {"quota": {"family": "ip", "name": "q", "table": "t", "handle": 0, "bytes": 26214400, "used": 0, "inv": false}}}
+
+I delete quota ip t q
+O -
+J {"delete": {"quota": {"family": "ip", "name": "q", "table": "t", "handle": 0, "bytes": 26214400, "used": 0, "inv": false}}}
+
+# FIXME: input/output shouldn't be asynchronous here
+I add limit ip t l rate 1/second
+O add limit ip t l { rate 1/second }
+J {"add": {"limit": {"family": "ip", "name": "l", "table": "t", "handle": 0, "rate": 1, "per": "second", "burst": 5}}}
+
+I delete limit ip t l
+O -
+J {"delete": {"limit": {"family": "ip", "name": "l", "table": "t", "handle": 0, "rate": 1, "per": "second", "burst": 5}}}
+
+I add ct helper ip t cth { type "sip" protocol tcp; l3proto ip; }
+O -
+J {"add": {"ct helper": {"family": "ip", "name": "cth", "table": "t", "handle": 0, "type": "sip", "protocol": "tcp", "l3proto": "ip"}}}
+
+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 : 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}}}}
+
+I delete ct timeout ip t ctt
+O -
+J {"delete": {"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-interval.t b/tests/monitor/testcases/set-interval.t
new file mode 100644
index 0000000..5053c59
--- /dev/null
+++ b/tests/monitor/testcases/set-interval.t
@@ -0,0 +1,30 @@
+# setup first
+I add table ip t
+I add chain ip t c
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}}
+
+# add set with elements, monitor output expectedly differs
+I add set ip t s { type inet_service; flags interval; elements = { 20, 30-40 }; }
+O add set ip t s { type inet_service; flags interval; }
+O add element ip t s { 20 }
+O add element ip t s { 30-40 }
+J {"add": {"set": {"family": "ip", "name": "s", "table": "t", "type": "inet_service", "handle": 0, "flags": ["interval"]}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [20]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [{"range": [30, 40]}]}}}}
+
+# this would crash nft
+I add rule ip t c tcp dport @s
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": "@s"}}]}}}
+
+# test anonymous interval sets as well
+I add rule ip t c tcp dport { 20, 30-40 }
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": {"set": [20, {"range": [30, 40]}]}}}]}}}
+
+# ... and anon concat range
+I add rule ip t c ether saddr . ip saddr { 08:00:27:40:f7:09 . 192.168.56.10-192.168.56.12 }
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"concat": [{"payload": {"protocol": "ether", "field": "saddr"}}, {"payload": {"protocol": "ip", "field": "saddr"}}]}, "right": {"set": [{"concat": ["08:00:27:40:f7:09", {"range": ["192.168.56.10", "192.168.56.12"]}]}]}}}]}}}
diff --git a/tests/monitor/testcases/set-maps.t b/tests/monitor/testcases/set-maps.t
new file mode 100644
index 0000000..acda480
--- /dev/null
+++ b/tests/monitor/testcases/set-maps.t
@@ -0,0 +1,14 @@
+# first the setup
+I add table ip t
+I add map ip t portip { type inet_service: ipv4_addr; flags interval; }
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"map": {"family": "ip", "name": "portip", "table": "t", "type": "inet_service", "handle": 0, "map": "ipv4_addr", "flags": ["interval"]}}}
+
+I add element ip t portip { 80-100: 10.0.0.1 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portip", "elem": {"set": [[{"range": [80, 100]}, "10.0.0.1"]]}}}}
+
+I add element ip t portip { 1024-65535: 10.0.0.1 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portip", "elem": {"set": [[{"range": [1024, 65535]}, "10.0.0.1"]]}}}}
diff --git a/tests/monitor/testcases/set-mixed.t b/tests/monitor/testcases/set-mixed.t
new file mode 100644
index 0000000..08c2011
--- /dev/null
+++ b/tests/monitor/testcases/set-mixed.t
@@ -0,0 +1,22 @@
+# first the setup
+I add table ip t
+I add set ip t portrange { type inet_service; flags interval; }
+I add set ip t ports { type inet_service; }
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"set": {"family": "ip", "name": "portrange", "table": "t", "type": "inet_service", "handle": 0, "flags": ["interval"]}}}
+J {"add": {"set": {"family": "ip", "name": "ports", "table": "t", "type": "inet_service", "handle": 0}}}
+
+# make sure concurrent adds work
+I add element ip t portrange { 1024-65535 }
+I add element ip t ports { 10 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "ports", "elem": {"set": [10]}}}}
+
+# delete items again
+I delete element ip t portrange { 1024-65535 }
+I delete element ip t ports { 10 }
+O -
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "ports", "elem": {"set": [10]}}}}
diff --git a/tests/monitor/testcases/set-multiple.t b/tests/monitor/testcases/set-multiple.t
new file mode 100644
index 0000000..bd7a624
--- /dev/null
+++ b/tests/monitor/testcases/set-multiple.t
@@ -0,0 +1,15 @@
+# first the setup
+I add table ip t
+I add set ip t portrange { type inet_service; flags interval; }
+I add set ip t portrange2 { type inet_service; flags interval; }
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"set": {"family": "ip", "name": "portrange", "table": "t", "type": "inet_service", "handle": 0, "flags": ["interval"]}}}
+J {"add": {"set": {"family": "ip", "name": "portrange2", "table": "t", "type": "inet_service", "handle": 0, "flags": ["interval"]}}}
+
+# make sure concurrent adds work
+I add element ip t portrange { 1024-65535 }
+I add element ip t portrange2 { 10-20 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange2", "elem": {"set": [{"range": [10, 20]}]}}}}
diff --git a/tests/monitor/testcases/set-simple.t b/tests/monitor/testcases/set-simple.t
new file mode 100644
index 0000000..8ca4f32
--- /dev/null
+++ b/tests/monitor/testcases/set-simple.t
@@ -0,0 +1,61 @@
+# first the setup
+I add table ip t
+I add set ip t portrange { type inet_service; flags interval; }
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"set": {"family": "ip", "name": "portrange", "table": "t", "type": "inet_service", "handle": 0, "flags": ["interval"]}}}
+
+# adding some ranges
+I add element ip t portrange { 1-10 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1, 10]}]}}}}
+I add element ip t portrange { 1024-65535 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+I add element ip t portrange { 20-30, 40-50 }
+O add element ip t portrange { 20-30 }
+O add element ip t portrange { 40-50 }
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [20, 30]}]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [40, 50]}]}}}}
+
+# test flushing -> elements are removed in reverse
+I flush set ip t portrange
+O delete element ip t portrange { 1024-65535 }
+O delete element ip t portrange { 40-50 }
+O delete element ip t portrange { 20-30 }
+O delete element ip t portrange { 1-10 }
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [40, 50]}]}}}}
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [20, 30]}]}}}}
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1, 10]}]}}}}
+
+# make sure lower scope boundary works
+I add element ip t portrange { 0-10 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [0, 10]}]}}}}
+
+# make sure half open before other element works
+I add element ip t portrange { 1024-65535 }
+I add element ip t portrange { 100-200 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [100, 200]}]}}}}
+
+# make sure deletion of elements works
+I delete element ip t portrange { 0-10 }
+O -
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [0, 10]}]}}}}
+I delete element ip t portrange { 100-200 }
+I delete element ip t portrange { 1024-65535 }
+O -
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [100, 200]}]}}}}
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+
+# make sure mixed add/delete works
+I add element ip t portrange { 10-20 }
+I add element ip t portrange { 1024-65535 }
+I delete element ip t portrange { 10-20 }
+O -
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [10, 20]}]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [1024, 65535]}]}}}}
+J {"delete": {"element": {"family": "ip", "table": "t", "name": "portrange", "elem": {"set": [{"range": [10, 20]}]}}}}
diff --git a/tests/monitor/testcases/simple.t b/tests/monitor/testcases/simple.t
new file mode 100644
index 0000000..67be5c8
--- /dev/null
+++ b/tests/monitor/testcases/simple.t
@@ -0,0 +1,28 @@
+# first the setup
+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}}}
+
+I add rule ip t c accept
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"accept": null}]}}}
+
+I add rule ip t c tcp dport { 22, 80, 443 } accept
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": {"set": [22, 80, 443]}}}, {"accept": null}]}}}
+
+I insert rule ip t c counter accept
+O insert rule ip t c counter packets 0 bytes 0 accept
+J {"insert": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"counter": {"packets": 0, "bytes": 0}}, {"accept": null}]}}}
+
+I replace rule ip t c handle 2 accept comment "foo bar"
+O delete rule ip t c handle 2
+O add rule ip t c handle 5 accept comment "foo bar"
+J {"delete": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"accept": null}]}}}
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "comment": "foo bar", "expr": [{"accept": null}]}}}
+
+I add counter ip t cnt
+O add counter ip t cnt { packets 0 bytes 0 }
+J {"add": {"counter": {"family": "ip", "name": "cnt", "table": "t", "handle": 0, "packets": 0, "bytes": 0}}}
diff --git a/tests/py/README b/tests/py/README
new file mode 100644
index 0000000..864a966
--- /dev/null
+++ b/tests/py/README
@@ -0,0 +1,197 @@
+Author: Ana Rey <anarey@gmail.com>
+Date: 18/Sept/2014
+
+Here, the automated regression testing for nftables and some test
+files.
+
+This script checks that the rule input and output of nft matches.
+More details here below.
+
+A) What is this testing?
+
+This script tests two different paths:
+
+* The rule input from the command-line. This checks the different steps
+ from the command line to the kernel. This includes the parsing,
+ evaluation and netlink generation steps.
+
+* The output listing that is obtained from the kernel. This checks the
+ different steps from the kernel to the command line: The netlink
+ message parsing, postprocess and textify steps to display the rule
+ listing.
+
+As a final step, this script compares that the rule that is added can
+be listed by nft.
+
+B) What options are available?
+
+The script offers the following options:
+
+* Execute test files:
+
+./nft-test.py # Run all test files
+./nft-test.py path/file.t # Run this test file
+
+If there is a problem, it shows the differences between the rule that
+is added and the rule that is listed by nft.
+
+In case you hit an error, the script doesn't keep testing for more
+families. Unless you specify the --force-family option.
+
+* Execute broken tests:
+
+./nft-test.py -e
+
+This runs tests for rules that need a fix: This mode runs the lines that
+that start with a "-" symbol.
+
+* Debugging:
+
+./nft-test.py -d
+
+This shows all the commands that the script executes, so you can watch
+its internal behaviour.
+
+* Keep testing all families on error.
+
+./nft-test.py -f
+
+Don't stop testing for more families in case of error.
+
+C) What is the structure of the test file?
+
+A test file contains a set of rules that are added in the system.
+
+Here, an example of a test file:
+
+ :input;type filter hook input priority 0 # line 1
+
+ *ip;test-ipv4;input # line 2
+ *ip6;test-ipv6;input # line 3
+ *inet;test-inet;input # line 4
+
+ ah hdrlength != 11-23;ok;ah hdrlength < 11 ah hdrlength > 23 # line 5
+ - tcp dport != {22-25} # line 6
+
+ !set1 ipv4_addr;ok # line 7
+ ?set1 192.168.3.8 192.168.3.9;ok # line 8
+ # This is a commented-line. # line 9
+
+Line 1 defines a chain. The name of this chain is "input". The type is "filter",
+the hook is "input" and the priority is 0.
+
+Line 2 defines a table. The name of the table is 'test-ipv4', the family is ip
+and the chain to be added to it is 'input'. Lines 3 and 4 defines more tables for
+different families so the rules in this test file are also tested there.
+
+Line 5 defines the rule, the ";" character is used as separator of several
+parts:
+
+* Part 1: "ah hdrlength != 11-23" is the rule to check.
+* Part 2: "ok" is the result expected with the execute of this rule.
+* Part 3: "ah hdrlength < 11 ah hdrlength > 23". This is the expected
+ output. You can leave this empty if the output is the same as the
+ input.
+
+Line 6 is a marked line. This means that this rule is tested if
+'-e' is passed as argument to nft-test.py.
+
+Line 7 adds a new set. The name of this set is "set1" and the type
+of this set is "ipv4_addr".
+
+Line 8 adds two elements into the 'set1' set: "192.168.3.8" and
+"192.168.3.9". A whitespace separates the elements of the set.
+
+Line 9 uses the "#" symbol that means that this line is commented out.
+
+D) What is a payload file?
+
+A payload file contains info about the netlink message exchanged to achieve the
+transaction.
+
+The output can be generated in two ways. Let's see an example via socket
+matching.
+
+ # generate an empty payload file
+ $ touch inet/socket.t.payload
+
+ $ ./nft-test.py inet/socket.t # this will generate inet/socket.t.payload.got
+
+ $ mv inet/socket.t.payload.got inet/socket.t.payload
+
+The other way is using nft --debug=netlink. This has a drawback over the former
+option, as rules has to be run one by one and also a comment has to be added
+before every rule in the payload file.
+
+ $ nft --debug=netlink add rule ip sockip4 sockchain socket exists
+ ip sockip4 sockchain
+ [ match name socket rev 3 ]
+
+E) The test folders
+
+The test files are divided in several directories: ip, ip6, inet, arp,
+bridge and any.
+
+ * "ip" folder contains the test files that are executed in ip and inet
+ table.
+
+ * "ip6" folder contains the test files that are executed in ip6 and inet
+ table.
+
+ * "inet" folder contains the test files that are executed in the ip, ip6
+ and inet table.
+
+ * "arp" folder contains the test files that are executed in the arp
+ table.
+
+ * "bridge" folder: Here are the test files are executed in bridge
+ tables.
+
+ * "any" folder: Here are the test files are executed in ip, ip6, inet,
+ arp and bridge tables.
+
+F) Meaning of messages:
+
+* A warning message means the rule input and output of nft mismatches.
+* An error message means the nft-tool shows an error when we add it or
+ the listing is broken after the rule is added.
+* An info message means something that is not necessarily related to any test
+ case and does not indicate faulty behaviour.
+
+G) Acknowledgements
+
+Thanks to the Outreach Program for Women (OPW) for sponsoring this test
+infrastructure and my mentor Pablo Neira.
+
+H) JSON (-j) Mode
+
+This mode is supposed to repeat the same tests using JSON syntax. For each test
+file example.t, there is supposed to be a file example.t.json holding the JSON
+equivalents of each rule in example.t. The file's syntax is similar to payload
+files: An initial comment identifies the rule belonging to the following JSON
+equivalent. Pairs of comment and JSON are separated by a single blank line.
+
+If the example.t.json file does not exist, the test script will warn and create
+(or append to) example.t.json.got. The JSON equivalent written is generated by
+applying the rule in standard syntax and listing the ruleset in JSON format.
+After thorough review, it may be renamed to example.t.json.
+
+One common case for editing the content in example.t.json.got is expected
+differences between input and output. The generated content will match the
+output while it is supposed to match the input.
+
+If a rule is expected to differ in output, the expected output must be recorded
+in example.t.json.output. Its syntax is identical to example.t.json, i.e. pairs
+of comment identifying the rule (in standard syntax) and JSON (output) format
+separated by blank lines. Note: the comment states the rule as in input, not
+output.
+
+If the example.t.json.output file does not exist and output differs from input,
+the file example.t.json.output.got is created with the actual output recorded.
+
+JSON mode will also check the payload created for the rule in JSON syntax by
+comparing it to the recorded one in example.t.payload. Should it differ, it
+will be recorded in example.t.json.payload.got. This is always a bug: A rule's
+JSON equivalent must turn into the same bytecode as the rule itself.
+
+-EOF-
diff --git a/tests/py/any/counter.t b/tests/py/any/counter.t
new file mode 100644
index 0000000..1c72742
--- /dev/null
+++ b/tests/py/any/counter.t
@@ -0,0 +1,14 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*arp;test-arp;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress
+
+counter;ok
+counter packets 0 bytes 0;ok;counter
+counter packets 2 bytes 1;ok;counter
+counter bytes 1024 packets 1;ok;counter
diff --git a/tests/py/any/counter.t.json b/tests/py/any/counter.t.json
new file mode 100644
index 0000000..2d1eaa9
--- /dev/null
+++ b/tests/py/any/counter.t.json
@@ -0,0 +1,39 @@
+# counter
+[
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ }
+]
+
+# counter packets 0 bytes 0
+[
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ }
+]
+
+# counter packets 2 bytes 1
+[
+ {
+ "counter": {
+ "bytes": 1,
+ "packets": 2
+ }
+ }
+]
+
+# counter bytes 1024 packets 1
+[
+ {
+ "counter": {
+ "bytes": 1024,
+ "packets": 1
+ }
+ }
+]
diff --git a/tests/py/any/counter.t.json.output b/tests/py/any/counter.t.json.output
new file mode 100644
index 0000000..6a62ffb
--- /dev/null
+++ b/tests/py/any/counter.t.json.output
@@ -0,0 +1,28 @@
+# counter
+[
+ {
+ "counter": null
+ }
+]
+
+# counter packets 0 bytes 0
+[
+ {
+ "counter": null
+ }
+]
+
+# counter packets 2 bytes 1
+[
+ {
+ "counter": null
+ }
+]
+
+# counter bytes 1024 packets 1
+[
+ {
+ "counter": null
+ }
+]
+
diff --git a/tests/py/any/counter.t.payload b/tests/py/any/counter.t.payload
new file mode 100644
index 0000000..23e96ba
--- /dev/null
+++ b/tests/py/any/counter.t.payload
@@ -0,0 +1,15 @@
+# counter
+ip
+ [ counter pkts 0 bytes 0 ]
+
+# counter packets 0 bytes 0
+ip
+ [ counter pkts 0 bytes 0 ]
+
+# counter packets 2 bytes 1
+ip
+ [ counter pkts 2 bytes 1 ]
+
+# counter bytes 1024 packets 1
+ip
+ [ counter pkts 1 bytes 1024 ]
diff --git a/tests/py/any/ct.t b/tests/py/any/ct.t
new file mode 100644
index 0000000..f73fa4e
--- /dev/null
+++ b/tests/py/any/ct.t
@@ -0,0 +1,149 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+
+ct state new,established, related, untracked;ok;ct state established,related,new,untracked
+ct state != related;ok
+ct state {new,established, related, untracked};ok
+ct state != {new,established, related, untracked};ok
+ct state invalid drop;ok
+ct state established accept;ok
+ct state 8;ok;ct state new
+ct state xxx;fail
+
+ct direction original;ok
+ct direction != original;ok
+ct direction reply;ok
+ct direction != reply;ok
+ct direction {reply, original};ok
+ct direction != {reply, original};ok
+ct direction xxx;fail
+
+ct status expected;ok
+ct status != expected;ok
+ct status seen-reply;ok
+ct status != seen-reply;ok
+ct status {expected, seen-reply, assured, confirmed, dying};ok
+ct status != {expected, seen-reply, assured, confirmed, dying};ok
+ct status expected,seen-reply,assured,confirmed,snat,dnat,dying;ok
+ct status snat;ok
+ct status dnat;ok
+ct status ! dnat;ok
+ct status xxx;fail
+
+ct mark 0;ok;ct mark 0x00000000
+ct mark or 0x23 == 0x11;ok;ct mark | 0x00000023 == 0x00000011
+ct mark or 0x3 != 0x1;ok;ct mark | 0x00000003 != 0x00000001
+ct mark and 0x23 == 0x11;ok;ct mark & 0x00000023 == 0x00000011
+ct mark and 0x3 != 0x1;ok;ct mark & 0x00000003 != 0x00000001
+ct mark xor 0x23 == 0x11;ok;ct mark 0x00000032
+ct mark xor 0x3 != 0x1;ok;ct mark != 0x00000002
+ct mark set ct mark or 0x00000001;ok;ct mark set ct mark | 0x00000001
+
+ct mark 0x00000032;ok
+ct mark != 0x00000032;ok
+ct mark 0x00000032-0x00000045;ok
+ct mark != 0x00000032-0x00000045;ok
+ct mark {0x32, 0x2222, 0x42de3};ok;ct mark { 0x00042de3, 0x00002222, 0x00000032}
+ct mark {0x32-0x2222, 0x4444-0x42de3};ok;ct mark { 0x00000032-0x00002222, 0x00004444-0x00042de3}
+ct mark != {0x32, 0x2222, 0x42de3};ok;ct mark != { 0x00042de3, 0x00002222, 0x00000032}
+
+# ct mark != {0x32, 0x2222, 0x42de3};ok
+# BUG: invalid expression type set
+# nft: src/evaluate.c:975: expr_evaluate_relational: Assertion '0' failed.
+
+ct mark set 0x11 xor 0x1331;ok;ct mark set 0x00001320
+ct mark set 0x11333 and 0x11;ok;ct mark set 0x00000011
+ct mark set 0x12 or 0x11;ok;ct mark set 0x00000013
+ct mark set 0x11;ok;ct mark set 0x00000011
+ct mark set mark;ok;ct mark set meta mark
+ct mark set (meta mark | 0x10) << 8;ok;ct mark set (meta mark | 0x00000010) << 8
+ct mark set mark map { 1 : 10, 2 : 20, 3 : 30 };ok;ct mark set meta mark map { 0x00000003 : 0x0000001e, 0x00000002 : 0x00000014, 0x00000001 : 0x0000000a}
+
+ct mark set {0x11333, 0x11};fail
+ct zone set {123, 127};fail
+ct label set {123, 127};fail
+ct event set {new, related, destroy, label};fail
+
+ct expiration 30s;ok
+ct expiration 30000ms;ok;ct expiration 30s
+ct expiration 1m-1h;ok;ct expiration 60s-3600s
+ct expiration 1d-1h;fail
+ct expiration > 4d23h59m59s;ok
+ct expiration != 233;ok;ct expiration != 3m53s
+ct expiration 33-45;ok;ct expiration 33s-45s
+ct expiration != 33-45;ok;ct expiration != 33s-45s
+ct expiration {33, 55, 67, 88};ok;ct expiration { 1m7s, 33s, 55s, 1m28s}
+ct expiration != {33, 55, 67, 88};ok;ct expiration != { 1m7s, 33s, 55s, 1m28s}
+ct expiration {33-55, 66-88};ok;ct expiration { 33s-55s, 66s-88s}
+ct expiration != {33-55, 66-88};ok;ct expiration != { 33s-55s, 66s-88s}
+
+ct helper "ftp";ok
+ct helper "12345678901234567";fail
+ct helper "";fail
+
+ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634};ok
+ct direction . ct mark { original . 0x12345678, reply . 0x87654321};ok
+ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept};ok
+
+ct original bytes > 100000;ok
+ct reply packets < 100;ok
+ct bytes > 100000;ok
+
+ct avgpkt > 200;ok
+ct original avgpkt < 500;ok
+
+# bogus direction
+ct both bytes gt 1;fail
+# nonsensical
+ct bytes original reply;fail
+
+# missing direction
+ct ip saddr 1.2.3.4;fail
+
+# wrong base (ip6 but ipv4 address given)
+meta nfproto ipv6 ct original ip saddr 1.2.3.4;fail
+
+# direction, but must be used without
+ct original mark 42;fail
+# swapped key and direction
+ct mark original;fail
+
+ct event set new;ok
+ct event set new or related or destroy or foobar;fail
+ct event set new | related | destroy | label;ok;ct event set new,related,destroy,label
+ct event set new,related,destroy,label;ok
+ct event set new,destroy;ok
+ct event set 1;ok;ct event set new
+ct event set 0x0;ok
+
+ct label 127;ok
+ct label set 127;ok
+ct label 128;fail
+
+ct zone 0;ok
+ct zone 23;ok
+ct zone 65536;fail
+ct both zone 1;fail
+ct original zone 1;ok
+ct reply zone 1;ok
+
+ct id 12345;ok
+
+ct zone set 1;ok
+ct original zone set 1;ok
+ct reply zone set 1;ok
+ct zone set mark map { 1 : 1, 2 : 2 };ok;ct zone set meta mark map { 0x00000001 : 1, 0x00000002 : 2}
+ct both zone set 1;fail
+
+ct invalid;fail
+ct invalid original;fail
+ct set invalid original 42;fail
+ct set invalid 42;fail
+
+notrack;ok
+
+ct count 3;ok
+ct count over 3;ok
diff --git a/tests/py/any/ct.t.json b/tests/py/any/ct.t.json
new file mode 100644
index 0000000..a2a0602
--- /dev/null
+++ b/tests/py/any/ct.t.json
@@ -0,0 +1,1523 @@
+# ct state new,established, related, untracked
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "new",
+ "established",
+ "related",
+ "untracked"
+ ]
+ }
+ }
+]
+
+# ct state != related
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "!=",
+ "right": "related"
+ }
+ }
+]
+
+# ct state {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ "new",
+ "established",
+ "related",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state != {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "new",
+ "established",
+ "related",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state invalid drop
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": "invalid"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ct state established accept
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": "established"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ct state 8
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": 8
+ }
+ }
+]
+
+# ct direction original
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "==",
+ "right": "original"
+ }
+ }
+]
+
+# ct direction != original
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": "original"
+ }
+ }
+]
+
+# ct direction reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "==",
+ "right": "reply"
+ }
+ }
+]
+
+# ct direction != reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": "reply"
+ }
+ }
+]
+
+# ct direction {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ "reply",
+ "original"
+ ]
+ }
+ }
+ }
+]
+
+# ct direction != {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "reply",
+ "original"
+ ]
+ }
+ }
+ }
+]
+
+# ct status expected
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "expected"
+ }
+ }
+]
+
+# ct status != expected
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!=",
+ "right": "expected"
+ }
+ }
+]
+
+# ct status seen-reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "seen-reply"
+ }
+ }
+]
+
+# ct status != seen-reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!=",
+ "right": "seen-reply"
+ }
+ }
+]
+
+# ct status {expected, seen-reply, assured, confirmed, dying}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "expected",
+ "seen-reply",
+ "assured",
+ "confirmed",
+ "dying"
+ ]
+ }
+ }
+ }
+]
+
+# ct status != {expected, seen-reply, assured, confirmed, dying}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "expected",
+ "seen-reply",
+ "assured",
+ "confirmed",
+ "dying"
+ ]
+ }
+ }
+ }
+]
+
+# ct status expected,seen-reply,assured,confirmed,snat,dnat,dying
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": [
+ "expected",
+ "seen-reply",
+ "assured",
+ "confirmed",
+ "snat",
+ "dnat",
+ "dying"
+ ]
+ }
+ }
+]
+
+# ct status snat
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "snat"
+ }
+ }
+]
+
+# ct status dnat
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "dnat"
+ }
+ }
+]
+
+# ct status ! dnat
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!",
+ "right": "dnat"
+ }
+ }
+]
+
+# ct mark 0
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# ct mark or 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x23"
+ ]
+ },
+ "op": "==",
+ "right": "0x11"
+ }
+ }
+]
+
+# ct mark or 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x3"
+ ]
+ },
+ "op": "!=",
+ "right": "0x1"
+ }
+ }
+]
+
+# ct mark and 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x23"
+ ]
+ },
+ "op": "==",
+ "right": "0x11"
+ }
+ }
+]
+
+# ct mark and 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x3"
+ ]
+ },
+ "op": "!=",
+ "right": "0x1"
+ }
+ }
+]
+
+# ct mark xor 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x23"
+ ]
+ },
+ "op": "==",
+ "right": "0x11"
+ }
+ }
+]
+
+# ct mark xor 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x3"
+ ]
+ },
+ "op": "!=",
+ "right": "0x1"
+ }
+ }
+]
+
+# ct mark set ct mark or 0x00000001
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 1
+ ]
+ }
+ }
+ }
+]
+
+# ct mark 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": "0x00000032"
+ }
+ }
+]
+
+# ct mark != 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": "0x00000032"
+ }
+ }
+]
+
+# ct mark 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "0x00000032", "0x00000045" ]
+ }
+ }
+ }
+]
+
+# ct mark != 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "0x00000032", "0x00000045" ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ "0x32",
+ "0x2222",
+ "0x42de3"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32-0x2222, 0x4444-0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ {
+ "range": [ "0x32", "0x2222" ]
+ },
+ {
+ "range": [ "0x4444", "0x42de3" ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct mark != {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "0x32",
+ "0x2222",
+ "0x42de3"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set 0x11 xor 0x1331
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": { "^": [ "0x11", "0x1331" ] }
+ }
+ }
+]
+
+# ct mark set 0x11333 and 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": { "&": [ "0x11333", "0x11" ] }
+ }
+ }
+]
+
+# ct mark set 0x12 or 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": { "|": [ "0x12", "0x11" ] }
+ }
+ }
+]
+
+# ct mark set 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": "0x11"
+ }
+ }
+]
+
+# ct mark set mark
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "meta": { "key": "mark" }
+ }
+ }
+ }
+]
+
+# ct mark set (meta mark | 0x10) << 8
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "<<": [
+ {
+ "|": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ 16
+ ]
+ },
+ 8
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set mark map { 1 : 10, 2 : 20, 3 : 30 }
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "data": {
+ "set": [
+ [ 1, 10 ],
+ [ 2, 20 ],
+ [ 3, 30 ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# ct expiration 30s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": "30s"
+ }
+ }
+]
+
+# ct expiration 30000ms
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": "30000ms"
+ }
+ }
+]
+
+# ct expiration 1m-1h
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "1m", "1h" ]
+ }
+ }
+ }
+]
+
+# ct expiration > 4d23h59m59s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": ">",
+ "right": "4d23h59m59s"
+ }
+ }
+]
+
+# ct expiration != 233
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ct expiration 33-45
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ct expiration != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ct expiration {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ct expiration != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ct expiration {33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct expiration != {33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct helper "ftp"
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "helper"
+ }
+ },
+ "op": "==",
+ "right": "ftp"
+ }
+ }
+]
+
+# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "concat": [ "new", "0x12345678" ] },
+ { "concat": [ "new", "0x34127856" ] },
+ { "concat": [ "established", "0x12785634" ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct direction . ct mark { original . 0x12345678, reply . 0x87654321}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "original",
+ "0x12345678"
+ ]
+ },
+ {
+ "concat": [
+ "reply",
+ "0x87654321"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "new",
+ "0x12345678"
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "established",
+ "0x87654321"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ct original bytes > 100000
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "bytes"
+ }
+ },
+ "op": ">",
+ "right": 100000
+ }
+ }
+]
+
+# ct reply packets < 100
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "packets"
+ }
+ },
+ "op": "<",
+ "right": 100
+ }
+ }
+]
+
+# ct bytes > 100000
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "bytes"
+ }
+ },
+ "op": ">",
+ "right": 100000
+ }
+ }
+]
+
+# ct avgpkt > 200
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "avgpkt"
+ }
+ },
+ "op": ">",
+ "right": 200
+ }
+ }
+]
+
+# ct original avgpkt < 500
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "avgpkt"
+ }
+ },
+ "op": "<",
+ "right": 500
+ }
+ }
+]
+
+# ct event set new
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": "new"
+ }
+ }
+]
+
+# ct event set new | related | destroy | label
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": [
+ "new",
+ "related",
+ "destroy",
+ "label"
+ ]
+ }
+ }
+]
+
+# ct event set new,related,destroy,label
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": [
+ "new",
+ "related",
+ "destroy",
+ "label"
+ ]
+ }
+ }
+]
+
+# ct event set new,destroy
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": [
+ "new",
+ "destroy"
+ ]
+ }
+ }
+]
+
+# ct event set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct event set 0x0
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": "0x0"
+ }
+ }
+]
+
+# ct label 127
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "label"
+ }
+ },
+ "op": "in",
+ "right": 127
+ }
+ }
+]
+
+# ct label set 127
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "label"
+ }
+ },
+ "value": 127
+ }
+ }
+]
+
+# ct zone 0
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# ct zone 23
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 23
+ }
+ }
+]
+
+# ct original zone 1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ct reply zone 1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ct zone set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct original zone set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "dir": "original",
+ "key": "zone"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct reply zone set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "dir": "reply",
+ "key": "zone"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct id 12345
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "id"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ }
+]
+
+# ct zone set mark map { 1 : 1, 2 : 2 }
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "data": {
+ "set": [
+ [ 1, 1 ],
+ [ 2, 2 ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# notrack
+[
+ {
+ "notrack": null
+ }
+]
+
+# ct count 3
+[
+ {
+ "ct count": {
+ "val": 3
+ }
+ }
+]
+
+# ct count over 3
+[
+ {
+ "ct count": {
+ "inv": true,
+ "val": 3
+ }
+ }
+]
+
diff --git a/tests/py/any/ct.t.json.output b/tests/py/any/ct.t.json.output
new file mode 100644
index 0000000..70ade7e
--- /dev/null
+++ b/tests/py/any/ct.t.json.output
@@ -0,0 +1,666 @@
+# ct state new,established, related, untracked
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "established",
+ "related",
+ "new",
+ "untracked"
+ ]
+ }
+ }
+]
+
+# ct state {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "established",
+ "related",
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state != {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "established",
+ "related",
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state 8
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": "new"
+ }
+ }
+]
+
+# ct direction {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "original",
+ "reply"
+ ]
+ }
+ }
+ }
+]
+
+# ct direction != {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "original",
+ "reply"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark or 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 35
+ ]
+ },
+ "op": "==",
+ "right": 17
+ }
+ }
+]
+
+# ct mark or 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# ct mark and 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 35
+ ]
+ },
+ "op": "==",
+ "right": 17
+ }
+ }
+]
+
+# ct mark and 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# ct mark xor 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# ct mark xor 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": 2
+ }
+ }
+]
+
+# ct mark 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# ct mark != 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": 50
+ }
+ }
+]
+
+# ct mark 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 50, 69 ]
+ }
+ }
+ }
+]
+
+# ct mark != 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 50, 69 ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 50,
+ 8738,
+ 273891
+ ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32-0x2222, 0x4444-0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 50, 8738 ] },
+ { "range": [ 17476, 273891 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct mark != {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 50,
+ 8738,
+ 273891
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set 0x11 xor 0x1331
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 4896
+ }
+ }
+]
+
+# ct mark set 0x11333 and 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 17
+ }
+ }
+]
+
+# ct mark set 0x12 or 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 19
+ }
+ }
+]
+
+# ct mark set 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 17
+ }
+ }
+]
+
+# ct expiration 30s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": 30
+ }
+ }
+]
+
+# ct expiration 30000ms
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": 30
+ }
+ }
+]
+
+# ct expiration 1m-1h
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 60, 3600 ]
+ }
+ }
+ }
+]
+
+# ct expiration > 4d23h59m59s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": ">",
+ "right": 431999
+ }
+ }
+]
+
+# ct state . ct mark { new . 0x12345678}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "new",
+ 305419896
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "new",
+ 305419896
+ ]
+ },
+ {
+ "concat": [
+ "established",
+ 309876276
+ ]
+ },
+ {
+ "concat": [
+ "new",
+ 873625686
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct direction . ct mark { original . 0x12345678, reply . 0x87654321}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "original",
+ 305419896
+ ]
+ },
+ {
+ "concat": [
+ "reply",
+ 2271560481
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "new",
+ 305419896
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "established",
+ 2271560481
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ct event set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": "new"
+ }
+ }
+]
+
+# ct event set 0x0
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": 0
+ }
+ }
+]
+
diff --git a/tests/py/any/ct.t.payload b/tests/py/any/ct.t.payload
new file mode 100644
index 0000000..ed868e5
--- /dev/null
+++ b/tests/py/any/ct.t.payload
@@ -0,0 +1,518 @@
+# ct state new,established, related, untracked
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000004e ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct state != related
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ cmp neq reg 1 0x00000004 ]
+
+# ct state {new,established, related, untracked}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000040 : 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct state != {new,established, related, untracked}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000040 : 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct state invalid drop
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ immediate reg 0 drop ]
+
+# ct state established accept
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# ct state 8
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000008 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct direction original
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct direction != original
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct direction reply
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ct direction != reply
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct direction {reply, original}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct direction != {reply, original}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct status expected
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status != expected
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct status seen-reply
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status != seen-reply
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# ct status {expected, seen-reply, assured, confirmed, dying}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000008 : 0 [end] element 00000200 : 0 [end]
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct status != {expected, seen-reply, assured, confirmed, dying}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000008 : 0 [end] element 00000200 : 0 [end]
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct mark 0
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct mark or 0x23 == 0x11
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffdc ) ^ 0x00000023 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# ct mark or 0x3 != 0x1
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffc ) ^ 0x00000003 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct mark and 0x23 == 0x11
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000023 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# ct mark and 0x3 != 0x1
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct mark xor 0x23 == 0x11
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# ct mark xor 0x3 != 0x1
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# ct mark 0x00000032
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# ct mark != 0x00000032
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000032 ]
+
+# ct mark 0x00000032-0x00000045
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x32000000 ]
+ [ cmp lte reg 1 0x45000000 ]
+
+# ct mark != 0x00000032-0x00000045
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x32000000 0x45000000 ]
+
+# ct mark {0x32, 0x2222, 0x42de3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000032 : 0 [end] element 00002222 : 0 [end] element 00042de3 : 0 [end]
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark {0x32-0x2222, 0x4444-0x42de3}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 32000000 : 0 [end] element 23220000 : 1 [end] element 44440000 : 0 [end] element e42d0400 : 1 [end]
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark != {0x32, 0x2222, 0x42de3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000032 : 0 [end] element 00002222 : 0 [end] element 00042de3 : 0 [end]
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct mark set 0x11 xor 0x1331
+ip test-ip4 output
+ [ immediate reg 1 0x00001320 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set 0x11333 and 0x11
+ip test-ip4 output
+ [ immediate reg 1 0x00000011 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set 0x12 or 0x11
+ip test-ip4 output
+ [ immediate reg 1 0x00000013 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set 0x11
+ip test-ip4 output
+ [ immediate reg 1 0x00000011 ]
+ [ ct set mark with reg 1 ]
+
+# ct expiration 30s
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ cmp eq reg 1 0x00007530 ]
+
+# ct expiration 30000ms
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ cmp eq reg 1 0x00007530 ]
+
+# ct expiration 1m-1h
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x60ea0000 ]
+ [ cmp lte reg 1 0x80ee3600 ]
+
+# ct expiration > 4d23h59m59s
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gt reg 1 0x18c8bf19 ]
+
+# ct expiration != 233
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ cmp neq reg 1 0x00038e28 ]
+
+# ct expiration 33-45
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xe8800000 ]
+ [ cmp lte reg 1 0xc8af0000 ]
+
+# ct expiration != 33-45
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xe8800000 0xc8af0000 ]
+
+# ct expiration {33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 000080e8 : 0 [end] element 0000d6d8 : 0 [end] element 000105b8 : 0 [end] element 000157c0 : 0 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct expiration != {33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 000080e8 : 0 [end] element 0000d6d8 : 0 [end] element 000105b8 : 0 [end] element 000157c0 : 0 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct expiration {33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element e8800000 : 0 [end] element d9d60000 : 1 [end] element d0010100 : 0 [end] element c1570100 : 1 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# ct expiration != {33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element e8800000 : 0 [end] element d9d60000 : 1 [end] element d0010100 : 0 [end] element c1570100 : 1 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct helper "ftp"
+ip test-ip4 output
+ [ ct load helper => reg 1 ]
+ [ cmp eq reg 1 0x00707466 0x00000000 0x00000000 0x00000000 ]
+
+# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 12345678 : 0 [end] element 00000008 34127856 : 0 [end] element 00000002 12785634 : 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ ct load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark set mark
+ip test-ip4 output
+ [ meta load mark => reg 1 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set (meta mark | 0x10) << 8
+inet test-inet output
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000008 ) ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set mark map { 1 : 10, 2 : 20, 3 : 30 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000001 : 0000000a 0 [end] element 00000002 : 00000014 0 [end] element 00000003 : 0000001e 0 [end]
+ip test-ip4 output
+ [ meta load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ ct set mark with reg 1 ]
+
+# ct original bytes > 100000
+ip test-ip4 output
+ [ ct load bytes => reg 1 , dir original ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0x00000000 0xa0860100 ]
+
+# ct reply packets < 100
+ip test-ip4 output
+ [ ct load packets => reg 1 , dir reply ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0x00000000 0x64000000 ]
+
+# ct bytes > 100000
+ip test-ip4 output
+ [ ct load bytes => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0x00000000 0xa0860100 ]
+
+# ct avgpkt > 200
+ip test-ip4 output
+ [ ct load avgpkt => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0x00000000 0xc8000000 ]
+
+# ct original avgpkt < 500
+ip test-ip4 output
+ [ ct load avgpkt => reg 1 , dir original ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0x00000000 0xf4010000 ]
+
+# ct status expected,seen-reply,assured,confirmed,snat,dnat,dying
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000023f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status snat
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status dnat
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct event set new
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set event with reg 1 ]
+
+# ct event set new | related | destroy | label
+ip test-ip4 output
+ [ immediate reg 1 0x00000407 ]
+ [ ct set event with reg 1 ]
+
+# ct event set new,related,destroy,label
+ip test-ip4 output
+ [ immediate reg 1 0x00000407 ]
+ [ ct set event with reg 1 ]
+
+# ct event set new,destroy
+ip test-ip4 output
+ [ immediate reg 1 0x00000005 ]
+ [ ct set event with reg 1 ]
+
+# ct event set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set event with reg 1 ]
+
+# ct event set 0x0
+ip test-ip4 output
+ [ immediate reg 1 0x00000000 ]
+ [ ct set event with reg 1 ]
+
+# ct label 127
+ip test-ip4 output
+ [ ct load label => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000000 0x00000000 0x00000000 0x80000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
+
+# ct label set 127
+ip test-ip4 output
+ [ immediate reg 1 0x00000000 0x00000000 0x00000000 0x80000000 ]
+ [ ct set label with reg 1 ]
+
+# ct zone 0
+ip test-ip4 output
+ [ ct load zone => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct zone 23
+ip test-ip4 output
+ [ ct load zone => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# ct original zone 1
+ip test-ip4 output
+ [ ct load zone => reg 1 , dir original ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ct reply zone 1
+ip test-ip4 output
+ [ ct load zone => reg 1 , dir reply ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ct zone set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set zone with reg 1 ]
+
+# ct original zone set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set zone with reg 1 , dir original ]
+
+# ct reply zone set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set zone with reg 1 , dir reply ]
+
+# ct zone set mark map { 1 : 1, 2 : 2 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000001 : 00000001 0 [end] element 00000002 : 00000002 0 [end]
+ip test-ip4 output
+ [ meta load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ ct set zone with reg 1 ]
+
+# notrack
+ip test-ip4 output
+ [ notrack ]
+
+# ct direction . ct mark { original . 0x12345678, reply . 0x87654321}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 12345678 : 0 [end] element 00000001 87654321 : 0 [end]
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ ct load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept}
+__map%d test-ip4 b size 2
+__map%d test-ip4 0
+ element 00000008 12345678 : drop 0 [end] element 00000002 87654321 : accept 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ ct load mark => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ct mark set ct mark or 0x00000001
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffe ) ^ 0x00000001 ]
+ [ ct set mark with reg 1 ]
+
+# ct id 12345
+ip test-ip4 output
+ [ ct load unknown => reg 1 ]
+ [ cmp eq reg 1 0x39300000 ]
+
+# ct status ! dnat
+ip6
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct count 3
+ip test-ip4 output
+ [ connlimit count 3 flags 0 ]
+
+# ct count over 3
+ip test-ip4 output
+ [ connlimit count 3 flags 1 ]
+
diff --git a/tests/py/any/icmpX.t.netdev b/tests/py/any/icmpX.t.netdev
new file mode 100644
index 0000000..cf40242
--- /dev/null
+++ b/tests/py/any/icmpX.t.netdev
@@ -0,0 +1,9 @@
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*netdev;test-netdev;ingress,egress
+
+ip protocol icmp icmp type echo-request;ok;icmp type echo-request
+icmp type echo-request;ok
+ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/any/icmpX.t.netdev.payload b/tests/py/any/icmpX.t.netdev.payload
new file mode 100644
index 0000000..8b8107c
--- /dev/null
+++ b/tests/py/any/icmpX.t.netdev.payload
@@ -0,0 +1,36 @@
+# ip protocol icmp icmp type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# icmpv6 type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
diff --git a/tests/py/any/last.t b/tests/py/any/last.t
new file mode 100644
index 0000000..5c53046
--- /dev/null
+++ b/tests/py/any/last.t
@@ -0,0 +1,13 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*arp;test-arp;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress
+
+last;ok
+last used 300s;ok;last
+last used foo;fail
diff --git a/tests/py/any/last.t.json b/tests/py/any/last.t.json
new file mode 100644
index 0000000..2a2b9e7
--- /dev/null
+++ b/tests/py/any/last.t.json
@@ -0,0 +1,16 @@
+# last
+[
+ {
+ "last": null
+ }
+]
+
+# last used 300s
+[
+ {
+ "last": {
+ "used": 300000
+ }
+ }
+]
+
diff --git a/tests/py/any/last.t.json.output b/tests/py/any/last.t.json.output
new file mode 100644
index 0000000..b8a977e
--- /dev/null
+++ b/tests/py/any/last.t.json.output
@@ -0,0 +1,14 @@
+# last
+[
+ {
+ "last": null
+ }
+]
+
+# last used 300s
+[
+ {
+ "last": null
+ }
+]
+
diff --git a/tests/py/any/last.t.payload b/tests/py/any/last.t.payload
new file mode 100644
index 0000000..ed47d0f
--- /dev/null
+++ b/tests/py/any/last.t.payload
@@ -0,0 +1,8 @@
+# last
+ip
+ [ last never ]
+
+# last used 300s
+ip
+ [ last 300000 ]
+
diff --git a/tests/py/any/limit.t b/tests/py/any/limit.t
new file mode 100644
index 0000000..a04ef42
--- /dev/null
+++ b/tests/py/any/limit.t
@@ -0,0 +1,55 @@
+:output;type filter hook output priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+*netdev;test-netdev;ingress,egress
+
+limit rate 400/minute;ok;limit rate 400/minute burst 5 packets
+limit rate 20/second;ok;limit rate 20/second burst 5 packets
+limit rate 400/hour;ok;limit rate 400/hour burst 5 packets
+limit rate 40/day;ok;limit rate 40/day burst 5 packets
+limit rate 400/week;ok;limit rate 400/week burst 5 packets
+limit rate 1023/second burst 10 packets;ok
+limit rate 1023/second burst 10 bytes;fail
+
+limit rate 1 kbytes/second;ok
+limit rate 2 kbytes/second;ok
+limit rate 1025 kbytes/second;ok
+limit rate 1023 mbytes/second;ok
+limit rate 10230 mbytes/second;ok
+limit rate 1023000 mbytes/second;ok
+limit rate 512 kbytes/second burst 5 packets;fail
+
+limit rate 1 bytes / second;ok;limit rate 1 bytes/second
+limit rate 1 kbytes / second;ok;limit rate 1 kbytes/second
+limit rate 1 mbytes / second;ok;limit rate 1 mbytes/second
+limit rate 1 gbytes / second;fail
+
+limit rate 1025 bytes/second burst 512 bytes;ok
+limit rate 1025 kbytes/second burst 1023 kbytes;ok
+limit rate 1025 mbytes/second burst 1025 kbytes;ok
+limit rate 1025000 mbytes/second burst 1023 mbytes;ok
+
+limit rate over 400/minute;ok;limit rate over 400/minute burst 5 packets
+limit rate over 20/second;ok;limit rate over 20/second burst 5 packets
+limit rate over 400/hour;ok;limit rate over 400/hour burst 5 packets
+limit rate over 40/day;ok;limit rate over 40/day burst 5 packets
+limit rate over 400/week;ok;limit rate over 400/week burst 5 packets
+limit rate over 1023/second burst 10 packets;ok
+
+limit rate over 1 kbytes/second;ok
+limit rate over 2 kbytes/second;ok
+limit rate over 1025 kbytes/second;ok
+limit rate over 1023 mbytes/second;ok
+limit rate over 10230 mbytes/second;ok
+limit rate over 1023000 mbytes/second;ok
+
+limit rate over 1025 bytes/second burst 512 bytes;ok
+limit rate over 1025 kbytes/second burst 1023 kbytes;ok
+limit rate over 1025 mbytes/second burst 1025 kbytes;ok
+limit rate over 1025000 mbytes/second burst 1023 mbytes;ok
diff --git a/tests/py/any/limit.t.json b/tests/py/any/limit.t.json
new file mode 100644
index 0000000..e001ba0
--- /dev/null
+++ b/tests/py/any/limit.t.json
@@ -0,0 +1,413 @@
+# limit rate 400/minute
+[
+ {
+ "limit": {
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 20/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate 400/hour
+[
+ {
+ "limit": {
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 40/day
+[
+ {
+ "limit": {
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate 400/week
+[
+ {
+ "limit": {
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 1023/second burst 10 packets
+[
+ {
+ "limit": {
+ "burst": 10,
+ "per": "second",
+ "rate": 1023
+ }
+ }
+]
+
+# limit rate 1 kbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 2 kbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1025 kbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1023 mbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 10230 mbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1 bytes / second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "bytes"
+ }
+ }
+]
+
+# limit rate 1 kbytes / second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1 mbytes / second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1025 bytes/second burst 512 bytes
+[
+ {
+ "limit": {
+ "burst": 512,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "bytes"
+ }
+ }
+]
+
+# limit rate 1025 kbytes/second burst 1023 kbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "kbytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1025 mbytes/second burst 1025 kbytes
+[
+ {
+ "limit": {
+ "burst": 1025,
+ "burst_unit": "kbytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1025000 mbytes/second burst 1023 mbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "mbytes",
+ "per": "second",
+ "rate": 1025000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 400/minute
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 20/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate over 400/hour
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 40/day
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate over 400/week
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 1023/second burst 10 packets
+[
+ {
+ "limit": {
+ "burst": 10,
+ "inv": true,
+ "per": "second",
+ "rate": 1023
+ }
+ }
+]
+
+# limit rate over 1 kbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 2 kbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1025 kbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1023 mbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 10230 mbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1025 bytes/second burst 512 bytes
+[
+ {
+ "limit": {
+ "burst": 512,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "bytes"
+ }
+ }
+]
+
+# limit rate over 1025 kbytes/second burst 1023 kbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "kbytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1025 mbytes/second burst 1025 kbytes
+[
+ {
+ "limit": {
+ "burst": 1025,
+ "burst_unit": "kbytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1025000 mbytes/second burst 1023 mbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "mbytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
diff --git a/tests/py/any/limit.t.json.output b/tests/py/any/limit.t.json.output
new file mode 100644
index 0000000..5a95f5e
--- /dev/null
+++ b/tests/py/any/limit.t.json.output
@@ -0,0 +1,277 @@
+# limit rate 400/minute
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 20/second
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate 400/hour
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 40/day
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate 400/week
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 1 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 2 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1025 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1023 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 10230 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 400/minute
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 20/second
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate over 400/hour
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 40/day
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate over 400/week
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 1 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 2 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1025 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1023 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 10230 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
diff --git a/tests/py/any/limit.t.payload b/tests/py/any/limit.t.payload
new file mode 100644
index 0000000..0c7ee94
--- /dev/null
+++ b/tests/py/any/limit.t.payload
@@ -0,0 +1,141 @@
+# limit rate 400/minute
+ip test-ip4 output
+ [ limit rate 400/minute burst 5 type packets flags 0x0 ]
+
+# limit rate 20/second
+ip test-ip4 output
+ [ limit rate 20/second burst 5 type packets flags 0x0 ]
+
+# limit rate 400/hour
+ip test-ip4 output
+ [ limit rate 400/hour burst 5 type packets flags 0x0 ]
+
+# limit rate 400/week
+ip test-ip4 output
+ [ limit rate 400/week burst 5 type packets flags 0x0 ]
+
+# limit rate 40/day
+ip test-ip4 output
+ [ limit rate 40/day burst 5 type packets flags 0x0 ]
+
+# limit rate 1023/second burst 10 packets
+ip test-ip4 output
+ [ limit rate 1023/second burst 10 type packets flags 0x0 ]
+
+# limit rate 1 kbytes/second
+ip test-ip4 output
+ [ limit rate 1024/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 2 kbytes/second
+ip test-ip4 output
+ [ limit rate 2048/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1025 kbytes/second
+ip test-ip4 output
+ [ limit rate 1049600/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1023 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 10230 mbytes/second
+ip test-ip4 output
+ [ limit rate 10726932480/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1023000 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248000/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1 bytes / second
+ip
+ [ limit rate 1/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1 kbytes / second
+ip
+ [ limit rate 1024/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1 mbytes / second
+ip
+ [ limit rate 1048576/second burst 0 type bytes flags 0x0 ]
+
+
+# limit rate 1025 bytes/second burst 512 bytes
+ip test-ip4 output
+ [ limit rate 1025/second burst 512 type bytes flags 0x0 ]
+
+# limit rate 1025 kbytes/second burst 1023 kbytes
+ip test-ip4 output
+ [ limit rate 1049600/second burst 1047552 type bytes flags 0x0 ]
+
+# limit rate 1025 mbytes/second burst 1025 kbytes
+ip test-ip4 output
+ [ limit rate 1074790400/second burst 1049600 type bytes flags 0x0 ]
+
+# limit rate 1025000 mbytes/second burst 1023 mbytes
+ip test-ip4 output
+ [ limit rate 1074790400000/second burst 1072693248 type bytes flags 0x0 ]
+
+# limit rate over 400/minute
+ip test-ip4 output
+ [ limit rate 400/minute burst 5 type packets flags 0x1 ]
+
+# limit rate over 20/second
+ip test-ip4 output
+ [ limit rate 20/second burst 5 type packets flags 0x1 ]
+
+# limit rate over 400/hour
+ip test-ip4 output
+ [ limit rate 400/hour burst 5 type packets flags 0x1 ]
+
+# limit rate over 400/week
+ip test-ip4 output
+ [ limit rate 400/week burst 5 type packets flags 0x1 ]
+
+# limit rate over 40/day
+ip test-ip4 output
+ [ limit rate 40/day burst 5 type packets flags 0x1 ]
+
+# limit rate over 1023/second burst 10 packets
+ip test-ip4 output
+ [ limit rate 1023/second burst 10 type packets flags 0x1 ]
+
+# limit rate over 1 kbytes/second
+ip test-ip4 output
+ [ limit rate 1024/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 2 kbytes/second
+ip test-ip4 output
+ [ limit rate 2048/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1025 kbytes/second
+ip test-ip4 output
+ [ limit rate 1049600/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1023 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 10230 mbytes/second
+ip test-ip4 output
+ [ limit rate 10726932480/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1023000 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248000/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1025 bytes/second burst 512 bytes
+ip test-ip4 output
+ [ limit rate 1025/second burst 512 type bytes flags 0x1 ]
+
+# limit rate over 1025 kbytes/second burst 1023 kbytes
+ip test-ip4 output
+ [ limit rate 1049600/second burst 1047552 type bytes flags 0x1 ]
+
+# limit rate over 1025 mbytes/second burst 1025 kbytes
+ip test-ip4 output
+ [ limit rate 1074790400/second burst 1049600 type bytes flags 0x1 ]
+
+# limit rate over 1025000 mbytes/second burst 1023 mbytes
+ip test-ip4 output
+ [ limit rate 1074790400000/second burst 1072693248 type bytes flags 0x1 ]
+
diff --git a/tests/py/any/log.t b/tests/py/any/log.t
new file mode 100644
index 0000000..f4ccaf0
--- /dev/null
+++ b/tests/py/any/log.t
@@ -0,0 +1,41 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+
+log;ok
+log level emerg;ok
+log level alert;ok
+log level crit;ok
+log level err;ok
+log level warn;ok;log
+log level notice;ok
+log level info;ok
+log level debug;ok
+log level audit;ok
+
+log level emerg group 2;fail
+log level alert group 2 prefix "log test2";fail
+
+# log level audit must reject all other parameters
+log level audit prefix "foo";fail
+log level audit group 42;fail
+log level audit snaplen 23;fail
+log level audit queue-threshold 1337;fail
+log level audit flags all;fail
+
+log prefix aaaaa-aaaaaa group 2 snaplen 33;ok;log prefix "aaaaa-aaaaaa" group 2 snaplen 33
+# TODO: Add an exception: 'queue-threshold' attribute needs 'group' attribute
+# The correct rule is log group 2 queue-threshold 2
+log group 2 queue-threshold 2;ok
+log group 2 snaplen 33;ok
+log group 2 prefix "nft-test: ";ok;log prefix "nft-test: " group 2
+
+log flags all;ok
+log level debug flags ip options flags skuid;ok
+log flags tcp sequence,options;ok
+log flags ip options flags ether flags skuid flags tcp sequence,options;ok;log flags all
+log flags all group 2;fail
diff --git a/tests/py/any/log.t.json b/tests/py/any/log.t.json
new file mode 100644
index 0000000..7bcc20e
--- /dev/null
+++ b/tests/py/any/log.t.json
@@ -0,0 +1,178 @@
+# log
+[
+ {
+ "log": null
+ }
+]
+
+# log level emerg
+[
+ {
+ "log": {
+ "level": "emerg"
+ }
+ }
+]
+
+# log level alert
+[
+ {
+ "log": {
+ "level": "alert"
+ }
+ }
+]
+
+# log level crit
+[
+ {
+ "log": {
+ "level": "crit"
+ }
+ }
+]
+
+# log level err
+[
+ {
+ "log": {
+ "level": "err"
+ }
+ }
+]
+
+# log level warn
+[
+ {
+ "log": {
+ "level": "warn"
+ }
+ }
+]
+
+# log level notice
+[
+ {
+ "log": {
+ "level": "notice"
+ }
+ }
+]
+
+# log level info
+[
+ {
+ "log": {
+ "level": "info"
+ }
+ }
+]
+
+# log level debug
+[
+ {
+ "log": {
+ "level": "debug"
+ }
+ }
+]
+
+# log level audit
+[
+ {
+ "log": {
+ "level": "audit"
+ }
+ }
+]
+
+# log prefix aaaaa-aaaaaa group 2 snaplen 33
+[
+ {
+ "log": {
+ "group": 2,
+ "prefix": "aaaaa-aaaaaa",
+ "snaplen": 33
+ }
+ }
+]
+
+# log group 2 queue-threshold 2
+[
+ {
+ "log": {
+ "group": 2,
+ "queue-threshold": 2
+ }
+ }
+]
+
+# log group 2 snaplen 33
+[
+ {
+ "log": {
+ "group": 2,
+ "snaplen": 33
+ }
+ }
+]
+
+# log group 2 prefix "nft-test: "
+[
+ {
+ "log": {
+ "group": 2,
+ "prefix": "nft-test: "
+ }
+ }
+]
+
+# log flags all
+[
+ {
+ "log": {
+ "flags": "all"
+ }
+ }
+]
+
+# log level debug flags ip options flags skuid
+[
+ {
+ "log": {
+ "flags": [
+ "ip options",
+ "skuid"
+ ],
+ "level": "debug"
+ }
+ }
+]
+
+# log flags tcp sequence,options
+[
+ {
+ "log": {
+ "flags": [
+ "tcp sequence",
+ "tcp options"
+ ]
+ }
+ }
+]
+
+# log flags ip options flags ether flags skuid flags tcp sequence,options
+[
+ {
+ "log": {
+ "flags": [
+ "ip options",
+ "ether",
+ "skuid",
+ "tcp sequence",
+ "tcp options"
+ ]
+ }
+ }
+]
+
diff --git a/tests/py/any/log.t.json.output b/tests/py/any/log.t.json.output
new file mode 100644
index 0000000..051c448
--- /dev/null
+++ b/tests/py/any/log.t.json.output
@@ -0,0 +1,16 @@
+# log level warn
+[
+ {
+ "log": null
+ }
+]
+
+# log flags ip options flags ether flags skuid flags tcp sequence,options
+[
+ {
+ "log": {
+ "flags": "all"
+ }
+ }
+]
+
diff --git a/tests/py/any/log.t.payload b/tests/py/any/log.t.payload
new file mode 100644
index 0000000..1330445
--- /dev/null
+++ b/tests/py/any/log.t.payload
@@ -0,0 +1,71 @@
+# log
+ip test-ip4 output
+ [ log ]
+
+# log level emerg
+ip test-ip4 output
+ [ log level 0 ]
+
+# log level alert
+ip test-ip4 output
+ [ log level 1 ]
+
+# log level crit
+ip test-ip4 output
+ [ log level 2 ]
+
+# log level err
+ip test-ip4 output
+ [ log level 3 ]
+
+# log level warn
+ip test-ip4 output
+ [ log level 4 ]
+
+# log level notice
+ip test-ip4 output
+ [ log level 5 ]
+
+# log level info
+ip test-ip4 output
+ [ log level 6 ]
+
+# log level debug
+ip test-ip4 output
+ [ log level 7 ]
+
+# log level audit
+ip test-ip4 output
+ [ log level 8 ]
+
+# log prefix aaaaa-aaaaaa group 2 snaplen 33
+ip test-ip4 output
+ [ log prefix aaaaa-aaaaaa group 2 snaplen 33 qthreshold 0 ]
+
+# log group 2 queue-threshold 2
+ip test-ip4 output
+ [ log group 2 snaplen 0 qthreshold 2 ]
+
+# log group 2 snaplen 33
+ip test-ip4 output
+ [ log group 2 snaplen 33 qthreshold 0 ]
+
+# log group 2 prefix "nft-test: "
+ip test-ip4 output
+ [ log prefix nft-test: group 2 snaplen 0 qthreshold 0 ]
+
+# log flags all
+ip test-ip4 output
+ [ log tcpseq tcpopt ipopt uid macdecode ]
+
+# log level debug flags ip options flags skuid
+ip test-ip4 output
+ [ log level 7 ipopt uid ]
+
+# log flags tcp sequence,options
+ip test-ip4 output
+ [ log tcpseq tcpopt ]
+
+# log flags ip options flags ether flags skuid flags tcp sequence,options
+ip test-ip4 output
+ [ log tcpseq tcpopt ipopt uid macdecode ]
diff --git a/tests/py/any/meta.t b/tests/py/any/meta.t
new file mode 100644
index 0000000..12fabb7
--- /dev/null
+++ b/tests/py/any/meta.t
@@ -0,0 +1,226 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*arp;test-arp;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress,egress
+
+meta length 1000;ok
+meta length 22;ok
+meta length != 233;ok
+meta length 33-45;ok
+meta length != 33-45;ok
+meta length { 33, 55, 67, 88};ok
+meta length { 33-55, 67-88};ok
+meta length { 33-55, 56-88, 100-120};ok;meta length { 33-88, 100-120}
+meta length != { 33, 55, 67, 88};ok
+meta length { 33-55, 66-88};ok
+meta length != { 33-55, 66-88};ok
+
+meta protocol { ip, arp, ip6, vlan };ok;meta protocol { ip6, ip, 8021q, arp}
+meta protocol != {ip, arp, ip6, 8021q};ok
+meta protocol ip;ok
+meta protocol != ip;ok
+
+meta l4proto 22;ok
+meta l4proto != 233;ok
+meta l4proto 33-45;ok
+meta l4proto != 33-45;ok
+meta l4proto { 33, 55, 67, 88};ok
+meta l4proto != { 33, 55, 67, 88};ok
+meta l4proto { 33-55, 66-88};ok
+meta l4proto != { 33-55, 66-88};ok
+
+meta priority root;ok
+meta priority none;ok
+meta priority 0x87654321;ok;meta priority 8765:4321
+meta priority 2271560481;ok;meta priority 8765:4321
+meta priority 1:1234;ok
+meta priority bcad:dadc;ok
+meta priority aabb:0;ok
+meta priority != bcad:dadc;ok
+meta priority != aabb:0;ok
+meta priority bcad:dada-bcad:dadc;ok
+meta priority != bcad:dada-bcad:dadc;ok
+meta priority {bcad:dada, bcad:dadc, aaaa:bbbb};ok
+meta priority set cafe:beef;ok
+meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb};ok
+
+meta mark 0x4;ok;meta mark 0x00000004
+meta mark 0x32;ok;meta mark 0x00000032
+meta mark and 0x03 == 0x01;ok;meta mark & 0x00000003 == 0x00000001
+meta mark and 0x03 != 0x01;ok;meta mark & 0x00000003 != 0x00000001
+meta mark 0x10;ok;meta mark 0x00000010
+meta mark != 0x10;ok;meta mark != 0x00000010
+meta mark 0xffffff00/24;ok
+
+meta mark or 0x03 == 0x01;ok;meta mark | 0x00000003 == 0x00000001
+meta mark or 0x03 != 0x01;ok;meta mark | 0x00000003 != 0x00000001
+meta mark xor 0x03 == 0x01;ok;meta mark 0x00000002
+meta mark xor 0x03 != 0x01;ok;meta mark != 0x00000002
+
+meta iif "lo" accept;ok;iif "lo" accept
+meta iif != "lo" accept;ok;iif != "lo" accept
+
+meta iifname "dummy0";ok;iifname "dummy0"
+meta iifname != "dummy0";ok;iifname != "dummy0"
+meta iifname {"dummy0", "lo"};ok;iifname {"dummy0", "lo"}
+meta iifname != {"dummy0", "lo"};ok;iifname != {"dummy0", "lo"}
+meta iifname "dummy*";ok;iifname "dummy*"
+meta iifname "dummy\*";ok;iifname "dummy\*"
+meta iifname "";fail
+
+meta iiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta iiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta iiftype != ether;ok
+meta iiftype ether;ok
+meta iiftype != ppp;ok
+meta iiftype ppp;ok
+
+meta oif "lo" accept;ok;oif "lo" accept
+meta oif != "lo" accept;ok;oif != "lo" accept
+
+meta oifname "dummy0";ok;oifname "dummy0"
+meta oifname != "dummy0";ok;oifname != "dummy0"
+meta oifname { "dummy0", "lo"};ok;oifname { "dummy0", "lo"}
+meta oifname "dummy*";ok;oifname "dummy*"
+meta oifname "dummy\*";ok;oifname "dummy\*"
+meta oifname "";fail
+
+meta oiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta oiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta oiftype != ether;ok
+meta oiftype ether;ok
+
+meta skuid {"bin", "root", "daemon"} accept;ok;meta skuid { 0, 1, 2} accept
+meta skuid != {"bin", "root", "daemon"} accept;ok;meta skuid != { 1, 0, 2} accept
+meta skuid "root";ok;meta skuid 0
+meta skuid != "root";ok;meta skuid != 0
+meta skuid lt 3000 accept;ok;meta skuid < 3000 accept
+meta skuid gt 3000 accept;ok;meta skuid > 3000 accept
+meta skuid eq 3000 accept;ok;meta skuid 3000 accept
+meta skuid 3001-3005 accept;ok
+meta skuid != 2001-2005 accept;ok
+meta skuid { 2001-2005, 3001-3005} accept;ok
+meta skuid != { 2001-2005, 3001-3005} accept;ok
+
+meta skgid {"bin", "root", "daemon"} accept;ok;meta skgid { 0, 1, 2} accept
+meta skgid != {"bin", "root", "daemon"} accept;ok;meta skgid != { 1, 0, 2} accept
+meta skgid "root";ok;meta skgid 0
+meta skgid != "root";ok;meta skgid != 0
+meta skgid lt 3000 accept;ok;meta skgid < 3000 accept
+meta skgid gt 3000 accept;ok;meta skgid > 3000 accept
+meta skgid eq 3000 accept;ok;meta skgid 3000 accept
+meta skgid 2001-2005 accept;ok
+meta skgid != 2001-2005 accept;ok
+
+# BUG: meta nftrace 2 and meta nftrace 1
+# $ sudo nft add rule ip test input meta nftrace 2
+# <cmdline>:1:37-37: Error: Value 2 exceeds valid range 0-1
+# add rule ip test input meta nftrace 2
+# ^
+# $ sudo nft add rule ip test input meta nftrace 1
+# <cmdline>:1:1-37: Error: Could not process rule: Operation not supported
+# add rule ip test input meta nftrace 1
+# -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+meta mark set 0xffffffc8 xor 0x16;ok;meta mark set 0xffffffde
+meta mark set 0x16 and 0x16;ok;meta mark set 0x00000016
+meta mark set 0xffffffe9 or 0x16;ok;meta mark set 0xffffffff
+meta mark set 0xffffffde and 0x16;ok;meta mark set 0x00000016
+meta mark set 0xf045ffde or 0x10;ok;meta mark set 0xf045ffde
+meta mark set 0xffffffde or 0x16;ok;meta mark set 0xffffffde
+meta mark set 0x32 or 0xfffff;ok;meta mark set 0x000fffff
+meta mark set 0xfffe xor 0x16;ok;meta mark set 0x0000ffe8
+
+meta mark set {0xffff, 0xcc};fail
+meta pkttype set {unicast, multicast, broadcast};fail
+
+meta iif "lo";ok;iif "lo"
+meta oif "lo";ok;oif "lo"
+meta oifname "dummy2" accept;ok;oifname "dummy2" accept
+meta skuid 3000;ok
+meta skgid 3000;ok
+# BUG: meta nftrace 1;ok
+# <cmdline>:1:1-37: Error: Could not process rule: Operation not supported
+- meta nftrace 1;ok
+meta rtclassid "cosmos";ok
+
+meta pkttype broadcast;ok
+meta pkttype host;ok
+meta pkttype multicast;ok
+meta pkttype != broadcast;ok
+meta pkttype != host;ok
+meta pkttype != multicast;ok
+meta pkttype broadcastttt;fail
+pkttype { broadcast, multicast} accept;ok;meta pkttype { broadcast, multicast} accept
+
+meta cpu 1;ok
+meta cpu != 1;ok
+meta cpu 1-3;ok
+meta cpu != 1-2;ok
+meta cpu { 2,3};ok
+meta cpu { 2-3, 5-7};ok
+meta cpu != { 2,3};ok
+
+meta iifgroup 0;ok;iifgroup "default"
+meta iifgroup != 0;ok;iifgroup != "default"
+meta iifgroup "default";ok;iifgroup "default"
+meta iifgroup != "default";ok;iifgroup != "default"
+meta iifgroup {"default", 11};ok;iifgroup {"default", 11}
+meta iifgroup != {"default", 11};ok;iifgroup != {"default", 11}
+meta iifgroup { 11,33};ok;iifgroup { 11,33}
+meta iifgroup {11-33, 44-55};ok;iifgroup {11-33, 44-55}
+meta iifgroup != { 11,33};ok;iifgroup != { 11,33}
+meta iifgroup != {11-33, 44-55};ok;iifgroup != {11-33, 44-55}
+meta oifgroup 0;ok;oifgroup "default"
+meta oifgroup != 0;ok;oifgroup != "default"
+meta oifgroup "default";ok;oifgroup "default"
+meta oifgroup != "default";ok;oifgroup != "default"
+meta oifgroup {"default", 11};ok;oifgroup {"default", 11}
+meta oifgroup != {"default", 11};ok;oifgroup != {"default", 11}
+meta oifgroup { 11,33};ok;oifgroup { 11,33}
+meta oifgroup {11-33, 44-55};ok;oifgroup {11-33, 44-55}
+meta oifgroup != { 11,33};ok;oifgroup != { 11,33}
+meta oifgroup != {11-33, 44-55};ok;oifgroup != {11-33, 44-55}
+
+meta cgroup 1048577;ok
+meta cgroup != 1048577;ok
+meta cgroup { 1048577, 1048578 };ok
+meta cgroup != { 1048577, 1048578};ok
+meta cgroup 1048577-1048578;ok
+meta cgroup != 1048577-1048578;ok
+
+meta iif . meta oif { "lo" . "lo" };ok;iif . oif { "lo" . "lo" }
+meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a };ok;iif . oif . meta mark { "lo" . "lo" . 0x0000000a }
+meta iif . meta oif vmap { "lo" . "lo" : drop };ok;iif . oif vmap { "lo" . "lo" : drop }
+
+meta random eq 1;ok;meta random 1
+meta random gt 1000000;ok;meta random > 1000000
+
+meta time "1970-05-23 21:07:14" drop;ok
+meta time 12341234 drop;ok;meta time "1970-05-23 22:07:14" drop
+meta time "2019-06-21 17:00:00" drop;ok
+meta time "2019-07-01 00:00:00" drop;ok
+meta time "2019-07-01 00:01:00" drop;ok
+meta time "2019-07-01 00:00:01" drop;ok
+meta time < "2022-07-01 11:00:00" accept;ok
+meta time > "2022-07-01 11:00:00" accept;ok
+meta day "Saturday" drop;ok
+meta day 6 drop;ok;meta day "Saturday" drop
+meta day "Satturday" drop;fail
+meta hour "17:00" drop;ok
+meta hour "17:00:00" drop;ok;meta hour "17:00" drop
+meta hour "17:00:01" drop;ok
+meta hour "00:00" drop;ok
+meta hour "00:01" drop;ok
+time < "2022-07-01 11:00:00" accept;ok;meta time < "2022-07-01 11:00:00" accept
+time > "2022-07-01 11:00:00" accept;ok;meta time > "2022-07-01 11:00:00" accept
+
+meta time "meh";fail
+meta hour "24:00" drop;fail
+meta day 7 drop;fail
diff --git a/tests/py/any/meta.t.json b/tests/py/any/meta.t.json
new file mode 100644
index 0000000..4734bbf
--- /dev/null
+++ b/tests/py/any/meta.t.json
@@ -0,0 +1,2760 @@
+# meta length 1000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": 1000
+ }
+ }
+]
+
+# meta length 22
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# meta length != 233
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# meta length 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta length != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta length { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta length { 33-55, 67-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 67, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta length { 33-55, 56-88, 100-120}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 88 ] },
+ { "range": [ 100, 120 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta length != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta length { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta length != { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol { ip, arp, ip6, vlan }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "ip6",
+ "vlan"
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol != {ip, arp, ip6, 8021q}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "ip6",
+ "8021q"
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol ip
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ }
+]
+
+# meta protocol != ip
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "!=",
+ "right": "ip"
+ }
+ }
+]
+
+# meta l4proto 22
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# meta l4proto != 233
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# meta l4proto 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta l4proto != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta l4proto { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto != { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta priority root
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "root"
+ }
+ }
+]
+
+# meta priority none
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "none"
+ }
+ }
+]
+
+# meta priority 0x87654321
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "0x87654321"
+ }
+ }
+]
+
+# meta priority 2271560481
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": 2271560481
+ }
+ }
+]
+
+# meta priority 1:1234
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "1:1234"
+ }
+ }
+]
+
+# meta priority bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "bcad:dadc"
+ }
+ }
+]
+
+# meta priority aabb:0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "aabb:0"
+ }
+ }
+]
+
+# meta priority != bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": "bcad:dadc"
+ }
+ }
+]
+
+# meta priority != aabb:0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": "aabb:0"
+ }
+ }
+]
+
+# meta priority bcad:dada-bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "bcad:dada", "bcad:dadc" ]
+ }
+ }
+ }
+]
+
+# meta priority != bcad:dada-bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "bcad:dada", "bcad:dadc" ]
+ }
+ }
+ }
+]
+
+# meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "bcad:dada",
+ "bcad:dadc",
+ "aaaa:bbbb"
+ ]
+ }
+ }
+ }
+]
+
+# meta priority set cafe:beef
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "priority" }
+ },
+ "value": "cafe:beef"
+ }
+ }
+]
+
+# meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "aaaa:bbbb",
+ "bcad:dada",
+ "bcad:dadc"
+ ]
+ }
+ }
+ }
+]
+
+# meta mark 0x4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x4"
+ }
+ }
+]
+
+# meta mark 0x32
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x32"
+ }
+ }
+]
+
+# meta mark and 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "==",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark and 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "!=",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x10"
+ }
+ }
+]
+
+# meta mark != 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "!=",
+ "right": "0x10"
+ }
+ }
+]
+
+# meta mark 0xffffff00/24
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": 4294967040,
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# meta mark or 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "==",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark or 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "!=",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark xor 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "==",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark xor 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "!=",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta iif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta iif != "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "!=",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta iifname "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta iifname != "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "!=",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta iifname {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "dummy0",
+ "lo"
+ ]
+ }
+ }
+ }
+]
+
+# meta iifname != {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "dummy0",
+ "lo"
+ ]
+ }
+ }
+ }
+]
+
+# meta iifname "dummy*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "dummy*"
+ }
+ }
+]
+
+# meta iifname "dummy\*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "dummy\\*"
+ }
+ }
+]
+
+# meta iiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta iiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta iiftype != ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "!=",
+ "right": "ether"
+ }
+ }
+]
+
+# meta iiftype ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ }
+]
+
+# meta iiftype != ppp
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "!=",
+ "right": "ppp"
+ }
+ }
+]
+
+# meta iiftype ppp
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ppp"
+ }
+ }
+]
+
+# meta oif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta oif != "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oif" }
+ },
+ "op": "!=",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta oifname "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta oifname != "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "!=",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta oifname { "dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "dummy0",
+ "lo"
+ ]
+ }
+ }
+ }
+]
+
+# meta oifname "dummy*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy*"
+ }
+ }
+]
+
+# meta oifname "dummy\*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy\\*"
+ }
+ }
+]
+
+# meta oiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta oiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta oiftype != ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "!=",
+ "right": "ether"
+ }
+ }
+]
+
+# meta oiftype ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ }
+]
+
+# meta skuid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": "root"
+ }
+ }
+]
+
+# meta skuid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": "root"
+ }
+ }
+]
+
+# meta skuid lt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "<",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid gt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": ">",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid eq 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid 3001-3005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 3001, 3005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != 2001-2005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 2001, 2005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid { 2001-2005, 3001-3005} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 2001, 2005 ] },
+ { "range": [ 3001, 3005 ] }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != { 2001-2005, 3001-3005} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 2001, 2005 ] },
+ { "range": [ 3001, 3005 ] }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": "root"
+ }
+ }
+]
+
+# meta skgid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": "root"
+ }
+ }
+]
+
+# meta skgid lt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "<",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid gt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": ">",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid eq 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid 2001-2005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 2001, 2005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid != 2001-2005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 2001, 2005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta mark set 0xffffffc8 xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "^": [ "0xffffffc8", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0x16 and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "&": [ "0x16", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0xffffffe9 or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0xffffffe9", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0xffffffde and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "&": [ "0xffffffde", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0xf045ffde or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0xf045ffde", "0x10" ] }
+ }
+ }
+]
+
+# meta mark set 0xffffffde or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0xffffffde", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0x32 or 0xfffff
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0x32", "0xfffff" ] }
+ }
+ }
+]
+
+# meta mark set 0xfffe xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "^": [ "0xfffe", "0x16" ] }
+ }
+ }
+]
+
+# meta iif "lo"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ }
+]
+
+# meta oif "lo"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ }
+]
+
+# meta oifname "dummy2" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy2"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid 3000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ }
+]
+
+# meta skgid 3000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ }
+]
+
+# meta rtclassid "cosmos"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "rtclassid" }
+ },
+ "op": "==",
+ "right": "cosmos"
+ }
+ }
+]
+
+# meta pkttype broadcast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": "broadcast"
+ }
+ }
+]
+
+# meta pkttype host
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": "host"
+ }
+ }
+]
+
+# meta pkttype multicast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": "multicast"
+ }
+ }
+]
+
+# meta pkttype != broadcast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "!=",
+ "right": "broadcast"
+ }
+ }
+]
+
+# meta pkttype != host
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "!=",
+ "right": "host"
+ }
+ }
+]
+
+# meta pkttype != multicast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "!=",
+ "right": "multicast"
+ }
+ }
+]
+
+# pkttype { broadcast, multicast} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "broadcast",
+ "multicast"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta cpu 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta cpu != 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# meta cpu 1-3
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 1, 3 ]
+ }
+ }
+ }
+]
+
+# meta cpu != 1-2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 1, 2 ]
+ }
+ }
+ }
+]
+
+# meta cpu { 2,3}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 2,
+ 3
+ ]
+ }
+ }
+ }
+]
+
+# meta cpu { 2-3, 5-7}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 2, 3 ] },
+ { "range": [ 5, 7 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta cpu != { 2,3}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 2,
+ 3
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta iifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta iifgroup "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta iifgroup != "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta iifgroup {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup != {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup != { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup != {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta oifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta oifgroup "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup != "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup != {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup != { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup != {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup 1048577
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": 1048577
+ }
+ }
+]
+
+# meta cgroup != 1048577
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": 1048577
+ }
+ }
+]
+
+# meta cgroup { 1048577, 1048578 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1048577,
+ 1048578
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup != { 1048577, 1048578}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 1048577,
+ 1048578
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup 1048577-1048578
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 1048577, 1048578 ]
+ }
+ }
+ }
+]
+
+# meta cgroup != 1048577-1048578
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 1048577, 1048578 ]
+ }
+ }
+ }
+]
+
+# meta cgroup {1048577-1048578}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [ 1048577, 1048578 ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup != { 1048577-1048578}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ {
+ "range": [ 1048577, 1048578 ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta iif . meta oif { "lo" . "lo" }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "lo",
+ "lo"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ },
+ {
+ "meta": { "key": "mark" }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "lo",
+ "lo",
+ "0x0000000a"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta iif . meta oif vmap { "lo" . "lo" : drop }
+[
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "lo",
+ "lo"
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# meta random eq 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "random" }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta random gt 1000000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "random" }
+ },
+ "op": ">",
+ "right": 1000000
+ }
+ }
+]
+
+# meta time "1970-05-23 21:07:14" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "1970-05-23 21:07:14"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time 12341234 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "12341234"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-06-21 17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-06-21 17:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:01:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:01:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time < "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "<",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta time > "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": ">",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta day "Saturday" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "Saturday"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta day 6 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "6"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# time < "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "<",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# time > "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": ">",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
diff --git a/tests/py/any/meta.t.json.output b/tests/py/any/meta.t.json.output
new file mode 100644
index 0000000..4e9e669
--- /dev/null
+++ b/tests/py/any/meta.t.json.output
@@ -0,0 +1,828 @@
+# meta protocol { ip, arp, ip6, vlan }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "8021q",
+ "ip6"
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol != {ip, arp, ip6, 8021q}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "8021q",
+ "ip6"
+ ]
+ }
+ }
+ }
+]
+
+# meta priority 0x87654321
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "8765:4321"
+ }
+ }
+]
+
+# meta priority 2271560481
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "8765:4321"
+ }
+ }
+]
+
+# meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "aaaa:bbbb",
+ "bcad:dada",
+ "bcad:dadc"
+ ]
+ }
+ }
+ }
+]
+
+# meta mark 0x4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 4
+ }
+ }
+]
+
+# meta mark 0x32
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# meta mark and 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta mark and 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# meta mark 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 16
+ }
+ }
+]
+
+# meta mark != 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "!=",
+ "right": 16
+ }
+ }
+]
+
+# meta mark or 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta mark or 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# meta mark xor 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# meta mark xor 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "!=",
+ "right": 2
+ }
+ }
+]
+
+# meta iifname {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "lo",
+ "dummy0"
+ ]
+ }
+ }
+ }
+]
+
+# meta iifname != {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "lo",
+ "dummy0"
+ ]
+ }
+ }
+ }
+]
+
+# meta oifname { "dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "lo",
+ "dummy0"
+ ]
+ }
+ }
+ }
+]
+
+# meta skuid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta skuid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta skgid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta skgid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta mark set 0xffffffc8 xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4294967262
+ }
+ }
+]
+
+# meta mark set 0x16 and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 22
+ }
+ }
+]
+
+# meta mark set 0xffffffe9 or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4294967295
+ }
+ }
+]
+
+# meta mark set 0xffffffde and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 22
+ }
+ }
+]
+
+# meta mark set 0xf045ffde or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4031119326
+ }
+ }
+]
+
+# meta mark set 0xffffffde or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4294967262
+ }
+ }
+]
+
+# meta mark set 0x32 or 0xfffff
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 1048575
+ }
+ }
+]
+
+# meta mark set 0xfffe xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 65512
+ }
+ }
+]
+
+# meta iifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta iifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ },
+ {
+ "meta": { "key": "mark" }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "lo",
+ "lo",
+ 10
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta time "1970-05-23 21:07:14" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "1970-05-23 21:07:14"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time 12341234 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "1970-05-23 22:07:14"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-06-21 17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-06-21 17:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:01:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:01:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta day "Saturday" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "Saturday"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta day 6 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "Saturday"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
diff --git a/tests/py/any/meta.t.payload b/tests/py/any/meta.t.payload
new file mode 100644
index 0000000..16dc121
--- /dev/null
+++ b/tests/py/any/meta.t.payload
@@ -0,0 +1,1074 @@
+# meta length 1000
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ cmp eq reg 1 0x000003e8 ]
+
+# meta length 22
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# meta length != 233
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# meta length 33-45
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# meta length != 33-45
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# meta length { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length { 33-55, 67-88}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end] element 43000000 : 0 [end] element 59000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length { 33-55, 56-88, 100-120}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 59000000 : 1 [end] element 64000000 : 0 [end] element 79000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta protocol { ip, arp, ip6, vlan }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000608 : 0 [end] element 0000dd86 : 0 [end] element 00000081 : 0 [end]
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta protocol != {ip, arp, ip6, 8021q}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000608 : 0 [end] element 0000dd86 : 0 [end] element 00000081 : 0 [end]
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta protocol ip
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta protocol != ip
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ cmp neq reg 1 0x00000008 ]
+
+# meta l4proto 22
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# meta l4proto != 233
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# meta l4proto 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# meta l4proto != 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# meta l4proto { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta l4proto != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta mark 0x4
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+
+# meta mark 0x32
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# meta mark and 0x03 == 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta mark and 0x03 != 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta mark 0x10
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# meta mark != 0x10
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000010 ]
+
+# meta mark 0xffffff00/24
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffff00 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0xffffff00 ]
+
+# meta mark or 0x03 == 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffc ) ^ 0x00000003 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta mark or 0x03 != 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffc ) ^ 0x00000003 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta mark xor 0x03 == 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# meta mark xor 0x03 != 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# meta iif "lo" accept
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta iif != "lo" accept
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta iifname "dummy0"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta iifname != "dummy0"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp neq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta iifname {"dummy0", "lo"}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 6d6d7564 00003079 00000000 00000000 : 0 [end] element 00006f6c 00000000 00000000 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifname != {"dummy0", "lo"}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 6d6d7564 00003079 00000000 00000000 : 0 [end] element 00006f6c 00000000 00000000 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iifname "dummy*"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00000079 ]
+
+# meta iifname "dummy\*"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00002a79 0x00000000 0x00000000 ]
+
+# meta iiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iiftype != ether
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta iiftype ether
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta iiftype != ppp
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp neq reg 1 0x00000200 ]
+
+# meta iiftype ppp
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# meta oif "lo" accept
+ip test-ip4 input
+ [ meta load oif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta oif != "lo" accept
+ip test-ip4 input
+ [ meta load oif => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta oifname "dummy0"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta oifname != "dummy0"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp neq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta oifname { "dummy0", "lo"}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 6d6d7564 00003079 00000000 00000000 : 0 [end] element 00006f6c 00000000 00000000 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifname "dummy*"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00000079 ]
+
+# meta oifname "dummy\*"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00002a79 0x00000000 0x00000000 ]
+
+# meta oiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta oiftype != ether
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta oiftype ether
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta skuid {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta skuid != {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid "root"
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta skuid != "root"
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta skuid lt 3000 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp lt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid gt 3000 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid eq 3000 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid 3001-3005 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xb90b0000 ]
+ [ cmp lte reg 1 0xbd0b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid != 2001-2005 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xd1070000 0xd5070000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta skgid != {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid "root"
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta skgid != "root"
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta skgid lt 3000 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp lt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid gt 3000 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid eq 3000 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid 2001-2005 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xd1070000 ]
+ [ cmp lte reg 1 0xd5070000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid != 2001-2005 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xd1070000 0xd5070000 ]
+ [ immediate reg 0 accept ]
+
+# meta mark set 0xffffffc8 xor 0x16
+ip test-ip4 input
+ [ immediate reg 1 0xffffffde ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0x16 and 0x16
+ip test-ip4 input
+ [ immediate reg 1 0x00000016 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xffffffe9 or 0x16
+ip test-ip4 input
+ [ immediate reg 1 0xffffffff ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xffffffde and 0x16
+ip test-ip4 input
+ [ immediate reg 1 0x00000016 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xf045ffde or 0x10
+ip test-ip4 input
+ [ immediate reg 1 0xf045ffde ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xffffffde or 0x16
+ip test-ip4 input
+ [ immediate reg 1 0xffffffde ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0x32 or 0xfffff
+ip test-ip4 input
+ [ immediate reg 1 0x000fffff ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xfffe xor 0x16
+ip test-ip4 input
+ [ immediate reg 1 0x0000ffe8 ]
+ [ meta set mark with reg 1 ]
+
+# meta iif "lo"
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta oif "lo"
+ip test-ip4 input
+ [ meta load oif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta oifname "dummy2" accept
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00003279 0x00000000 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid 3000
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+
+# meta skgid 3000
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+
+# meta rtclassid "cosmos"
+ip test-ip4 input
+ [ meta load rtclassid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta pkttype broadcast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta pkttype host
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta pkttype multicast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# meta pkttype != broadcast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta pkttype != host
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta pkttype != multicast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# pkttype { broadcast, multicast} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta cpu 1
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta cpu != 1
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta cpu 1-3
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x01000000 ]
+ [ cmp lte reg 1 0x03000000 ]
+
+# meta cpu != 1-2
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x01000000 0x02000000 ]
+
+# meta cpu { 2,3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 00000003 : 0 [end]
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta cpu != { 2,3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 00000003 : 0 [end]
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta cpu { 2-3, 5-7}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 02000000 : 0 [end] element 04000000 : 1 [end] element 05000000 : 0 [end] element 08000000 : 1 [end]
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifgroup 0
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta iifgroup != 0
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta iifgroup "default"
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta iifgroup != "default"
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta iifgroup { 11,33}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifgroup 0
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta oifgroup != 0
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta oifgroup "default"
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta oifgroup != "default"
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta oifgroup { 11,33}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta cgroup 1048577
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ cmp eq reg 1 0x00100001 ]
+
+# meta cgroup != 1048577
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ cmp neq reg 1 0x00100001 ]
+
+# meta cgroup { 1048577, 1048578 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00100001 : 0 [end] element 00100002 : 0 [end]
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta cgroup != { 1048577, 1048578}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00100001 : 0 [end] element 00100002 : 0 [end]
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta cgroup 1048577-1048578
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x01001000 ]
+ [ cmp lte reg 1 0x02001000 ]
+
+# meta cgroup != 1048577-1048578
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x01001000 0x02001000 ]
+
+# meta iif . meta oif { "lo" . "lo" }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 00000001 : 0 [end]
+ip test-ip4 output
+ [ meta load iif => reg 1 ]
+ [ meta load oif => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 00000001 0000000a : 0 [end]
+ip test-ip4 output
+ [ meta load iif => reg 1 ]
+ [ meta load oif => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iif . meta oif vmap { "lo" . "lo" : drop }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000001 00000001 : drop 0 [end]
+ip test-ip4 output
+ [ meta load iif => reg 1 ]
+ [ meta load oif => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta random eq 1
+ip test-ip4 input
+ [ meta load prandom => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# meta random gt 1000000
+ip test-ip4 input
+ [ meta load prandom => reg 1 ]
+ [ cmp gt reg 1 0x40420f00 ]
+
+# meta priority root
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0xffffffff ]
+
+# meta priority none
+netdev test-netdev ingress
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta priority 1:1234
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x00011234 ]
+
+# meta priority bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0xbcaddadc ]
+
+# meta priority aabb:0
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0xaabb0000 ]
+
+# meta priority != bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp neq reg 1 0xbcaddadc ]
+
+# meta priority != aabb:0
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp neq reg 1 0xaabb0000 ]
+
+# meta priority bcad:dada-bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xdadaadbc ]
+ [ cmp lte reg 1 0xdcdaadbc ]
+
+# meta priority != bcad:dada-bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xdadaadbc 0xdcdaadbc ]
+
+# meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element bcaddada : 0 [end] element bcaddadc : 0 [end] element aaaabbbb : 0 [end]
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta priority set cafe:beef
+ip test-ip4 input
+ [ immediate reg 1 0xcafebeef ]
+ [ meta set priority with reg 1 ]
+
+# meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element bcaddada : 0 [end] element bcaddadc : 0 [end] element aaaabbbb : 0 [end]
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta priority 0x87654321
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x87654321 ]
+
+# meta priority 2271560481
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x87654321 ]
+
+# meta length { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end] element 42000000 : 0 [end] element 59000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length != { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end] element 42000000 : 0 [end] element 59000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta l4proto { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end] element 00000042 : 0 [end] element 00000059 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta l4proto != { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end] element 00000042 : 0 [end] element 00000059 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta skuid { 2001-2005, 3001-3005} accept
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element d1070000 : 0 [end] element d6070000 : 1 [end] element b90b0000 : 0 [end] element be0b0000 : 1 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta iifgroup {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifgroup != {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iifgroup {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifgroup != { 11,33}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iifgroup != {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta oifgroup {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifgroup {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifgroup != { 11,33}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta oifgroup != {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta skuid != { 2001-2005, 3001-3005} accept
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element d1070000 : 0 [end] element d6070000 : 1 [end] element b90b0000 : 0 [end] element be0b0000 : 1 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# meta oifgroup != {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta time "1970-05-23 21:07:14" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x43f05400 0x002bd503 ]
+ [ immediate reg 0 drop ]
+
+# meta time 12341234 drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x74a8f400 0x002bd849 ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-06-21 17:00:00" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x767d6000 0x15aa3ebc ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-07-01 00:00:00" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0xe750c000 0x15ad18e0 ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-07-01 00:01:00" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0xdf981800 0x15ad18ee ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-07-01 00:00:01" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x22eb8a00 0x15ad18e1 ]
+ [ immediate reg 0 drop ]
+
+# meta time < "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
+
+# meta time > "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
+
+# meta day "Saturday" drop
+ip test-ip4 input
+ [ meta load day => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 drop ]
+
+# meta day 6 drop
+ip test-ip4 input
+ [ meta load day => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "17:00" drop
+ip test-ip4 input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0000d2f0 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "17:00:00" drop
+ip test-ip4 input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0000d2f0 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "17:00:01" drop
+ip meta-test input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0000d2f1 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "00:00" drop
+ip meta-test input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x00013560 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "00:01" drop
+ip meta-test input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0001359c ]
+ [ immediate reg 0 drop ]
+
+# time < "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
+
+# time > "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/any/objects.t b/tests/py/any/objects.t
new file mode 100644
index 0000000..7b51f91
--- /dev/null
+++ b/tests/py/any/objects.t
@@ -0,0 +1,16 @@
+:output;type filter hook output priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+*netdev;test-netdev;ingress,egress
+
+%cnt1 type counter;ok
+%qt1 type quota 25 mbytes;ok
+%qt2 type quota over 1 kbytes;ok
+%lim0 type limit rate 400/minute;ok
+%lim2 type limit rate over 1024 bytes/second burst 512 bytes;ok
diff --git a/tests/py/any/queue.t b/tests/py/any/queue.t
new file mode 100644
index 0000000..2e51136
--- /dev/null
+++ b/tests/py/any/queue.t
@@ -0,0 +1,33 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*bridge;test-bridge;output
+
+queue;ok;queue to 0
+queue num 2;ok;queue to 2
+queue num 65535;ok;queue to 65535
+queue num 65536;fail
+queue num 2-3;ok;queue to 2-3
+queue num 1-65535;ok;queue to 1-65535
+queue num 4-5 fanout bypass;ok;queue flags bypass,fanout to 4-5
+queue num 4-5 fanout;ok;queue flags fanout to 4-5
+queue num 4-5 bypass;ok;queue flags bypass to 4-5
+
+queue to symhash mod 2 offset 65536;fail
+queue num symhash mod 65536;fail
+queue to symhash mod 65536;ok
+queue flags fanout to symhash mod 65536;fail
+queue flags bypass,fanout to symhash mod 65536;fail
+queue flags bypass to numgen inc mod 65536;ok
+queue to jhash oif . meta mark mod 32;ok
+queue to 2;ok
+queue to 65535;ok
+queue flags bypass to 65535;ok
+queue flags bypass to 1-65535;ok
+queue flags bypass,fanout to 1-65535;ok
+queue to 1-65535;ok
+queue to oif;fail
+queue num oif;fail
+queue flags bypass to oifname map { "eth0" : 0, "ppp0" : 2, "eth1" : 2 };ok
diff --git a/tests/py/any/queue.t.json b/tests/py/any/queue.t.json
new file mode 100644
index 0000000..5f7f901
--- /dev/null
+++ b/tests/py/any/queue.t.json
@@ -0,0 +1,251 @@
+# queue
+[
+ {
+ "queue": null
+ }
+]
+
+# queue num 2
+[
+ {
+ "queue": {
+ "num": 2
+ }
+ }
+]
+
+# queue num 65535
+[
+ {
+ "queue": {
+ "num": 65535
+ }
+ }
+]
+
+# queue num 2-3
+[
+ {
+ "queue": {
+ "num": {
+ "range": [ 2, 3 ]
+ }
+ }
+ }
+]
+
+# queue num 1-65535
+[
+ {
+ "queue": {
+ "num": {
+ "range": [ 1, 65535 ]
+ }
+ }
+ }
+]
+
+# queue num 4-5 fanout bypass
+[
+ {
+ "queue": {
+ "flags": [
+ "bypass",
+ "fanout"
+ ],
+ "num": {
+ "range": [ 4, 5 ]
+ }
+ }
+ }
+]
+
+# queue num 4-5 fanout
+[
+ {
+ "queue": {
+ "flags": "fanout",
+ "num": {
+ "range": [ 4, 5 ]
+ }
+ }
+ }
+]
+
+# queue num 4-5 bypass
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "range": [ 4, 5 ]
+ }
+ }
+ }
+]
+
+# queue to symhash mod 65536
+[
+ {
+ "queue": {
+ "num": {
+ "symhash": {
+ "mod": 65536
+ }
+ }
+ }
+ }
+]
+
+# queue flags bypass to numgen inc mod 65536
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "numgen": {
+ "mod": 65536,
+ "mode": "inc",
+ "offset": 0
+ }
+ }
+ }
+ }
+]
+
+# queue to jhash oif . meta mark mod 32
+[
+ {
+ "queue": {
+ "num": {
+ "jhash": {
+ "expr": {
+ "concat": [
+ {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "mod": 32
+ }
+ }
+ }
+ }
+]
+
+# queue flags bypass to oifname map { "eth0" : 0, "ppp0" : 2, "eth1" : 2 }
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "eth0",
+ 0
+ ],
+ [
+ "ppp0",
+ 2
+ ],
+ [
+ "eth1",
+ 2
+ ]
+ ]
+ },
+ "key": {
+ "meta": {
+ "key": "oifname"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# queue to 2
+[
+ {
+ "queue": {
+ "num": 2
+ }
+ }
+]
+
+# queue to 65535
+[
+ {
+ "queue": {
+ "num": 65535
+ }
+ }
+]
+
+# queue flags bypass to 65535
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": 65535
+ }
+ }
+]
+
+# queue flags bypass to 1-65535
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ }
+ }
+]
+
+# queue flags bypass,fanout to 1-65535
+[
+ {
+ "queue": {
+ "flags": [
+ "bypass",
+ "fanout"
+ ],
+ "num": {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ }
+ }
+]
+
+# queue to 1-65535
+[
+ {
+ "queue": {
+ "num": {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/any/queue.t.json.output b/tests/py/any/queue.t.json.output
new file mode 100644
index 0000000..1104d76
--- /dev/null
+++ b/tests/py/any/queue.t.json.output
@@ -0,0 +1,9 @@
+# queue
+[
+ {
+ "queue": {
+ "num": 0
+ }
+ }
+]
+
diff --git a/tests/py/any/queue.t.payload b/tests/py/any/queue.t.payload
new file mode 100644
index 0000000..2f22193
--- /dev/null
+++ b/tests/py/any/queue.t.payload
@@ -0,0 +1,81 @@
+# queue
+ip test-ip4 output
+ [ queue num 0 ]
+
+# queue num 2
+ip test-ip4 output
+ [ queue num 2 ]
+
+# queue num 65535
+ip test-ip4 output
+ [ queue num 65535 ]
+
+# queue num 2-3
+ip test-ip4 output
+ [ queue num 2-3 ]
+
+# queue num 1-65535
+ip test-ip4 output
+ [ queue num 1-65535 ]
+
+# queue num 4-5 fanout bypass
+ip test-ip4 output
+ [ queue num 4-5 bypass fanout ]
+
+# queue num 4-5 fanout
+ip test-ip4 output
+ [ queue num 4-5 fanout ]
+
+# queue num 4-5 bypass
+ip test-ip4 output
+ [ queue num 4-5 bypass ]
+
+# queue to symhash mod 65536
+ip
+ [ hash reg 1 = symhash() % mod 65536 ]
+ [ queue sreg_qnum 1 ]
+
+# queue to jhash oif . meta mark mod 32
+ip
+ [ meta load oif => reg 2 ]
+ [ meta load mark => reg 13 ]
+ [ hash reg 1 = jhash(reg 2, 8, 0x0) % mod 32 ]
+ [ queue sreg_qnum 1 ]
+
+# queue flags bypass to numgen inc mod 65536
+ip
+ [ numgen reg 1 = inc mod 65536 ]
+ [ queue sreg_qnum 1 bypass ]
+
+# queue flags bypass to oifname map { "eth0" : 0, "ppp0" : 2, "eth1" : 2 }
+__map%d test-ip4 b size 3
+__map%d test-ip4 0
+ element 30687465 00000000 00000000 00000000 : 00000000 0 [end] element 30707070 00000000 00000000 00000000 : 00000002 0 [end] element 31687465 00000000 00000000 00000000 : 00000002 0 [end]
+ip
+ [ meta load oifname => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ queue sreg_qnum 1 bypass ]
+
+# queue to 2
+ip
+ [ queue num 2 ]
+
+# queue to 65535
+ip
+ [ queue num 65535 ]
+
+# queue flags bypass to 65535
+ip
+ [ queue num 65535 bypass ]
+
+# queue flags bypass to 1-65535
+ip
+ [ queue num 1-65535 bypass ]
+
+# queue flags bypass,fanout to 1-65535
+ip
+ [ queue num 1-65535 bypass fanout ]
+
+# queue to 1-65535
+ip
+ [ queue num 1-65535 ]
diff --git a/tests/py/any/quota.t b/tests/py/any/quota.t
new file mode 100644
index 0000000..79dd765
--- /dev/null
+++ b/tests/py/any/quota.t
@@ -0,0 +1,25 @@
+:output;type filter hook output priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+*netdev;test-netdev;ingress,egress
+
+quota 1025 bytes;ok
+quota 1 kbytes;ok
+quota 2 kbytes;ok
+quota 1025 kbytes;ok
+quota 1023 mbytes;ok
+quota 10230 mbytes;ok
+quota 1023000 mbytes;ok
+
+quota over 1 kbytes;ok
+quota over 2 kbytes;ok
+quota over 1025 kbytes;ok
+quota over 1023 mbytes;ok
+quota over 10230 mbytes;ok
+quota over 1023000 mbytes;ok
diff --git a/tests/py/any/quota.t.json b/tests/py/any/quota.t.json
new file mode 100644
index 0000000..59ccc72
--- /dev/null
+++ b/tests/py/any/quota.t.json
@@ -0,0 +1,136 @@
+# quota 1025 bytes
+[
+ {
+ "quota": {
+ "val": 1025,
+ "val_unit": "bytes"
+ }
+ }
+]
+
+# quota 1 kbytes
+[
+ {
+ "quota": {
+ "val": 1,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota 2 kbytes
+[
+ {
+ "quota": {
+ "val": 2,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota 1025 kbytes
+[
+ {
+ "quota": {
+ "val": 1025,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota 1023 mbytes
+[
+ {
+ "quota": {
+ "val": 1023,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota 10230 mbytes
+[
+ {
+ "quota": {
+ "val": 10230,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota 1023000 mbytes
+[
+ {
+ "quota": {
+ "val": 1023000,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota over 1 kbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota over 2 kbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 2,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota over 1025 kbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1025,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota over 1023 mbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1023,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota over 10230 mbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 10230,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota over 1023000 mbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1023000,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
diff --git a/tests/py/any/quota.t.payload b/tests/py/any/quota.t.payload
new file mode 100644
index 0000000..31cfccb
--- /dev/null
+++ b/tests/py/any/quota.t.payload
@@ -0,0 +1,52 @@
+# quota 1025 bytes
+ip test-ip4 output
+ [ quota bytes 1025 consumed 0 flags 0 ]
+
+# quota 1 kbytes
+ip test-ip4 output
+ [ quota bytes 1024 consumed 0 flags 0 ]
+
+# quota 2 kbytes
+ip test-ip4 output
+ [ quota bytes 2048 consumed 0 flags 0 ]
+
+# quota 1025 kbytes
+ip test-ip4 output
+ [ quota bytes 1049600 consumed 0 flags 0 ]
+
+# quota 1023 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248 consumed 0 flags 0 ]
+
+# quota 10230 mbytes
+ip test-ip4 output
+ [ quota bytes 10726932480 consumed 0 flags 0 ]
+
+# quota 1023000 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248000 consumed 0 flags 0 ]
+
+# quota over 1 kbytes
+ip test-ip4 output
+ [ quota bytes 1024 consumed 0 flags 1 ]
+
+# quota over 2 kbytes
+ip test-ip4 output
+ [ quota bytes 2048 consumed 0 flags 1 ]
+
+# quota over 1025 kbytes
+ip test-ip4 output
+ [ quota bytes 1049600 consumed 0 flags 1 ]
+
+# quota over 1023 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248 consumed 0 flags 1 ]
+
+# quota over 10230 mbytes
+ip test-ip4 output
+ [ quota bytes 10726932480 consumed 0 flags 1 ]
+
+# quota over 1023000 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248000 consumed 0 flags 1 ]
+
diff --git a/tests/py/any/rawpayload.t b/tests/py/any/rawpayload.t
new file mode 100644
index 0000000..5bc9d35
--- /dev/null
+++ b/tests/py/any/rawpayload.t
@@ -0,0 +1,24 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 };ok;meta l4proto { 6, 17, 132} th dport { 22, 23, 80}
+meta l4proto tcp @th,16,16 { 22, 23, 80};ok;tcp dport { 22, 23, 80}
+@nh,8,8 0xff;ok
+@nh,8,16 0x0;ok
+
+# out of range (0-1)
+@th,16,1 2;fail
+
+@ll,0,0 2;fail
+@ll,0,1;fail
+@ll,0,1 1;ok;@ll,0,8 & 0x80 == 0x80
+@ll,0,8 & 0x80 == 0x80;ok
+@ll,0,128 0xfedcba987654321001234567890abcde;ok
+
+meta l4proto 91 @th,400,16 0x0 accept;ok
+
+@ih,32,32 0x14000000;ok
diff --git a/tests/py/any/rawpayload.t.json b/tests/py/any/rawpayload.t.json
new file mode 100644
index 0000000..4cae4d4
--- /dev/null
+++ b/tests/py/any/rawpayload.t.json
@@ -0,0 +1,206 @@
+# meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "tcp",
+ "udp",
+ "sctp"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "th",
+ "len": 16,
+ "offset": 16
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto tcp @th,16,16 { 22, 23, 80}
+[
+ {
+ "match": {
+ "left": { "meta": { "key": "l4proto" } },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "th",
+ "len": 16,
+ "offset": 16
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# @nh,8,8 0xff
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "nh",
+ "len": 8,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": "0xff"
+ }
+ }
+]
+
+# @nh,8,16 0x0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "nh",
+ "len": 16,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# @ll,0,1 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "ll",
+ "len": 1,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# @ll,0,8 & 0x80 == 0x80
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "base": "ll",
+ "len": 8,
+ "offset": 0
+ }
+ },
+ "0x80"
+ ]
+ },
+ "op": "==",
+ "right": "0x80"
+ }
+ }
+]
+
+# @ll,0,128 0xfedcba987654321001234567890abcde
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "ll",
+ "len": 128,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": "0xfedcba987654321001234567890abcde"
+ }
+ }
+]
+
+# meta l4proto 91 @th,400,16 0x0 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 91
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "th",
+ "len": 16,
+ "offset": 400
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# @ih,32,32 0x14000000
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "ih",
+ "len": 32,
+ "offset": 32
+ }
+ },
+ "op": "==",
+ "right": 335544320
+ }
+ }
+]
+
diff --git a/tests/py/any/rawpayload.t.json.output b/tests/py/any/rawpayload.t.json.output
new file mode 100644
index 0000000..291b237
--- /dev/null
+++ b/tests/py/any/rawpayload.t.json.output
@@ -0,0 +1,119 @@
+# meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 132
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto tcp @th,16,16 { 22, 23, 80}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# @ll,0,1 1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "base": "ll",
+ "len": 8,
+ "offset": 0
+ }
+ },
+ 128
+ ]
+ },
+ "op": "==",
+ "right": 128
+ }
+ }
+]
+
+# @ll,0,8 & 0x80 == 0x80
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "base": "ll",
+ "len": 8,
+ "offset": 0
+ }
+ },
+ 128
+ ]
+ },
+ "op": "==",
+ "right": 128
+ }
+ }
+]
+
+# @nh,8,8 0xff
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "nh",
+ "len": 8,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": 255
+ }
+ }
+]
diff --git a/tests/py/any/rawpayload.t.payload b/tests/py/any/rawpayload.t.payload
new file mode 100644
index 0000000..fe2377e
--- /dev/null
+++ b/tests/py/any/rawpayload.t.payload
@@ -0,0 +1,63 @@
+# meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 }
+__set%d test-inet 3 size 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end] element 00000084 : 0 [end]
+__set%d test-inet 3 size 3
+__set%d test-inet 0
+ element 00001600 : 0 [end] element 00001700 : 0 [end] element 00005000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta l4proto tcp @th,16,16 { 22, 23, 80}
+__set%d test-inet 3 size 3
+__set%d test-inet 0
+ element 00001600 : 0 [end] element 00001700 : 0 [end] element 00005000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# @nh,8,8 0xff
+inet test-inet input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# @nh,8,16 0x0
+inet test-inet input
+ [ payload load 2b @ network header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# @ll,0,1 1
+inet test-inet input
+ [ payload load 1b @ link header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000080 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# @ll,0,8 & 0x80 == 0x80
+inet test-inet input
+ [ payload load 1b @ link header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000080 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# @ll,0,128 0xfedcba987654321001234567890abcde
+inet test-inet input
+ [ payload load 16b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x98badcfe 0x10325476 0x67452301 0xdebc0a89 ]
+
+# meta l4proto 91 @th,400,16 0x0 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000005b ]
+ [ payload load 2b @ transport header + 50 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# @ih,32,32 0x14000000
+inet test-inet input
+ [ payload load 4b @ inner header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000014 ]
+
diff --git a/tests/py/any/rt.t b/tests/py/any/rt.t
new file mode 100644
index 0000000..3ce57e0
--- /dev/null
+++ b/tests/py/any/rt.t
@@ -0,0 +1,9 @@
+:output;type filter hook input priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+
+rt classid "cosmos";ok
+rt ipsec exists;ok
+rt ipsec missing;ok
diff --git a/tests/py/any/rt.t.json b/tests/py/any/rt.t.json
new file mode 100644
index 0000000..2ca6fe0
--- /dev/null
+++ b/tests/py/any/rt.t.json
@@ -0,0 +1,45 @@
+# rt classid "cosmos"
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "classid"
+ }
+ },
+ "op": "==",
+ "right": "cosmos"
+ }
+ }
+]
+
+# rt ipsec exists
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "ipsec"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# rt ipsec missing
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "ipsec"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
diff --git a/tests/py/any/rt.t.payload b/tests/py/any/rt.t.payload
new file mode 100644
index 0000000..e1ecb28
--- /dev/null
+++ b/tests/py/any/rt.t.payload
@@ -0,0 +1,15 @@
+# rt classid "cosmos"
+ip test-ip4 input
+ [ rt load classid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# rt ipsec exists
+ip test-ip4 input
+ [ rt load ipsec => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# rt ipsec missing
+ip test-ip4 input
+ [ rt load ipsec => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
new file mode 100644
index 0000000..177f01c
--- /dev/null
+++ b/tests/py/any/tcpopt.t
@@ -0,0 +1,62 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+
+tcp option eol exists;ok
+tcp option nop exists;ok
+tcp option maxseg exists;ok
+tcp option maxseg length 1;ok
+tcp option maxseg size 1;ok
+tcp option window length 1;ok
+tcp option window count 1;ok
+tcp option sack-perm exists;ok
+tcp option sack-perm length 1;ok
+tcp option sack exists;ok
+tcp option sack length 1;ok
+tcp option sack left 1;ok
+tcp option sack0 left 1;ok;tcp option sack left 1
+tcp option sack1 left 1;ok
+tcp option sack2 left 1;ok
+tcp option sack3 left 1;ok
+tcp option sack right 1;ok
+tcp option sack0 right 1;ok;tcp option sack right 1
+tcp option sack1 right 1;ok
+tcp option sack2 right 1;ok
+tcp option sack3 right 1;ok
+tcp option timestamp exists;ok
+tcp option timestamp length 1;ok
+tcp option timestamp tsval 1;ok
+tcp option timestamp tsecr 1;ok
+tcp option 255 missing;ok
+tcp option 6 exists;ok
+tcp option @255,8,8 255;ok
+
+tcp option foobar;fail
+tcp option foo bar;fail
+tcp option eol left;fail
+tcp option eol left 1;fail
+tcp option sack window;fail
+tcp option sack window 1;fail
+tcp option 256 exists;fail
+tcp option @255,8,8 256;fail
+
+tcp option window exists;ok
+tcp option window missing;ok
+
+tcp option maxseg size set 1360;ok
+
+tcp option md5sig exists;ok
+tcp option fastopen exists;ok
+tcp option mptcp exists;ok
+
+tcp option mptcp subtype 0;ok
+tcp option mptcp subtype 1;ok
+tcp option mptcp subtype { 0, 2};ok
+
+reset tcp option mptcp;ok
+reset tcp option 2;ok;reset tcp option maxseg
+reset tcp option 123;ok
+reset tcp option meh;fail
+reset tcp option 256;fail
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
new file mode 100644
index 0000000..4466f14
--- /dev/null
+++ b/tests/py/any/tcpopt.t.json
@@ -0,0 +1,622 @@
+# tcp option eol exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "eol"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option nop exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "nop"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option maxseg exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "maxseg"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option maxseg length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "maxseg"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option maxseg size 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "size",
+ "name": "maxseg"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option window length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option window count 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "count",
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack-perm exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "sack-perm"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option sack-perm length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "sack-perm"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option sack length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack0 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack1 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack1"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack2 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack2"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack3 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack3"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack0 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack1 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack1"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack2 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack2"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack3 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack3"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option timestamp exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option timestamp length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option timestamp tsval 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "tsval",
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option timestamp tsecr 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "tsecr",
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option 255 missing
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 255,
+ "len": 8,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# tcp option 6 exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 6,
+ "len": 8,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option @255,8,8 255
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 255,
+ "len": 8,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": 255
+ }
+ }
+]
+
+# tcp option window exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option window missing
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# tcp option maxseg size set 1360
+[
+ {
+ "mangle": {
+ "key": {
+ "tcp option": {
+ "field": "size",
+ "name": "maxseg"
+ }
+ },
+ "value": 1360
+ }
+ }
+]
+
+# tcp option md5sig exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "md5sig"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option fastopen exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "fastopen"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option mptcp exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option mptcp subtype 0
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "subtype",
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# tcp option mptcp subtype 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "subtype",
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option mptcp subtype { 0, 2}
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "subtype",
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 0,
+ 2
+ ]
+ }
+ }
+ }
+]
+
+# reset tcp option mptcp
+[
+ {
+ "reset": {
+ "tcp option": {
+ "name": "mptcp"
+ }
+ }
+ }
+]
+
+# reset tcp option 2
+[
+ {
+ "reset": {
+ "tcp option": {
+ "name": "maxseg"
+ }
+ }
+ }
+]
+
+# reset tcp option 123
+[
+ {
+ "reset": {
+ "tcp option": {
+ "base": 123,
+ "len": 0,
+ "offset": 0
+ }
+ }
+ }
+]
diff --git a/tests/py/any/tcpopt.t.json.output b/tests/py/any/tcpopt.t.json.output
new file mode 100644
index 0000000..ad0d25f
--- /dev/null
+++ b/tests/py/any/tcpopt.t.json.output
@@ -0,0 +1,32 @@
+# tcp option sack0 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack0 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
new file mode 100644
index 0000000..99b8985
--- /dev/null
+++ b/tests/py/any/tcpopt.t.payload
@@ -0,0 +1,202 @@
+# tcp option eol exists
+inet
+ [ exthdr load tcpopt 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option nop exists
+inet
+ [ exthdr load tcpopt 1b @ 1 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg exists
+inet
+ [ exthdr load tcpopt 1b @ 2 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg length 1
+inet
+ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg size 1
+inet
+ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# tcp option window length 1
+inet
+ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window count 1
+inet
+ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-perm exists
+inet
+ [ exthdr load tcpopt 1b @ 4 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-perm length 1
+inet
+ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack exists
+inet
+ [ exthdr load tcpopt 1b @ 5 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack length 1
+inet
+ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp exists
+inet
+ [ exthdr load tcpopt 1b @ 8 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp length 1
+inet
+ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp tsval 1
+inet
+ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp tsecr 1
+inet
+ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option 255 missing
+inet
+ [ exthdr load tcpopt 1b @ 255 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option 6 exists
+inet
+ [ exthdr load tcpopt 1b @ 6 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option @255,8,8 255
+inet
+ [ exthdr load tcpopt 1b @ 255 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# tcp option window exists
+inet
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window missing
+inet
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option maxseg size set 1360
+inet
+ [ immediate reg 1 0x00005005 ]
+ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
+
+# tcp option md5sig exists
+inet
+ [ exthdr load tcpopt 1b @ 19 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option fastopen exists
+inet
+ [ exthdr load tcpopt 1b @ 34 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option mptcp exists
+inet
+ [ exthdr load tcpopt 1b @ 30 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option mptcp subtype 0
+inet
+ [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option mptcp subtype 1
+inet
+ [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# tcp option mptcp subtype { 0, 2}
+__set%d test-inet 3 size 2
+__set%d test-inet 0
+ element 00000000 : 0 [end] element 00000020 : 0 [end]
+inet
+ [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# reset tcp option mptcp
+ip test-ip4 input
+ [ exthdr reset tcpopt 30 ]
+
+# reset tcp option 2
+ip test-ip4 input
+ [ exthdr reset tcpopt 2 ]
+
+# reset tcp option 123
+ip test-ip4 input
+ [ exthdr reset tcpopt 123 ]
diff --git a/tests/py/arp/arp.t b/tests/py/arp/arp.t
new file mode 100644
index 0000000..222b91c
--- /dev/null
+++ b/tests/py/arp/arp.t
@@ -0,0 +1,60 @@
+# filter chains available are: input, output, forward
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*arp;test-arp;input
+*netdev;test-netdev;ingress,egress
+
+arp htype 1;ok
+arp htype != 1;ok
+arp htype 22;ok
+arp htype != 233;ok
+arp htype 33-45;ok
+arp htype != 33-45;ok
+arp htype { 33, 55, 67, 88};ok
+arp htype != { 33, 55, 67, 88};ok
+
+arp ptype 0x0800;ok;arp ptype ip
+
+arp hlen 22;ok
+arp hlen != 233;ok
+arp hlen 33-45;ok
+arp hlen != 33-45;ok
+arp hlen { 33, 55, 67, 88};ok
+arp hlen != { 33, 55, 67, 88};ok
+
+arp plen 22;ok
+arp plen != 233;ok
+arp plen 33-45;ok
+arp plen != 33-45;ok
+arp plen { 33, 55, 67, 88};ok
+arp plen != { 33, 55, 67, 88};ok
+
+arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request};ok
+arp operation != {nak, inreply, inrequest, rreply, rrequest, reply, request};ok
+arp operation 1-2;ok
+arp operation request;ok
+arp operation reply;ok
+arp operation rrequest;ok
+arp operation rreply;ok
+arp operation inrequest;ok
+arp operation inreply;ok
+arp operation nak;ok
+arp operation != request;ok
+arp operation != reply;ok
+arp operation != rrequest;ok
+arp operation != rreply;ok
+arp operation != inrequest;ok
+arp operation != inreply;ok
+arp operation != nak;ok
+
+arp saddr ip 1.2.3.4;ok
+arp daddr ip 4.3.2.1;ok
+arp saddr ether aa:bb:cc:aa:bb:cc;ok
+arp daddr ether aa:bb:cc:aa:bb:cc;ok
+
+arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee;ok
+arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1;ok;arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+
+meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566;ok;iifname "invalid" arp htype 1 arp ptype ip arp hlen 6 arp plen 4 arp daddr ip 192.168.143.16 arp daddr ether set 11:22:33:44:55:66
diff --git a/tests/py/arp/arp.t.json b/tests/py/arp/arp.t.json
new file mode 100644
index 0000000..7ce7609
--- /dev/null
+++ b/tests/py/arp/arp.t.json
@@ -0,0 +1,893 @@
+# arp htype 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# arp htype != 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# arp htype 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# arp htype != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# arp htype 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# arp htype != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# arp htype { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# arp htype != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# arp ptype 0x0800
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ptype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "0x0800"
+ }
+ }
+]
+
+# arp hlen 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# arp hlen != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# arp hlen 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# arp hlen != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# arp hlen { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# arp hlen != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# arp plen 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# arp plen != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# arp plen 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# arp plen != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# arp plen { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# arp plen != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "nak",
+ "inreply",
+ "inrequest",
+ "rreply",
+ "rrequest",
+ "reply",
+ "request"
+ ]
+ }
+ }
+ }
+]
+
+# arp operation != {nak, inreply, inrequest, rreply, rrequest, reply, request}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "nak",
+ "inreply",
+ "inrequest",
+ "rreply",
+ "rrequest",
+ "reply",
+ "request"
+ ]
+ }
+ }
+ }
+]
+
+# arp operation 1-2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ "request",
+ "reply"
+ ]
+ }
+ }
+ }
+]
+
+# arp operation request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "request"
+ }
+ }
+]
+
+# arp operation reply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "reply"
+ }
+ }
+]
+
+# arp operation rrequest
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "rrequest"
+ }
+ }
+]
+
+# arp operation rreply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "rreply"
+ }
+ }
+]
+
+# arp operation inrequest
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "inrequest"
+ }
+ }
+]
+
+# arp operation inreply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "inreply"
+ }
+ }
+]
+
+# arp operation nak
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "nak"
+ }
+ }
+]
+
+# arp operation != request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": "request"
+ }
+ }
+]
+
+# arp operation != reply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": "reply"
+ }
+ }
+]
+
+# arp operation != rrequest
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": "rrequest"
+ }
+ }
+]
+
+# arp operation != rreply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": "rreply"
+ }
+ }
+]
+
+# arp operation != inrequest
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": "inrequest"
+ }
+ }
+]
+
+# arp operation != inreply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": "inreply"
+ }
+ }
+]
+
+# arp operation != nak
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": "nak"
+ }
+ }
+]
+
+# arp saddr ip 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
+# arp daddr ip 4.3.2.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "4.3.2.1"
+ }
+ }
+]
+
+# arp saddr ether aa:bb:cc:aa:bb:cc
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "aa:bb:cc:aa:bb:cc"
+ }
+ }
+]
+
+# arp daddr ether aa:bb:cc:aa:bb:cc
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "aa:bb:cc:aa:bb:cc"
+ }
+ }
+]
+
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ }
+]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ }
+]
+
+# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "invalid"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ptype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "0x0800"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 4
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "nh",
+ "len": 32,
+ "offset": 192
+ }
+ },
+ "op": "==",
+ "right": "0xc0a88f10"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "base": "nh",
+ "len": 48,
+ "offset": 144
+ }
+ },
+ "value": "0x112233445566"
+ }
+ }
+]
+
diff --git a/tests/py/arp/arp.t.json.output b/tests/py/arp/arp.t.json.output
new file mode 100644
index 0000000..afa75b2
--- /dev/null
+++ b/tests/py/arp/arp.t.json.output
@@ -0,0 +1,180 @@
+# arp ptype 0x0800
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ptype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ }
+]
+
+# arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "request",
+ "reply",
+ "rrequest",
+ "rreply",
+ "inrequest",
+ "inreply",
+ "nak"
+ ]
+ }
+ }
+ }
+]
+
+# arp operation != {nak, inreply, inrequest, rreply, rrequest, reply, request}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "operation",
+ "protocol": "arp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "request",
+ "reply",
+ "rrequest",
+ "rreply",
+ "inrequest",
+ "inreply",
+ "nak"
+ ]
+ }
+ }
+ }
+]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ }
+]
+
+# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "invalid"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "htype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ptype",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hlen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "plen",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": 4
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.143.16"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "value": "11:22:33:44:55:66"
+ }
+ }
+]
+
diff --git a/tests/py/arp/arp.t.payload b/tests/py/arp/arp.t.payload
new file mode 100644
index 0000000..d56927b
--- /dev/null
+++ b/tests/py/arp/arp.t.payload
@@ -0,0 +1,261 @@
+# arp htype 1
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# arp htype != 1
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000100 ]
+
+# arp htype 22
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# arp htype != 233
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# arp htype 33-45
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# arp htype != 33-45
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# arp htype { 33, 55, 67, 88}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp htype != { 33, 55, 67, 88}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+arp test-arp input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp ptype 0x0800
+arp test-arp input
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# arp hlen 22
+arp test-arp input
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# arp hlen != 233
+arp test-arp input
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# arp hlen 33-45
+arp test-arp input
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# arp hlen != 33-45
+arp test-arp input
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# arp hlen { 33, 55, 67, 88}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+arp test-arp input
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp hlen != { 33, 55, 67, 88}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+arp test-arp input
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp plen 22
+arp test-arp input
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# arp plen != 233
+arp test-arp input
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# arp plen 33-45
+arp test-arp input
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# arp plen != 33-45
+arp test-arp input
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# arp plen { 33, 55, 67, 88}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+arp test-arp input
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp plen != { 33, 55, 67, 88}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+arp test-arp input
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00000a00 : 0 [end] element 00000900 : 0 [end] element 00000800 : 0 [end] element 00000400 : 0 [end] element 00000300 : 0 [end] element 00000200 : 0 [end] element 00000100 : 0 [end]
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp operation != {nak, inreply, inrequest, rreply, rrequest, reply, request}
+__set%d test-arp 3
+__set%d test-arp 0
+ element 00000a00 : 0 [end] element 00000900 : 0 [end] element 00000800 : 0 [end] element 00000400 : 0 [end] element 00000300 : 0 [end] element 00000200 : 0 [end] element 00000100 : 0 [end]
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp operation 1-2
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00000100 ]
+ [ cmp lte reg 1 0x00000200 ]
+
+# arp operation request
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# arp operation reply
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# arp operation rrequest
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000300 ]
+
+# arp operation rreply
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000400 ]
+
+# arp operation inrequest
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000800 ]
+
+# arp operation inreply
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000900 ]
+
+# arp operation nak
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000a00 ]
+
+# arp operation != request
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000100 ]
+
+# arp operation != reply
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000200 ]
+
+# arp operation != rrequest
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000300 ]
+
+# arp operation != rreply
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000400 ]
+
+# arp operation != inrequest
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000800 ]
+
+# arp operation != inreply
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000900 ]
+
+# arp operation != nak
+arp test-arp input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000a00 ]
+
+# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
+arp test-arp input
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x61766e69 0x0064696c 0x00000000 0x00000000 ]
+ [ payload load 4b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00080100 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000406 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x108fa8c0 ]
+ [ immediate reg 1 0x44332211 0x00006655 ]
+ [ payload write reg 1 => 6b @ network header + 18 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# arp saddr ip 1.2.3.4
+arp test-arp input
+ [ payload load 4b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+
+# arp daddr ip 4.3.2.1
+arp test-arp input
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x01020304 ]
+
+# arp saddr ether aa:bb:cc:aa:bb:cc
+arp test-arp input
+ [ payload load 6b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+
+# arp daddr ether aa:bb:cc:aa:bb:cc
+arp test-arp input
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+arp
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+arp
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
diff --git a/tests/py/arp/arp.t.payload.netdev b/tests/py/arp/arp.t.payload.netdev
new file mode 100644
index 0000000..92df240
--- /dev/null
+++ b/tests/py/arp/arp.t.payload.netdev
@@ -0,0 +1,351 @@
+# arp htype 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# arp htype != 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000100 ]
+
+# arp htype 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# arp htype != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# arp htype 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# arp htype != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# arp htype { 33, 55, 67, 88}
+__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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp htype != { 33, 55, 67, 88}
+__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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp ptype 0x0800
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# arp hlen 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# arp hlen != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# arp hlen 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# arp hlen != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# arp hlen { 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 test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp hlen != { 33, 55, 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 test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp plen 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# arp plen != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# arp plen 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# arp plen != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# arp plen { 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 test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp plen != { 33, 55, 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 test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00000a00 : 0 [end] element 00000900 : 0 [end] element 00000800 : 0 [end] element 00000400 : 0 [end] element 00000300 : 0 [end] element 00000200 : 0 [end] element 00000100 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# arp operation != {nak, inreply, inrequest, rreply, rrequest, reply, request}
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00000a00 : 0 [end] element 00000900 : 0 [end] element 00000800 : 0 [end] element 00000400 : 0 [end] element 00000300 : 0 [end] element 00000200 : 0 [end] element 00000100 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# arp operation 1-2
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00000100 ]
+ [ cmp lte reg 1 0x00000200 ]
+
+# arp operation request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# arp operation reply
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# arp operation rrequest
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000300 ]
+
+# arp operation rreply
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000400 ]
+
+# arp operation inrequest
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000800 ]
+
+# arp operation inreply
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000900 ]
+
+# arp operation nak
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000a00 ]
+
+# arp operation != request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000100 ]
+
+# arp operation != reply
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000200 ]
+
+# arp operation != rrequest
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000300 ]
+
+# arp operation != rreply
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000400 ]
+
+# arp operation != inrequest
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000800 ]
+
+# arp operation != inreply
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000900 ]
+
+# arp operation != nak
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000a00 ]
+
+# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
+netdev test-netdev ingress
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x61766e69 0x0064696c 0x00000000 0x00000000 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 4b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00080100 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000406 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x108fa8c0 ]
+ [ immediate reg 1 0x44332211 0x00006655 ]
+ [ payload write reg 1 => 6b @ network header + 18 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# arp saddr ip 1.2.3.4
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 4b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+
+# arp daddr ip 4.3.2.1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x01020304 ]
+
+# arp saddr ether aa:bb:cc:aa:bb:cc
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 6b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+
+# arp daddr ether aa:bb:cc:aa:bb:cc
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
diff --git a/tests/py/arp/chains.t b/tests/py/arp/chains.t
new file mode 100644
index 0000000..1ea39f7
--- /dev/null
+++ b/tests/py/arp/chains.t
@@ -0,0 +1,5 @@
+# filter chains available are: input, output
+:input;type filter hook input priority 0
+:output;type filter hook output priority 0
+
+*arp;test-arp;input,output
diff --git a/tests/py/arp/chains.t.payload b/tests/py/arp/chains.t.payload
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/py/arp/chains.t.payload
diff --git a/tests/py/bridge/chains.t b/tests/py/bridge/chains.t
new file mode 100644
index 0000000..e071d9a
--- /dev/null
+++ b/tests/py/bridge/chains.t
@@ -0,0 +1,8 @@
+# filter chains available are: prerouting, input, output, forward, postrouting
+:filter-pre;type filter hook prerouting priority 0
+:filter-output;type filter hook output priority 0
+:filter-forward;type filter hook forward priority 0
+:filter-input;type filter hook input priority 0
+:filter-post;type filter hook postrouting priority 0
+
+*bridge;test-bridge;filter-pre,filter-output,filter-forward,filter-input,filter-post
diff --git a/tests/py/bridge/chains.t.payload b/tests/py/bridge/chains.t.payload
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/py/bridge/chains.t.payload
diff --git a/tests/py/bridge/ether.t b/tests/py/bridge/ether.t
new file mode 100644
index 0000000..e4f75d1
--- /dev/null
+++ b/tests/py/bridge/ether.t
@@ -0,0 +1,12 @@
+:input;type filter hook input priority 0
+
+*bridge;test-bridge;input
+
+tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04 accept
+tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04;ok
+tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4;ok
+ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept;ok
+
+ether daddr 00:01:02:03:04:05 ether saddr set ff:fe:dc:ba:98:76 drop;ok
+
+ether daddr set {01:00:5e:00:01:01, 01:00:5e:00:02:02};fail
diff --git a/tests/py/bridge/ether.t.json b/tests/py/bridge/ether.t.json
new file mode 100644
index 0000000..485ceee
--- /dev/null
+++ b/tests/py/bridge/ether.t.json
@@ -0,0 +1,193 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ }
+]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
+# ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether daddr 00:01:02:03:04:05 ether saddr set ff:fe:dc:ba:98:76 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:05"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "value": "ff:fe:dc:ba:98:76"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
diff --git a/tests/py/bridge/ether.t.json.output b/tests/py/bridge/ether.t.json.output
new file mode 100644
index 0000000..5bb2e47
--- /dev/null
+++ b/tests/py/bridge/ether.t.json.output
@@ -0,0 +1,43 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/bridge/ether.t.payload b/tests/py/bridge/ether.t.payload
new file mode 100644
index 0000000..eaff9c3
--- /dev/null
+++ b/tests/py/bridge/ether.t.payload
@@ -0,0 +1,60 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+bridge test-bridge input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
+bridge test-bridge input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4
+bridge test-bridge input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+
+# ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept
+bridge test-bridge input
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ immediate reg 0 accept ]
+
+# ether daddr 00:01:02:03:04:05 ether saddr set ff:fe:dc:ba:98:76 drop
+bridge test-bridge input
+ [ payload load 6b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00000504 ]
+ [ immediate reg 1 0xbadcfeff 0x00007698 ]
+ [ payload write reg 1 => 6b @ link header + 6 csum_type 0 csum_off 0 csum_flags 0x0 ]
+ [ immediate reg 0 drop ]
+
diff --git a/tests/py/bridge/icmpX.t b/tests/py/bridge/icmpX.t
new file mode 100644
index 0000000..7c35c26
--- /dev/null
+++ b/tests/py/bridge/icmpX.t
@@ -0,0 +1,8 @@
+:input;type filter hook input priority 0
+
+*bridge;test-bridge;input
+
+ip protocol icmp icmp type echo-request;ok;ip protocol 1 icmp type echo-request
+icmp type echo-request;ok
+ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;ip6 nexthdr 58 icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/bridge/icmpX.t.json b/tests/py/bridge/icmpX.t.json
new file mode 100644
index 0000000..2dd341e
--- /dev/null
+++ b/tests/py/bridge/icmpX.t.json
@@ -0,0 +1,88 @@
+# ip protocol icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "icmpv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
diff --git a/tests/py/bridge/icmpX.t.json.output b/tests/py/bridge/icmpX.t.json.output
new file mode 100644
index 0000000..8cf4679
--- /dev/null
+++ b/tests/py/bridge/icmpX.t.json.output
@@ -0,0 +1,56 @@
+# ip protocol icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": 58
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
diff --git a/tests/py/bridge/icmpX.t.payload b/tests/py/bridge/icmpX.t.payload
new file mode 100644
index 0000000..f9ea7b6
--- /dev/null
+++ b/tests/py/bridge/icmpX.t.payload
@@ -0,0 +1,36 @@
+# ip protocol icmp icmp type echo-request
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# icmpv6 type echo-request
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
diff --git a/tests/py/bridge/meta.t b/tests/py/bridge/meta.t
new file mode 100644
index 0000000..171aa61
--- /dev/null
+++ b/tests/py/bridge/meta.t
@@ -0,0 +1,13 @@
+:input;type filter hook input priority 0
+
+*bridge;test-bridge;input
+
+meta obrname "br0";ok
+meta ibrname "br0";ok
+meta ibrvproto vlan;ok;meta ibrvproto 8021q
+meta ibrpvid 100;ok
+
+meta protocol ip udp dport 67;ok
+meta protocol ip6 udp dport 67;ok
+
+meta broute set 1;fail
diff --git a/tests/py/bridge/meta.t.json b/tests/py/bridge/meta.t.json
new file mode 100644
index 0000000..d7dc9d7
--- /dev/null
+++ b/tests/py/bridge/meta.t.json
@@ -0,0 +1,105 @@
+# meta obrname "br0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "obrname" }
+ },
+ "op": "==",
+ "right": "br0"
+ }
+ }
+]
+
+# meta ibrname "br0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "ibrname" }
+ },
+ "op": "==",
+ "right": "br0"
+ }
+ }
+]
+
+# meta ibrvproto vlan
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "ibrvproto" }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ }
+]
+
+# meta ibrpvid 100
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "ibrpvid" }
+ },
+ "op": "==",
+ "right": 100
+ }
+ }
+]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
diff --git a/tests/py/bridge/meta.t.payload b/tests/py/bridge/meta.t.payload
new file mode 100644
index 0000000..0a39842
--- /dev/null
+++ b/tests/py/bridge/meta.t.payload
@@ -0,0 +1,37 @@
+# meta obrname "br0"
+bridge test-bridge input
+ [ meta load bri_oifname => reg 1 ]
+ [ cmp eq reg 1 0x00307262 0x00000000 0x00000000 0x00000000 ]
+
+# meta ibrname "br0"
+bridge test-bridge input
+ [ meta load bri_iifname => reg 1 ]
+ [ cmp eq reg 1 0x00307262 0x00000000 0x00000000 0x00000000 ]
+
+# meta ibrvproto vlan
+bridge test-bridge input
+ [ meta load bri_iifvproto => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+
+# meta ibrpvid 100
+bridge test-bridge input
+ [ meta load bri_iifpvid => reg 1 ]
+ [ cmp eq reg 1 0x00000064 ]
+
+# meta protocol ip udp dport 67
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta protocol ip6 udp dport 67
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
diff --git a/tests/py/bridge/redirect.t b/tests/py/bridge/redirect.t
new file mode 100644
index 0000000..5181e79
--- /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 0000000..7e32b32
--- /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 0000000..1fcfa5f
--- /dev/null
+++ b/tests/py/bridge/redirect.t.payload
@@ -0,0 +1,4 @@
+# meta broute set 1
+bridge test-bridge prerouting
+ [ immediate reg 1 0x00000001 ]
+ [ meta set broute with reg 1 ]
diff --git a/tests/py/bridge/reject.t b/tests/py/bridge/reject.t
new file mode 100644
index 0000000..336b51b
--- /dev/null
+++ b/tests/py/bridge/reject.t
@@ -0,0 +1,42 @@
+:input;type filter hook input priority 0
+
+*bridge;test-bridge;input
+
+# The output is specific for bridge family
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok
+
+mark 12345 ip protocol tcp reject with tcp reset;ok;meta mark 0x00003039 ip protocol 6 reject with tcp reset
+
+reject;ok
+ether type ip reject;ok;reject with icmp port-unreachable
+ether type ip6 reject;ok;reject with icmpv6 port-unreachable
+
+reject with icmpx host-unreachable;ok
+reject with icmpx no-route;ok
+reject with icmpx admin-prohibited;ok
+reject with icmpx port-unreachable;ok;reject
+
+ether type ipv6 reject with icmp host-unreachable;fail
+ether type ip6 reject with icmp host-unreachable;fail
+ether type ip reject with icmpv6 no-route;fail
+ether type vlan reject;ok;ether type 8021q reject
+ether type arp reject;fail
+ether type vlan reject with tcp reset;ok;meta l4proto 6 ether type 8021q reject with tcp reset
+ether type arp reject with tcp reset;fail
+ip protocol udp reject with tcp reset;fail
+
+ether type ip reject with icmpx admin-prohibited;ok
+ether type ip6 reject with icmpx admin-prohibited;ok
+ether type 8021q reject with icmpx admin-prohibited;ok
+ether type arp reject with icmpx admin-prohibited;fail
diff --git a/tests/py/bridge/reject.t.json b/tests/py/bridge/reject.t.json
new file mode 100644
index 0000000..9f9e6c1
--- /dev/null
+++ b/tests/py/bridge/reject.t.json
@@ -0,0 +1,341 @@
+# reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-unreachable
+[
+ {
+ "reject": {
+ "expr": "net-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp prot-unreachable
+[
+ {
+ "reject": {
+ "expr": "prot-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-prohibited
+[
+ {
+ "reject": {
+ "expr": "net-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp host-prohibited
+[
+ {
+ "reject": {
+ "expr": "host-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 addr-unreachable
+[
+ {
+ "reject": {
+ "expr": "addr-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# mark 12345 ip protocol tcp reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# reject
+[
+ {
+ "reject": null
+ }
+]
+
+# ether type ip reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "reject": null
+ }
+]
+
+# ether type ip6 reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "reject": null
+ }
+]
+
+# reject with icmpx host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# ether type ip reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# ether type ip6 reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# ether type vlan reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# ether type vlan reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "vlan"
+ }
+ },
+ {
+ "reject": null
+ }
+]
+
+# ether type 8021q reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
diff --git a/tests/py/bridge/reject.t.json.output b/tests/py/bridge/reject.t.json.output
new file mode 100644
index 0000000..b8a44f0
--- /dev/null
+++ b/tests/py/bridge/reject.t.json.output
@@ -0,0 +1,83 @@
+# mark 12345 ip protocol tcp reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# ether type ip reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# ether type ip6 reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# ether type vlan reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
diff --git a/tests/py/bridge/reject.t.payload b/tests/py/bridge/reject.t.payload
new file mode 100644
index 0000000..bad9adc
--- /dev/null
+++ b/tests/py/bridge/reject.t.payload
@@ -0,0 +1,140 @@
+# reject with icmp host-unreachable
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 1 ]
+
+# reject with icmp net-unreachable
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 0 ]
+
+# reject with icmp prot-unreachable
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 2 ]
+
+# reject with icmp port-unreachable
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 3 ]
+
+# reject with icmp net-prohibited
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 9 ]
+
+# reject with icmp host-prohibited
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 10 ]
+
+# reject with icmp admin-prohibited
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 13 ]
+
+# reject with icmpv6 no-route
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 0 ]
+
+# reject with icmpv6 admin-prohibited
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 1 ]
+
+# reject with icmpv6 addr-unreachable
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 3 ]
+
+# reject with icmpv6 port-unreachable
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 4 ]
+
+# mark 12345 ip protocol tcp reject with tcp reset
+bridge test-bridge input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00003039 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ reject type 1 code 0 ]
+
+# reject
+bridge test-bridge input
+ [ reject type 2 code 1 ]
+
+# ether type ip reject
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 3 ]
+
+# ether type ip6 reject
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 4 ]
+
+# reject with icmpx host-unreachable
+bridge test-bridge input
+ [ reject type 2 code 2 ]
+
+# reject with icmpx no-route
+bridge test-bridge input
+ [ reject type 2 code 0 ]
+
+# reject with icmpx admin-prohibited
+bridge test-bridge input
+ [ reject type 2 code 3 ]
+
+# reject with icmpx port-unreachable
+bridge test-bridge input
+ [ reject type 2 code 1 ]
+
+# ether type ip reject with icmpx admin-prohibited
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 2 code 3 ]
+
+# ether type ip6 reject with icmpx admin-prohibited
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 2 code 3 ]
+
+# ether type vlan reject
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 2 code 1 ]
+
+# ether type vlan reject with tcp reset
+bridge
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 1 code 0 ]
+
+# ether type 8021q reject with icmpx admin-prohibited
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 2 code 3 ]
+
diff --git a/tests/py/bridge/vlan.t b/tests/py/bridge/vlan.t
new file mode 100644
index 0000000..8fa90da
--- /dev/null
+++ b/tests/py/bridge/vlan.t
@@ -0,0 +1,56 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress,egress
+
+vlan id 4094;ok
+vlan id 0;ok
+# bad vlan id
+vlan id 4096;fail
+vlan id 4094 vlan dei 0;ok
+vlan id 4094 vlan dei 1;ok
+vlan id 4094 vlan dei != 1;ok
+vlan id 4094 vlan cfi 1;ok;vlan id 4094 vlan dei 1
+# bad dei
+vlan id 4094 vlan dei 2;fail
+vlan id 4094 vlan dei 1 vlan pcp 8;fail
+vlan id 4094 vlan dei 1 vlan pcp 7;ok
+vlan id 4094 vlan dei 1 vlan pcp 3;ok
+
+ether type vlan vlan id 4094;ok;vlan id 4094
+ether type vlan vlan id 0;ok;vlan id 0
+ether type vlan vlan id 4094 vlan dei 0;ok;vlan id 4094 vlan dei 0
+ether type vlan vlan id 4094 vlan dei 1;ok;vlan id 4094 vlan dei 1
+ether type vlan vlan id 4094 vlan dei 2;fail
+
+vlan id 4094 tcp dport 22;ok
+vlan id 1 ip saddr 10.0.0.1;ok
+vlan id 1 ip saddr 10.0.0.0/23;ok
+vlan id 1 ip saddr 10.0.0.0/23 udp dport 53;ok
+ether type vlan vlan id 1 ip saddr 10.0.0.0/23 udp dport 53;ok;vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
+
+vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3;ok
+vlan id { 1, 2, 4, 100, 4096 };fail
+
+ether type vlan ip protocol 1 accept;ok;ether type 8021q ip protocol 1 accept
+
+# IEEE 802.1AD
+ether type 8021ad vlan id 1 ip protocol 6 accept;ok
+ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter;ok
+ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6;ok;ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 ip protocol 6
+
+# illegal dependencies
+ether type ip vlan id 1;fail
+ether type ip vlan id 1 ip saddr 10.0.0.1;fail
+
+# mangling
+vlan id 1 vlan id set 2;ok
+
+ether saddr 00:01:02:03:04:05 vlan id 1;ok
+vlan id 2 ether saddr 0:1:2:3:4:6;ok;ether saddr 00:01:02:03:04:06 vlan id 2
+
+ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 };ok
+
+ether saddr 00:11:22:33:44:55 counter ether type 8021q;ok
diff --git a/tests/py/bridge/vlan.t.json b/tests/py/bridge/vlan.t.json
new file mode 100644
index 0000000..7dfcdb4
--- /dev/null
+++ b/tests/py/bridge/vlan.t.json
@@ -0,0 +1,894 @@
+# vlan id 4094
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ }
+]
+
+# vlan id 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# vlan id 4094 vlan dei 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# vlan id 4094 vlan dei 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 4094 vlan dei != 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 4094 vlan cfi 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 4094 vlan dei 1 vlan pcp 7
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "pcp",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 7
+ }
+ }
+]
+
+# vlan id 4094 vlan dei 1 vlan pcp 3
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "pcp",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 3
+ }
+ }
+]
+
+# ether type vlan vlan id 4094
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ }
+]
+
+# ether type vlan vlan id 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# ether type vlan vlan id 4094 vlan dei 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# ether type vlan vlan id 4094 vlan dei 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 4094 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# vlan id 1 ip saddr 10.0.0.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "10.0.0.1"
+ }
+ }
+]
+
+# vlan id 1 ip saddr 10.0.0.0/23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 23
+ }
+ }
+ }
+ }
+]
+
+# vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 23
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ }
+]
+
+# ether type vlan vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 23
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ }
+]
+
+# vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1,
+ 2,
+ 4,
+ 100,
+ 4095
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "pcp",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 1, 3 ]
+ }
+ }
+ }
+]
+
+# ether type vlan ip protocol 1 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "vlan"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ }
+]
+
+# vlan id 1 vlan id set 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "value": 2
+ }
+ }
+]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:05"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:06"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 42
+ ]
+ },
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 4095
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ether saddr 00:11:22:33:44:55 counter ether type 8021q
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:11:22:33:44:55"
+ }
+ },
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.json.output b/tests/py/bridge/vlan.t.json.output
new file mode 100644
index 0000000..2f90c8f
--- /dev/null
+++ b/tests/py/bridge/vlan.t.json.output
@@ -0,0 +1,204 @@
+# ether type vlan ip protocol 1 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "counter": null
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.payload b/tests/py/bridge/vlan.t.payload
new file mode 100644
index 0000000..2592bb9
--- /dev/null
+++ b/tests/py/bridge/vlan.t.payload
@@ -0,0 +1,314 @@
+# vlan id 4094
+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 0x0000fe0f ]
+
+# vlan id 0
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# vlan id 4094 vlan cfi 1
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# vlan id 4094 vlan dei 0
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# vlan id 4094 vlan dei != 1
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000010 ]
+
+# vlan id 4094 vlan dei 1
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# ether type vlan vlan id 4094
+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 0x0000fe0f ]
+
+# ether type vlan vlan id 0
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ether type vlan vlan id 4094 vlan dei 0
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ether type vlan vlan id 4094 vlan dei 1
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# vlan id 4094 tcp dport 22
+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 0x0000fe0f ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# vlan id 1 ip saddr 10.0.0.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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0100000a ]
+
+# vlan id 1 ip saddr 10.0.0.0/23
+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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000a ]
+
+# vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
+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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+
+# ether type vlan vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
+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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+
+# vlan id 4094 vlan dei 1 vlan pcp 7
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x000000e0 ]
+
+# vlan id 4094 vlan dei 1 vlan pcp 3
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000060 ]
+
+# vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3
+__set%d test-bridge 3
+__set%d test-bridge 0
+ element 00000100 : 0 [end] element 00000200 : 0 [end] element 00000400 : 0 [end] element 00006400 : 0 [end] element 0000ff0f : 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 __set%d ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ cmp gte reg 1 0x00000020 ]
+ [ cmp lte reg 1 0x00000060 ]
+
+# ether type vlan ip protocol 1 accept
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 accept ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# vlan id 1 vlan id set 2
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
+ [ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-bridge 3 size 2
+__set%d test-bridge 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ether saddr 00:11:22:33:44:55 counter ether type 8021q
+bridge test-bridge input
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x33221100 0x00005544 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
diff --git a/tests/py/bridge/vlan.t.payload.netdev b/tests/py/bridge/vlan.t.payload.netdev
new file mode 100644
index 0000000..f334194
--- /dev/null
+++ b/tests/py/bridge/vlan.t.payload.netdev
@@ -0,0 +1,368 @@
+# vlan id 4094
+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 0x0000fe0f ]
+
+# vlan id 0
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# vlan id 4094 vlan dei 0
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# vlan id 4094 vlan dei != 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000010 ]
+
+# vlan id 4094 vlan cfi 1
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# vlan id 4094 vlan dei 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# ether type vlan vlan id 4094
+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 0x0000fe0f ]
+
+# ether type vlan vlan id 0
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ether type vlan vlan id 4094 vlan dei 0
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ether type vlan vlan id 4094 vlan dei 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# vlan id 4094 tcp dport 22
+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 0x0000fe0f ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# vlan id 1 ip saddr 10.0.0.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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0100000a ]
+
+# vlan id 1 ip saddr 10.0.0.0/23
+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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000a ]
+
+# vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
+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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+
+# ether type vlan vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
+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 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+
+# vlan id 4094 vlan dei 1 vlan pcp 7
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x000000e0 ]
+
+# vlan id 4094 vlan dei 1 vlan pcp 3
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000060 ]
+
+# vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00000100 : 0 [end] element 00000200 : 0 [end] element 00000400 : 0 [end] element 00006400 : 0 [end] element 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 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ cmp gte reg 1 0x00000020 ]
+ [ cmp lte reg 1 0x00000060 ]
+
+# ether type vlan ip protocol 1 accept
+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 + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 accept ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# vlan id 1 vlan id set 2
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
+ [ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-netdev 3 size 2
+__set%d test-netdev 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ether saddr 00:11:22:33:44:55 counter ether type 8021q
+bridge test-bridge input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x33221100 0x00005544 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
diff --git a/tests/py/inet/ah.t b/tests/py/inet/ah.t
new file mode 100644
index 0000000..83b6202
--- /dev/null
+++ b/tests/py/inet/ah.t
@@ -0,0 +1,47 @@
+: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
+
+- ah nexthdr esp;ok
+- ah nexthdr ah;ok
+- ah nexthdr comp;ok
+- ah nexthdr udp;ok
+- ah nexthdr udplite;ok
+- ah nexthdr tcp;ok
+- ah nexthdr dccp;ok
+- ah nexthdr sctp;ok
+
+- ah nexthdr { esp, ah, comp, udp, udplite, tcp, dccp, sctp};ok;ah nexthdr { 6, 132, 50, 17, 136, 33, 51, 108}
+- ah nexthdr != { esp, ah, comp, udp, udplite, tcp, dccp, sctp};ok
+
+ah hdrlength 11-23;ok
+ah hdrlength != 11-23;ok
+ah hdrlength {11, 23, 44 };ok
+ah hdrlength != {11, 23, 44 };ok
+
+ah reserved 22;ok
+ah reserved != 233;ok
+ah reserved 33-45;ok
+ah reserved != 33-45;ok
+ah reserved {23, 100};ok
+ah reserved != {23, 100};ok
+
+ah spi 111;ok
+ah spi != 111;ok
+ah spi 111-222;ok
+ah spi != 111-222;ok
+ah spi {111, 122};ok
+ah spi != {111, 122};ok
+
+# sequence
+ah sequence 123;ok
+ah sequence != 123;ok
+ah sequence {23, 25, 33};ok
+ah sequence != {23, 25, 33};ok
+ah sequence 23-33;ok
+ah sequence != 23-33;ok
diff --git a/tests/py/inet/ah.t.json b/tests/py/inet/ah.t.json
new file mode 100644
index 0000000..217280b
--- /dev/null
+++ b/tests/py/inet/ah.t.json
@@ -0,0 +1,412 @@
+# ah hdrlength 11-23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 11, 23 ]
+ }
+ }
+ }
+]
+
+# ah hdrlength != 11-23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 11, 23 ]
+ }
+ }
+ }
+]
+
+# ah hdrlength {11, 23, 44 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 11,
+ 23,
+ 44
+ ]
+ }
+ }
+ }
+]
+
+# ah hdrlength != {11, 23, 44 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 11,
+ 23,
+ 44
+ ]
+ }
+ }
+ }
+]
+
+# ah reserved 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "reserved",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ah reserved != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "reserved",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ah reserved 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "reserved",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ah reserved != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "reserved",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ah reserved {23, 100}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "reserved",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 100
+ ]
+ }
+ }
+ }
+]
+
+# ah reserved != {23, 100}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "reserved",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 100
+ ]
+ }
+ }
+ }
+]
+
+# ah spi 111
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": 111
+ }
+ }
+]
+
+# ah spi != 111
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": 111
+ }
+ }
+]
+
+# ah spi 111-222
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 111, 222 ]
+ }
+ }
+ }
+]
+
+# ah spi != 111-222
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 111, 222 ]
+ }
+ }
+ }
+]
+
+# ah spi {111, 122}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 111,
+ 122
+ ]
+ }
+ }
+ }
+]
+
+# ah spi != {111, 122}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 111,
+ 122
+ ]
+ }
+ }
+ }
+]
+
+# ah sequence 123
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": 123
+ }
+ }
+]
+
+# ah sequence != 123
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": 123
+ }
+ }
+]
+
+# ah sequence {23, 25, 33}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 25,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# ah sequence != {23, 25, 33}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 25,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# ah sequence 23-33
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "ah"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 23, 33 ]
+ }
+ }
+ }
+]
+
+# ah sequence != 23-33
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "ah"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 23, 33 ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/ah.t.payload b/tests/py/inet/ah.t.payload
new file mode 100644
index 0000000..7ddd72d
--- /dev/null
+++ b/tests/py/inet/ah.t.payload
@@ -0,0 +1,182 @@
+# ah hdrlength 11-23
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp gte reg 1 0x0000000b ]
+ [ cmp lte reg 1 0x00000017 ]
+
+# ah hdrlength != 11-23
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ range neq reg 1 0x0000000b 0x00000017 ]
+
+# ah hdrlength {11, 23, 44 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0000000b : 0 [end] element 00000017 : 0 [end] element 0000002c : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ah hdrlength != {11, 23, 44 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0000000b : 0 [end] element 00000017 : 0 [end] element 0000002c : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ah reserved 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ah reserved != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ah reserved 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ah reserved != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ah reserved {23, 100}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00006400 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ah reserved != {23, 100}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00006400 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ah spi 111
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x6f000000 ]
+
+# ah spi != 111
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x6f000000 ]
+
+# ah spi 111-222
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x6f000000 ]
+ [ cmp lte reg 1 0xde000000 ]
+
+# ah spi != 111-222
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x6f000000 0xde000000 ]
+
+# ah spi {111, 122}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 6f000000 : 0 [end] element 7a000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ah spi != {111, 122}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 6f000000 : 0 [end] element 7a000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ah sequence 123
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x7b000000 ]
+
+# ah sequence != 123
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp neq reg 1 0x7b000000 ]
+
+# ah sequence {23, 25, 33}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 17000000 : 0 [end] element 19000000 : 0 [end] element 21000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ah sequence != {23, 25, 33}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 17000000 : 0 [end] element 19000000 : 0 [end] element 21000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ah sequence 23-33
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp gte reg 1 0x17000000 ]
+ [ cmp lte reg 1 0x21000000 ]
+
+# ah sequence != 23-33
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ range neq reg 1 0x17000000 0x21000000 ]
+
diff --git a/tests/py/inet/comp.t b/tests/py/inet/comp.t
new file mode 100644
index 0000000..2ef5382
--- /dev/null
+++ b/tests/py/inet/comp.t
@@ -0,0 +1,30 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+# BUG: nft: payload.c:88: payload_expr_pctx_update: Assertion `left->payload.base + 1 <= (__PROTO_BASE_MAX - 1)' failed.
+- comp nexthdr esp;ok;comp nexthdr 50
+comp nexthdr != esp;ok;comp nexthdr != 50
+
+- comp nexthdr {esp, ah, comp, udp, udplite, tcp, tcp, dccp, sctp};ok
+# comp flags ## 8-bit field. Reserved for future use. MUST be set to zero.
+
+# Bug comp flags: to list. List the decimal value.
+comp flags 0x0;ok
+comp flags != 0x23;ok
+comp flags 0x33-0x45;ok
+comp flags != 0x33-0x45;ok
+comp flags {0x33, 0x55, 0x67, 0x88};ok
+comp flags != {0x33, 0x55, 0x67, 0x88};ok
+
+comp cpi 22;ok
+comp cpi != 233;ok
+comp cpi 33-45;ok
+comp cpi != 33-45;ok
+comp cpi {33, 55, 67, 88};ok
+comp cpi != {33, 55, 67, 88};ok
diff --git a/tests/py/inet/comp.t.json b/tests/py/inet/comp.t.json
new file mode 100644
index 0000000..c9f6fca
--- /dev/null
+++ b/tests/py/inet/comp.t.json
@@ -0,0 +1,244 @@
+# comp nexthdr != esp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": "esp"
+ }
+ }
+]
+
+# comp flags 0x0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": "0x0"
+ }
+ }
+]
+
+# comp flags != 0x23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": "0x23"
+ }
+ }
+]
+
+# comp flags 0x33-0x45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "0x33", "0x45" ]
+ }
+ }
+ }
+]
+
+# comp flags != 0x33-0x45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "0x33", "0x45" ]
+ }
+ }
+ }
+]
+
+# comp flags {0x33, 0x55, 0x67, 0x88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "0x33",
+ "0x55",
+ "0x67",
+ "0x88"
+ ]
+ }
+ }
+ }
+]
+
+# comp flags != {0x33, 0x55, 0x67, 0x88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "0x33",
+ "0x55",
+ "0x67",
+ "0x88"
+ ]
+ }
+ }
+ }
+]
+
+# comp cpi 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "cpi",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# comp cpi != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "cpi",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# comp cpi 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "cpi",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# comp cpi != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "cpi",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# comp cpi {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "cpi",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# comp cpi != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "cpi",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/comp.t.json.output b/tests/py/inet/comp.t.json.output
new file mode 100644
index 0000000..435c3de
--- /dev/null
+++ b/tests/py/inet/comp.t.json.output
@@ -0,0 +1,170 @@
+# comp nexthdr != esp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": 50
+ }
+ }
+]
+
+# comp flags 0x0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# comp flags != 0x23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": 35
+ }
+ }
+]
+
+# comp flags 0x33-0x45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 51, 69 ]
+ }
+ }
+ }
+]
+
+# comp flags != 0x33-0x45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 51, 69 ]
+ }
+ }
+ }
+]
+
+# comp flags {0x33, 0x55, 0x67, 0x88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 51,
+ 85,
+ 103,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# comp flags != {0x33, 0x55, 0x67, 0x88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 51,
+ 85,
+ 103,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# comp flags { 0x33-0x55}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 51, 85 ] }
+ ]
+ }
+ }
+ }
+]
+
+# comp flags != { 0x33-0x55}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "comp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 51, 85 ] }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/comp.t.payload b/tests/py/inet/comp.t.payload
new file mode 100644
index 0000000..024e47c
--- /dev/null
+++ b/tests/py/inet/comp.t.payload
@@ -0,0 +1,105 @@
+# comp nexthdr != esp
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000032 ]
+
+# comp flags 0x0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# comp flags != 0x23
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp neq reg 1 0x00000023 ]
+
+# comp flags 0x33-0x45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000033 ]
+ [ cmp lte reg 1 0x00000045 ]
+
+# comp flags != 0x33-0x45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ range neq reg 1 0x00000033 0x00000045 ]
+
+# comp flags {0x33, 0x55, 0x67, 0x88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000033 : 0 [end] element 00000055 : 0 [end] element 00000067 : 0 [end] element 00000088 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# comp flags != {0x33, 0x55, 0x67, 0x88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000033 : 0 [end] element 00000055 : 0 [end] element 00000067 : 0 [end] element 00000088 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# comp cpi 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# comp cpi != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# comp cpi 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# comp cpi != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# comp cpi {33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# comp cpi != {33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000006c ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/inet/ct.t b/tests/py/inet/ct.t
new file mode 100644
index 0000000..5312b32
--- /dev/null
+++ b/tests/py/inet/ct.t
@@ -0,0 +1,15 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+
+*inet;test-inet;input
+
+meta nfproto ipv4 ct original saddr 1.2.3.4;ok;ct original ip saddr 1.2.3.4
+ct original ip6 saddr ::1;ok
+
+ct original ip daddr 1.2.3.4 accept;ok
+
+# missing protocol context
+ct original saddr ::1;fail
+
+# wrong protocol context
+ct original ip saddr ::1;fail
diff --git a/tests/py/inet/ct.t.json b/tests/py/inet/ct.t.json
new file mode 100644
index 0000000..223ac9e
--- /dev/null
+++ b/tests/py/inet/ct.t.json
@@ -0,0 +1,60 @@
+# meta nfproto ipv4 ct original saddr 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "saddr"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
+# ct original ip6 saddr ::1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "ip6 saddr"
+ }
+ },
+ "op": "==",
+ "right": "::1"
+ }
+ }
+]
+
+# ct original ip daddr 1.2.3.4 accept
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "ip daddr"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/inet/ct.t.json.output b/tests/py/inet/ct.t.json.output
new file mode 100644
index 0000000..74c436a
--- /dev/null
+++ b/tests/py/inet/ct.t.json.output
@@ -0,0 +1,16 @@
+# meta nfproto ipv4 ct original saddr 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "saddr"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
diff --git a/tests/py/inet/ct.t.payload b/tests/py/inet/ct.t.payload
new file mode 100644
index 0000000..f7a2ef2
--- /dev/null
+++ b/tests/py/inet/ct.t.payload
@@ -0,0 +1,17 @@
+# meta nfproto ipv4 ct original saddr 1.2.3.4
+ip test-ip4 output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ ct load src => reg 1 , dir original ]
+ [ cmp eq reg 1 0x04030201 ]
+
+# ct original ip6 saddr ::1
+inet test-inet input
+ [ ct load src_ip6 => reg 1 , dir original ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
+
+# ct original ip daddr 1.2.3.4 accept
+inet test-inet input
+ [ ct load dst_ip => reg 1 , dir original ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/inet/dccp.t b/tests/py/inet/dccp.t
new file mode 100644
index 0000000..99cddbe
--- /dev/null
+++ b/tests/py/inet/dccp.t
@@ -0,0 +1,30 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+dccp sport 21-35;ok
+dccp sport != 21-35;ok
+dccp sport {23, 24, 25};ok
+dccp sport != {23, 24, 25};ok
+
+dccp sport 20-50;ok
+
+# dccp dport 21-35;ok
+# dccp dport != 21-35;ok
+dccp dport {23, 24, 25};ok
+dccp dport != {23, 24, 25};ok
+
+dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack};ok
+dccp type != {request, response, data, ack, dataack, closereq, close, reset, sync, syncack};ok
+dccp type request;ok
+dccp type != request;ok
+
+dccp option 0 exists;ok
+dccp option 43 missing;ok
+dccp option 255 exists;ok
+dccp option 256 exists;fail
diff --git a/tests/py/inet/dccp.t.json b/tests/py/inet/dccp.t.json
new file mode 100644
index 0000000..9f47e97
--- /dev/null
+++ b/tests/py/inet/dccp.t.json
@@ -0,0 +1,276 @@
+# dccp sport 21-35
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 21, 35 ]
+ }
+ }
+ }
+]
+
+# dccp sport != 21-35
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 21, 35 ]
+ }
+ }
+ }
+]
+
+# dccp sport {23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# dccp sport != {23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# dccp sport 20-50
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 20, 50 ]
+ }
+ }
+ }
+]
+
+# dccp dport {23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# dccp dport != {23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "dccp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "request",
+ "response",
+ "data",
+ "ack",
+ "dataack",
+ "closereq",
+ "close",
+ "reset",
+ "sync",
+ "syncack"
+ ]
+ }
+ }
+ }
+]
+
+# dccp type != {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "dccp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "request",
+ "response",
+ "data",
+ "ack",
+ "dataack",
+ "closereq",
+ "close",
+ "reset",
+ "sync",
+ "syncack"
+ ]
+ }
+ }
+ }
+]
+
+# dccp type request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "dccp"
+ }
+ },
+ "op": "==",
+ "right": "request"
+ }
+ }
+]
+
+# dccp type != request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "dccp"
+ }
+ },
+ "op": "!=",
+ "right": "request"
+ }
+ }
+]
+
+# 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.json.output b/tests/py/inet/dccp.t.json.output
new file mode 100644
index 0000000..146741d
--- /dev/null
+++ b/tests/py/inet/dccp.t.json.output
@@ -0,0 +1,18 @@
+# dccp sport ftp-data - re-mail-ck
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "dccp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 20, 50 ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/dccp.t.payload b/tests/py/inet/dccp.t.payload
new file mode 100644
index 0000000..c0b87be
--- /dev/null
+++ b/tests/py/inet/dccp.t.payload
@@ -0,0 +1,115 @@
+# dccp sport 21-35
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00001500 ]
+ [ cmp lte reg 1 0x00002300 ]
+
+# dccp sport != 21-35
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ range neq reg 1 0x00001500 0x00002300 ]
+
+# dccp sport {23, 24, 25}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dccp sport != {23, 24, 25}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# dccp sport 20-50
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00001400 ]
+ [ cmp lte reg 1 0x00003200 ]
+
+# dccp dport {23, 24, 25}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dccp dport != {23, 24, 25}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000000 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000006 : 0 [end] element 00000008 : 0 [end] element 0000000a : 0 [end] element 0000000c : 0 [end] element 0000000e : 0 [end] element 00000010 : 0 [end] element 00000012 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 1b @ transport header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# dccp type != {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000000 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000006 : 0 [end] element 00000008 : 0 [end] element 0000000a : 0 [end] element 0000000c : 0 [end] element 0000000e : 0 [end] element 00000010 : 0 [end] element 00000012 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 1b @ transport header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# dccp type request
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 1b @ transport header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# dccp type != request
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000021 ]
+ [ payload load 1b @ transport header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# dccp option 0 exists
+ip test-inet input
+ [ exthdr load 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# dccp option 43 missing
+ip test-inet input
+ [ exthdr load 1b @ 43 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# dccp option 255 exists
+ip test-inet input
+ [ exthdr load 1b @ 255 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/inet/dnat.t b/tests/py/inet/dnat.t
new file mode 100644
index 0000000..e4e169f
--- /dev/null
+++ b/tests/py/inet/dnat.t
@@ -0,0 +1,22 @@
+:prerouting;type nat hook prerouting priority 0
+
+*inet;test-inet;prerouting
+
+iifname "foo" tcp dport 80 redirect to :8080;ok
+
+iifname "eth0" tcp dport 443 dnat ip to 192.168.3.2;ok
+iifname "eth0" tcp dport 443 dnat ip6 to [dead::beef]:4443;ok
+meta l4proto tcp dnat to :80;ok;meta l4proto 6 dnat to :80
+
+dnat ip to ct mark map { 0x00000014 : 1.2.3.4};ok
+dnat ip to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};ok
+
+dnat ip6 to 1.2.3.4;fail
+dnat to 1.2.3.4;fail
+dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};fail
+ip6 daddr dead::beef dnat to 10.1.2.3;fail
+
+meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80;ok;meta l4proto { 6, 17} dnat ip to 1.1.1.1:80
+ip protocol { tcp, udp } dnat ip to 1.1.1.1:80;ok;ip protocol { 6, 17} dnat ip to 1.1.1.1:80
+meta l4proto { tcp, udp } tcp dport 20 dnat to 1.1.1.1:80;fail
+ip protocol { tcp, udp } tcp dport 20 dnat to 1.1.1.1:80;fail
diff --git a/tests/py/inet/dnat.t.json b/tests/py/inet/dnat.t.json
new file mode 100644
index 0000000..c341a04
--- /dev/null
+++ b/tests/py/inet/dnat.t.json
@@ -0,0 +1,241 @@
+# iifname "foo" tcp dport 80 redirect to :8080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "foo"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 80
+ }
+ },
+ {
+ "redirect": {
+ "port": 8080
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 443 dnat ip to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 443
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2",
+ "family": "ip"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 443 dnat ip6 to [dead::beef]:4443
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 443
+ }
+ },
+ {
+ "dnat": {
+ "addr": "dead::beef",
+ "family": "ip6",
+ "port": 4443
+ }
+ }
+]
+
+# dnat ip to ct mark map { 0x00000014 : 1.2.3.4}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ 20,
+ "1.2.3.4"
+ ]
+ ]
+ },
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# dnat ip to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ 20,
+ "1.1.1.1"
+ ]
+ },
+ "1.2.3.4"
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17
+ ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "1.1.1.1",
+ "family": "ip",
+ "port": 80
+ }
+ }
+]
+
+# ip protocol { tcp, udp } dnat ip to 1.1.1.1:80
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17
+ ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "1.1.1.1",
+ "family": "ip",
+ "port": 80
+ }
+ }
+]
+
+# meta l4proto tcp dnat to :80
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "dnat": {
+ "port": 80
+ }
+ }
+]
+
diff --git a/tests/py/inet/dnat.t.payload b/tests/py/inet/dnat.t.payload
new file mode 100644
index 0000000..ce1601a
--- /dev/null
+++ b/tests/py/inet/dnat.t.payload
@@ -0,0 +1,86 @@
+# iifname "foo" tcp dport 80 redirect to :8080
+inet test-inet prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x006f6f66 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005000 ]
+ [ immediate reg 1 0x0000901f ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# iifname "eth0" tcp dport 443 dnat ip to 192.168.3.2
+inet test-inet prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000bb01 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport 443 dnat ip6 to [dead::beef]:4443
+inet test-inet prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000bb01 ]
+ [ immediate reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
+ [ immediate reg 2 0x00005b11 ]
+ [ nat dnat ip6 addr_min reg 1 proto_min reg 2 flags 0x2 ]
+
+# dnat ip to ct mark map { 0x00000014 : 1.2.3.4}
+__map%d test-inet b size 1
+__map%d test-inet 0
+ element 00000014 : 04030201 0 [end]
+inet test-inet prerouting
+ [ ct load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# dnat ip to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
+__map%d test-inet b size 1
+__map%d test-inet 0
+ element 00000014 01010101 : 04030201 0 [end]
+inet test-inet prerouting
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ ct load mark => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+inet
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x01010101 ]
+ [ immediate reg 2 0x00005000 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 flags 0x2 ]
+
+# ip protocol { tcp, udp } dnat ip to 1.1.1.1:80
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x01010101 ]
+ [ immediate reg 2 0x00005000 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 flags 0x2 ]
+
+# meta l4proto tcp dnat to :80
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00005000 ]
+ [ nat dnat inet proto_min reg 1 flags 0x2 ]
+
diff --git a/tests/py/inet/esp.t b/tests/py/inet/esp.t
new file mode 100644
index 0000000..536260c
--- /dev/null
+++ b/tests/py/inet/esp.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
+
+esp spi 100;ok
+esp spi != 100;ok
+esp spi 111-222;ok
+esp spi != 111-222;ok
+esp spi { 100, 102};ok
+esp spi != { 100, 102};ok
+
+esp sequence 22;ok
+esp sequence 22-24;ok
+esp sequence != 22-24;ok
+esp sequence { 22, 24};ok
+esp sequence != { 22, 24};ok
diff --git a/tests/py/inet/esp.t.json b/tests/py/inet/esp.t.json
new file mode 100644
index 0000000..a9dedd6
--- /dev/null
+++ b/tests/py/inet/esp.t.json
@@ -0,0 +1,204 @@
+# esp spi 100
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "esp"
+ }
+ },
+ "op": "==",
+ "right": 100
+ }
+ }
+]
+
+# esp spi != 100
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "esp"
+ }
+ },
+ "op": "!=",
+ "right": 100
+ }
+ }
+]
+
+# esp spi 111-222
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "esp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 111, 222 ]
+ }
+ }
+ }
+]
+
+# esp spi != 111-222
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "esp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 111, 222 ]
+ }
+ }
+ }
+]
+
+# esp spi { 100, 102}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "esp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 100,
+ 102
+ ]
+ }
+ }
+ }
+]
+
+# esp spi != { 100, 102}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "spi",
+ "protocol": "esp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 100,
+ 102
+ ]
+ }
+ }
+ }
+]
+
+# esp sequence 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "esp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# esp sequence 22-24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "esp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 22, 24 ]
+ }
+ }
+ }
+]
+
+# esp sequence != 22-24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "esp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 22, 24 ]
+ }
+ }
+ }
+]
+
+# esp sequence { 22, 24}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "esp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 24
+ ]
+ }
+ }
+ }
+]
+
+# esp sequence != { 22, 24}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "esp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 22,
+ 24
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/esp.t.payload b/tests/py/inet/esp.t.payload
new file mode 100644
index 0000000..0353b05
--- /dev/null
+++ b/tests/py/inet/esp.t.payload
@@ -0,0 +1,91 @@
+# esp spi 100
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x64000000 ]
+
+# esp spi != 100
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x64000000 ]
+
+# esp spi 111-222
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x6f000000 ]
+ [ cmp lte reg 1 0xde000000 ]
+
+# esp spi != 111-222
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ range neq reg 1 0x6f000000 0xde000000 ]
+
+# esp spi { 100, 102}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 64000000 : 0 [end] element 66000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# esp spi != { 100, 102}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 64000000 : 0 [end] element 66000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# esp sequence 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# esp sequence 22-24
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x16000000 ]
+ [ cmp lte reg 1 0x18000000 ]
+
+# esp sequence != 22-24
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x16000000 0x18000000 ]
+
+# esp sequence { 22, 24}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 16000000 : 0 [end] element 18000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# esp sequence != { 22, 24}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 16000000 : 0 [end] element 18000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/inet/ether-ip.t b/tests/py/inet/ether-ip.t
new file mode 100644
index 0000000..759124d
--- /dev/null
+++ b/tests/py/inet/ether-ip.t
@@ -0,0 +1,9 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept
+tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04;ok
diff --git a/tests/py/inet/ether-ip.t.json b/tests/py/inet/ether-ip.t.json
new file mode 100644
index 0000000..8f35b3d
--- /dev/null
+++ b/tests/py/inet/ether-ip.t.json
@@ -0,0 +1,92 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ }
+]
+
diff --git a/tests/py/inet/ether-ip.t.json.output b/tests/py/inet/ether-ip.t.json.output
new file mode 100644
index 0000000..f659113
--- /dev/null
+++ b/tests/py/inet/ether-ip.t.json.output
@@ -0,0 +1,43 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/inet/ether-ip.t.payload b/tests/py/inet/ether-ip.t.payload
new file mode 100644
index 0000000..62e37a5
--- /dev/null
+++ b/tests/py/inet/ether-ip.t.payload
@@ -0,0 +1,28 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00080411 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ immediate reg 0 accept ]
+
+# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
diff --git a/tests/py/inet/ether-ip.t.payload.netdev b/tests/py/inet/ether-ip.t.payload.netdev
new file mode 100644
index 0000000..b0fa6d8
--- /dev/null
+++ b/tests/py/inet/ether-ip.t.payload.netdev
@@ -0,0 +1,29 @@
+# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00080411 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ immediate reg 0 accept ]
+
diff --git a/tests/py/inet/ether.t b/tests/py/inet/ether.t
new file mode 100644
index 0000000..8625f70
--- /dev/null
+++ b/tests/py/inet/ether.t
@@ -0,0 +1,20 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress,egress
+
+tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
+tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept;ok
+
+ether saddr 00:0f:54:0c:11:04 accept;ok
+
+vlan id 1;ok
+ether type vlan vlan id 2;ok;vlan id 2
+
+# invalid dependency
+ether type ip vlan id 1;fail
diff --git a/tests/py/inet/ether.t.json b/tests/py/inet/ether.t.json
new file mode 100644
index 0000000..c7a7f88
--- /dev/null
+++ b/tests/py/inet/ether.t.json
@@ -0,0 +1,122 @@
+# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether saddr 00:0f:54:0c:11:04 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# 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.json.output b/tests/py/inet/ether.t.json.output
new file mode 100644
index 0000000..9ae8c44
--- /dev/null
+++ b/tests/py/inet/ether.t.json.output
@@ -0,0 +1,31 @@
+# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/inet/ether.t.payload b/tests/py/inet/ether.t.payload
new file mode 100644
index 0000000..8b74a78
--- /dev/null
+++ b/tests/py/inet/ether.t.payload
@@ -0,0 +1,52 @@
+# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# ether saddr 00:0f:54:0c:11:04 accept
+inet test-inet input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# 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
new file mode 100644
index 0000000..0128d5f
--- /dev/null
+++ b/tests/py/inet/ether.t.payload.bridge
@@ -0,0 +1,44 @@
+# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
+bridge test-bridge input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
+bridge test-bridge input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# ether saddr 00:0f:54:0c:11:04 accept
+bridge test-bridge input
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ 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
new file mode 100644
index 0000000..7c91f41
--- /dev/null
+++ b/tests/py/inet/ether.t.payload.ip
@@ -0,0 +1,52 @@
+# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# ether saddr 00:0f:54:0c:11:04 accept
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# 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/fib.t b/tests/py/inet/fib.t
new file mode 100644
index 0000000..dbe45d9
--- /dev/null
+++ b/tests/py/inet/fib.t
@@ -0,0 +1,17 @@
+:prerouting;type filter hook prerouting priority 0
+
+*ip;test-ip;prerouting
+*ip6;test-ip6;prerouting
+
+fib saddr . daddr oif lo;fail
+fib iif . oif . daddr oif lo;fail
+fib mark oif lo;fail
+fib saddr . iif oif ne 0;ok;fib saddr . iif oif != 0
+fib saddr . iif oifname "lo";ok
+
+fib daddr . iif type local;ok
+fib daddr . iif type vmap { blackhole : drop, prohibit : drop, unicast : accept };ok
+fib daddr . oif type local;fail
+
+fib daddr oif exists;ok
+fib daddr oif missing;ok
diff --git a/tests/py/inet/fib.t.json b/tests/py/inet/fib.t.json
new file mode 100644
index 0000000..c298915
--- /dev/null
+++ b/tests/py/inet/fib.t.json
@@ -0,0 +1,132 @@
+# fib saddr . iif oif ne 0
+[
+ {
+ "match": {
+ "left": {
+ "fib": {
+ "flags": [
+ "saddr",
+ "iif"
+ ],
+ "result": "oif"
+ }
+ },
+ "op": "!=",
+ "right": "0"
+ }
+ }
+]
+
+# fib saddr . iif oifname "lo"
+[
+ {
+ "match": {
+ "left": {
+ "fib": {
+ "flags": [
+ "saddr",
+ "iif"
+ ],
+ "result": "oifname"
+ }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ }
+]
+
+# fib daddr . iif type local
+[
+ {
+ "match": {
+ "left": {
+ "fib": {
+ "flags": [
+ "daddr",
+ "iif"
+ ],
+ "result": "type"
+ }
+ },
+ "op": "==",
+ "right": "local"
+ }
+ }
+]
+
+# fib daddr . iif type vmap { blackhole : drop, prohibit : drop, unicast : accept }
+[
+ {
+ "vmap": {
+ "key": {
+ "fib": {
+ "flags": [
+ "daddr",
+ "iif"
+ ],
+ "result": "type"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "blackhole",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "prohibit",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "unicast",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# fib daddr oif exists
+[
+ {
+ "match": {
+ "left": {
+ "fib": {
+ "flags": [
+ "daddr"
+ ],
+ "result": "oif"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# fib daddr oif missing
+[
+ {
+ "match": {
+ "left": {
+ "fib": {
+ "flags": [
+ "daddr"
+ ],
+ "result": "oif"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
diff --git a/tests/py/inet/fib.t.json.output b/tests/py/inet/fib.t.json.output
new file mode 100644
index 0000000..52cd46b
--- /dev/null
+++ b/tests/py/inet/fib.t.json.output
@@ -0,0 +1,39 @@
+# fib daddr . iif type vmap { blackhole : drop, prohibit : drop, unicast : accept }
+[
+ {
+ "vmap": {
+ "key": {
+ "fib": {
+ "flags": [
+ "daddr",
+ "iif"
+ ],
+ "result": "type"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "unicast",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "blackhole",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "prohibit",
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/fib.t.payload b/tests/py/inet/fib.t.payload
new file mode 100644
index 0000000..050857d
--- /dev/null
+++ b/tests/py/inet/fib.t.payload
@@ -0,0 +1,32 @@
+# fib saddr . iif oif ne 0
+ip test-ip prerouting
+ [ fib saddr . iif oif => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# fib saddr . iif oifname "lo"
+ip test-ip prerouting
+ [ fib saddr . iif oifname => reg 1 ]
+ [ cmp eq reg 1 0x00006f6c 0x00000000 0x00000000 0x00000000 ]
+
+# fib daddr . iif type local
+ip test-ip prerouting
+ [ fib daddr . iif type => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# fib daddr . iif type vmap { blackhole : drop, prohibit : drop, unicast : accept }
+__map%d test-ip b
+__map%d test-ip 0
+ element 00000006 : drop 0 [end] element 00000008 : drop 0 [end] element 00000001 : accept 0 [end]
+ip test-ip prerouting
+ [ fib daddr . iif type => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# fib daddr oif exists
+ip test-ip prerouting
+ [ fib daddr oif present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# fib daddr oif missing
+ip test-ip prerouting
+ [ fib daddr oif present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
diff --git a/tests/py/inet/geneve.t b/tests/py/inet/geneve.t
new file mode 100644
index 0000000..101f6df
--- /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 0000000..a299fcd
--- /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 0000000..1ce54de
--- /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 0000000..a3e046a
--- /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 0000000..c443176
--- /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 0000000..333133e
--- /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 0000000..cd7ee21
--- /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 0000000..36fa978
--- /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 0000000..654c71e
--- /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/icmp.t b/tests/py/inet/icmp.t
new file mode 100644
index 0000000..9014f84
--- /dev/null
+++ b/tests/py/inet/icmp.t
@@ -0,0 +1,18 @@
+:output;type filter hook output priority 0
+
+*inet;test-inet;output
+
+# without nfproto specified, these should add an implicit dependency on
+# the likely l3 proto (i.e., IPv6 for icmpv6 and IPv4 for icmp)
+
+icmp type echo-request;ok
+icmpv6 type echo-request;ok
+
+# make sure only those nfproto matches are dropped if
+# the next statement would add it as a dependency anyway
+
+meta nfproto ipv4 icmp type echo-request;ok;icmp type echo-request
+meta nfproto ipv4 icmpv6 type echo-request;ok
+
+meta nfproto ipv6 icmp type echo-request;ok
+meta nfproto ipv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
diff --git a/tests/py/inet/icmp.t.json b/tests/py/inet/icmp.t.json
new file mode 100644
index 0000000..64be2b3
--- /dev/null
+++ b/tests/py/inet/icmp.t.json
@@ -0,0 +1,124 @@
+# icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv4 icmp type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": { "key": "nfproto" } },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv4 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": { "key": "nfproto" } },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv6 icmp type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": { "key": "nfproto" } },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": { "meta": { "key": "nfproto" } },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
diff --git a/tests/py/inet/icmp.t.json.output b/tests/py/inet/icmp.t.json.output
new file mode 100644
index 0000000..062c82f
--- /dev/null
+++ b/tests/py/inet/icmp.t.json.output
@@ -0,0 +1,32 @@
+# meta nfproto ipv4 icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta nfproto ipv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
diff --git a/tests/py/inet/icmp.t.payload b/tests/py/inet/icmp.t.payload
new file mode 100644
index 0000000..f98cfc3
--- /dev/null
+++ b/tests/py/inet/icmp.t.payload
@@ -0,0 +1,54 @@
+# icmp type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmpv6 type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# meta nfproto ipv4 icmp type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta nfproto ipv4 icmpv6 type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# meta nfproto ipv6 icmp type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta nfproto ipv6 icmpv6 type echo-request
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
diff --git a/tests/py/inet/icmpX.t b/tests/py/inet/icmpX.t
new file mode 100644
index 0000000..9430b3d
--- /dev/null
+++ b/tests/py/inet/icmpX.t
@@ -0,0 +1,10 @@
+:input;type filter hook input priority 0
+
+*inet;test-inet;input
+
+ip protocol icmp icmp type echo-request;ok;ip protocol 1 icmp type echo-request
+icmp type echo-request;ok
+ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;ip6 nexthdr 58 icmpv6 type echo-request
+icmpv6 type echo-request;ok
+# must not remove 'ip protocol' dependency, this explicitly matches icmpv6-in-ipv4.
+ip protocol ipv6-icmp meta l4proto ipv6-icmp icmpv6 type 1;ok;ip protocol 58 icmpv6 type destination-unreachable
diff --git a/tests/py/inet/icmpX.t.json b/tests/py/inet/icmpX.t.json
new file mode 100644
index 0000000..8e13091
--- /dev/null
+++ b/tests/py/inet/icmpX.t.json
@@ -0,0 +1,125 @@
+# ip protocol icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "icmpv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# ip protocol ipv6-icmp meta l4proto ipv6-icmp icmpv6 type 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "ipv6-icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": "ipv6-icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
diff --git a/tests/py/inet/icmpX.t.json.output b/tests/py/inet/icmpX.t.json.output
new file mode 100644
index 0000000..7765cd9
--- /dev/null
+++ b/tests/py/inet/icmpX.t.json.output
@@ -0,0 +1,84 @@
+# ip protocol icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": 58
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# ip protocol ipv6-icmp meta l4proto ipv6-icmp icmpv6 type 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 58
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "destination-unreachable"
+ }
+ }
+]
+
diff --git a/tests/py/inet/icmpX.t.payload b/tests/py/inet/icmpX.t.payload
new file mode 100644
index 0000000..9a761ee
--- /dev/null
+++ b/tests/py/inet/icmpX.t.payload
@@ -0,0 +1,46 @@
+# ip protocol icmp icmp type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# icmpv6 type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# ip protocol ipv6-icmp meta l4proto ipv6-icmp icmpv6 type 1
+inet filter input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/inet/ip.t b/tests/py/inet/ip.t
new file mode 100644
index 0000000..bdb3330
--- /dev/null
+++ b/tests/py/inet/ip.t
@@ -0,0 +1,12 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*inet;test-inet;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress,egress
+
+ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe };ok
+ip saddr vmap { 10.0.1.0-10.0.1.255 : accept, 10.0.1.1-10.0.2.255 : drop };fail
+ip saddr vmap { 3.3.3.3-3.3.3.4 : accept, 1.1.1.1-1.1.1.255 : accept, 1.1.1.0-1.1.2.1 : drop};fail
diff --git a/tests/py/inet/ip.t.json b/tests/py/inet/ip.t.json
new file mode 100644
index 0000000..638fb7d
--- /dev/null
+++ b/tests/py/inet/ip.t.json
@@ -0,0 +1,42 @@
+# ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.1.1.1",
+ "2.2.2.2",
+ "ca:fe:ca:fe:ca:fe"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/ip.t.payload b/tests/py/inet/ip.t.payload
new file mode 100644
index 0000000..589a5cd
--- /dev/null
+++ b/tests/py/inet/ip.t.payload
@@ -0,0 +1,11 @@
+# ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 01010101 02020202 fecafeca 0000feca : 0 [end]
+inet test-ip input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 6b @ link header + 6 => reg 10 ]
+ [ lookup reg 1 set __set%d ]
diff --git a/tests/py/inet/ip.t.payload.bridge b/tests/py/inet/ip.t.payload.bridge
new file mode 100644
index 0000000..57dbc9e
--- /dev/null
+++ b/tests/py/inet/ip.t.payload.bridge
@@ -0,0 +1,11 @@
+# ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe }
+__set%d test-bridge 3
+__set%d test-bridge 0
+ element 01010101 02020202 fecafeca 0000feca : 0 [end]
+bridge test-bridge input
+ [ 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 ]
+ [ payload load 6b @ link header + 6 => reg 10 ]
+ [ lookup reg 1 set __set%d ]
diff --git a/tests/py/inet/ip.t.payload.inet b/tests/py/inet/ip.t.payload.inet
new file mode 100644
index 0000000..8df41de
--- /dev/null
+++ b/tests/py/inet/ip.t.payload.inet
@@ -0,0 +1,14 @@
+# ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 01010101 02020202 fecafeca 0000feca : 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 4b @ network header + 16 => reg 9 ]
+ [ payload load 6b @ link header + 6 => reg 10 ]
+ [ lookup reg 1 set __set%d ]
+
diff --git a/tests/py/inet/ip.t.payload.netdev b/tests/py/inet/ip.t.payload.netdev
new file mode 100644
index 0000000..95be919
--- /dev/null
+++ b/tests/py/inet/ip.t.payload.netdev
@@ -0,0 +1,14 @@
+# ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe }
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 01010101 02020202 fecafeca 0000feca : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 6b @ link header + 6 => reg 10 ]
+ [ lookup reg 1 set __set%d ]
+
diff --git a/tests/py/inet/ip_tcp.t b/tests/py/inet/ip_tcp.t
new file mode 100644
index 0000000..03bafc0
--- /dev/null
+++ b/tests/py/inet/ip_tcp.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
+
+*inet;test-inet;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress,egress
+
+# must not remove ip dependency -- ONLY ipv4 packets should be matched
+ip protocol tcp tcp dport 22;ok;ip protocol 6 tcp dport 22
+
+# could in principle remove it here since ipv4 is implied via saddr.
+ip protocol tcp ip saddr 1.2.3.4 tcp dport 22;ok;ip protocol 6 ip saddr 1.2.3.4 tcp dport 22
+
+# but not here.
+ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22;ok;ip protocol 6 counter ip saddr 1.2.3.4 tcp dport 22
+
+# or here.
+ip protocol tcp counter tcp dport 22;ok;ip protocol 6 counter tcp dport 22
+
+ether type ip tcp dport 22;ok
diff --git a/tests/py/inet/ip_tcp.t.json b/tests/py/inet/ip_tcp.t.json
new file mode 100644
index 0000000..87cb9bf
--- /dev/null
+++ b/tests/py/inet/ip_tcp.t.json
@@ -0,0 +1,170 @@
+# ip protocol tcp tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp ip saddr 1.2.3.4 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp counter tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ether type ip tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
diff --git a/tests/py/inet/ip_tcp.t.json.output b/tests/py/inet/ip_tcp.t.json.output
new file mode 100644
index 0000000..acad8b1
--- /dev/null
+++ b/tests/py/inet/ip_tcp.t.json.output
@@ -0,0 +1,142 @@
+# ip protocol tcp tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp ip saddr 1.2.3.4 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp counter tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
diff --git a/tests/py/inet/ip_tcp.t.payload b/tests/py/inet/ip_tcp.t.payload
new file mode 100644
index 0000000..1e16f85
--- /dev/null
+++ b/tests/py/inet/ip_tcp.t.payload
@@ -0,0 +1,52 @@
+# ip protocol tcp tcp dport 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp ip saddr 1.2.3.4 tcp dport 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp counter tcp dport 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ether type ip tcp dport 22
+inet test-inet input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
diff --git a/tests/py/inet/ip_tcp.t.payload.bridge b/tests/py/inet/ip_tcp.t.payload.bridge
new file mode 100644
index 0000000..0344cd6
--- /dev/null
+++ b/tests/py/inet/ip_tcp.t.payload.bridge
@@ -0,0 +1,51 @@
+# ip protocol tcp tcp dport 22
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp ip saddr 1.2.3.4 tcp dport 22
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp counter tcp dport 22
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ether type ip tcp dport 22
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
diff --git a/tests/py/inet/ip_tcp.t.payload.netdev b/tests/py/inet/ip_tcp.t.payload.netdev
new file mode 100644
index 0000000..915a787
--- /dev/null
+++ b/tests/py/inet/ip_tcp.t.payload.netdev
@@ -0,0 +1,53 @@
+# ip protocol tcp tcp dport 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp ip saddr 1.2.3.4 tcp dport 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp counter tcp dport 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ether type ip tcp dport 22
+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 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
diff --git a/tests/py/inet/ipsec.t b/tests/py/inet/ipsec.t
new file mode 100644
index 0000000..b18df39
--- /dev/null
+++ b/tests/py/inet/ipsec.t
@@ -0,0 +1,23 @@
+:ipsec-forw;type filter hook forward priority 0
+
+*ip;ipsec-ip4;ipsec-forw
+*ip6;ipsec-ip6;ipsec-forw
+*inet;ipsec-inet;ipsec-forw
+
+ipsec in reqid 1;ok
+ipsec in spnum 0 reqid 1;ok;ipsec in reqid 1
+
+ipsec out reqid 0xffffffff;ok;ipsec out reqid 4294967295
+ipsec out spnum 0x100000000;fail
+
+ipsec i reqid 1;fail
+
+ipsec out spi 1-561;ok
+
+ipsec in spnum 2 ip saddr { 1.2.3.4, 10.6.0.0/16 };ok
+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
new file mode 100644
index 0000000..18a64f3
--- /dev/null
+++ b/tests/py/inet/ipsec.t.json
@@ -0,0 +1,157 @@
+# ipsec in reqid 1
+[
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "in",
+ "key": "reqid",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ipsec in spnum 0 reqid 1
+[
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "in",
+ "key": "reqid",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ipsec out reqid 0xffffffff
+[
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "out",
+ "key": "reqid",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": 4294967295
+ }
+ }
+]
+
+# ipsec out spi 1-561
+[
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "out",
+ "key": "spi",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 1,
+ 561
+ ]
+ }
+ }
+ }
+]
+
+# ipsec in spnum 2 ip saddr { 1.2.3.4, 10.6.0.0/16 }
+[
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "in",
+ "family": "ip",
+ "key": "saddr",
+ "spnum": 2
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "1.2.3.4",
+ {
+ "prefix": {
+ "addr": "10.6.0.0",
+ "len": 16
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ipsec in ip6 daddr dead::beef
+[
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "in",
+ "family": "ip6",
+ "key": "daddr",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": "dead::beef"
+ }
+ }
+]
+
+# ipsec out ip6 saddr dead::feed
+[
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "out",
+ "family": "ip6",
+ "key": "saddr",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": "dead::feed"
+ }
+ }
+]
+
+# 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
new file mode 100644
index 0000000..9648255
--- /dev/null
+++ b/tests/py/inet/ipsec.t.payload
@@ -0,0 +1,45 @@
+# ipsec in reqid 1
+ip ipsec-ip4 ipsec-input
+ [ xfrm load in 0 reqid => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ipsec in spnum 0 reqid 1
+ip ipsec-ip4 ipsec-input
+ [ xfrm load in 0 reqid => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ipsec out reqid 0xffffffff
+ip ipsec-ip4 ipsec-input
+ [ xfrm load out 0 reqid => reg 1 ]
+ [ cmp eq reg 1 0xffffffff ]
+
+# ipsec out spi 1-561
+inet ipsec-inet ipsec-post
+ [ xfrm load out 0 spi => reg 1 ]
+ [ cmp gte reg 1 0x01000000 ]
+ [ cmp lte reg 1 0x31020000 ]
+
+# ipsec in spnum 2 ip saddr { 1.2.3.4, 10.6.0.0/16 }
+__set%d ipsec-ip4 7 size 5
+__set%d ipsec-ip4 0
+ element 00000000 : 1 [end] element 04030201 : 0 [end] element 05030201 : 1 [end] element 0000060a : 0 [end] element 0000070a : 1 [end]
+ip ipsec-ip4 ipsec-input
+ [ xfrm load in 2 saddr4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ipsec in ip6 daddr dead::beef
+ip ipsec-ip4 ipsec-forw
+ [ xfrm load in 0 daddr6 => reg 1 ]
+ [ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
+
+# ipsec out ip6 saddr dead::feed
+ip ipsec-ip4 ipsec-forw
+ [ xfrm load out 0 saddr6 => reg 1 ]
+ [ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xedfe0000 ]
+
+# counter ipsec out ip daddr 192.168.1.2
+ip ipsec-ip4 ipsec-forw
+ [ counter pkts 0 bytes 0 ]
+ [ xfrm load out 0 daddr4 => reg 1 ]
+ [ cmp eq reg 1 0x0201a8c0 ]
+
diff --git a/tests/py/inet/map.t b/tests/py/inet/map.t
new file mode 100644
index 0000000..5a7161b
--- /dev/null
+++ b/tests/py/inet/map.t
@@ -0,0 +1,10 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017};ok;meta mark set ip saddr map { 10.2.3.1 : 0x00000017, 10.2.3.2 : 0x0000002a}
+mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001};ok;meta mark set ip hdrlength map { 4 : 0x00000001, 5 : 0x00000017}
diff --git a/tests/py/inet/map.t.json b/tests/py/inet/map.t.json
new file mode 100644
index 0000000..1cb28e0
--- /dev/null
+++ b/tests/py/inet/map.t.json
@@ -0,0 +1,66 @@
+# mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017}
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "10.2.3.2",
+ "0x0000002a"
+ ],
+ [
+ "10.2.3.1",
+ "0x00000017"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001}
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ip"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 5,
+ "0x00000017"
+ ],
+ [
+ 4,
+ "0x00000001"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/map.t.json.output b/tests/py/inet/map.t.json.output
new file mode 100644
index 0000000..b0bb7dd
--- /dev/null
+++ b/tests/py/inet/map.t.json.output
@@ -0,0 +1,66 @@
+# mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017}
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "10.2.3.1",
+ 23
+ ],
+ [
+ "10.2.3.2",
+ 42
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001}
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ip"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 4,
+ 1
+ ],
+ [
+ 5,
+ 23
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/map.t.payload b/tests/py/inet/map.t.payload
new file mode 100644
index 0000000..50344ad
--- /dev/null
+++ b/tests/py/inet/map.t.payload
@@ -0,0 +1,23 @@
+# mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017}
+__map%d test-inet b
+__map%d test-inet 0
+ element 0203020a : 0000002a 0 [end] element 0103020a : 00000017 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00000005 : 00000017 0 [end] element 00000004 : 00000001 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
diff --git a/tests/py/inet/map.t.payload.ip b/tests/py/inet/map.t.payload.ip
new file mode 100644
index 0000000..3e45667
--- /dev/null
+++ b/tests/py/inet/map.t.payload.ip
@@ -0,0 +1,19 @@
+# mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017}
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 0203020a : 0000002a 0 [end] element 0103020a : 00000017 0 [end]
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001}
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000005 : 00000017 0 [end] element 00000004 : 00000001 0 [end]
+ip test-ip4 input
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
diff --git a/tests/py/inet/map.t.payload.netdev b/tests/py/inet/map.t.payload.netdev
new file mode 100644
index 0000000..2e60f09
--- /dev/null
+++ b/tests/py/inet/map.t.payload.netdev
@@ -0,0 +1,23 @@
+# mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 0203020a : 0000002a 0 [end] element 0103020a : 00000017 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000005 : 00000017 0 [end] element 00000004 : 00000001 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
diff --git a/tests/py/inet/meta.t b/tests/py/inet/meta.t
new file mode 100644
index 0000000..5c062b3
--- /dev/null
+++ b/tests/py/inet/meta.t
@@ -0,0 +1,32 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+
+*inet;test-inet;input
+
+meta nfproto ipv4;ok
+meta nfproto ipv6;ok
+meta nfproto {ipv4, ipv6};ok
+meta nfproto != {ipv4, ipv6};ok
+meta nfproto ipv6 tcp dport 22;ok
+meta nfproto ipv4 tcp dport 22;ok
+meta nfproto ipv4 ip saddr 1.2.3.4;ok;ip saddr 1.2.3.4
+meta nfproto ipv6 meta l4proto tcp;ok;meta nfproto ipv6 meta l4proto 6
+meta nfproto ipv4 counter ip saddr 1.2.3.4;ok
+
+meta protocol ip udp dport 67;ok
+meta protocol ip6 udp dport 67;ok
+
+meta ipsec exists;ok
+meta secpath missing;ok;meta ipsec missing
+meta ibrname "br0";fail
+meta obrname "br0";fail
+meta mark set ct mark >> 8;ok
+
+meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 };ok
+ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 1.2.3.6-1.2.3.8 . 0x00000200-0x00000300 };ok
+ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 5.6.7.8 . 0x00000200 };ok
+
+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
new file mode 100644
index 0000000..3ba0fd1
--- /dev/null
+++ b/tests/py/inet/meta.t.json
@@ -0,0 +1,528 @@
+# meta nfproto ipv4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ }
+]
+
+# meta nfproto ipv6
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv6"
+ }
+ }
+]
+
+# meta nfproto {ipv4, ipv6}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ipv4",
+ "ipv6"
+ ]
+ }
+ }
+ }
+]
+
+# meta nfproto != {ipv4, ipv6}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ipv4",
+ "ipv6"
+ ]
+ }
+ }
+ }
+]
+
+# meta nfproto ipv6 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# meta nfproto ipv4 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# meta nfproto ipv4 ip saddr 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
+# meta nfproto ipv6 meta l4proto tcp
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ }
+]
+
+# meta nfproto ipv4 counter ip saddr 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
+# meta ipsec exists
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "ipsec"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# meta secpath missing
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "secpath" }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# meta mark set ct mark >> 8
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ ">>": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 8
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ {
+ "range": [
+ 10,
+ 20
+ ]
+ },
+ {
+ "range": [
+ 80,
+ 90
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ 1048576,
+ 1048867
+ ]
+ },
+ {
+ "range": [
+ 100,
+ 120
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 1.2.3.6-1.2.3.8 . 0x00000200-0x00000300 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ 256
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ "1.2.3.6",
+ "1.2.3.8"
+ ]
+ },
+ {
+ "range": [
+ 512,
+ 768
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 5.6.7.8 . 0x00000200 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ 256
+ ]
+ },
+ {
+ "concat": [
+ "5.6.7.8",
+ 512
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip dscp
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip dscp | 0x40
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 64
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp | 0x40
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 64
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/meta.t.json.got b/tests/py/inet/meta.t.json.got
new file mode 100644
index 0000000..f2fad0b
--- /dev/null
+++ b/tests/py/inet/meta.t.json.got
@@ -0,0 +1,86 @@
+# 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
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/meta.t.json.output b/tests/py/inet/meta.t.json.output
new file mode 100644
index 0000000..3e7dd21
--- /dev/null
+++ b/tests/py/inet/meta.t.json.output
@@ -0,0 +1,53 @@
+# meta nfproto ipv4 ip saddr 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
+# meta nfproto ipv6 meta l4proto tcp
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 6
+ }
+ }
+]
+
+# meta secpath missing
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "ipsec"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
diff --git a/tests/py/inet/meta.t.payload b/tests/py/inet/meta.t.payload
new file mode 100644
index 0000000..c53b507
--- /dev/null
+++ b/tests/py/inet/meta.t.payload
@@ -0,0 +1,175 @@
+# meta nfproto ipv4
+ip test-ip4 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# meta nfproto ipv6
+ip test-ip4 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+
+# meta nfproto {ipv4, ipv6}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 0000000a : 0 [end]
+ip test-ip4 input
+ [ meta load nfproto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta nfproto != {ipv4, ipv6}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 0000000a : 0 [end]
+ip test-ip4 input
+ [ meta load nfproto => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta nfproto ipv6 tcp dport 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# meta nfproto ipv4 tcp dport 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# meta nfproto ipv4 ip saddr 1.2.3.4
+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 ]
+
+# meta nfproto ipv6 meta l4proto tcp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# meta nfproto ipv4 counter ip saddr 1.2.3.4
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+
+# meta ipsec exists
+inet test-inet input
+ [ meta load secpath => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta secpath missing
+inet test-inet input
+ [ meta load secpath => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta mark set ct mark >> 8
+inet test-inet input
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000008 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta protocol ip udp dport 67
+inet test-inet input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta protocol ip6 udp dport 67
+inet test-inet input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 }
+__set%d test-inet 87 size 1
+__set%d test-inet 0
+ element 0a000000 00005000 - 14000000 00005a00 : 0 [end] element 00001000 00006400 - 23011000 00007800 : 0 [end]
+ip test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 1.2.3.6-1.2.3.8 . 0x00000200-0x00000300 }
+__set%d test-inet 87 size 2
+__set%d test-inet 0
+ element 04030201 00010000 - 04030201 00010000 : 0 [end] element 06030201 00020000 - 08030201 00030000 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ meta load mark => reg 9 ]
+ [ byteorder reg 9 = hton(reg 9, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 5.6.7.8 . 0x00000200 }
+__set%d test-inet 3 size 2
+__set%d test-inet 0
+ element 04030201 00000100 : 0 [end] element 08070605 00000200 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ meta load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta mark set ip dscp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip dscp | 0x40
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffbf ) ^ 0x00000040 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp | 0x40
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffbf ) ^ 0x00000040 ]
+ [ meta set mark with reg 1 ]
+
diff --git a/tests/py/inet/meta.t.payload.got b/tests/py/inet/meta.t.payload.got
new file mode 100644
index 0000000..be3f566
--- /dev/null
+++ b/tests/py/inet/meta.t.payload.got
@@ -0,0 +1,40 @@
+# 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 ]
+
diff --git a/tests/py/inet/osf.t b/tests/py/inet/osf.t
new file mode 100644
index 0000000..c828541
--- /dev/null
+++ b/tests/py/inet/osf.t
@@ -0,0 +1,18 @@
+:osfchain;type filter hook input priority 0
+
+*ip;osfip;osfchain
+*ip6;osfip6;osfchain
+*inet;osfinet;osfchain
+
+osf name "Linux";ok
+osf ttl loose name "Linux";ok
+osf ttl skip name "Linux";ok
+osf ttl skip version "Linux:3.0";ok
+osf ttl skip version "morethan:sixteenbytes";fail
+osf ttl nottl name "Linux";fail
+osf name "morethansixteenbytes";fail
+osf name ;fail
+osf name { "Windows", "MacOs" };ok
+osf version { "Windows:XP", "MacOs:Sierra" };ok
+ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 };ok
+ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 };ok
diff --git a/tests/py/inet/osf.t.json b/tests/py/inet/osf.t.json
new file mode 100644
index 0000000..cedb7f6
--- /dev/null
+++ b/tests/py/inet/osf.t.json
@@ -0,0 +1,170 @@
+# osf name "Linux"
+[
+ {
+ "match": {
+ "left": {
+ "osf": {
+ "key": "name"
+ }
+ },
+ "op": "==",
+ "right": "Linux"
+ }
+ }
+]
+
+# osf ttl loose name "Linux"
+[
+ {
+ "match": {
+ "left": {
+ "osf": {
+ "key": "name",
+ "ttl": "loose"
+ }
+ },
+ "op": "==",
+ "right": "Linux"
+ }
+ }
+]
+
+# osf ttl skip name "Linux"
+[
+ {
+ "match": {
+ "left": {
+ "osf": {
+ "key": "name",
+ "ttl": "skip"
+ }
+ },
+ "op": "==",
+ "right": "Linux"
+ }
+ }
+]
+
+# osf ttl skip version "Linux:3.0"
+[
+ {
+ "match": {
+ "left": {
+ "osf": {
+ "key": "version",
+ "ttl": "skip"
+ }
+ },
+ "op": "==",
+ "right": "Linux:3.0"
+ }
+ }
+]
+
+# osf name { "Windows", "MacOs" }
+[
+ {
+ "match": {
+ "left": {
+ "osf": {
+ "key": "name"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "MacOs",
+ "Windows"
+ ]
+ }
+ }
+ }
+]
+
+# osf version { "Windows:XP", "MacOs:Sierra" }
+[
+ {
+ "match": {
+ "left": {
+ "osf": {
+ "key": "version"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "Windows:XP",
+ "MacOs:Sierra"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 }
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "MacOs",
+ 2
+ ],
+ [
+ "Windows",
+ 1
+ ]
+ ]
+ },
+ "key": {
+ "osf": {
+ "key": "name"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 }
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "Windows:XP",
+ 3
+ ],
+ [
+ "MacOs:Sierra",
+ 4
+ ]
+ ]
+ },
+ "key": {
+ "osf": {
+ "key": "version"
+ }
+ }
+ }
+ }
+ }
+ }
+]
diff --git a/tests/py/inet/osf.t.payload b/tests/py/inet/osf.t.payload
new file mode 100644
index 0000000..6ddab97
--- /dev/null
+++ b/tests/py/inet/osf.t.payload
@@ -0,0 +1,53 @@
+# osf name "Linux"
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
+
+# osf ttl loose name "Linux"
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
+
+# osf ttl skip name "Linux"
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
+
+# osf ttl skip version "Linux:3.0"
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ cmp eq reg 1 0x756e694c 0x2e333a78 0x00000030 0x00000000 ]
+
+# osf name { "Windows", "MacOs" }
+__set%d osfinet 3 size 2
+__set%d osfinet 0
+ element 646e6957 0073776f 00000000 00000000 : 0 [end] element 4f63614d 00000073 00000000 00000000 : 0 [end]
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# osf version { "Windows:XP", "MacOs:Sierra" }
+__set%d osfinet 3 size 2
+__set%d osfinet 0
+ element 646e6957 3a73776f 00005058 00000000 : 0 [end] element 4f63614d 69533a73 61727265 00000000 : 0 [end]
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 }
+__map%d osfinet b size 2
+__map%d osfinet 0
+ element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end]
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 }
+__map%d osfinet b size 2
+__map%d osfinet 0
+ element 646e6957 3a73776f 00005058 00000000 : 00000003 0 [end] element 4f63614d 69533a73 61727265 00000000 : 00000004 0 [end]
+inet osfinet osfchain
+ [ osf dreg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ ct set mark with reg 1 ]
diff --git a/tests/py/inet/reject.t b/tests/py/inet/reject.t
new file mode 100644
index 0000000..61a6d55
--- /dev/null
+++ b/tests/py/inet/reject.t
@@ -0,0 +1,41 @@
+:input;type filter hook input priority 0
+
+*inet;test-inet;input
+
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok
+
+mark 12345 reject with tcp reset;ok;meta l4proto 6 meta mark 0x00003039 reject with tcp reset
+
+reject;ok
+meta nfproto ipv4 reject;ok;reject with icmp port-unreachable
+meta nfproto ipv6 reject;ok;reject with icmpv6 port-unreachable
+
+reject with icmpx host-unreachable;ok
+reject with icmpx no-route;ok
+reject with icmpx admin-prohibited;ok
+reject with icmpx port-unreachable;ok;reject
+reject with icmpx 3;ok;reject with icmpx admin-prohibited
+
+meta nfproto ipv4 reject with icmp host-unreachable;ok;reject with icmp host-unreachable
+meta nfproto ipv6 reject with icmpv6 no-route;ok;reject with icmpv6 no-route
+
+meta nfproto ipv6 reject with icmp host-unreachable;fail
+meta nfproto ipv4 ip protocol icmp reject with icmpv6 no-route;fail
+meta nfproto ipv6 ip protocol icmp reject with icmp host-unreachable;fail
+meta l4proto udp reject with tcp reset;fail
+
+meta nfproto ipv4 reject with icmpx admin-prohibited;ok
+meta nfproto ipv6 reject with icmpx admin-prohibited;ok
+
+ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject;ok;ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject with icmp port-unreachable
diff --git a/tests/py/inet/reject.t.json b/tests/py/inet/reject.t.json
new file mode 100644
index 0000000..02ac900
--- /dev/null
+++ b/tests/py/inet/reject.t.json
@@ -0,0 +1,331 @@
+# reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-unreachable
+[
+ {
+ "reject": {
+ "expr": "net-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp prot-unreachable
+[
+ {
+ "reject": {
+ "expr": "prot-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-prohibited
+[
+ {
+ "reject": {
+ "expr": "net-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp host-prohibited
+[
+ {
+ "reject": {
+ "expr": "host-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 addr-unreachable
+[
+ {
+ "reject": {
+ "expr": "addr-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# mark 12345 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# reject
+[
+ {
+ "reject": null
+ }
+]
+
+# meta nfproto ipv4 reject
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "reject": null
+ }
+]
+
+# meta nfproto ipv6 reject
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "reject": null
+ }
+]
+
+# reject with icmpx host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx 3
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta nfproto ipv4 reject with icmp host-unreachable
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# meta nfproto ipv6 reject with icmpv6 no-route
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# meta nfproto ipv4 reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta nfproto ipv6 reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "op": "==",
+ "right": "ipv6"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "aa:bb:cc:dd:ee:ff"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ },
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
diff --git a/tests/py/inet/reject.t.json.output b/tests/py/inet/reject.t.json.output
new file mode 100644
index 0000000..496ce55
--- /dev/null
+++ b/tests/py/inet/reject.t.json.output
@@ -0,0 +1,77 @@
+# mark 12345 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta nfproto ipv4 reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# meta nfproto ipv6 reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# meta nfproto ipv4 reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# meta nfproto ipv6 reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
diff --git a/tests/py/inet/reject.t.payload.inet b/tests/py/inet/reject.t.payload.inet
new file mode 100644
index 0000000..828cb83
--- /dev/null
+++ b/tests/py/inet/reject.t.payload.inet
@@ -0,0 +1,144 @@
+# reject with icmp host-unreachable
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 1 ]
+
+# reject with icmp net-unreachable
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 0 ]
+
+# reject with icmp prot-unreachable
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 2 ]
+
+# reject with icmp port-unreachable
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 3 ]
+
+# reject with icmp net-prohibited
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 9 ]
+
+# reject with icmp host-prohibited
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 10 ]
+
+# reject with icmp admin-prohibited
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 13 ]
+
+# reject with icmpv6 no-route
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ reject type 0 code 0 ]
+
+# reject with icmpv6 admin-prohibited
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ reject type 0 code 1 ]
+
+# reject with icmpv6 addr-unreachable
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ reject type 0 code 3 ]
+
+# reject with icmpv6 port-unreachable
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ reject type 0 code 4 ]
+
+# mark 12345 reject with tcp reset
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00003039 ]
+ [ reject type 1 code 0 ]
+
+# reject
+inet test-inet input
+ [ reject type 2 code 1 ]
+
+# meta nfproto ipv4 reject
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 3 ]
+
+# meta nfproto ipv6 reject
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ reject type 0 code 4 ]
+
+# reject with icmpx host-unreachable
+inet test-inet input
+ [ reject type 2 code 2 ]
+
+# reject with icmpx no-route
+inet test-inet input
+ [ reject type 2 code 0 ]
+
+# reject with icmpx admin-prohibited
+inet test-inet input
+ [ reject type 2 code 3 ]
+
+# reject with icmpx port-unreachable
+inet test-inet input
+ [ reject type 2 code 1 ]
+
+# reject with icmpx 3
+inet test-inet input
+ [ reject type 2 code 3 ]
+
+# meta nfproto ipv4 reject with icmp host-unreachable
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 0 code 1 ]
+
+# meta nfproto ipv6 reject with icmpv6 no-route
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ reject type 0 code 0 ]
+
+# meta nfproto ipv4 reject with icmpx admin-prohibited
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ reject type 2 code 3 ]
+
+# meta nfproto ipv6 reject with icmpx admin-prohibited
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ reject type 2 code 3 ]
+
+# ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject
+inet test-inet input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0xddccbbaa 0x0008ffee ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ reject type 0 code 3 ]
+
diff --git a/tests/py/inet/rt.t b/tests/py/inet/rt.t
new file mode 100644
index 0000000..a0e0d00
--- /dev/null
+++ b/tests/py/inet/rt.t
@@ -0,0 +1,15 @@
+:output;type filter hook output priority 0
+
+*inet;test-inet;output
+
+meta nfproto ipv4 rt nexthop 192.168.0.1;ok;meta nfproto ipv4 rt ip nexthop 192.168.0.1
+rt ip6 nexthop fd00::1;ok
+
+# missing context
+rt nexthop 192.168.0.1;fail
+rt nexthop fd00::1;fail
+
+# wrong context
+rt ip nexthop fd00::1;fail
+
+tcp option maxseg size set rt mtu;ok
diff --git a/tests/py/inet/rt.t.json b/tests/py/inet/rt.t.json
new file mode 100644
index 0000000..6dbea41
--- /dev/null
+++ b/tests/py/inet/rt.t.json
@@ -0,0 +1,59 @@
+# meta nfproto ipv4 rt nexthop 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "nexthop"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
+# rt ip6 nexthop fd00::1
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "family": "ip6",
+ "key": "nexthop"
+ }
+ },
+ "op": "==",
+ "right": "fd00::1"
+ }
+ }
+]
+
+# tcp option maxseg size set rt mtu
+[
+ {
+ "mangle": {
+ "key": {
+ "tcp option": {
+ "field": "size",
+ "name": "maxseg"
+ }
+ },
+ "value": {
+ "rt": {
+ "key": "mtu"
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/rt.t.json.output b/tests/py/inet/rt.t.json.output
new file mode 100644
index 0000000..382ef87
--- /dev/null
+++ b/tests/py/inet/rt.t.json.output
@@ -0,0 +1,25 @@
+# meta nfproto ipv4 rt nexthop 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "nfproto" }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "family": "ip",
+ "key": "nexthop"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
diff --git a/tests/py/inet/rt.t.payload b/tests/py/inet/rt.t.payload
new file mode 100644
index 0000000..84dea12
--- /dev/null
+++ b/tests/py/inet/rt.t.payload
@@ -0,0 +1,18 @@
+# meta nfproto ipv4 rt nexthop 192.168.0.1
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ rt load nexthop4 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# rt ip6 nexthop fd00::1
+inet test-inet output
+ [ rt load nexthop6 => reg 1 ]
+ [ cmp eq reg 1 0x000000fd 0x00000000 0x00000000 0x01000000 ]
+
+# tcp option maxseg size set rt mtu
+inet test-inet output
+ [ rt load tcpmss => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 2, 2) ]
+ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
+
diff --git a/tests/py/inet/sctp.t b/tests/py/inet/sctp.t
new file mode 100644
index 0000000..016173b
--- /dev/null
+++ b/tests/py/inet/sctp.t
@@ -0,0 +1,73 @@
+: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
+
+sctp sport 23;ok
+sctp sport != 23;ok
+sctp sport 23-44;ok
+sctp sport != 23-44;ok
+sctp sport { 23, 24, 25};ok
+sctp sport != { 23, 24, 25};ok
+
+sctp dport 23;ok
+sctp dport != 23;ok
+sctp dport 23-44;ok
+sctp dport != 23-44;ok
+sctp dport { 23, 24, 25};ok
+sctp dport != { 23, 24, 25};ok
+
+sctp checksum 1111;ok
+sctp checksum != 11;ok
+sctp checksum 21-333;ok
+sctp checksum != 32-111;ok
+sctp checksum { 22, 33, 44};ok
+sctp checksum != { 22, 33, 44};ok
+
+sctp vtag 22;ok
+sctp vtag != 233;ok
+sctp vtag 33-45;ok
+sctp vtag != 33-45;ok
+sctp vtag {33, 55, 67, 88};ok
+sctp vtag != {33, 55, 67, 88};ok
+
+# assert all chunk types are recognized
+sctp chunk data exists;ok
+sctp chunk init exists;ok
+sctp chunk init-ack exists;ok
+sctp chunk sack exists;ok
+sctp chunk heartbeat exists;ok
+sctp chunk heartbeat-ack exists;ok
+sctp chunk abort exists;ok
+sctp chunk shutdown exists;ok
+sctp chunk shutdown-ack exists;ok
+sctp chunk error exists;ok
+sctp chunk cookie-echo exists;ok
+sctp chunk cookie-ack exists;ok
+sctp chunk ecne exists;ok
+sctp chunk cwr exists;ok
+sctp chunk shutdown-complete exists;ok
+sctp chunk asconf-ack exists;ok
+sctp chunk forward-tsn exists;ok
+sctp chunk asconf exists;ok
+
+# test common header fields in random chunk types
+sctp chunk data type 0;ok
+sctp chunk init flags 23;ok
+sctp chunk init-ack length 42;ok
+
+# test one custom field in every applicable chunk type
+sctp chunk data stream 1337;ok
+sctp chunk init initial-tsn 5;ok
+sctp chunk init-ack num-outbound-streams 3;ok
+sctp chunk sack a-rwnd 1;ok
+sctp chunk shutdown cum-tsn-ack 65535;ok
+sctp chunk ecne lowest-tsn 5;ok
+sctp chunk cwr lowest-tsn 8;ok
+sctp chunk asconf-ack seqno 12345;ok
+sctp chunk forward-tsn new-cum-tsn 31337;ok
+sctp chunk asconf seqno 12345;ok
diff --git a/tests/py/inet/sctp.t.json b/tests/py/inet/sctp.t.json
new file mode 100644
index 0000000..75a9b01
--- /dev/null
+++ b/tests/py/inet/sctp.t.json
@@ -0,0 +1,928 @@
+# sctp sport 23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": 23
+ }
+ }
+]
+
+# sctp sport != 23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": 23
+ }
+ }
+]
+
+# sctp sport 23-44
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 23, 44 ]
+ }
+ }
+ }
+]
+
+# sctp sport != 23-44
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 23, 44 ]
+ }
+ }
+ }
+]
+
+# sctp sport { 23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# sctp sport != { 23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# sctp dport 23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": 23
+ }
+ }
+]
+
+# sctp dport != 23
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": 23
+ }
+ }
+]
+
+# sctp dport 23-44
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 23, 44 ]
+ }
+ }
+ }
+]
+
+# sctp dport != 23-44
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 23, 44 ]
+ }
+ }
+ }
+]
+
+# sctp dport { 23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# sctp dport != { 23, 24, 25}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 24,
+ 25
+ ]
+ }
+ }
+ }
+]
+
+# sctp checksum 1111
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": 1111
+ }
+ }
+]
+
+# sctp checksum != 11
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": 11
+ }
+ }
+]
+
+# sctp checksum 21-333
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 21, 333 ]
+ }
+ }
+ }
+]
+
+# sctp checksum != 32-111
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 32, 111 ]
+ }
+ }
+ }
+]
+
+# sctp checksum { 22, 33, 44}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 33,
+ 44
+ ]
+ }
+ }
+ }
+]
+
+# sctp checksum != { 22, 33, 44}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 22,
+ 33,
+ 44
+ ]
+ }
+ }
+ }
+]
+
+# sctp vtag 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vtag",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# sctp vtag != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vtag",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# sctp vtag 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vtag",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# sctp vtag != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vtag",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# sctp vtag {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vtag",
+ "protocol": "sctp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# sctp vtag != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vtag",
+ "protocol": "sctp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# sctp chunk data exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "data"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk init exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "init"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk init-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "init-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk sack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk heartbeat exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "heartbeat"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk heartbeat-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "heartbeat-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk abort exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "abort"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk shutdown exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "shutdown"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk shutdown-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "shutdown-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk error exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "error"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk cookie-echo exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "cookie-echo"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk cookie-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "cookie-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk ecne exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "ecne"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk cwr exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "cwr"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk shutdown-complete exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "shutdown-complete"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk asconf-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "asconf-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk forward-tsn exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "forward-tsn"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk asconf exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "asconf"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk data type 0
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "type",
+ "name": "data"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# sctp chunk init flags 23
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "flags",
+ "name": "init"
+ }
+ },
+ "op": "==",
+ "right": 23
+ }
+ }
+]
+
+# sctp chunk init-ack length 42
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "length",
+ "name": "init-ack"
+ }
+ },
+ "op": "==",
+ "right": 42
+ }
+ }
+]
+
+# sctp chunk data stream 1337
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "stream",
+ "name": "data"
+ }
+ },
+ "op": "==",
+ "right": 1337
+ }
+ }
+]
+
+# sctp chunk init initial-tsn 5
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "initial-tsn",
+ "name": "init"
+ }
+ },
+ "op": "==",
+ "right": 5
+ }
+ }
+]
+
+# sctp chunk init-ack num-outbound-streams 3
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "num-outbound-streams",
+ "name": "init-ack"
+ }
+ },
+ "op": "==",
+ "right": 3
+ }
+ }
+]
+
+# sctp chunk sack a-rwnd 1
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "a-rwnd",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# sctp chunk shutdown cum-tsn-ack 65535
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "cum-tsn-ack",
+ "name": "shutdown"
+ }
+ },
+ "op": "==",
+ "right": 65535
+ }
+ }
+]
+
+# sctp chunk ecne lowest-tsn 5
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "lowest-tsn",
+ "name": "ecne"
+ }
+ },
+ "op": "==",
+ "right": 5
+ }
+ }
+]
+
+# sctp chunk cwr lowest-tsn 8
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "lowest-tsn",
+ "name": "cwr"
+ }
+ },
+ "op": "==",
+ "right": 8
+ }
+ }
+]
+
+# sctp chunk asconf-ack seqno 12345
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "seqno",
+ "name": "asconf-ack"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ }
+]
+
+# sctp chunk forward-tsn new-cum-tsn 31337
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "new-cum-tsn",
+ "name": "forward-tsn"
+ }
+ },
+ "op": "==",
+ "right": 31337
+ }
+ }
+]
+
+# sctp chunk asconf seqno 12345
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "seqno",
+ "name": "asconf"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ }
+]
+
diff --git a/tests/py/inet/sctp.t.payload b/tests/py/inet/sctp.t.payload
new file mode 100644
index 0000000..7337e2e
--- /dev/null
+++ b/tests/py/inet/sctp.t.payload
@@ -0,0 +1,351 @@
+# sctp sport 23
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00001700 ]
+
+# sctp sport != 23
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00001700 ]
+
+# sctp sport 23-44
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00001700 ]
+ [ cmp lte reg 1 0x00002c00 ]
+
+# sctp sport != 23-44
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ range neq reg 1 0x00001700 0x00002c00 ]
+
+# sctp sport { 23, 24, 25}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# sctp sport != { 23, 24, 25}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# sctp dport 23
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001700 ]
+
+# sctp dport != 23
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00001700 ]
+
+# sctp dport 23-44
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00001700 ]
+ [ cmp lte reg 1 0x00002c00 ]
+
+# sctp dport != 23-44
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00001700 0x00002c00 ]
+
+# sctp dport { 23, 24, 25}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# sctp dport != { 23, 24, 25}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00001800 : 0 [end] element 00001900 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# sctp checksum 1111
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x57040000 ]
+
+# sctp checksum != 11
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp neq reg 1 0x0b000000 ]
+
+# sctp checksum 21-333
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp gte reg 1 0x15000000 ]
+ [ cmp lte reg 1 0x4d010000 ]
+
+# sctp checksum != 32-111
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ range neq reg 1 0x20000000 0x6f000000 ]
+
+# sctp checksum { 22, 33, 44}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 16000000 : 0 [end] element 21000000 : 0 [end] element 2c000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# sctp checksum != { 22, 33, 44}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 16000000 : 0 [end] element 21000000 : 0 [end] element 2c000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# sctp vtag 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# sctp vtag != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0xe9000000 ]
+
+# sctp vtag 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# sctp vtag != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# sctp vtag {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# sctp vtag != {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# sctp chunk data exists
+ip
+ [ exthdr load 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk init exists
+ip
+ [ exthdr load 1b @ 1 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk init-ack exists
+ip
+ [ exthdr load 1b @ 2 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk sack exists
+ip
+ [ exthdr load 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk heartbeat exists
+ip
+ [ exthdr load 1b @ 4 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk heartbeat-ack exists
+ip
+ [ exthdr load 1b @ 5 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk abort exists
+ip
+ [ exthdr load 1b @ 6 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk shutdown exists
+ip
+ [ exthdr load 1b @ 7 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk shutdown-ack exists
+ip
+ [ exthdr load 1b @ 8 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk error exists
+ip
+ [ exthdr load 1b @ 9 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk cookie-echo exists
+ip
+ [ exthdr load 1b @ 10 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk cookie-ack exists
+ip
+ [ exthdr load 1b @ 11 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk ecne exists
+ip
+ [ exthdr load 1b @ 12 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk cwr exists
+ip
+ [ exthdr load 1b @ 13 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk shutdown-complete exists
+ip
+ [ exthdr load 1b @ 14 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk asconf-ack exists
+ip
+ [ exthdr load 1b @ 128 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk forward-tsn exists
+ip
+ [ exthdr load 1b @ 192 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk asconf exists
+ip
+ [ exthdr load 1b @ 193 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk data type 0
+ip
+ [ exthdr load 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# sctp chunk init flags 23
+ip
+ [ exthdr load 1b @ 1 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# sctp chunk init-ack length 42
+ip
+ [ exthdr load 2b @ 2 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00002a00 ]
+
+# sctp chunk data stream 1337
+ip
+ [ exthdr load 2b @ 0 + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003905 ]
+
+# sctp chunk init initial-tsn 5
+ip
+ [ exthdr load 4b @ 1 + 16 => reg 1 ]
+ [ cmp eq reg 1 0x05000000 ]
+
+# sctp chunk init-ack num-outbound-streams 3
+ip
+ [ exthdr load 2b @ 2 + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000300 ]
+
+# sctp chunk sack a-rwnd 1
+ip
+ [ exthdr load 4b @ 3 + 8 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# sctp chunk shutdown cum-tsn-ack 65535
+ip
+ [ exthdr load 4b @ 7 + 4 => reg 1 ]
+ [ cmp eq reg 1 0xffff0000 ]
+
+# sctp chunk ecne lowest-tsn 5
+ip
+ [ exthdr load 4b @ 12 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x05000000 ]
+
+# sctp chunk cwr lowest-tsn 8
+ip
+ [ exthdr load 4b @ 13 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x08000000 ]
+
+# sctp chunk asconf-ack seqno 12345
+ip
+ [ exthdr load 4b @ 128 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x39300000 ]
+
+# sctp chunk forward-tsn new-cum-tsn 31337
+ip
+ [ exthdr load 4b @ 192 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x697a0000 ]
+
+# sctp chunk asconf seqno 12345
+ip
+ [ exthdr load 4b @ 193 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x39300000 ]
+
diff --git a/tests/py/inet/sets.t b/tests/py/inet/sets.t
new file mode 100644
index 0000000..5b22e1f
--- /dev/null
+++ b/tests/py/inet/sets.t
@@ -0,0 +1,25 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*inet;test-inet;input
+*bridge;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+!set1 type ipv4_addr timeout 60s;ok
+?set1 192.168.3.4 timeout 30s, 10.2.1.1;ok
+
+!set2 type ipv6_addr timeout 23d23h59m59s;ok
+?set2 dead::beef timeout 5s;ok
+
+ip saddr @set1 drop;ok
+ip saddr != @set2 drop;fail
+
+ip6 daddr != @set2 accept;ok
+ip6 daddr @set1 drop;fail
+
+!set3 type ipv4_addr . ipv4_addr . inet_service flags interval;ok
+?set3 10.0.0.0/8 . 192.168.1.3-192.168.1.9 . 1024-65535;ok
+
+ip saddr . ip daddr . tcp dport @set3 accept;ok
+ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept;ok
diff --git a/tests/py/inet/sets.t.json b/tests/py/inet/sets.t.json
new file mode 100644
index 0000000..b44ffc2
--- /dev/null
+++ b/tests/py/inet/sets.t.json
@@ -0,0 +1,136 @@
+# ip saddr @set1 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "@set1"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip6 daddr != @set2 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": "@set2"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip saddr . ip daddr . tcp dport @set3 accept
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": "@set3"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 8
+ }
+ },
+ {
+ "range": [
+ 10,
+ 23
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ "192.168.1.1",
+ "192.168.3.8"
+ ]
+ },
+ {
+ "range": [
+ 80,
+ 443
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
diff --git a/tests/py/inet/sets.t.payload.bridge b/tests/py/inet/sets.t.payload.bridge
new file mode 100644
index 0000000..3dd9d57
--- /dev/null
+++ b/tests/py/inet/sets.t.payload.bridge
@@ -0,0 +1,42 @@
+# ip saddr @set1 drop
+bridge test-inet input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 ]
+ [ immediate reg 0 drop ]
+
+# ip6 daddr != @set2 accept
+bridge test-inet input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip saddr . ip daddr . tcp dport @set3 accept
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-inet 87
+__set%d test-inet 0
+ element 0000000a 00000a00 - ffffff0a 00001700 : 0 [end] element 0101a8c0 00005000 - 0803a8c0 0000bb01 : 0 [end]
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
diff --git a/tests/py/inet/sets.t.payload.inet b/tests/py/inet/sets.t.payload.inet
new file mode 100644
index 0000000..53c6b18
--- /dev/null
+++ b/tests/py/inet/sets.t.payload.inet
@@ -0,0 +1,41 @@
+# ip saddr @set1 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 ]
+ [ immediate reg 0 drop ]
+
+# ip6 daddr != @set2 accept
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip saddr . ip daddr . tcp dport @set3 accept
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-inet 87
+__set%d test-inet 0
+ element 0000000a 00000a00 - ffffff0a 00001700 : 0 [end] element 0101a8c0 00005000 - 0803a8c0 0000bb01 : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/inet/sets.t.payload.netdev b/tests/py/inet/sets.t.payload.netdev
new file mode 100644
index 0000000..e31aeb9
--- /dev/null
+++ b/tests/py/inet/sets.t.payload.netdev
@@ -0,0 +1,41 @@
+# ip saddr @set1 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 ]
+ [ immediate reg 0 drop ]
+
+# ip6 daddr != @set2 accept
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip saddr . ip daddr . tcp dport @set3 accept
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-netdev 87
+__set%d test-netdev 0
+ element 0000000a 00000a00 - ffffff0a 00001700 : 0 [end] element 0101a8c0 00005000 - 0803a8c0 0000bb01 : 0 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/inet/snat.t b/tests/py/inet/snat.t
new file mode 100644
index 0000000..cf23b5c
--- /dev/null
+++ b/tests/py/inet/snat.t
@@ -0,0 +1,21 @@
+:postrouting;type nat hook postrouting priority 0
+
+*inet;test-inet;postrouting
+
+# explicit family: 'snat to ip':
+iifname "eth0" tcp dport 81 snat ip to 192.168.3.2;ok
+
+# infer snat target family from network header base:
+iifname "eth0" tcp dport 81 ip saddr 10.1.1.1 snat to 192.168.3.2;ok;iifname "eth0" tcp dport 81 ip saddr 10.1.1.1 snat ip to 192.168.3.2
+iifname "eth0" tcp dport 81 snat ip6 to dead::beef;ok
+
+iifname "foo" masquerade random;ok
+
+
+snat to 192.168.3.2;fail
+snat ip6 to 192.168.3.2;fail
+snat to dead::beef;fail
+snat ip to dead::beef;fail
+snat ip daddr 1.2.3.4 to dead::beef;fail
+snat ip daddr 1.2.3.4 ip6 to dead::beef;fail
+snat ip6 saddr dead::beef to 1.2.3.4;fail
diff --git a/tests/py/inet/snat.t.json b/tests/py/inet/snat.t.json
new file mode 100644
index 0000000..4671625
--- /dev/null
+++ b/tests/py/inet/snat.t.json
@@ -0,0 +1,131 @@
+# iifname "eth0" tcp dport 81 snat ip to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2",
+ "family": "ip"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 ip saddr 10.1.1.1 snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "10.1.1.1"
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2",
+ "family": "ip"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 snat ip6 to dead::beef
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "snat": {
+ "addr": "dead::beef",
+ "family": "ip6"
+ }
+ }
+]
+
+# iifname "foo" masquerade random
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "foo"
+ }
+ },
+ {
+ "masquerade": {
+ "flags": "random"
+ }
+ }
+]
+
diff --git a/tests/py/inet/snat.t.payload b/tests/py/inet/snat.t.payload
new file mode 100644
index 0000000..50519c6
--- /dev/null
+++ b/tests/py/inet/snat.t.payload
@@ -0,0 +1,42 @@
+# iifname "eth0" tcp dport 81 snat ip to 192.168.3.2
+inet test-inet postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport 81 ip saddr 10.1.1.1 snat to 192.168.3.2
+inet test-inet postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0101010a ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport 81 snat ip6 to dead::beef
+inet test-inet postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
+ [ nat snat ip6 addr_min reg 1 ]
+
+# iifname "foo" masquerade random
+inet test-inet postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x006f6f66 0x00000000 0x00000000 0x00000000 ]
+ [ masq flags 0x4 ]
diff --git a/tests/py/inet/socket.t b/tests/py/inet/socket.t
new file mode 100644
index 0000000..05e9ebb
--- /dev/null
+++ b/tests/py/inet/socket.t
@@ -0,0 +1,15 @@
+:sockchain;type filter hook prerouting priority -150
+
+*ip;sockip4;sockchain
+*ip6;sockip6;sockchain
+*inet;sockin;sockchain
+
+socket transparent 0;ok
+socket transparent 1;ok
+socket transparent 2;fail
+
+socket mark 0x00000005;ok
+
+socket wildcard 0;ok
+socket wildcard 1;ok
+socket wildcard 2;fail
diff --git a/tests/py/inet/socket.t.json b/tests/py/inet/socket.t.json
new file mode 100644
index 0000000..fa48e79
--- /dev/null
+++ b/tests/py/inet/socket.t.json
@@ -0,0 +1,74 @@
+# socket transparent 0
+[
+ {
+ "match": {
+ "left": {
+ "socket": {
+ "key": "transparent"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# socket transparent 1
+[
+ {
+ "match": {
+ "left": {
+ "socket": {
+ "key": "transparent"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# socket mark 0x00000005
+[
+ {
+ "match": {
+ "left": {
+ "socket": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 5
+ }
+ }
+]
+
+# socket wildcard 0
+[
+ {
+ "match": {
+ "left": {
+ "socket": {
+ "key": "wildcard"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# socket wildcard 1
+[
+ {
+ "match": {
+ "left": {
+ "socket": {
+ "key": "wildcard"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
diff --git a/tests/py/inet/socket.t.payload b/tests/py/inet/socket.t.payload
new file mode 100644
index 0000000..e66ccbf
--- /dev/null
+++ b/tests/py/inet/socket.t.payload
@@ -0,0 +1,24 @@
+# socket transparent 0
+inet sockin sockchain
+ [ socket load transparent => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# socket transparent 1
+inet sockin sockchain
+ [ socket load transparent => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# socket mark 0x00000005
+inet sockin sockchain
+ [ socket load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+
+# socket wildcard 0
+inet sockin sockchain
+ [ socket load wildcard => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# socket wildcard 1
+inet sockin sockchain
+ [ socket load wildcard => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/inet/synproxy.t b/tests/py/inet/synproxy.t
new file mode 100644
index 0000000..55a05e1
--- /dev/null
+++ b/tests/py/inet/synproxy.t
@@ -0,0 +1,13 @@
+:synproxychain;type filter hook input priority 0
+
+*ip;synproxyip;synproxychain
+*ip6;synproxyip6;synproxychain
+*inet;synproxyinet;synproxychain
+
+synproxy;ok
+synproxy mss 1460 wscale 7;ok
+synproxy mss 1460 wscale 5 timestamp sack-perm;ok
+synproxy timestamp sack-perm;ok
+synproxy timestamp;ok
+synproxy sack-perm;ok
+
diff --git a/tests/py/inet/synproxy.t.json b/tests/py/inet/synproxy.t.json
new file mode 100644
index 0000000..1dd85a6
--- /dev/null
+++ b/tests/py/inet/synproxy.t.json
@@ -0,0 +1,64 @@
+# synproxy
+[
+ {
+ "synproxy":null
+ }
+]
+
+# synproxy mss 1460 wscale 7
+[
+ {
+ "synproxy": {
+ "mss": 1460,
+ "wscale": 7
+ }
+ }
+]
+
+# synproxy timestamp
+[
+ {
+ "synproxy": {
+ "flags": [
+ "timestamp"
+ ]
+ }
+ }
+]
+
+# synproxy timestamp sack-perm
+[
+ {
+ "synproxy": {
+ "flags": [
+ "timestamp",
+ "sack-perm"
+ ]
+ }
+ }
+]
+
+# synproxy mss 1460 wscale 5 timestamp sack-perm
+[
+ {
+ "synproxy": {
+ "flags": [
+ "timestamp",
+ "sack-perm"
+ ],
+ "mss": 1460,
+ "wscale": 5
+ }
+ }
+]
+
+# synproxy sack-perm
+[
+ {
+ "synproxy": {
+ "flags": [
+ "sack-perm"
+ ]
+ }
+ }
+]
diff --git a/tests/py/inet/synproxy.t.payload b/tests/py/inet/synproxy.t.payload
new file mode 100644
index 0000000..dd318b9
--- /dev/null
+++ b/tests/py/inet/synproxy.t.payload
@@ -0,0 +1,24 @@
+# synproxy
+inet synproxyinet synproxychain
+ [ synproxy mss 0 wscale 0 ]
+
+# synproxy mss 1460 wscale 7
+inet synproxyinet synproxychain
+ [ synproxy mss 1460 wscale 7 ]
+
+# synproxy mss 1460 wscale 5 timestamp sack-perm
+inet synproxyinet synproxychain
+ [ synproxy mss 1460 wscale 5 ]
+
+# synproxy timestamp sack-perm
+inet synproxyinet synproxychain
+ [ synproxy mss 0 wscale 0 ]
+
+# synproxy timestamp
+inet synproxyinet synproxychain
+ [ synproxy mss 0 wscale 0 ]
+
+# synproxy sack-perm
+inet synproxyinet synproxychain
+ [ synproxy mss 0 wscale 0 ]
+
diff --git a/tests/py/inet/tcp.t b/tests/py/inet/tcp.t
new file mode 100644
index 0000000..f51ebd3
--- /dev/null
+++ b/tests/py/inet/tcp.t
@@ -0,0 +1,115 @@
+: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
+
+tcp dport set {1, 2, 3};fail
+
+tcp dport 22;ok
+tcp dport != 233;ok
+tcp dport 33-45;ok
+tcp dport != 33-45;ok
+tcp dport { 33, 55, 67, 88};ok
+tcp dport != { 33, 55, 67, 88};ok
+tcp dport {telnet, http, https} accept;ok;tcp dport { 443, 23, 80} accept
+tcp dport vmap { 22 : accept, 23 : drop };ok
+tcp dport vmap { 25:accept, 28:drop };ok
+tcp dport { 22, 53, 80, 110 };ok
+tcp dport != { 22, 53, 80, 110 };ok
+# BUG: invalid expression type set
+# nft: src/evaluate.c:975: expr_evaluate_relational: Assertion '0' failed.
+
+tcp sport 22;ok
+tcp sport != 233;ok
+tcp sport 33-45;ok
+tcp sport != 33-45;ok
+tcp sport { 33, 55, 67, 88};ok
+tcp sport != { 33, 55, 67, 88};ok
+tcp sport vmap { 25:accept, 28:drop };ok
+
+tcp sport 8080 drop;ok
+tcp sport 1024 tcp dport 22;ok
+tcp sport 1024 tcp dport 22 tcp sequence 0;ok
+
+tcp sequence 0 tcp sport 1024 tcp dport 22;ok
+tcp sequence 0 tcp sport { 1024, 1022} tcp dport 22;ok;tcp sequence 0 tcp sport { 1022, 1024} tcp dport 22
+
+tcp sequence 22;ok
+tcp sequence != 233;ok
+tcp sequence 33-45;ok
+tcp sequence != 33-45;ok
+tcp sequence { 33, 55, 67, 88};ok
+tcp sequence != { 33, 55, 67, 88};ok
+
+tcp ackseq 42949672 drop;ok
+tcp ackseq 22;ok
+tcp ackseq != 233;ok
+tcp ackseq 33-45;ok
+tcp ackseq != 33-45;ok
+tcp ackseq { 33, 55, 67, 88};ok
+tcp ackseq != { 33, 55, 67, 88};ok
+
+- tcp doff 22;ok
+- tcp doff != 233;ok
+- tcp doff 33-45;ok
+- tcp doff != 33-45;ok
+- tcp doff { 33, 55, 67, 88};ok
+- tcp doff != { 33, 55, 67, 88};ok
+
+# BUG reserved
+# BUG: It is accepted but it is not shown then. tcp reserver
+
+tcp flags { fin, syn, rst, psh, ack, urg, ecn, cwr} drop;ok
+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 & syn != 0;ok;tcp flags syn
+tcp flags & syn == 0;ok;tcp flags ! syn
+tcp flags & (syn | ack) != 0;ok;tcp flags syn,ack
+tcp flags & (syn | ack) == 0;ok;tcp flags ! syn,ack
+# it should be possible to transform this to: tcp flags syn
+tcp flags & syn == syn;ok
+tcp flags & syn != syn;ok
+tcp flags & (fin | syn | rst | ack) syn;ok;tcp flags 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 | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr;ok;tcp flags == 0xff
+tcp flags { syn, syn | ack };ok
+tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack };ok
+tcp flags ! fin,rst;ok
+tcp flags & (fin | syn | rst | ack) ! syn;fail
+
+tcp window 22222;ok
+tcp window 22;ok
+tcp window != 233;ok
+tcp window 33-45;ok
+tcp window != 33-45;ok
+tcp window { 33, 55, 67, 88};ok
+tcp window != { 33, 55, 67, 88};ok
+
+tcp checksum 22;ok
+tcp checksum != 233;ok
+tcp checksum 33-45;ok
+tcp checksum != 33-45;ok
+tcp checksum { 33, 55, 67, 88};ok
+tcp checksum != { 33, 55, 67, 88};ok
+
+tcp urgptr 1234 accept;ok
+tcp urgptr 22;ok
+tcp urgptr != 233;ok
+tcp urgptr 33-45;ok
+tcp urgptr != 33-45;ok
+tcp urgptr { 33, 55, 67, 88};ok
+tcp urgptr != { 33, 55, 67, 88};ok
+
+tcp doff 8;ok
diff --git a/tests/py/inet/tcp.t.json b/tests/py/inet/tcp.t.json
new file mode 100644
index 0000000..8439c2b
--- /dev/null
+++ b/tests/py/inet/tcp.t.json
@@ -0,0 +1,1799 @@
+# tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp dport != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# tcp dport 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp dport != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp dport { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp dport != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp dport {telnet, http, https} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "telnet",
+ "http",
+ "https"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp dport vmap { 22 : accept, 23 : drop }
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ {
+ "accept": null
+ }
+ ],
+ [
+ 23,
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# tcp dport vmap { 25:accept, 28:drop }
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 25,
+ {
+ "accept": null
+ }
+ ],
+ [
+ 28,
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# tcp dport { 22, 53, 80, 110 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 53,
+ 80,
+ 110
+ ]
+ }
+ }
+ }
+]
+
+# tcp dport != { 22, 53, 80, 110 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 22,
+ 53,
+ 80,
+ 110
+ ]
+ }
+ }
+ }
+]
+
+# tcp sport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp sport != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# tcp sport 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp sport != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp sport { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp sport != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp sport vmap { 25:accept, 28:drop }
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 25,
+ {
+ "accept": null
+ }
+ ],
+ [
+ 28,
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# tcp sport 8080 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 8080
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# tcp sport 1024 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 1024
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp sport 1024 tcp dport 22 tcp sequence 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 1024
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# tcp sequence 0 tcp sport 1024 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 1024
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp sequence 0 tcp sport { 1024, 1022} tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1024,
+ 1022
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp sequence 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp sequence != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# tcp sequence 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp sequence != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp sequence { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp sequence != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp ackseq 42949672 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ackseq",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 42949672
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# tcp ackseq 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ackseq",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp ackseq != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ackseq",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# tcp ackseq 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ackseq",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp ackseq != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ackseq",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp ackseq { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ackseq",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp ackseq != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ackseq",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags { fin, syn, rst, psh, ack, urg, ecn, cwr} drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "fin",
+ "syn",
+ "rst",
+ "psh",
+ "ack",
+ "urg",
+ "ecn",
+ "cwr"
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# tcp flags != { fin, urg, ecn, cwr} drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "fin",
+ "urg",
+ "ecn",
+ "cwr"
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# tcp flags cwr
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "in",
+ "right": "cwr"
+ }
+ }
+]
+
+# tcp flags != cwr
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": "cwr"
+ }
+ }
+]
+
+# tcp flags == syn
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (syn|fin) == (syn|fin)
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "syn",
+ "fin"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "|": [
+ "syn",
+ "fin"
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [ "fin", { "|": [ "syn", { "|": [ "rst", { "|": [ "psh", { "|": [ "ack", { "|": [ "urg", { "|": [ "ecn", "cwr" ] } ] } ] } ] } ] } ] } ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": { "|": [ "fin", { "|": [ "syn", { "|": [ "rst", { "|": [ "psh", { "|": [ "ack", { "|": [ "urg", { "|": [ "ecn", "cwr" ] } ] } ] } ] } ] } ] } ] }
+ }
+ }
+]
+
+# tcp window 22222
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "window",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22222
+ }
+ }
+]
+
+# tcp window 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "window",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp window != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "window",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# tcp window 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "window",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp window != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "window",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp window { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "window",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp window != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "window",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp checksum 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp checksum != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# tcp checksum 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp checksum != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp checksum { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp checksum != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp urgptr 1234 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "urgptr",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 1234
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp urgptr 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "urgptr",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp urgptr != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "urgptr",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# tcp urgptr 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "urgptr",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp urgptr != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "urgptr",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# tcp urgptr { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "urgptr",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp urgptr != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "urgptr",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# tcp doff 8
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "doff",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 8
+ }
+ }
+]
+
+# tcp flags { syn, syn | ack }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ "syn"
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ },
+ "rst"
+ ]
+ },
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "|": [
+ {
+ "|": [
+ "fin",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ "fin",
+ {
+ "|": [
+ "psh",
+ "ack"
+ ]
+ },
+ "ack"
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags ! fin,rst
+[
+ {
+ "match": {
+ "op": "!",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ "right": [
+ "fin",
+ "rst"
+ ]
+ }
+ }
+]
+
+# 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 & syn == 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & syn != 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "in",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (syn | ack) != 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "in",
+ "right": [
+ "syn",
+ "ack"
+ ]
+ }
+ }
+]
+
+# tcp flags & (syn | ack) == 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!",
+ "right": [
+ "syn",
+ "ack"
+ ]
+ }
+ }
+]
+
+# tcp flags & syn == syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "syn"
+ ]
+ },
+ "op": "==",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & syn != syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "syn"
+ ]
+ },
+ "op": "!=",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | ack) syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ ]
+ },
+ "op": "==",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | ack) == syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ ]
+ },
+ "op": "==",
+ "right": "syn"
+ }
+ }
+]
+
+
+# tcp flags & (fin | syn | rst | ack) != syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ ]
+ },
+ "op": "!=",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | ack) == (syn | ack)
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ ]
+ },
+ "op": "==",
+ "right": [
+ "syn",
+ "ack"
+ ]
+ }
+ }
+]
+
+# tcp flags & (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.json.output b/tests/py/inet/tcp.t.json.output
new file mode 100644
index 0000000..c471e8d
--- /dev/null
+++ b/tests/py/inet/tcp.t.json.output
@@ -0,0 +1,210 @@
+# tcp dport {telnet, http, https} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 80,
+ 443
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp sequence 0 tcp sport { 1024, 1022} tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1022,
+ 1024
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp flags & (syn|fin) == (syn|fin)
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 255
+ }
+ }
+]
+
+# tcp flags { syn, syn | ack }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "syn",
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ },
+ "rst"
+ ]
+ },
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "fin",
+ {
+ "|": [
+ {
+ "|": [
+ "fin",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "psh",
+ "ack"
+ ]
+ },
+ "ack"
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/inet/tcp.t.payload b/tests/py/inet/tcp.t.payload
new file mode 100644
index 0000000..1cfe500
--- /dev/null
+++ b/tests/py/inet/tcp.t.payload
@@ -0,0 +1,674 @@
+# tcp dport 22
+inet test-inet 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 dport != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# tcp dport 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# tcp dport != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# tcp dport { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp dport != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp dport {telnet, http, https} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001700 : 0 [end] element 00005000 : 0 [end] element 0000bb01 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# tcp dport vmap { 22 : accept, 23 : drop }
+__map%d test-inet b
+__map%d test-inet 0
+ element 00001600 : accept 0 [end] element 00001700 : drop 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# tcp dport vmap { 25:accept, 28:drop }
+__map%d test-inet b
+__map%d test-inet 0
+ element 00001900 : accept 0 [end] element 00001c00 : drop 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# tcp dport { 22, 53, 80, 110 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001600 : 0 [end] element 00003500 : 0 [end] element 00005000 : 0 [end] element 00006e00 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp dport != { 22, 53, 80, 110 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00001600 : 0 [end] element 00003500 : 0 [end] element 00005000 : 0 [end] element 00006e00 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp sport 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# tcp sport != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# tcp sport 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# tcp sport != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# tcp sport { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp sport != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp sport vmap { 25:accept, 28:drop }
+__map%d test-inet b
+__map%d test-inet 0
+ element 00001900 : accept 0 [end] element 00001c00 : drop 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# tcp sport 8080 drop
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000901f ]
+ [ immediate reg 0 drop ]
+
+# tcp sport 1024 tcp dport 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x16000004 ]
+
+# tcp sport 1024 tcp dport 22 tcp sequence 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x16000004 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp sequence 0 tcp sport 1024 tcp dport 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x16000004 ]
+
+# tcp sequence 0 tcp sport { 1024, 1022} tcp dport 22
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000004 : 0 [end] element 0000fe03 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# tcp sequence 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# tcp sequence != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0xe9000000 ]
+
+# tcp sequence 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# tcp sequence != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# tcp sequence { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp sequence != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp ackseq 42949672 drop
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x285c8f02 ]
+ [ immediate reg 0 drop ]
+
+# tcp ackseq 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# tcp ackseq != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp neq reg 1 0xe9000000 ]
+
+# tcp ackseq 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# tcp ackseq != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# tcp ackseq { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp ackseq != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp flags { fin, syn, rst, psh, ack, urg, ecn, cwr} drop
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000001 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000008 : 0 [end] element 00000010 : 0 [end] element 00000020 : 0 [end] element 00000040 : 0 [end] element 00000080 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 drop ]
+
+# tcp flags != { fin, urg, ecn, cwr} drop
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000001 : 0 [end] element 00000020 : 0 [end] element 00000040 : 0 [end] element 00000080 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 drop ]
+
+# tcp flags cwr
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000080 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# tcp flags != cwr
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ cmp neq reg 1 0x00000080 ]
+
+# tcp flags == syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# tcp flags fin,syn / fin,syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000003 ]
+
+# tcp flags != syn / fin,syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# tcp flags & syn != 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# tcp flags & syn == 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp flags & (syn | ack) != 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000012 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# tcp flags & (syn | ack) == 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000012 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp flags & syn == syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# tcp flags & syn != syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) == syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) != syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) == (syn | ack)
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000012 ]
+
+# tcp flags & (fin | syn | rst | ack) != (syn | ack)
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000012 ]
+
+# tcp flags & (syn | ack) == (syn | ack)
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000012 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000012 ]
+
+# tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# tcp window 22222
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0000ce56 ]
+
+# tcp window 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# tcp window != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 14 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# tcp window 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 14 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# tcp window != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 14 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# tcp window { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 14 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp window != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 14 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp checksum 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# tcp checksum != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 16 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# tcp checksum 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# tcp checksum != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 16 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# tcp checksum { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp checksum != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp urgptr 1234 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x0000d204 ]
+ [ immediate reg 0 accept ]
+
+# tcp urgptr 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# tcp urgptr != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 18 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# tcp urgptr 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 18 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# tcp urgptr != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 18 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# tcp urgptr { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 18 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp urgptr != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 18 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# tcp doff 8
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000001 : 0 [end] element 00000010 : 0 [end] element 00000018 : 0 [end] element 00000019 : 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp flags { syn, syn | ack }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000002 : 0 [end] element 00000012 : 0 [end]
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp flags ! fin,rst
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000005 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
diff --git a/tests/py/inet/tproxy.t b/tests/py/inet/tproxy.t
new file mode 100644
index 0000000..d23bbcb
--- /dev/null
+++ b/tests/py/inet/tproxy.t
@@ -0,0 +1,21 @@
+:y;type filter hook prerouting priority -150
+
+*inet;x;y
+
+tproxy;fail
+meta l4proto 17 tproxy to 192.0.2.1;fail
+meta l4proto 6 tproxy to 192.0.2.1:50080;fail
+meta l4proto 17 tproxy ip to 192.0.2.1;ok
+meta l4proto 6 tproxy ip to 192.0.2.1:50080;ok
+ip protocol 6 tproxy ip6 to [2001:db8::1];fail
+
+meta l4proto 6 tproxy to [2001:db8::1];fail
+meta l4proto 17 tproxy to [2001:db8::1]:50080;fail
+meta l4proto 6 tproxy ip6 to [2001:db8::1];ok
+meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080;ok
+ip6 nexthdr 6 tproxy ip to 192.0.2.1;fail
+
+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
diff --git a/tests/py/inet/tproxy.t.json b/tests/py/inet/tproxy.t.json
new file mode 100644
index 0000000..7b3b11c
--- /dev/null
+++ b/tests/py/inet/tproxy.t.json
@@ -0,0 +1,185 @@
+# meta l4proto 17 tproxy ip to 192.0.2.1
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1",
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto 6 tproxy ip to 192.0.2.1:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1",
+ "family": "ip",
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 6 tproxy ip6 to [2001:db8::1]
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1",
+ "family": "ip6"
+ }
+ }
+]
+
+# meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1",
+ "family": "ip6",
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 17 tproxy ip to :50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "family": "ip",
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 17 tproxy ip6 to :50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "family": "ip6",
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 17 tproxy to :50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "port": 50080
+ }
+ }
+]
+
+# ip daddr 0.0.0.0/0 meta l4proto 6 tproxy ip to :2000
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "0.0.0.0",
+ "len": 0
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "family": "ip",
+ "port": 2000
+ }
+ }
+]
diff --git a/tests/py/inet/tproxy.t.payload b/tests/py/inet/tproxy.t.payload
new file mode 100644
index 0000000..24bf8f6
--- /dev/null
+++ b/tests/py/inet/tproxy.t.payload
@@ -0,0 +1,63 @@
+# meta l4proto 17 tproxy ip to 192.0.2.1
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x010200c0 ]
+ [ tproxy ip addr reg 1 ]
+
+# meta l4proto 6 tproxy ip to 192.0.2.1:50080
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x010200c0 ]
+ [ immediate reg 2 0x0000a0c3 ]
+ [ tproxy ip addr reg 1 port reg 2 ]
+
+# meta l4proto 6 tproxy ip6 to [2001:db8::1]
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0xb80d0120 0x00000000 0x00000000 0x01000000 ]
+ [ tproxy ip6 addr reg 1 ]
+
+# meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0xb80d0120 0x00000000 0x00000000 0x01000000 ]
+ [ immediate reg 2 0x0000a0c3 ]
+ [ tproxy ip6 addr reg 1 port reg 2 ]
+
+# meta l4proto 17 tproxy to :50080
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x0000a0c3 ]
+ [ tproxy port reg 1 ]
+
+# meta l4proto 17 tproxy ip to :50080
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x0000a0c3 ]
+ [ tproxy ip port reg 1 ]
+
+# meta l4proto 17 tproxy ip6 to :50080
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x0000a0c3 ]
+ [ tproxy ip6 port reg 1 ]
+
+# ip daddr 0.0.0.0/0 meta l4proto 6 tproxy ip to :2000
+inet x y
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000000 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x0000d007 ]
+ [ tproxy ip port reg 1 ]
+
diff --git a/tests/py/inet/udp.t b/tests/py/inet/udp.t
new file mode 100644
index 0000000..7f21c8e
--- /dev/null
+++ b/tests/py/inet/udp.t
@@ -0,0 +1,45 @@
+: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
+
+udp sport 80 accept;ok
+udp sport != 60 accept;ok
+udp sport 50-70 accept;ok
+udp sport != 50-60 accept;ok
+udp sport { 49, 50} drop;ok
+udp sport != { 50, 60} accept;ok
+
+udp dport set {1, 2, 3};fail
+
+udp dport 80 accept;ok
+udp dport != 60 accept;ok
+udp dport 70-75 accept;ok
+udp dport != 50-60 accept;ok
+udp dport { 49, 50} drop;ok
+udp dport != { 50, 60} accept;ok
+
+udp length 6666;ok
+udp length != 6666;ok
+udp length 50-65 accept;ok
+udp length != 50-65 accept;ok
+udp length { 50, 65} accept;ok
+udp length != { 50, 65} accept;ok
+
+udp checksum 6666 drop;ok
+udp checksum != { 444, 555} accept;ok
+
+udp checksum 22;ok
+udp checksum != 233;ok
+udp checksum 33-45;ok
+udp checksum != 33-45;ok
+udp checksum { 33, 55, 67, 88};ok
+udp checksum != { 33, 55, 67, 88};ok
+
+# limit impact to lo
+iif "lo" udp checksum set 0;ok
+iif "lo" udp dport set 65535;ok
diff --git a/tests/py/inet/udp.t.json b/tests/py/inet/udp.t.json
new file mode 100644
index 0000000..665998e
--- /dev/null
+++ b/tests/py/inet/udp.t.json
@@ -0,0 +1,583 @@
+# udp sport 80 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 80
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp sport != 60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": 60
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp sport 50-70 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 50, 70 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp sport != 50-60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 50, 60 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp sport { 49, 50} drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 49,
+ 50
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# udp sport != { 50, 60} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 50,
+ 60
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp dport 80 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 80
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp dport != 60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": 60
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp dport 70-75 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 70, 75 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp dport != 50-60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 50, 60 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp dport { 49, 50} drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 49,
+ 50
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# udp dport != { 50, 60} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 50,
+ 60
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp length 6666
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6666
+ }
+ }
+]
+
+# udp length != 6666
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": 6666
+ }
+ }
+]
+
+# udp length 50-65 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 50, 65 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp length != 50-65 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 50, 65 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp length { 50, 65} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 50,
+ 65
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp length != { 50, 65} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 50,
+ 65
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp checksum 6666 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6666
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# udp checksum != { 444, 555} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 444,
+ 555
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udp checksum 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# udp checksum != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# udp checksum 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# udp checksum != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# udp checksum { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# udp checksum != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# iif "lo" udp checksum set 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udp"
+ }
+ },
+ "value": 0
+ }
+ }
+]
+
+# iif "lo" udp dport set 65535
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "value": 65535
+ }
+ }
+]
+
diff --git a/tests/py/inet/udp.t.payload b/tests/py/inet/udp.t.payload
new file mode 100644
index 0000000..e6beda7
--- /dev/null
+++ b/tests/py/inet/udp.t.payload
@@ -0,0 +1,248 @@
+# udp sport 80 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00005000 ]
+ [ immediate reg 0 accept ]
+
+# udp sport != 60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udp sport 50-70 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00003200 ]
+ [ cmp lte reg 1 0x00004600 ]
+ [ immediate reg 0 accept ]
+
+# udp sport != 50-60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ range neq reg 1 0x00003200 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udp sport { 49, 50} drop
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00003100 : 0 [end] element 00003200 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 drop ]
+
+# udp sport != { 50, 60} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00003200 : 0 [end] element 00003c00 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# udp dport 80 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005000 ]
+ [ immediate reg 0 accept ]
+
+# udp dport != 60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udp dport 70-75 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00004600 ]
+ [ cmp lte reg 1 0x00004b00 ]
+ [ immediate reg 0 accept ]
+
+# udp dport != 50-60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00003200 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udp dport { 49, 50} drop
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00003100 : 0 [end] element 00003200 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 drop ]
+
+# udp dport != { 50, 60} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00003200 : 0 [end] element 00003c00 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# udp length 6666
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000a1a ]
+
+# udp length != 6666
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x00000a1a ]
+
+# udp length 50-65 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00003200 ]
+ [ cmp lte reg 1 0x00004100 ]
+ [ immediate reg 0 accept ]
+
+# udp length != 50-65 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x00003200 0x00004100 ]
+ [ immediate reg 0 accept ]
+
+# udp length { 50, 65} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00003200 : 0 [end] element 00004100 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# udp length != { 50, 65} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00003200 : 0 [end] element 00004100 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# udp checksum 6666 drop
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000a1a ]
+ [ immediate reg 0 drop ]
+
+# udp checksum != { 444, 555} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0000bc01 : 0 [end] element 00002b02 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# udp checksum 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# udp checksum != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# udp checksum 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# udp checksum != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# udp checksum { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# udp checksum != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# iif "lo" udp checksum set 0
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ transport header + 6 csum_type 1 csum_off 6 csum_flags 0x0 ]
+
+# iif "lo" udp dport set 65535
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x0000ffff ]
+ [ payload write reg 1 => 2b @ transport header + 2 csum_type 1 csum_off 6 csum_flags 0x0 ]
diff --git a/tests/py/inet/udplite.t b/tests/py/inet/udplite.t
new file mode 100644
index 0000000..6a54709
--- /dev/null
+++ b/tests/py/inet/udplite.t
@@ -0,0 +1,38 @@
+: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
+
+udplite sport 80 accept;ok
+udplite sport != 60 accept;ok
+udplite sport 50-70 accept;ok
+udplite sport != 50-60 accept;ok
+udplite sport { 49, 50} drop;ok
+udplite sport != { 49, 50} accept;ok
+
+udplite dport 80 accept;ok
+udplite dport != 60 accept;ok
+udplite dport 70-75 accept;ok
+udplite dport != 50-60 accept;ok
+udplite dport { 49, 50} drop;ok
+udplite dport != { 49, 50} accept;ok
+
+- udplite csumcov 6666;ok
+- udplite csumcov != 6666;ok
+- udplite csumcov 50-65 accept;ok
+- udplite csumcov != 50-65 accept;ok
+- udplite csumcov { 50, 65} accept;ok
+- udplite csumcov != { 50, 65} accept;ok
+
+udplite checksum 6666 drop;ok
+udplite checksum != { 444, 555} accept;ok
+udplite checksum 22;ok
+udplite checksum != 233;ok
+udplite checksum 33-45;ok
+udplite checksum != 33-45;ok
+udplite checksum { 33, 55, 67, 88};ok
+udplite checksum != { 33, 55, 67, 88};ok
diff --git a/tests/py/inet/udplite.t.json b/tests/py/inet/udplite.t.json
new file mode 100644
index 0000000..713a534
--- /dev/null
+++ b/tests/py/inet/udplite.t.json
@@ -0,0 +1,413 @@
+# udplite sport 80 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": 80
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite sport != 60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": 60
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite sport 50-70 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 50, 70 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite sport != 50-60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 50, 60 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite sport { 49, 50} drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 49,
+ 50
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# udplite sport != { 49, 50} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 49,
+ 50
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite dport 80 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": 80
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite dport != 60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": 60
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite dport 70-75 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 70, 75 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite dport != 50-60 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 50, 60 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite dport { 49, 50} drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 49,
+ 50
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# udplite dport != { 49, 50} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 49,
+ 50
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite checksum 6666 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": 6666
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# udplite checksum != { 444, 555} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 444,
+ 555
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# udplite checksum 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# udplite checksum != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# udplite checksum 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# udplite checksum != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# udplite checksum { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# udplite checksum != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "udplite"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/udplite.t.payload b/tests/py/inet/udplite.t.payload
new file mode 100644
index 0000000..de9d09e
--- /dev/null
+++ b/tests/py/inet/udplite.t.payload
@@ -0,0 +1,178 @@
+# udplite sport 80 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00005000 ]
+ [ immediate reg 0 accept ]
+
+# udplite sport != 60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udplite sport 50-70 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00003200 ]
+ [ cmp lte reg 1 0x00004600 ]
+ [ immediate reg 0 accept ]
+
+# udplite sport != 50-60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ range neq reg 1 0x00003200 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udplite sport { 49, 50} drop
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00003100 : 0 [end] element 00003200 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 drop ]
+
+# udplite sport != { 49, 50} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00003100 : 0 [end] element 00003200 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# udplite dport 80 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005000 ]
+ [ immediate reg 0 accept ]
+
+# udplite dport != 60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udplite dport 70-75 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00004600 ]
+ [ cmp lte reg 1 0x00004b00 ]
+ [ immediate reg 0 accept ]
+
+# udplite dport != 50-60 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00003200 0x00003c00 ]
+ [ immediate reg 0 accept ]
+
+# udplite dport { 49, 50} drop
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00003100 : 0 [end] element 00003200 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 drop ]
+
+# udplite dport != { 49, 50} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00003100 : 0 [end] element 00003200 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# udplite checksum 6666 drop
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000a1a ]
+ [ immediate reg 0 drop ]
+
+# udplite checksum != { 444, 555} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0000bc01 : 0 [end] element 00002b02 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# udplite checksum 22
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# udplite checksum != 233
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# udplite checksum 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# udplite checksum != 33-45
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# udplite checksum { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# udplite checksum != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/inet/vmap.t b/tests/py/inet/vmap.t
new file mode 100644
index 0000000..0ac6e56
--- /dev/null
+++ b/tests/py/inet/vmap.t
@@ -0,0 +1,10 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop };ok;iifname . ip protocol . th dport vmap { "eth0" . 6 . 22 : accept, "eth1" . 17 . 67 : drop }
+ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e };ok
+udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept };ok
diff --git a/tests/py/inet/vmap.t.json b/tests/py/inet/vmap.t.json
new file mode 100644
index 0000000..37472cc
--- /dev/null
+++ b/tests/py/inet/vmap.t.json
@@ -0,0 +1,144 @@
+# iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "eth0",
+ 6,
+ 22
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "eth1",
+ 17,
+ 67
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "base": "ih",
+ "len": 32,
+ "offset": 32
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.1.1.1",
+ 20
+ ]
+ },
+ {
+ "concat": [
+ "2.2.2.2",
+ 30
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ 47,
+ 63
+ ]
+ },
+ "0xe373135363130333131303735353203"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ {
+ "payload": {
+ "base": "th",
+ "len": 128,
+ "offset": 160
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/vmap.t.payload b/tests/py/inet/vmap.t.payload
new file mode 100644
index 0000000..29ec846
--- /dev/null
+++ b/tests/py/inet/vmap.t.payload
@@ -0,0 +1,34 @@
+# iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+__map%d test-inet b size 2
+__map%d test-inet 0
+ element 30687465 00000000 00000000 00000000 00000006 00001600 : accept 0 [end] element 31687465 00000000 00000000 00000000 00000011 00004300 : drop 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load iifname => reg 1 ]
+ [ payload load 1b @ network header + 9 => reg 2 ]
+ [ payload load 2b @ transport header + 2 => reg 13 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+__set%d test-inet 3 size 2
+__set%d test-inet 0
+ element 01010101 14000000 : 0 [end] element 02020202 1e000000 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ inner header + 4 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+__map%d x 8f size 1
+__map%d x 0
+ element 00002f00 3531370e 33303136 37303131 03323535 - 00003f00 3531370e 33303136 37303131 03323535 : accept 0 [end]
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ payload load 16b @ transport header + 20 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
diff --git a/tests/py/inet/vmap.t.payload.netdev b/tests/py/inet/vmap.t.payload.netdev
new file mode 100644
index 0000000..3f51bb3
--- /dev/null
+++ b/tests/py/inet/vmap.t.payload.netdev
@@ -0,0 +1,34 @@
+# iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+__map%d test-netdev b size 2
+__map%d test-netdev 0
+ element 30687465 00000000 00000000 00000000 00000006 00001600 : accept 0 [end] element 31687465 00000000 00000000 00000000 00000011 00004300 : drop 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load iifname => reg 1 ]
+ [ payload load 1b @ network header + 9 => reg 2 ]
+ [ payload load 2b @ transport header + 2 => reg 13 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+__set%d test-netdev 3 size 2
+__set%d test-netdev 0
+ element 01010101 14000000 : 0 [end] element 02020202 1e000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ inner header + 4 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+__map%d test-netdev 8f size 1
+__map%d test-netdev 0
+ element 00002f00 3531370e 33303136 37303131 03323535 - 00003f00 3531370e 33303136 37303131 03323535 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ payload load 16b @ transport header + 20 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
diff --git a/tests/py/inet/vxlan.t b/tests/py/inet/vxlan.t
new file mode 100644
index 0000000..10cdb7a
--- /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 0000000..91b3d29
--- /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 0000000..cde8e56
--- /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/chains.t b/tests/py/ip/chains.t
new file mode 100644
index 0000000..fc3745e
--- /dev/null
+++ b/tests/py/ip/chains.t
@@ -0,0 +1,15 @@
+# filter chains available are: input, output, forward, prerouting, postrouting
+:filter-input;type filter hook input priority 0
+:filter-pre;type filter hook prerouting priority 0
+:filter-forw;type filter hook forward priority 0
+:filter-out;type filter hook output priority 0
+:filter-post;type filter hook postrouting priority 0
+# nat chains available are: input, output, prerouting, postrouting
+:nat-input-t;type nat hook input priority 0
+:nat-pre-t;type nat hook prerouting priority 0
+:nat-out-t;type nat hook output priority 0
+:nat-post-t;type nat hook postrouting priority 0
+# route chain available are: output
+:route-out-t;type route hook output priority 0
+
+*ip;test-ip4;filter-input,filter-pre,filter-forw,filter-out,filter-post,nat-input-t,nat-pre-t,nat-out-t,nat-post-t,route-out-t
diff --git a/tests/py/ip/ct.t b/tests/py/ip/ct.t
new file mode 100644
index 0000000..a0a2228
--- /dev/null
+++ b/tests/py/ip/ct.t
@@ -0,0 +1,36 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+
+ct original ip saddr 192.168.0.1;ok
+ct reply ip saddr 192.168.0.1;ok
+ct original ip daddr 192.168.0.1;ok
+ct reply ip daddr 192.168.0.1;ok
+
+# same, but with a netmask
+ct original ip saddr 192.168.1.0/24;ok
+ct reply ip saddr 192.168.1.0/24;ok
+ct original ip daddr 192.168.1.0/24;ok
+ct reply ip daddr 192.168.1.0/24;ok
+
+ct l3proto ipv4;ok
+ct l3proto foobar;fail
+
+ct protocol 6 ct original proto-dst 22;ok
+ct original protocol 17 ct reply proto-src 53;ok;ct protocol 17 ct reply proto-src 53
+
+# wrong address family
+ct reply ip daddr dead::beef;fail
+
+meta mark set ct original daddr map { 1.1.1.1 : 0x00000011 };fail
+meta mark set ct original ip daddr map { 1.1.1.1 : 0x00000011 };ok
+meta mark set ct original saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e };fail
+meta mark set ct original ip saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e };ok
+ct original saddr . meta mark { 1.1.1.1 . 0x00000014 };fail
+ct original ip saddr . meta mark { 1.1.1.1 . 0x00000014 };ok
+ct mark set ip dscp << 2 | 0x10;ok
+ct mark set ip dscp << 26 | 0x10;ok
+ct mark set ip dscp & 0x0f << 1;ok;ct mark set ip dscp & af33
+ct mark set ip dscp & 0x0f << 2;ok;ct mark set ip dscp & 0x3c
+ct mark set ip dscp | 0x04;ok
+ct mark set ip dscp | 1 << 20;ok;ct mark set ip dscp | 0x100000
diff --git a/tests/py/ip/ct.t.json b/tests/py/ip/ct.t.json
new file mode 100644
index 0000000..915632a
--- /dev/null
+++ b/tests/py/ip/ct.t.json
@@ -0,0 +1,481 @@
+# ct original ip saddr 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "ip saddr"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
+# ct reply ip saddr 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "ip saddr"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
+# ct original ip daddr 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "ip daddr"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
+# ct reply ip daddr 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "ip daddr"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
+# ct original ip saddr 192.168.1.0/24
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "ip saddr"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "192.168.1.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# ct reply ip saddr 192.168.1.0/24
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "ip saddr"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "192.168.1.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# ct original ip daddr 192.168.1.0/24
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "ip daddr"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "192.168.1.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# ct reply ip daddr 192.168.1.0/24
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "ip daddr"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "192.168.1.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# ct l3proto ipv4
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "l3proto"
+ }
+ },
+ "op": "==",
+ "right": "ipv4"
+ }
+ }
+]
+
+# ct protocol 6 ct original proto-dst 22
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "proto-dst"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ct original protocol 17 ct reply proto-src 53
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "proto-src"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ }
+]
+
+# meta mark set ct original ip daddr map { 1.1.1.1 : 0x00000011 }
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ 17
+ ]
+ ]
+ },
+ "key": {
+ "ct": {
+ "dir": "original",
+ "key": "ip daddr"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ct original ip saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e }
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "1.1.1.1",
+ 20
+ ]
+ },
+ 30
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "dir": "original",
+ "key": "ip saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# ct original ip saddr . meta mark { 1.1.1.1 . 0x00000014 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "dir": "original",
+ "key": "ip saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.1.1.1",
+ 20
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp & 0x0f << 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "&": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "af33"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp & 0x0f << 2
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "&": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 60
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp | 0x04
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp | 1 << 20
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 1048576
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/ip/ct.t.json.output b/tests/py/ip/ct.t.json.output
new file mode 100644
index 0000000..cf4abae
--- /dev/null
+++ b/tests/py/ip/ct.t.json.output
@@ -0,0 +1,27 @@
+# ct original protocol 17 ct reply proto-src 53
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "proto-src"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ }
+]
+
diff --git a/tests/py/ip/ct.t.payload b/tests/py/ip/ct.t.payload
new file mode 100644
index 0000000..692011d
--- /dev/null
+++ b/tests/py/ip/ct.t.payload
@@ -0,0 +1,136 @@
+# ct original ip saddr 192.168.0.1
+ip test-ip4 output
+ [ ct load src_ip => reg 1 , dir original ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ct reply ip saddr 192.168.0.1
+ip test-ip4 output
+ [ ct load src_ip => reg 1 , dir reply ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ct original ip daddr 192.168.0.1
+ip test-ip4 output
+ [ ct load dst_ip => reg 1 , dir original ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ct reply ip daddr 192.168.0.1
+ip test-ip4 output
+ [ ct load dst_ip => reg 1 , dir reply ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ct original ip saddr 192.168.1.0/24
+ip test-ip4 output
+ [ ct load src_ip => reg 1 , dir original ]
+ [ cmp eq reg 1 0x0001a8c0 ]
+
+# ct reply ip saddr 192.168.1.0/24
+ip test-ip4 output
+ [ ct load src_ip => reg 1 , dir reply ]
+ [ cmp eq reg 1 0x0001a8c0 ]
+
+# ct original ip daddr 192.168.1.0/24
+ip test-ip4 output
+ [ ct load dst_ip => reg 1 , dir original ]
+ [ cmp eq reg 1 0x0001a8c0 ]
+
+# ct reply ip daddr 192.168.1.0/24
+ip test-ip4 output
+ [ ct load dst_ip => reg 1 , dir reply ]
+ [ cmp eq reg 1 0x0001a8c0 ]
+
+# ct l3proto ipv4
+ip test-ip4 output
+ [ ct load l3protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# ct protocol 6 ct original proto-dst 22
+ip test-ip4 output
+ [ ct load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ ct load proto_dst => reg 1 , dir original ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ct original protocol 17 ct reply proto-src 53
+ip test-ip4 output
+ [ ct load protocol => reg 1 , dir original ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ ct load proto_src => reg 1 , dir reply ]
+ [ cmp eq reg 1 0x00003500 ]
+
+# meta mark set ct original ip daddr map { 1.1.1.1 : 0x00000011 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 : 00000011 0 [end]
+ip
+ [ ct load dst_ip => reg 1 , dir original ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ct original ip saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 00000014 : 0000001e 0 [end]
+ip
+ [ ct load src_ip => reg 1 , dir original ]
+ [ meta load mark => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# ct original ip saddr . meta mark { 1.1.1.1 . 0x00000014 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 01010101 00000014 : 0 [end]
+ip
+ [ ct load src_ip => reg 1 , dir original ]
+ [ meta load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark set ip dscp << 2 | 0x10
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp << 26 | 0x10
+ip
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp & 0x0f << 1
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp & 0x0f << 2
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003c ) ^ 0x00000000 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp | 0x04
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffb ) ^ 0x00000004 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp | 1 << 20
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffefffff ) ^ 0x00100000 ]
+ [ ct set mark with reg 1 ]
diff --git a/tests/py/ip/dnat.t b/tests/py/ip/dnat.t
new file mode 100644
index 0000000..881571d
--- /dev/null
+++ b/tests/py/ip/dnat.t
@@ -0,0 +1,23 @@
+:prerouting;type nat hook prerouting priority 0
+
+*ip;test-ip4;prerouting
+
+iifname "eth0" tcp dport 80-90 dnat to 192.168.3.2;ok
+iifname "eth0" tcp dport != 80-90 dnat to 192.168.3.2;ok
+iifname "eth0" tcp dport {80, 90, 23} dnat to 192.168.3.2;ok
+iifname "eth0" tcp dport != {80, 90, 23} dnat to 192.168.3.2;ok
+iifname "eth0" tcp dport != 23-34 dnat to 192.168.3.2;ok
+iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080;ok
+iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080-8999;ok
+iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080;ok
+iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080-8999;ok
+
+dnat to ct mark map { 0x00000014 : 1.2.3.4};ok
+dnat to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};ok
+
+dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 8888 - 8999 };ok
+dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 80 };ok
+dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2 . 8888 - 8999 };ok
+ip daddr 192.168.0.1 dnat ip to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 };ok
+meta l4proto 6 dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 };ok
+dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 };ok
diff --git a/tests/py/ip/dnat.t.json b/tests/py/ip/dnat.t.json
new file mode 100644
index 0000000..fe15d07
--- /dev/null
+++ b/tests/py/ip/dnat.t.json
@@ -0,0 +1,743 @@
+# iifname "eth0" tcp dport 80-90 dnat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport != 80-90 dnat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport {80, 90, 23} dnat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport != {80, 90, 23} dnat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport != 23-34 dnat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 23, 34 ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2",
+ "port": 8080
+ }
+ }
+]
+
+# dnat to ct mark map { 0x00000014 : 1.2.3.4}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "0x00000014",
+ "1.2.3.4"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# dnat to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "0x00000014",
+ "1.1.1.1"
+ ]
+ },
+ "1.2.3.4"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080-8999
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2",
+ "port": {
+ "range": [
+ 8080,
+ 8999
+ ]
+ }
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080-8999
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "range": [
+ "192.168.3.2",
+ "192.168.3.4"
+ ]
+ },
+ "port": {
+ "range": [
+ 8080,
+ 8999
+ ]
+ }
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "range": [
+ "192.168.3.2",
+ "192.168.3.4"
+ ]
+ },
+ "port": 8080
+ }
+ }
+]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2 . 8888 - 8999 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "192.168.1.2",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ "10.141.10.2",
+ {
+ "range": [
+ 8888,
+ 8999
+ ]
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 8888 - 8999 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "192.168.1.2",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.141.10.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ 8888,
+ 8999
+ ]
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 80 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "192.168.1.2",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.141.10.0",
+ "len": 24
+ }
+ },
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# ip daddr 192.168.0.1 dnat ip to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ 80,
+ {
+ "concat": [
+ "10.141.10.4",
+ 8080
+ ]
+ }
+ ],
+ [
+ 443,
+ {
+ "concat": [
+ "10.141.10.4",
+ 8443
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto 6 dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "enp2s0",
+ "10.1.1.136"
+ ]
+ },
+ {
+ "concat": [
+ "1.1.2.69",
+ 22
+ ]
+ }
+ ],
+ [
+ {
+ "concat": [
+ "enp2s0",
+ {
+ "range": [
+ "10.1.1.1",
+ "10.1.1.135"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ "1.1.2.66",
+ "1.84.236.78"
+ ]
+ },
+ 22
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "enp2s0",
+ "10.1.1.136"
+ ]
+ },
+ {
+ "prefix": {
+ "addr": "1.1.2.69",
+ "len": 32
+ }
+ }
+ ],
+ [
+ {
+ "concat": [
+ "enp2s0",
+ {
+ "range": [
+ "10.1.1.1",
+ "10.1.1.135"
+ ]
+ }
+ ]
+ },
+ {
+ "range": [
+ "1.1.2.66",
+ "1.84.236.78"
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
diff --git a/tests/py/ip/dnat.t.json.output b/tests/py/ip/dnat.t.json.output
new file mode 100644
index 0000000..4f2c6df
--- /dev/null
+++ b/tests/py/ip/dnat.t.json.output
@@ -0,0 +1,65 @@
+# dnat to ct mark map { 0x00000014 : 1.2.3.4}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 20,
+ "1.2.3.4"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# dnat to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ 20,
+ "1.1.1.1"
+ ]
+ },
+ "1.2.3.4"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip/dnat.t.payload.ip b/tests/py/ip/dnat.t.payload.ip
new file mode 100644
index 0000000..439c6ab
--- /dev/null
+++ b/tests/py/ip/dnat.t.payload.ip
@@ -0,0 +1,204 @@
+# iifname "eth0" tcp dport 80-90 dnat to 192.168.3.2
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport != 80-90 dnat to 192.168.3.2
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00005000 0x00005a00 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport {80, 90, 23} dnat to 192.168.3.2
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00005000 : 0 [end] element 00005a00 : 0 [end] element 00001700 : 0 [end]
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport != {80, 90, 23} dnat to 192.168.3.2
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00005000 : 0 [end] element 00005a00 : 0 [end] element 00001700 : 0 [end]
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport != 23-34 dnat to 192.168.3.2
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00001700 0x00002200 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ immediate reg 2 0x0000901f ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 flags 0x2 ]
+
+# dnat to ct mark map { 0x00000014 : 1.2.3.4}
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000014 : 04030201 0 [end]
+ip test-ip4 prerouting
+ [ ct load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# dnat to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000014 01010101 : 04030201 0 [end]
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 8888 - 8999 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0201a8c0 00005000 : 000a8d0a 0000b822 ff0a8d0a 00002723 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 80 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0201a8c0 00005000 : 000a8d0a 00005000 ff0a8d0a 00005000 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2 . 8888 - 8999 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0201a8c0 00005000 : 020a8d0a 0000b822 020a8d0a 00002723 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080-8999
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ immediate reg 2 0x0000901f ]
+ [ immediate reg 3 0x00002723 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 proto_max reg 3 flags 0x2 ]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ immediate reg 2 0x0403a8c0 ]
+ [ immediate reg 3 0x0000901f ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 2 proto_min reg 3 flags 0x2 ]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080-8999
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ immediate reg 2 0x0403a8c0 ]
+ [ immediate reg 3 0x0000901f ]
+ [ immediate reg 4 0x00002723 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
+
+# ip daddr 192.168.0.1 dnat ip to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 }
+__map%d test-ip4 b size 2
+__map%d test-ip4 0
+ element 0000bb01 : 040a8d0a 0000fb20 0 [end] element 00005000 : 040a8d0a 0000901f 0 [end]
+ip
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 9 ]
+
+# meta l4proto 6 dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+__map%d test-ip4 8f size 2
+__map%d test-ip4 0
+ element 32706e65 00003073 00000000 00000000 8801010a - 32706e65 00003073 00000000 00000000 8801010a : 45020101 00001600 45020101 00001600 0 [end] element 32706e65 00003073 00000000 00000000 0101010a - 32706e65 00003073 00000000 00000000 8701010a : 42020101 00001600 4eec5401 00001600 0 [end]
+ip test-ip4 prerouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load iifname => reg 1 ]
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+__map%d test-ip4 8f size 2
+__map%d test-ip4 0
+ element 32706e65 00003073 00000000 00000000 8801010a - 32706e65 00003073 00000000 00000000 8801010a : 45020101 45020101 0 [end] element 32706e65 00003073 00000000 00000000 0101010a - 32706e65 00003073 00000000 00000000 8701010a : 42020101 4eec5401 0 [end]
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 9 ]
+
diff --git a/tests/py/ip/dup.t b/tests/py/ip/dup.t
new file mode 100644
index 0000000..700031c
--- /dev/null
+++ b/tests/py/ip/dup.t
@@ -0,0 +1,7 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+
+dup to 192.168.2.1;ok
+dup to 192.168.2.1 device "lo";ok
+dup to ip saddr map { 192.168.2.120 : 192.168.2.1 } device "lo";ok
diff --git a/tests/py/ip/dup.t.json b/tests/py/ip/dup.t.json
new file mode 100644
index 0000000..aa1e826
--- /dev/null
+++ b/tests/py/ip/dup.t.json
@@ -0,0 +1,46 @@
+# dup to 192.168.2.1
+[
+ {
+ "dup": {
+ "addr": "192.168.2.1"
+ }
+ }
+]
+
+# dup to 192.168.2.1 device "lo"
+[
+ {
+ "dup": {
+ "addr": "192.168.2.1",
+ "dev": "lo"
+ }
+ }
+]
+
+# dup to ip saddr map { 192.168.2.120 : 192.168.2.1 } device "lo"
+[
+ {
+ "dup": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "192.168.2.120",
+ "192.168.2.1"
+ ]
+ ]
+ }
+ }
+ },
+ "dev": "lo"
+ }
+ }
+]
+
diff --git a/tests/py/ip/dup.t.payload b/tests/py/ip/dup.t.payload
new file mode 100644
index 0000000..347dc07
--- /dev/null
+++ b/tests/py/ip/dup.t.payload
@@ -0,0 +1,21 @@
+# dup to 192.168.2.1
+ip test-ip4 test
+ [ immediate reg 1 0x0102a8c0 ]
+ [ dup sreg_addr 1 ]
+
+# dup to 192.168.2.1 device "lo"
+ip test-ip4 test
+ [ immediate reg 1 0x0102a8c0 ]
+ [ immediate reg 2 0x00000001 ]
+ [ dup sreg_addr 1 sreg_dev 2 ]
+
+# dup to ip saddr map { 192.168.2.120 : 192.168.2.1 } device "lo"
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 7802a8c0 : 0102a8c0 0 [end]
+ip test-ip4 test
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ immediate reg 2 0x00000001 ]
+ [ dup sreg_addr 1 sreg_dev 2 ]
+
diff --git a/tests/py/ip/ether.t b/tests/py/ip/ether.t
new file mode 100644
index 0000000..e1d302c
--- /dev/null
+++ b/tests/py/ip/ether.t
@@ -0,0 +1,8 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip;input
+
+tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04 accept
+tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04;ok
+tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4;ok
+ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept;ok
diff --git a/tests/py/ip/ether.t.json b/tests/py/ip/ether.t.json
new file mode 100644
index 0000000..355c7fc
--- /dev/null
+++ b/tests/py/ip/ether.t.json
@@ -0,0 +1,163 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ }
+]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ }
+]
+
+# ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/ip/ether.t.json.output b/tests/py/ip/ether.t.json.output
new file mode 100644
index 0000000..1e5dd50
--- /dev/null
+++ b/tests/py/ip/ether.t.json.output
@@ -0,0 +1,43 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/ip/ether.t.payload b/tests/py/ip/ether.t.payload
new file mode 100644
index 0000000..bd7c8f1
--- /dev/null
+++ b/tests/py/ip/ether.t.payload
@@ -0,0 +1,50 @@
+# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
+ip test-ip input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4
+ip test-ip input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+
+# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
+ip test-ip input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+
+# ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept
+ip test-ip input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ immediate reg 0 accept ]
+
diff --git a/tests/py/ip/flowtable.t b/tests/py/ip/flowtable.t
new file mode 100644
index 0000000..086c6cf
--- /dev/null
+++ b/tests/py/ip/flowtable.t
@@ -0,0 +1,5 @@
+: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
new file mode 100644
index 0000000..a03cc9d
--- /dev/null
+++ b/tests/py/ip/flowtable.t.json
@@ -0,0 +1,24 @@
+# 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
new file mode 100644
index 0000000..c0aad39
--- /dev/null
+++ b/tests/py/ip/flowtable.t.payload
@@ -0,0 +1,7 @@
+# meter xyz size 8192 { ip saddr timeout 30s counter}
+xyz test-ip 31
+xyz test-ip 0
+ip test-ip input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ dynset update reg_key 1 set xyz timeout 30000ms expr [ counter pkts 0 bytes 0 ] ]
+
diff --git a/tests/py/ip/hash.t b/tests/py/ip/hash.t
new file mode 100644
index 0000000..cbfc7ee
--- /dev/null
+++ b/tests/py/ip/hash.t
@@ -0,0 +1,10 @@
+:pre;type nat hook prerouting priority 0
+*ip;test-ip4;pre
+
+ct mark set jhash ip saddr . ip daddr mod 2 seed 0xdeadbeef;ok
+ct mark set jhash ip saddr . ip daddr mod 2;ok
+ct mark set jhash ip saddr . ip daddr mod 2 seed 0x0;ok
+ct mark set jhash ip saddr . ip daddr mod 2 seed 0xdeadbeef offset 100;ok
+ct mark set jhash ip saddr . ip daddr mod 2 offset 100;ok
+dnat to jhash ip saddr mod 2 seed 0xdeadbeef map { 0 : 192.168.20.100, 1 : 192.168.30.100 };ok
+ct mark set symhash mod 2 offset 100;ok
diff --git a/tests/py/ip/hash.t.json b/tests/py/ip/hash.t.json
new file mode 100644
index 0000000..a95cf22
--- /dev/null
+++ b/tests/py/ip/hash.t.json
@@ -0,0 +1,230 @@
+# ct mark set jhash ip saddr . ip daddr mod 2 seed 0xdeadbeef
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "jhash": {
+ "expr": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "mod": 2,
+ "seed": 3735928559
+ }
+ }
+ }
+ }
+]
+
+# ct mark set jhash ip saddr . ip daddr mod 2
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "jhash": {
+ "expr": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "mod": 2
+ }
+ }
+ }
+ }
+]
+
+# ct mark set jhash ip saddr . ip daddr mod 2 seed 0x0
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "jhash": {
+ "expr": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "mod": 2,
+ "seed": 0
+ }
+ }
+ }
+ }
+]
+
+# ct mark set jhash ip saddr . ip daddr mod 2 seed 0xdeadbeef offset 100
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "jhash": {
+ "expr": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "mod": 2,
+ "offset": 100,
+ "seed": 3735928559
+ }
+ }
+ }
+ }
+]
+
+# ct mark set jhash ip saddr . ip daddr mod 2 offset 100
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "jhash": {
+ "expr": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "mod": 2,
+ "offset": 100
+ }
+ }
+ }
+ }
+]
+
+# dnat to jhash ip saddr mod 2 seed 0xdeadbeef map { 0 : 192.168.20.100, 1 : 192.168.30.100 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "jhash": {
+ "expr": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "mod": 2,
+ "seed": 3735928559
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 0,
+ "192.168.20.100"
+ ],
+ [
+ 1,
+ "192.168.30.100"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# ct mark set symhash mod 2 offset 100
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "symhash": {
+ "mod": 2,
+ "offset": 100
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip/hash.t.payload b/tests/py/ip/hash.t.payload
new file mode 100644
index 0000000..fefe492
--- /dev/null
+++ b/tests/py/ip/hash.t.payload
@@ -0,0 +1,49 @@
+# ct mark set jhash ip saddr . ip daddr mod 2 seed 0xdeadbeef
+ip test-ip4 pre
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ payload load 4b @ network header + 16 => reg 13 ]
+ [ hash reg 1 = jhash(reg 2, 8, 0xdeadbeef) % mod 2 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set jhash ip saddr . ip daddr mod 2
+ip test-ip4 pre
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ payload load 4b @ network header + 16 => reg 13 ]
+ [ hash reg 1 = jhash(reg 2, 8, 0x0) % mod 2 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set jhash ip saddr . ip daddr mod 2 seed 0x0
+ip test-ip4 pre
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ payload load 4b @ network header + 16 => reg 13 ]
+ [ hash reg 1 = jhash(reg 2, 8, 0x0) % mod 2 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set jhash ip saddr . ip daddr mod 2 seed 0xdeadbeef offset 100
+ip test-ip4 pre
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ payload load 4b @ network header + 16 => reg 13 ]
+ [ hash reg 1 = jhash(reg 2, 8, 0xdeadbeef) % mod 2 offset 100 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set jhash ip saddr . ip daddr mod 2 offset 100
+ip test-ip4 pre
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ payload load 4b @ network header + 16 => reg 13 ]
+ [ hash reg 1 = jhash(reg 2, 8, 0x0) % mod 2 offset 100 ]
+ [ ct set mark with reg 1 ]
+
+# dnat to jhash ip saddr mod 2 seed 0xdeadbeef map { 0 : 192.168.20.100, 1 : 192.168.30.100 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000000 : 6414a8c0 0 [end] element 00000001 : 641ea8c0 0 [end]
+ip test-ip4 pre
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ hash reg 1 = jhash(reg 2, 4, 0xdeadbeef) % mod 2 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# ct mark set symhash mod 2 offset 100
+ip test-ip4 pre
+ [ hash reg 1 = symhash() % mod 2 offset 100 ]
+ [ ct set mark with reg 1 ]
diff --git a/tests/py/ip/icmp.t b/tests/py/ip/icmp.t
new file mode 100644
index 0000000..7ddf8b3
--- /dev/null
+++ b/tests/py/ip/icmp.t
@@ -0,0 +1,77 @@
+# BUG: There is a bug with icmp protocol and inet family.
+# *inet;test-inet
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+
+icmp type echo-reply accept;ok
+icmp type destination-unreachable accept;ok
+icmp type source-quench accept;ok
+icmp type redirect accept;ok
+icmp type echo-request accept;ok
+icmp type time-exceeded accept;ok
+icmp type parameter-problem accept;ok
+icmp type timestamp-request accept;ok
+icmp type timestamp-reply accept;ok
+icmp type info-request accept;ok
+icmp type info-reply accept;ok
+icmp type address-mask-request accept;ok
+icmp type address-mask-reply accept;ok
+icmp type router-advertisement accept;ok
+icmp type router-solicitation accept;ok
+icmp type {echo-reply, destination-unreachable, source-quench, redirect, echo-request, time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request, info-reply, address-mask-request, address-mask-reply, router-advertisement, router-solicitation} accept;ok
+icmp type != {echo-reply, destination-unreachable, source-quench};ok
+
+icmp code 111 accept;ok
+icmp code != 111 accept;ok
+icmp code 33-55;ok
+icmp code != 33-55;ok
+icmp code { 2, 4, 54, 33, 56};ok;icmp code { prot-unreachable, frag-needed, 33, 54, 56}
+icmp code != { prot-unreachable, frag-needed, 33, 54, 56};ok
+
+icmp checksum 12343 accept;ok
+icmp checksum != 12343 accept;ok
+icmp checksum 11-343 accept;ok
+icmp checksum != 11-343 accept;ok
+icmp checksum { 1111, 222, 343} accept;ok
+icmp checksum != { 1111, 222, 343} accept;ok
+
+icmp id 1245 log;ok;icmp type { echo-reply, echo-request} icmp id 1245 log
+icmp id 22;ok;icmp type { echo-reply, echo-request} icmp id 22
+icmp id != 233;ok;icmp type { echo-reply, echo-request} icmp id != 233
+icmp id 33-45;ok;icmp type { echo-reply, echo-request} icmp id 33-45
+icmp id != 33-45;ok;icmp type { echo-reply, echo-request} icmp id != 33-45
+
+icmp id { 22, 34, 333};ok;icmp type { echo-request, echo-reply} icmp id { 22, 34, 333}
+icmp id != { 22, 34, 333};ok;icmp type { echo-request, echo-reply} icmp id != { 22, 34, 333}
+
+icmp sequence 22;ok;icmp type { echo-reply, echo-request} icmp sequence 22
+icmp sequence != 233;ok;icmp type { echo-reply, echo-request} icmp sequence != 233
+icmp sequence 33-45;ok;icmp type { echo-reply, echo-request} icmp sequence 33-45
+icmp sequence != 33-45;ok;icmp type { echo-reply, echo-request} icmp sequence != 33-45
+icmp sequence { 33, 55, 67, 88};ok;icmp type { echo-request, echo-reply} icmp sequence { 33, 55, 67, 88}
+icmp sequence != { 33, 55, 67, 88};ok;icmp type { echo-request, echo-reply} icmp sequence != { 33, 55, 67, 88}
+icmp id 1 icmp sequence 2;ok;icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2
+icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2;ok
+icmp type echo-reply icmp id 1;ok
+
+icmp mtu 33;ok
+icmp mtu 22-33;ok
+icmp mtu 22;ok
+icmp mtu != 233;ok
+icmp mtu 33-45;ok
+icmp mtu != 33-45;ok
+icmp mtu { 33, 55, 67, 88};ok
+icmp mtu != { 33, 55, 67, 88};ok
+
+icmp gateway 22;ok
+icmp gateway != 233;ok
+icmp gateway 33-45;ok
+icmp gateway != 33-45;ok
+icmp gateway { 33, 55, 67, 88};ok
+icmp gateway != { 33, 55, 67, 88};ok
+icmp gateway != 34;ok
+icmp gateway != { 333, 334};ok
+
+icmp code 1 icmp type 2;ok;icmp type 2 icmp code host-unreachable
+icmp code != 1 icmp type 2 icmp mtu 5;fail
diff --git a/tests/py/ip/icmp.t.json b/tests/py/ip/icmp.t.json
new file mode 100644
index 0000000..4f05250
--- /dev/null
+++ b/tests/py/ip/icmp.t.json
@@ -0,0 +1,1494 @@
+# icmp type echo-reply accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type destination-unreachable accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "destination-unreachable"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type source-quench accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "source-quench"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type redirect accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "redirect"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type echo-request accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type time-exceeded accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "time-exceeded"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type parameter-problem accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "parameter-problem"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type timestamp-request accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "timestamp-request"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type timestamp-reply accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "timestamp-reply"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type info-request accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "info-request"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type info-reply accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "info-reply"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type address-mask-request accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "address-mask-request"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type address-mask-reply accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "address-mask-reply"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type router-advertisement accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "router-advertisement"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type router-solicitation accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "router-solicitation"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type {echo-reply, destination-unreachable, source-quench, redirect, echo-request, time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request, info-reply, address-mask-request, address-mask-reply, router-advertisement, router-solicitation} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "destination-unreachable",
+ "source-quench",
+ "redirect",
+ "echo-request",
+ "router-advertisement",
+ "router-solicitation",
+ "time-exceeded",
+ "parameter-problem",
+ "timestamp-request",
+ "timestamp-reply",
+ "info-request",
+ "info-reply",
+ "address-mask-request",
+ "address-mask-reply"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp type != {echo-reply, destination-unreachable, source-quench}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "echo-reply",
+ "destination-unreachable",
+ "source-quench"
+ ]
+ }
+ }
+ }
+]
+
+# icmp code 111 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 111
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp code != 111 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 111
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp code 33-55
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ }
+ }
+]
+
+# icmp code != 33-55
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ }
+ }
+]
+
+# icmp code { 2, 4, 54, 33, 56}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 2,
+ 4,
+ 33,
+ 54,
+ 56
+ ]
+ }
+ }
+ }
+]
+
+# icmp code != { prot-unreachable, frag-needed, 33, 54, 56}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "prot-unreachable",
+ "frag-needed",
+ 33,
+ 54,
+ 56
+ ]
+ }
+ }
+ }
+]
+
+# icmp checksum 12343 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 12343
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp checksum != 12343 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 12343
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp checksum 11-343 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 11,
+ 343
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp checksum != 11-343 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 11,
+ 343
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp checksum { 1111, 222, 343} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 222,
+ 343,
+ 1111
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp checksum != { 1111, 222, 343} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 222,
+ 343,
+ 1111
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmp id 1245 log
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 1245
+ }
+ },
+ {
+ "log": null
+ }
+]
+
+# icmp id 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# icmp id != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# icmp id 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp id != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp id { 22, 34, 333}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 34,
+ 333
+ ]
+ }
+ }
+ }
+]
+
+# icmp id != { 22, 34, 333}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 22,
+ 34,
+ 333
+ ]
+ }
+ }
+ }
+]
+
+# icmp sequence 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# icmp sequence != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# icmp sequence 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp sequence != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp sequence { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmp sequence != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmp id 1 icmp sequence 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# icmp type echo-reply icmp id 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# icmp mtu 33
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 33
+ }
+ }
+]
+
+# icmp mtu 22-33
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 22,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# icmp mtu 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# icmp mtu != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# icmp mtu 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp mtu != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp mtu { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmp mtu != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmp gateway 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# icmp gateway != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# icmp gateway 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp gateway != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmp gateway { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmp gateway != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmp gateway != 34
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 34
+ }
+ }
+]
+
+# icmp gateway != { 333, 334}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "gateway",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 333,
+ 334
+ ]
+ }
+ }
+ }
+]
+
+# icmp code 1 icmp type 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "host-unreachable"
+ }
+ }
+]
diff --git a/tests/py/ip/icmp.t.json.output b/tests/py/ip/icmp.t.json.output
new file mode 100644
index 0000000..5a07585
--- /dev/null
+++ b/tests/py/ip/icmp.t.json.output
@@ -0,0 +1,169 @@
+# icmp code { 2, 4, 54, 33, 56}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "prot-unreachable",
+ "frag-needed",
+ 33,
+ 54,
+ 56
+ ]
+ }
+ }
+ }
+]
+
+# icmp id 1245 log
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 1245
+ }
+ },
+ {
+ "log": null
+ }
+]
+
+# icmp id 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# icmp id != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# icmp id { 33-55}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+
diff --git a/tests/py/ip/icmp.t.payload.ip b/tests/py/ip/icmp.t.payload.ip
new file mode 100644
index 0000000..3bc6de3
--- /dev/null
+++ b/tests/py/ip/icmp.t.payload.ip
@@ -0,0 +1,619 @@
+# icmp type echo-reply accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# icmp type destination-unreachable accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ immediate reg 0 accept ]
+
+# icmp type source-quench accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ immediate reg 0 accept ]
+
+# icmp type redirect accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ immediate reg 0 accept ]
+
+# icmp type echo-request accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 0 accept ]
+
+# icmp type time-exceeded accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000000b ]
+ [ immediate reg 0 accept ]
+
+# icmp type parameter-problem accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000000c ]
+ [ immediate reg 0 accept ]
+
+# icmp type timestamp-request accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000000d ]
+ [ immediate reg 0 accept ]
+
+# icmp type timestamp-reply accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000000e ]
+ [ immediate reg 0 accept ]
+
+# icmp type info-request accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000000f ]
+ [ immediate reg 0 accept ]
+
+# icmp type info-reply accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000010 ]
+ [ immediate reg 0 accept ]
+
+# icmp type address-mask-request accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 0 accept ]
+
+# icmp type address-mask-reply accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000012 ]
+ [ immediate reg 0 accept ]
+
+# icmp type != {echo-reply, destination-unreachable, source-quench}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 00000003 : 0 [end] element 00000004 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmp code 111 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x0000006f ]
+ [ immediate reg 0 accept ]
+
+# icmp code != 111 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp neq reg 1 0x0000006f ]
+ [ immediate reg 0 accept ]
+
+# icmp code 33-55
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x00000037 ]
+
+# icmp code != 33-55
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x00000037 ]
+
+# icmp code { 2, 4, 54, 33, 56}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000036 : 0 [end] element 00000021 : 0 [end] element 00000038 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmp code != { prot-unreachable, frag-needed, 33, 54, 56}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000036 : 0 [end] element 00000021 : 0 [end] element 00000038 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmp checksum 12343 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003730 ]
+ [ immediate reg 0 accept ]
+
+# icmp checksum != 12343 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00003730 ]
+ [ immediate reg 0 accept ]
+
+# icmp checksum 11-343 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00000b00 ]
+ [ cmp lte reg 1 0x00005701 ]
+ [ immediate reg 0 accept ]
+
+# icmp checksum != 11-343 accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00000b00 0x00005701 ]
+ [ immediate reg 0 accept ]
+
+# icmp checksum { 1111, 222, 343} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# icmp checksum != { 1111, 222, 343} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# icmp id 1245 log
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x0000dd04 ]
+ [ log ]
+
+# icmp id 22
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# icmp id != 233
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# icmp id 33-45
+__set%d test-ip4 3
+__set%d test-ip4 input
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# icmp id != 33-45
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# icmp id { 22, 34, 333}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00001600 : 0 [end] element 00002200 : 0 [end] element 00004d01 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmp id != { 22, 34, 333}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00001600 : 0 [end] element 00002200 : 0 [end] element 00004d01 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmp sequence 22
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# icmp sequence != 233
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# icmp sequence 33-45
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# icmp sequence != 33-45
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# icmp sequence { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmp sequence != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmp id 1 icmp sequence 2
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x02000100 ]
+
+# icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 00000008 : 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x02000100 ]
+
+# icmp type echo-reply icmp id 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# icmp mtu 33
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00002100 ]
+
+# icmp mtu 22-33
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00001600 ]
+ [ cmp lte reg 1 0x00002100 ]
+
+# icmp mtu 22
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# icmp mtu != 233
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# icmp mtu 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# icmp mtu != 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# icmp mtu { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmp mtu != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmp gateway 22
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# icmp gateway != 233
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0xe9000000 ]
+
+# icmp gateway 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# icmp gateway != 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# icmp gateway { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmp gateway != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmp gateway != 34
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x22000000 ]
+
+# icmp gateway != { 333, 334}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 4d010000 : 0 [end] element 4e010000 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmp type router-advertisement accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000009 ]
+ [ immediate reg 0 accept ]
+
+# icmp type router-solicitation accept
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ immediate reg 0 accept ]
+
+# icmp type {echo-reply, destination-unreachable, source-quench, redirect, echo-request, time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request, info-reply, address-mask-request, address-mask-reply, router-advertisement, router-solicitation} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 00000003 : 0 [end] element 00000004 : 0 [end] element 00000005 : 0 [end] element 00000008 : 0 [end] element 0000000b : 0 [end] element 0000000c : 0 [end] element 0000000d : 0 [end] element 0000000e : 0 [end] element 0000000f : 0 [end] element 00000010 : 0 [end] element 00000011 : 0 [end] element 00000012 : 0 [end] element 00000009 : 0 [end] element 0000000a : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# icmp code 1 icmp type 2
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000102 ]
diff --git a/tests/py/ip/igmp.t b/tests/py/ip/igmp.t
new file mode 100644
index 0000000..a556e47
--- /dev/null
+++ b/tests/py/ip/igmp.t
@@ -0,0 +1,23 @@
+# *inet;test-inet
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+
+igmp type membership-query;ok
+igmp type membership-report-v1;ok
+igmp type membership-report-v2;ok
+igmp type membership-report-v3;ok
+igmp type leave-group;ok
+
+igmp type { membership-report-v1, membership-report-v2, membership-report-v3};ok
+igmp type != { membership-report-v1, membership-report-v2, membership-report-v3};ok
+
+igmp checksum 12343;ok
+igmp checksum != 12343;ok
+igmp checksum 11-343;ok
+igmp checksum != 11-343;ok
+igmp checksum { 1111, 222, 343};ok
+igmp checksum != { 1111, 222, 343};ok
+
+igmp mrt 10;ok
+igmp mrt != 10;ok
diff --git a/tests/py/ip/igmp.t.json b/tests/py/ip/igmp.t.json
new file mode 100644
index 0000000..0e2a43f
--- /dev/null
+++ b/tests/py/ip/igmp.t.json
@@ -0,0 +1,273 @@
+# igmp type membership-query
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": "membership-query"
+ }
+ }
+]
+
+# igmp type membership-report-v1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": "membership-report-v1"
+ }
+ }
+]
+
+# igmp type membership-report-v2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": "membership-report-v2"
+ }
+ }
+]
+
+# igmp type membership-report-v3
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": "membership-report-v3"
+ }
+ }
+]
+
+# igmp type leave-group
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": "leave-group"
+ }
+ }
+]
+
+# igmp type { membership-report-v1, membership-report-v2, membership-report-v3}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "membership-report-v1",
+ "membership-report-v2",
+ "membership-report-v3"
+ ]
+ }
+ }
+ }
+]
+
+# igmp type != { membership-report-v1, membership-report-v2, membership-report-v3}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "igmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "membership-report-v1",
+ "membership-report-v2",
+ "membership-report-v3"
+ ]
+ }
+ }
+ }
+]
+
+# igmp checksum 12343
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": 12343
+ }
+ }
+]
+
+# igmp checksum != 12343
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "igmp"
+ }
+ },
+ "op": "!=",
+ "right": 12343
+ }
+ }
+]
+
+# igmp checksum 11-343
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 11,
+ 343
+ ]
+ }
+ }
+ }
+]
+
+# igmp checksum != 11-343
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "igmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 11,
+ 343
+ ]
+ }
+ }
+ }
+]
+
+# igmp checksum { 1111, 222, 343}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 222,
+ 343,
+ 1111
+ ]
+ }
+ }
+ }
+]
+
+# igmp checksum != { 1111, 222, 343}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "igmp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 222,
+ 343,
+ 1111
+ ]
+ }
+ }
+ }
+]
+
+# igmp mrt 10
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mrt",
+ "protocol": "igmp"
+ }
+ },
+ "op": "==",
+ "right": 10
+ }
+ }
+]
+
+# igmp mrt != 10
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mrt",
+ "protocol": "igmp"
+ }
+ },
+ "op": "!=",
+ "right": 10
+ }
+ }
+]
diff --git a/tests/py/ip/igmp.t.payload b/tests/py/ip/igmp.t.payload
new file mode 100644
index 0000000..940fe2c
--- /dev/null
+++ b/tests/py/ip/igmp.t.payload
@@ -0,0 +1,118 @@
+# igmp type membership-query
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# igmp type membership-report-v1
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000012 ]
+
+# igmp type membership-report-v2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# igmp type membership-report-v3
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000022 ]
+
+# igmp type leave-group
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# igmp checksum 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003730 ]
+
+# igmp checksum != 12343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00003730 ]
+
+# igmp checksum 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00000b00 ]
+ [ cmp lte reg 1 0x00005701 ]
+
+# igmp checksum != 11-343
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00000b00 0x00005701 ]
+
+# igmp checksum { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp checksum != { 1111, 222, 343}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp type { membership-report-v1, membership-report-v2, membership-report-v3}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# igmp type != { membership-report-v1, membership-report-v2, membership-report-v3}
+__set%d test-ip4 3 size 3
+__set%d test-ip4 0
+ element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# igmp mrt 10
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+
+# igmp mrt != 10
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp neq reg 1 0x0000000a ]
+
diff --git a/tests/py/ip/ip.t b/tests/py/ip/ip.t
new file mode 100644
index 0000000..720d9ae
--- /dev/null
+++ b/tests/py/ip/ip.t
@@ -0,0 +1,135 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*inet;test-inet;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress,egress
+
+- ip version 2;ok
+
+# bug ip hdrlength
+- ip hdrlength 10;ok
+- ip hdrlength != 5;ok
+- ip hdrlength 5-8;ok
+- ip hdrlength != 3-13;ok
+- ip hdrlength {3, 5, 6, 8};ok
+- ip hdrlength != {3, 5, 7, 8};ok
+- ip hdrlength { 3-5};ok
+- ip hdrlength != { 3-59};ok
+# ip hdrlength 12
+# <cmdline>:1:1-38: Error: Could not process rule: Invalid argument
+# add rule ip test input ip hdrlength 12
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+# <cmdline>:1:37-38: Error: Value 22 exceeds valid range 0-15
+# add rule ip test input ip hdrlength 22
+
+ip dscp cs1;ok
+ip dscp != cs1;ok
+ip dscp 0x38;ok;ip dscp cs7
+ip dscp != 0x20;ok;ip dscp != cs4
+ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef};ok
+- ip dscp {0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x00, 0x0a, 0x0c, 0x0e, 0x12, 0x14, 0x16, 0x1a, 0x1c, 0x1e, 0x22, 0x24, 0x26, 0x2e};ok
+ip dscp != {cs0, cs3};ok
+ip dscp vmap { cs1 : continue , cs4 : accept } counter;ok
+
+ip length 232;ok
+ip length != 233;ok
+ip length 333-435;ok
+ip length != 333-453;ok
+ip length { 333, 553, 673, 838};ok
+ip length != { 333, 553, 673, 838};ok
+
+ip id 22;ok
+ip id != 233;ok
+ip id 33-45;ok
+ip id != 33-45;ok
+ip id { 33, 55, 67, 88};ok
+ip id != { 33, 55, 67, 88};ok
+
+ip 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
+ip ttl 33-55;ok
+ip ttl != 45-50;ok
+ip ttl {43, 53, 45 };ok
+ip ttl != {43, 53, 45 };ok
+
+ip protocol tcp;ok;ip protocol 6
+ip protocol != tcp;ok;ip protocol != 6
+ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept;ok;ip protocol { 33, 136, 17, 51, 50, 6, 132, 1, 108} accept
+ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept;ok;ip protocol != { 33, 136, 17, 51, 50, 6, 132, 1, 108} accept
+
+ip protocol 255;ok
+ip protocol 256;fail
+
+ip checksum 13172 drop;ok
+ip checksum 22;ok
+ip checksum != 233;ok
+ip checksum 33-45;ok
+ip checksum != 33-45;ok
+ip checksum { 33, 55, 67, 88};ok
+ip checksum != { 33, 55, 67, 88};ok
+
+ip saddr set {192.19.1.2, 191.1.22.1};fail
+
+ip saddr 192.168.2.0/24;ok
+ip saddr != 192.168.2.0/24;ok
+ip saddr 192.168.3.1 ip daddr 192.168.3.100;ok
+ip saddr != 1.1.1.1;ok
+ip saddr 1.1.1.1;ok
+ip daddr 192.168.0.1-192.168.0.250;ok
+ip daddr 10.0.0.0-10.255.255.255;ok
+ip daddr 172.16.0.0-172.31.255.255;ok
+ip daddr 192.168.3.1-192.168.4.250;ok
+ip daddr != 192.168.0.1-192.168.0.250;ok
+ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept;ok
+ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept;ok
+
+ip daddr 192.168.1.2-192.168.1.55;ok
+ip daddr != 192.168.1.2-192.168.1.55;ok
+ip saddr 192.168.1.3-192.168.33.55;ok
+ip saddr != 192.168.1.3-192.168.33.55;ok
+
+ip daddr 192.168.0.1;ok
+ip daddr 192.168.0.1 drop;ok
+ip daddr 192.168.0.2;ok
+
+ip saddr & 0xff == 1;ok;ip saddr & 0.0.0.255 == 0.0.0.1
+ip saddr & 0.0.0.255 < 0.0.0.127;ok
+
+ip saddr & 0xffff0000 == 0xffff0000;ok;ip saddr 255.255.0.0/16
+
+ip version 4 ip hdrlength 5;ok
+ip hdrlength 0;ok
+ip hdrlength 15;ok
+ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter;ok
+ip hdrlength 16;fail
+
+# limit impact to lo
+iif "lo" ip daddr set 127.0.0.1;ok
+iif "lo" ip checksum set 0;ok
+iif "lo" ip id set 0;ok
+iif "lo" ip ecn set 1;ok;iif "lo" ip ecn set ect1
+iif "lo" ip ecn set ce;ok
+iif "lo" ip ttl set 23;ok
+iif "lo" ip protocol set 1;ok
+
+iif "lo" ip dscp set af23;ok
+iif "lo" ip dscp set cs0;ok
+
+ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 };ok
+ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept };ok
+
+ip saddr 1.2.3.4 ip daddr 3.4.5.6;ok
+ip saddr 1.2.3.4 counter ip daddr 3.4.5.6;ok
diff --git a/tests/py/ip/ip.t.json b/tests/py/ip/ip.t.json
new file mode 100644
index 0000000..882c94e
--- /dev/null
+++ b/tests/py/ip/ip.t.json
@@ -0,0 +1,1811 @@
+# ip dscp cs1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "cs1"
+ }
+ }
+]
+
+# ip dscp != cs1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "cs1"
+ }
+ }
+]
+
+# ip dscp 0x38
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "0x38"
+ }
+ }
+]
+
+# ip dscp != 0x20
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "0x20"
+ }
+ }
+]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "cs0",
+ "cs1",
+ "cs2",
+ "cs3",
+ "cs4",
+ "cs5",
+ "cs6",
+ "cs7",
+ "af11",
+ "af12",
+ "af13",
+ "af21",
+ "af22",
+ "af23",
+ "af31",
+ "af32",
+ "af33",
+ "af41",
+ "af42",
+ "af43",
+ "ef"
+ ]
+ }
+ }
+ }
+]
+
+# ip dscp != {cs0, cs3}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "cs0",
+ "cs3"
+ ]
+ }
+ }
+ }
+]
+
+# ip dscp vmap { cs1 : continue , cs4 : accept } counter
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "cs1",
+ {
+ "continue": null
+ }
+ ],
+ [
+ "cs4",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "counter": null
+ }
+]
+
+# ip length 232
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 232
+ }
+ }
+]
+
+# ip length != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ip length 333-435
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 333, 435 ]
+ }
+ }
+ }
+]
+
+# ip length != 333-453
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 333, 453 ]
+ }
+ }
+ }
+]
+
+# ip length { 333, 553, 673, 838}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 333,
+ 553,
+ 673,
+ 838
+ ]
+ }
+ }
+ }
+]
+
+# ip length != { 333, 553, 673, 838}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 333,
+ 553,
+ 673,
+ 838
+ ]
+ }
+ }
+ }
+]
+
+# ip id 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip id != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ip id 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip id != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip id { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip id != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip frag-off 0xde accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 222
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip frag-off != 0xe9
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ip frag-off 0x21-0x2d
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip frag-off != 0x21-0x2d
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip frag-off { 0x21, 0x37, 0x43, 0x58}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip frag-off != { 0x21, 0x37, 0x43, 0x58}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# 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
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ttl",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip ttl 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ttl",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 233
+ }
+ }
+]
+
+# ip ttl 33-55
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ttl",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 55 ]
+ }
+ }
+ }
+]
+
+# ip ttl != 45-50
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ttl",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 45, 50 ]
+ }
+ }
+ }
+]
+
+# ip ttl {43, 53, 45 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ttl",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 43,
+ 45,
+ 53
+ ]
+ }
+ }
+ }
+]
+
+# ip ttl != {43, 53, 45 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "ttl",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 43,
+ 45,
+ 53
+ ]
+ }
+ }
+ }
+]
+
+# ip protocol tcp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ }
+]
+
+# ip protocol != tcp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "tcp"
+ }
+ }
+]
+
+# ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "icmp",
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "icmp",
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip protocol 255
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 255
+ }
+ }
+]
+
+# ip checksum 13172 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 13172
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip checksum 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip checksum != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ip checksum 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip checksum != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip checksum { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip checksum != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr 192.168.2.0/24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# ip saddr != 192.168.2.0/24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# ip saddr 192.168.3.1 ip daddr 192.168.3.100
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.3.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.3.100"
+ }
+ }
+]
+
+# ip saddr != 1.1.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "1.1.1.1"
+ }
+ }
+]
+
+# ip saddr 1.1.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.1.1.1"
+ }
+ }
+]
+
+# ip daddr 192.168.0.1-192.168.0.250
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "192.168.0.1", "192.168.0.250" ]
+ }
+ }
+ }
+]
+
+# ip daddr 10.0.0.0-10.255.255.255
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "10.0.0.0", "10.255.255.255" ]
+ }
+ }
+ }
+]
+
+# ip daddr 172.16.0.0-172.31.255.255
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "172.16.0.0", "172.31.255.255" ]
+ }
+ }
+ }
+]
+
+# ip daddr 192.168.3.1-192.168.4.250
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "192.168.3.1", "192.168.4.250" ]
+ }
+ }
+ }
+]
+
+# ip daddr != 192.168.0.1-192.168.0.250
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "192.168.0.1", "192.168.0.250" ]
+ }
+ }
+ }
+]
+
+# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "192.168.5.1",
+ "192.168.5.2",
+ "192.168.5.3"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "192.168.5.1",
+ "192.168.5.2",
+ "192.168.5.3"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip daddr 192.168.1.2-192.168.1.55
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "192.168.1.2", "192.168.1.55" ]
+ }
+ }
+ }
+]
+
+# ip daddr != 192.168.1.2-192.168.1.55
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "192.168.1.2", "192.168.1.55" ]
+ }
+ }
+ }
+]
+
+# ip saddr 192.168.1.3-192.168.33.55
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "192.168.1.3", "192.168.33.55" ]
+ }
+ }
+ }
+]
+
+# ip saddr != 192.168.1.3-192.168.33.55
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "192.168.1.3", "192.168.33.55" ]
+ }
+ }
+ }
+]
+
+# ip daddr 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
+# ip daddr 192.168.0.1 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip daddr 192.168.0.2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.2"
+ }
+ }
+]
+
+# ip saddr & 0xff == 1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "0xff"
+ ]
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ip saddr & 0.0.0.255 < 0.0.0.127
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "0.0.0.255"
+ ]
+ },
+ "op": "<",
+ "right": "0.0.0.127"
+ }
+ }
+]
+
+# ip saddr & 0xffff0000 == 0xffff0000
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "0xffff0000"
+ ]
+ },
+ "op": "==",
+ "right": "0xffff0000"
+ }
+ }
+]
+
+# ip version 4 ip hdrlength 5
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "version",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 4
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 5
+ }
+ }
+]
+
+# ip hdrlength 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# ip hdrlength 15
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 15
+ }
+ }
+]
+
+# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "hdrlength",
+ "protocol": "ip"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ { "range": [ 0, 4 ] },
+ { "drop": null }
+ ],
+ [
+ 5,
+ { "accept": null }
+ ],
+ [
+ 6,
+ { "continue": null }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "counter": null
+ }
+]
+
+# iif "lo" ip daddr set 127.0.0.1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "value": "127.0.0.1"
+ }
+ }
+]
+
+# iif "lo" ip checksum set 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "ip"
+ }
+ },
+ "value": 0
+ }
+ }
+]
+
+# iif "lo" ip id set 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "id",
+ "protocol": "ip"
+ }
+ },
+ "value": 0
+ }
+ }
+]
+
+# iif "lo" ip ecn set 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "ecn",
+ "protocol": "ip"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# iif "lo" ip ecn set ce
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "ecn",
+ "protocol": "ip"
+ }
+ },
+ "value": "ce"
+ }
+ }
+]
+
+# iif "lo" ip ttl set 23
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "ttl",
+ "protocol": "ip"
+ }
+ },
+ "value": 23
+ }
+ }
+]
+
+# iif "lo" ip protocol set 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# iif "lo" ip dscp set af23
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "value": "af23"
+ }
+ }
+]
+
+# iif "lo" ip dscp set cs0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "value": "cs0"
+ }
+ }
+]
+
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "192.0.2.1",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.2"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ "192.168.5.1",
+ "192.168.5.128"
+ ]
+ },
+ {
+ "range": [
+ "192.168.6.1",
+ "192.168.6.128"
+ ]
+ }
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "3.4.5.6"
+ }
+ }
+]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "3.4.5.6"
+ }
+ }
+]
diff --git a/tests/py/ip/ip.t.json.got b/tests/py/ip/ip.t.json.got
new file mode 100644
index 0000000..07ab4e3
--- /dev/null
+++ b/tests/py/ip/ip.t.json.got
@@ -0,0 +1,62 @@
+# 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
+ }
+ }
+]
diff --git a/tests/py/ip/ip.t.json.output b/tests/py/ip/ip.t.json.output
new file mode 100644
index 0000000..b201cda
--- /dev/null
+++ b/tests/py/ip/ip.t.json.output
@@ -0,0 +1,232 @@
+# ip dscp 0x38
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "cs7"
+ }
+ }
+]
+
+# ip dscp != 0x20
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "cs4"
+ }
+ }
+]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "cs0",
+ "cs1",
+ "af11",
+ "af12",
+ "af13",
+ "cs2",
+ "af21",
+ "af22",
+ "af23",
+ "cs3",
+ "af31",
+ "af32",
+ "af33",
+ "cs4",
+ "af41",
+ "af42",
+ "af43",
+ "cs5",
+ "ef",
+ "cs6",
+ "cs7"
+ ]
+ }
+ }
+ }
+]
+
+# ip protocol tcp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ }
+]
+
+# ip protocol != tcp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": 6
+ }
+ }
+]
+
+# ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1,
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 1,
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip saddr & 0xff == 1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "0.0.0.255"
+ ]
+ },
+ "op": "==",
+ "right": "0.0.0.1"
+ }
+ }
+]
+
+# ip saddr & 0xffff0000 == 0xffff0000
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "255.255.0.0",
+ "len": 16
+ }
+ }
+ }
+ }
+]
+
+# iif "lo" ip ecn set 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "ecn",
+ "protocol": "ip"
+ }
+ },
+ "value": "ect1"
+ }
+ }
+]
+
diff --git a/tests/py/ip/ip.t.payload b/tests/py/ip/ip.t.payload
new file mode 100644
index 0000000..43605a3
--- /dev/null
+++ b/tests/py/ip/ip.t.payload
@@ -0,0 +1,558 @@
+# ip dscp cs1
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000020 ]
+
+# ip dscp != cs1
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000020 ]
+
+# ip dscp 0x38
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x000000e0 ]
+
+# ip dscp != 0x20
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000080 ]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000020 : 0 [end] element 00000040 : 0 [end] element 00000060 : 0 [end] element 00000080 : 0 [end] element 000000a0 : 0 [end] element 000000c0 : 0 [end] element 000000e0 : 0 [end] element 00000000 : 0 [end] element 00000028 : 0 [end] element 00000030 : 0 [end] element 00000038 : 0 [end] element 00000048 : 0 [end] element 00000050 : 0 [end] element 00000058 : 0 [end] element 00000068 : 0 [end] element 00000070 : 0 [end] element 00000078 : 0 [end] element 00000088 : 0 [end] element 00000090 : 0 [end] element 00000098 : 0 [end] element 000000b8 : 0 [end]
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip dscp != {cs0, cs3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 00000060 : 0 [end]
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip dscp vmap { cs1 : continue , cs4 : accept } counter
+__map%d test-ip4 b size 2
+__map%d test-ip4 0
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ip length 232
+ip test-ip4 input
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000e800 ]
+
+# ip length != 233
+ip test-ip4 input
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip length 333-435
+ip test-ip4 input
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00004d01 ]
+ [ cmp lte reg 1 0x0000b301 ]
+
+# ip length != 333-453
+ip test-ip4 input
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ range neq reg 1 0x00004d01 0x0000c501 ]
+
+# ip length { 333, 553, 673, 838}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+ip test-ip4 input
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip length != { 333, 553, 673, 838}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+ip test-ip4 input
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip id 22
+ip test-ip4 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip id != 233
+ip test-ip4 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip id 33-45
+ip test-ip4 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip id != 33-45
+ip test-ip4 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip id { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip id != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# 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 != 0xe9
+ip test-ip4 input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# 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 != 0x21-0x2d
+ip test-ip4 input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# 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]
+ip test-ip4 input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# 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]
+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 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ immediate reg 0 drop ]
+
+# ip ttl 233
+ip test-ip4 input
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x000000e9 ]
+
+# ip ttl 33-55
+ip test-ip4 input
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x00000037 ]
+
+# ip ttl != 45-50
+ip test-ip4 input
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ range neq reg 1 0x0000002d 0x00000032 ]
+
+# ip ttl {43, 53, 45 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+ip test-ip4 input
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip ttl != {43, 53, 45 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+ip test-ip4 input
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip protocol tcp
+ip test-ip4 input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# ip protocol != tcp
+ip test-ip4 input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp neq reg 1 0x00000006 ]
+
+# ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] 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]
+ip test-ip4 input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] 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]
+ip test-ip4 input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip protocol 255
+ip test-ip4 input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# ip checksum 13172 drop
+ip test-ip4 input
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00007433 ]
+ [ immediate reg 0 drop ]
+
+# ip checksum 22
+ip test-ip4 input
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip checksum != 233
+ip test-ip4 input
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip checksum 33-45
+ip test-ip4 input
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip checksum != 33-45
+ip test-ip4 input
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip checksum { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip checksum != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip test-ip4 input
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip saddr 192.168.2.0/24
+ip test-ip4 input
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0002a8c0 ]
+
+# ip saddr != 192.168.2.0/24
+ip test-ip4 input
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x0002a8c0 ]
+
+# ip saddr 192.168.3.1 ip daddr 192.168.3.100
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0103a8c0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x6403a8c0 ]
+
+# ip saddr != 1.1.1.1
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x01010101 ]
+
+# ip saddr 1.1.1.1
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x01010101 ]
+
+# ip daddr 192.168.0.1-192.168.0.250
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0100a8c0 ]
+ [ cmp lte reg 1 0xfa00a8c0 ]
+
+# ip daddr 10.0.0.0-10.255.255.255
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0000000a ]
+ [ cmp lte reg 1 0xffffff0a ]
+
+# ip daddr 172.16.0.0-172.31.255.255
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x000010ac ]
+ [ cmp lte reg 1 0xffff1fac ]
+
+# ip daddr 192.168.3.1-192.168.4.250
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0103a8c0 ]
+ [ cmp lte reg 1 0xfa04a8c0 ]
+
+# ip daddr != 192.168.0.1-192.168.0.250
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
+
+# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr 192.168.1.2-192.168.1.55
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0201a8c0 ]
+ [ cmp lte reg 1 0x3701a8c0 ]
+
+# ip daddr != 192.168.1.2-192.168.1.55
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0201a8c0 0x3701a8c0 ]
+
+# ip saddr 192.168.1.3-192.168.33.55
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp gte reg 1 0x0301a8c0 ]
+ [ cmp lte reg 1 0x3721a8c0 ]
+
+# ip saddr != 192.168.1.3-192.168.33.55
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ range neq reg 1 0x0301a8c0 0x3721a8c0 ]
+
+# ip daddr 192.168.0.1
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ip daddr 192.168.0.1 drop
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ immediate reg 0 drop ]
+
+# ip daddr 192.168.0.2
+ip test-ip4 input
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0200a8c0 ]
+
+# ip saddr & 0xff == 1
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# ip saddr & 0.0.0.255 < 0.0.0.127
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp lt reg 1 0x7f000000 ]
+
+# ip saddr & 0xffff0000 == 0xffff0000
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000ffff ]
+
+# ip version 4 ip hdrlength 5
+ip test-ip4 input
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000040 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000005 ]
+
+# ip hdrlength 0
+ip test-ip4 input
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ip hdrlength 15
+ip test-ip4 input
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000f ]
+
+# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
+__map%d test-ip4 f size 4
+__map%d test-ip4 0
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
+ip test-ip4 input
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# iif "lo" ip daddr set 127.0.0.1
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 1 0x0100007f ]
+ [ payload write reg 1 => 4b @ network header + 16 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# iif "lo" ip checksum set 0
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 10 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip id set 0
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 4 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set 1
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set ce
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip dscp set af23
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip dscp set cs0
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ttl set 23
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip protocol set 1
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-ip4 87 size 1
+__set%d test-ip4 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-ip4 8f size 1
+__map%d test-ip4 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
diff --git a/tests/py/ip/ip.t.payload.bridge b/tests/py/ip/ip.t.payload.bridge
new file mode 100644
index 0000000..e506f30
--- /dev/null
+++ b/tests/py/ip/ip.t.payload.bridge
@@ -0,0 +1,728 @@
+# ip dscp cs1
+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 ]
+ [ cmp eq reg 1 0x00000020 ]
+
+# ip dscp != cs1
+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 ]
+ [ cmp neq reg 1 0x00000020 ]
+
+# ip dscp 0x38
+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 ]
+ [ cmp eq reg 1 0x000000e0 ]
+
+# ip dscp != 0x20
+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 ]
+ [ cmp neq reg 1 0x00000080 ]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+__set%d test-bridge 3 size 21
+__set%d test-bridge 0
+ element 00000000 : 0 [end] element 00000020 : 0 [end] element 00000040 : 0 [end] element 00000060 : 0 [end] element 00000080 : 0 [end] element 000000a0 : 0 [end] element 000000c0 : 0 [end] element 000000e0 : 0 [end] element 00000028 : 0 [end] element 00000030 : 0 [end] element 00000038 : 0 [end] element 00000048 : 0 [end] element 00000050 : 0 [end] element 00000058 : 0 [end] element 00000068 : 0 [end] element 00000070 : 0 [end] element 00000078 : 0 [end] element 00000088 : 0 [end] element 00000090 : 0 [end] element 00000098 : 0 [end] element 000000b8 : 0 [end]
+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 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip dscp != {cs0, cs3}
+__set%d test-bridge 3 size 2
+__set%d test-bridge 0
+ element 00000000 : 0 [end] element 00000060 : 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip dscp vmap { cs1 : continue , cs4 : accept } counter
+__map%d test-bridge b size 2
+__map%d test-bridge 0
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ip length 232
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000e800 ]
+
+# ip length != 233
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip length 333-435
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00004d01 ]
+ [ cmp lte reg 1 0x0000b301 ]
+
+# ip length != 333-453
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ range neq reg 1 0x00004d01 0x0000c501 ]
+
+# ip length { 333, 553, 673, 838}
+__set%d test-bridge 3 size 4
+__set%d test-bridge 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip length != { 333, 553, 673, 838}
+__set%d test-bridge 3 size 4
+__set%d test-bridge 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip id 22
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip id != 233
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip id 33-45
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip id != 33-45
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip id { 33, 55, 67, 88}
+__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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip id != { 33, 55, 67, 88}
+__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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip frag-off 0xde accept
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000de00 ]
+ [ immediate reg 0 accept ]
+
+# 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 0x21-0x2d
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# 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 { 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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# 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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# 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 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ immediate reg 0 drop ]
+
+# ip ttl 233
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x000000e9 ]
+
+# ip ttl 33-55
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x00000037 ]
+
+# ip ttl != 45-50
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ range neq reg 1 0x0000002d 0x00000032 ]
+
+# ip ttl {43, 53, 45 }
+__set%d test-bridge 3 size 3
+__set%d test-bridge 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip ttl != {43, 53, 45 }
+__set%d test-bridge 3 size 3
+__set%d test-bridge 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip protocol tcp
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# ip protocol != tcp
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp neq reg 1 0x00000006 ]
+
+# ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-bridge 3 size 9
+__set%d test-bridge 0
+ element 00000001 : 0 [end] 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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-bridge 3 size 9
+__set%d test-bridge 0
+ element 00000001 : 0 [end] 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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip protocol 255
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# ip checksum 13172 drop
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00007433 ]
+ [ immediate reg 0 drop ]
+
+# ip checksum 22
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip checksum != 233
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip checksum 33-45
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip checksum != 33-45
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip checksum { 33, 55, 67, 88}
+__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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip checksum != { 33, 55, 67, 88}
+__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]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip saddr 192.168.2.0/24
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0002a8c0 ]
+
+# ip saddr != 192.168.2.0/24
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x0002a8c0 ]
+
+# ip saddr 192.168.3.1 ip daddr 192.168.3.100
+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 0x0103a8c0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x6403a8c0 ]
+
+# ip saddr != 1.1.1.1
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x01010101 ]
+
+# ip saddr 1.1.1.1
+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 0x01010101 ]
+
+# ip daddr 192.168.0.1-192.168.0.250
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0100a8c0 ]
+ [ cmp lte reg 1 0xfa00a8c0 ]
+
+# ip daddr 10.0.0.0-10.255.255.255
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0000000a ]
+ [ cmp lte reg 1 0xffffff0a ]
+
+# ip daddr 172.16.0.0-172.31.255.255
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x000010ac ]
+ [ cmp lte reg 1 0xffff1fac ]
+
+# ip daddr 192.168.3.1-192.168.4.250
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0103a8c0 ]
+ [ cmp lte reg 1 0xfa04a8c0 ]
+
+# ip daddr != 192.168.0.1-192.168.0.250
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
+
+# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-bridge 3 size 3
+__set%d test-bridge 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-bridge 3 size 3
+__set%d test-bridge 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr 192.168.1.2-192.168.1.55
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0201a8c0 ]
+ [ cmp lte reg 1 0x3701a8c0 ]
+
+# ip daddr != 192.168.1.2-192.168.1.55
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0201a8c0 0x3701a8c0 ]
+
+# ip saddr 192.168.1.3-192.168.33.55
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp gte reg 1 0x0301a8c0 ]
+ [ cmp lte reg 1 0x3721a8c0 ]
+
+# ip saddr != 192.168.1.3-192.168.33.55
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ range neq reg 1 0x0301a8c0 0x3721a8c0 ]
+
+# ip daddr 192.168.0.1
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ip daddr 192.168.0.1 drop
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ immediate reg 0 drop ]
+
+# ip daddr 192.168.0.2
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0200a8c0 ]
+
+# ip saddr & 0xff == 1
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# ip saddr & 0.0.0.255 < 0.0.0.127
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp lt reg 1 0x7f000000 ]
+
+# ip saddr & 0xffff0000 == 0xffff0000
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000ffff ]
+
+# ip version 4 ip hdrlength 5
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000040 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000005 ]
+
+# ip hdrlength 0
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ip hdrlength 15
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000f ]
+
+# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
+__map%d test-bridge f size 4
+__map%d test-bridge 0
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# iif "lo" ip daddr set 127.0.0.1
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x0100007f ]
+ [ payload write reg 1 => 4b @ network header + 16 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# iif "lo" ip checksum set 0
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 10 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip id set 0
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 4 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set 1
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set ce
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ttl set 23
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip protocol set 1
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# iif "lo" ip dscp set af23
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip dscp set cs0
+bridge test-bridge input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-bridge 87 size 1
+__set%d test-bridge 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-bridge 8f size 1
+__map%d test-bridge 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
diff --git a/tests/py/ip/ip.t.payload.bridge.got b/tests/py/ip/ip.t.payload.bridge.got
new file mode 100644
index 0000000..e728c23
--- /dev/null
+++ b/tests/py/ip/ip.t.payload.bridge.got
@@ -0,0 +1,24 @@
+# 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 ]
+
diff --git a/tests/py/ip/ip.t.payload.got b/tests/py/ip/ip.t.payload.got
new file mode 100644
index 0000000..9a5c942
--- /dev/null
+++ b/tests/py/ip/ip.t.payload.got
@@ -0,0 +1,18 @@
+# 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 ]
+
diff --git a/tests/py/ip/ip.t.payload.inet b/tests/py/ip/ip.t.payload.inet
new file mode 100644
index 0000000..a7fa0fa
--- /dev/null
+++ b/tests/py/ip/ip.t.payload.inet
@@ -0,0 +1,728 @@
+# ip dscp cs1
+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 ]
+ [ cmp eq reg 1 0x00000020 ]
+
+# ip dscp != cs1
+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 ]
+ [ cmp neq reg 1 0x00000020 ]
+
+# ip dscp 0x38
+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 ]
+ [ cmp eq reg 1 0x000000e0 ]
+
+# ip dscp != 0x20
+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 ]
+ [ cmp neq reg 1 0x00000080 ]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000020 : 0 [end] element 00000040 : 0 [end] element 00000060 : 0 [end] element 00000080 : 0 [end] element 000000a0 : 0 [end] element 000000c0 : 0 [end] element 000000e0 : 0 [end] element 00000000 : 0 [end] element 00000028 : 0 [end] element 00000030 : 0 [end] element 00000038 : 0 [end] element 00000048 : 0 [end] element 00000050 : 0 [end] element 00000058 : 0 [end] element 00000068 : 0 [end] element 00000070 : 0 [end] element 00000078 : 0 [end] element 00000088 : 0 [end] element 00000090 : 0 [end] element 00000098 : 0 [end] element 000000b8 : 0 [end]
+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 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip dscp != {cs0, cs3}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000000 : 0 [end] element 00000060 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip dscp vmap { cs1 : continue , cs4 : accept } counter
+__map%d test-inet b size 2
+__map%d test-inet 0
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ip length 232
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000e800 ]
+
+# ip length != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip length 333-435
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00004d01 ]
+ [ cmp lte reg 1 0x0000b301 ]
+
+# ip length != 333-453
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ range neq reg 1 0x00004d01 0x0000c501 ]
+
+# ip length { 333, 553, 673, 838}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip length != { 333, 553, 673, 838}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip id 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip id != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip id 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip id != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip id { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip id != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip frag-off 0xde accept
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000de00 ]
+ [ immediate reg 0 accept ]
+
+# 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 0x21-0x2d
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# 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 { 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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# 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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# 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 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ immediate reg 0 drop ]
+
+# ip ttl 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x000000e9 ]
+
+# ip ttl 33-55
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x00000037 ]
+
+# ip ttl != 45-50
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ range neq reg 1 0x0000002d 0x00000032 ]
+
+# ip ttl {43, 53, 45 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip ttl != {43, 53, 45 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip protocol tcp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# ip protocol != tcp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp neq reg 1 0x00000006 ]
+
+# ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000001 : 0 [end] 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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000001 : 0 [end] 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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip protocol 255
+ip test-ip4 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# ip checksum 13172 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00007433 ]
+ [ immediate reg 0 drop ]
+
+# ip checksum 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip checksum != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip checksum 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip checksum != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip checksum { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip checksum != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip saddr 192.168.2.0/24
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0002a8c0 ]
+
+# ip saddr != 192.168.2.0/24
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x0002a8c0 ]
+
+# ip saddr 192.168.3.1 ip daddr 192.168.3.100
+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 0x0103a8c0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x6403a8c0 ]
+
+# ip saddr != 1.1.1.1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x01010101 ]
+
+# ip saddr 1.1.1.1
+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 0x01010101 ]
+
+# ip daddr 192.168.0.1-192.168.0.250
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0100a8c0 ]
+ [ cmp lte reg 1 0xfa00a8c0 ]
+
+# ip daddr 10.0.0.0-10.255.255.255
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0000000a ]
+ [ cmp lte reg 1 0xffffff0a ]
+
+# ip daddr 172.16.0.0-172.31.255.255
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x000010ac ]
+ [ cmp lte reg 1 0xffff1fac ]
+
+# ip daddr 192.168.3.1-192.168.4.250
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0103a8c0 ]
+ [ cmp lte reg 1 0xfa04a8c0 ]
+
+# ip daddr != 192.168.0.1-192.168.0.250
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
+
+# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-inet 3
+__set%d test-inet 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr 192.168.1.2-192.168.1.55
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0201a8c0 ]
+ [ cmp lte reg 1 0x3701a8c0 ]
+
+# ip daddr != 192.168.1.2-192.168.1.55
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0201a8c0 0x3701a8c0 ]
+
+# ip saddr 192.168.1.3-192.168.33.55
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp gte reg 1 0x0301a8c0 ]
+ [ cmp lte reg 1 0x3721a8c0 ]
+
+# ip saddr != 192.168.1.3-192.168.33.55
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ range neq reg 1 0x0301a8c0 0x3721a8c0 ]
+
+# ip daddr 192.168.0.1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ip daddr 192.168.0.1 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ immediate reg 0 drop ]
+
+# ip daddr 192.168.0.2
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0200a8c0 ]
+
+# ip saddr & 0xff == 1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# ip saddr & 0.0.0.255 < 0.0.0.127
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp lt reg 1 0x7f000000 ]
+
+# ip saddr & 0xffff0000 == 0xffff0000
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000ffff ]
+
+# ip version 4 ip hdrlength 5
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000040 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000005 ]
+
+# ip hdrlength 0
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ip hdrlength 15
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000f ]
+
+# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
+__map%d test-inet f size 4
+__map%d test-inet 0
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# iif "lo" ip daddr set 127.0.0.1
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ immediate reg 1 0x0100007f ]
+ [ payload write reg 1 => 4b @ network header + 16 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# iif "lo" ip checksum set 0
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 10 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip id set 0
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 4 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set 1
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set ce
+inet test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip dscp set af23
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip dscp set cs0
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ttl set 23
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip protocol set 1
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-inet 87 size 1
+__set%d test-inet 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-inet 8f size 1
+__map%d test-inet 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
diff --git a/tests/py/ip/ip.t.payload.inet.got b/tests/py/ip/ip.t.payload.inet.got
new file mode 100644
index 0000000..ac52c78
--- /dev/null
+++ b/tests/py/ip/ip.t.payload.inet.got
@@ -0,0 +1,24 @@
+# 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 ]
+
diff --git a/tests/py/ip/ip.t.payload.netdev b/tests/py/ip/ip.t.payload.netdev
new file mode 100644
index 0000000..aebd9d6
--- /dev/null
+++ b/tests/py/ip/ip.t.payload.netdev
@@ -0,0 +1,728 @@
+# ip length 232
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000e800 ]
+
+# ip length != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip length 333-435
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00004d01 ]
+ [ cmp lte reg 1 0x0000b301 ]
+
+# ip length != 333-453
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ range neq reg 1 0x00004d01 0x0000c501 ]
+
+# ip length { 333, 553, 673, 838}
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip length != { 333, 553, 673, 838}
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00004d01 : 0 [end] element 00002902 : 0 [end] element 0000a102 : 0 [end] element 00004603 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip id 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip id != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip id 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip id != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip id { 33, 55, 67, 88}
+__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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip id != { 33, 55, 67, 88}
+__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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip frag-off 0xde accept
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000de00 ]
+ [ immediate reg 0 accept ]
+
+# 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 0x21-0x2d
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# 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 { 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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# 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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# 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 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ immediate reg 0 drop ]
+
+# ip ttl 33-55
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x00000037 ]
+
+# ip ttl != 45-50
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ range neq reg 1 0x0000002d 0x00000032 ]
+
+# ip ttl {43, 53, 45 }
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip ttl != {43, 53, 45 }
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 0000002b : 0 [end] element 00000035 : 0 [end] element 0000002d : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00000001 : 0 [end] element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00000001 : 0 [end] element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip protocol 255
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# ip checksum 13172 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00007433 ]
+ [ immediate reg 0 drop ]
+
+# ip checksum 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip checksum != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip checksum 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip checksum != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip checksum { 33, 55, 67, 88}
+__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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip checksum != { 33, 55, 67, 88}
+__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]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 10 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip saddr 192.168.2.0/24
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0002a8c0 ]
+
+# ip saddr != 192.168.2.0/24
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x0002a8c0 ]
+
+# ip saddr 192.168.3.1 ip daddr 192.168.3.100
+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 0x0103a8c0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x6403a8c0 ]
+
+# ip saddr 1.1.1.1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x01010101 ]
+
+# ip daddr 192.168.0.1-192.168.0.250
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0100a8c0 ]
+ [ cmp lte reg 1 0xfa00a8c0 ]
+
+# ip daddr 10.0.0.0-10.255.255.255
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0000000a ]
+ [ cmp lte reg 1 0xffffff0a ]
+
+# ip daddr 172.16.0.0-172.31.255.255
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x000010ac ]
+ [ cmp lte reg 1 0xffff1fac ]
+
+# ip daddr 192.168.3.1-192.168.4.250
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0103a8c0 ]
+ [ cmp lte reg 1 0xfa04a8c0 ]
+
+# ip daddr != 192.168.0.1-192.168.0.250
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
+
+# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 0105a8c0 : 0 [end] element 0205a8c0 : 0 [end] element 0305a8c0 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr 192.168.1.2-192.168.1.55
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0201a8c0 ]
+ [ cmp lte reg 1 0x3701a8c0 ]
+
+# ip daddr != 192.168.1.2-192.168.1.55
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ range neq reg 1 0x0201a8c0 0x3701a8c0 ]
+
+# ip saddr 192.168.1.3-192.168.33.55
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp gte reg 1 0x0301a8c0 ]
+ [ cmp lte reg 1 0x3721a8c0 ]
+
+# ip saddr != 192.168.1.3-192.168.33.55
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ range neq reg 1 0x0301a8c0 0x3721a8c0 ]
+
+# ip daddr 192.168.0.1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
+# ip daddr 192.168.0.1 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr & 0xff == 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# ip saddr & 0.0.0.255 < 0.0.0.127
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
+ [ cmp lt reg 1 0x7f000000 ]
+
+# ip saddr & 0xffff0000 == 0xffff0000
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000ffff ]
+
+# ip version 4 ip hdrlength 5
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000040 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000005 ]
+
+# ip hdrlength 0
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ip hdrlength 15
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000f ]
+
+# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
+__map%d test-netdev f size 4
+__map%d test-netdev 0
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ip ttl 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x000000e9 ]
+
+# ip protocol tcp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# ip protocol != tcp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp neq reg 1 0x00000006 ]
+
+# ip saddr != 1.1.1.1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp neq reg 1 0x01010101 ]
+
+# ip daddr 192.168.0.2
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0200a8c0 ]
+
+# ip dscp cs1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000020 ]
+
+# ip dscp != cs1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000020 ]
+
+# ip dscp 0x38
+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 ]
+ [ cmp eq reg 1 0x000000e0 ]
+
+# ip dscp != 0x20
+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 ]
+ [ cmp neq reg 1 0x00000080 ]
+
+# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00000000 : 0 [end] element 00000020 : 0 [end] element 00000040 : 0 [end] element 00000060 : 0 [end] element 00000080 : 0 [end] element 000000a0 : 0 [end] element 000000c0 : 0 [end] element 000000e0 : 0 [end] element 00000028 : 0 [end] element 00000030 : 0 [end] element 00000038 : 0 [end] element 00000048 : 0 [end] element 00000050 : 0 [end] element 00000058 : 0 [end] element 00000068 : 0 [end] element 00000070 : 0 [end] element 00000078 : 0 [end] element 00000088 : 0 [end] element 00000090 : 0 [end] element 00000098 : 0 [end] element 000000b8 : 0 [end]
+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 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip dscp != {cs0, cs3}
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00000000 : 0 [end] element 00000060 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip dscp vmap { cs1 : continue , cs4 : accept } counter
+__map%d test-netdev b size 2
+__map%d test-netdev 0
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# iif "lo" ip daddr set 127.0.0.1
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x0100007f ]
+ [ payload write reg 1 => 4b @ network header + 16 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# iif "lo" ip checksum set 0
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 10 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip id set 0
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ immediate reg 1 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 4 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set 1
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ecn set ce
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip dscp set af23
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip dscp set cs0
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip ttl set 23
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
+
+# iif "lo" ip protocol set 1
+netdev test-netdev ingress
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
+ [ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
+
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-netdev 87 size 1
+__set%d test-netdev 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-netdev 8f size 1
+__map%d test-netdev 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
diff --git a/tests/py/ip/ip.t.payload.netdev.got b/tests/py/ip/ip.t.payload.netdev.got
new file mode 100644
index 0000000..b3e2e35
--- /dev/null
+++ b/tests/py/ip/ip.t.payload.netdev.got
@@ -0,0 +1,24 @@
+# ip frag-off & 0x1fff != 0x0
+netdev test-netdev ingress
+ [ 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 test-netdev ingress
+ [ 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 test-netdev ingress
+ [ 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 ]
+
diff --git a/tests/py/ip/ip_tcp.t b/tests/py/ip/ip_tcp.t
new file mode 100644
index 0000000..ff398aa
--- /dev/null
+++ b/tests/py/ip/ip_tcp.t
@@ -0,0 +1,9 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip;input
+
+# can remove ip dependency -- its redundant in ip family
+ip protocol tcp tcp dport 22;ok;tcp dport 22
+
+# but not here
+ip protocol tcp meta mark set 1 tcp dport 22;ok;ip protocol 6 meta mark set 0x00000001 tcp dport 22
diff --git a/tests/py/ip/ip_tcp.t.json b/tests/py/ip/ip_tcp.t.json
new file mode 100644
index 0000000..3757d6e
--- /dev/null
+++ b/tests/py/ip/ip_tcp.t.json
@@ -0,0 +1,64 @@
+# ip protocol tcp tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp meta mark set 1 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
diff --git a/tests/py/ip/ip_tcp.t.json.output b/tests/py/ip/ip_tcp.t.json.output
new file mode 100644
index 0000000..2d671df
--- /dev/null
+++ b/tests/py/ip/ip_tcp.t.json.output
@@ -0,0 +1,52 @@
+# ip protocol tcp tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip protocol tcp meta mark set 1 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
diff --git a/tests/py/ip/ip_tcp.t.payload b/tests/py/ip/ip_tcp.t.payload
new file mode 100644
index 0000000..f6f640d
--- /dev/null
+++ b/tests/py/ip/ip_tcp.t.payload
@@ -0,0 +1,16 @@
+# ip protocol tcp tcp dport 22
+ip test-ip input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip protocol tcp meta mark set 1 tcp dport 22
+ip test-ip input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00000001 ]
+ [ meta set mark with reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
diff --git a/tests/py/ip/masquerade.t b/tests/py/ip/masquerade.t
new file mode 100644
index 0000000..384ac72
--- /dev/null
+++ b/tests/py/ip/masquerade.t
@@ -0,0 +1,30 @@
+:postrouting;type nat hook postrouting priority 0
+
+*ip;test-ip4;postrouting
+
+# nf_nat flags combination
+udp dport 53 masquerade;ok
+udp dport 53 masquerade random;ok
+udp dport 53 masquerade random,persistent;ok
+udp dport 53 masquerade random,persistent,fully-random;ok;udp dport 53 masquerade random,fully-random,persistent
+udp dport 53 masquerade random,fully-random;ok
+udp dport 53 masquerade random,fully-random,persistent;ok
+udp dport 53 masquerade persistent;ok
+udp dport 53 masquerade persistent,random;ok;udp dport 53 masquerade random,persistent
+udp dport 53 masquerade persistent,random,fully-random;ok;udp dport 53 masquerade random,fully-random,persistent
+udp dport 53 masquerade persistent,fully-random;ok;udp dport 53 masquerade fully-random,persistent
+udp dport 53 masquerade persistent,fully-random,random;ok;udp dport 53 masquerade random,fully-random,persistent
+
+# using ports
+ip protocol 6 masquerade to :1024;ok
+ip protocol 6 masquerade to :1024-2048;ok
+
+# masquerade is a terminal statement
+tcp dport 22 masquerade counter packets 0 bytes 0 accept;fail
+tcp sport 22 masquerade accept;fail
+ip saddr 10.1.1.1 masquerade drop;fail
+
+# masquerade with sets
+tcp dport { 1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} masquerade;ok
+ip daddr 10.0.0.0-10.2.3.4 udp dport 53 counter masquerade;ok
+iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade;ok
diff --git a/tests/py/ip/masquerade.t.json b/tests/py/ip/masquerade.t.json
new file mode 100644
index 0000000..4a90c70
--- /dev/null
+++ b/tests/py/ip/masquerade.t.json
@@ -0,0 +1,429 @@
+# udp dport 53 masquerade
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": null
+ }
+]
+
+# udp dport 53 masquerade random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": "random"
+ }
+ }
+]
+
+# udp dport 53 masquerade random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade random,persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "persistent",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade random,fully-random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": "persistent"
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "fully-random",
+ "random"
+ ]
+ }
+ }
+]
+
+# ip protocol 6 masquerade to :1024
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "masquerade": {
+ "port": 1024
+ }
+ }
+]
+
+# ip protocol 6 masquerade to :1024-2048
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "masquerade": {
+ "port": {
+ "range": [ 1024, 2048 ]
+ }
+ }
+ }
+]
+
+# tcp dport { 1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} masquerade
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 101,
+ 202,
+ 303,
+ 1001,
+ 2002,
+ 3003
+ ]
+ }
+ }
+ },
+ {
+ "masquerade": null
+ }
+]
+
+# ip daddr 10.0.0.0-10.2.3.4 udp dport 53 counter masquerade
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "10.0.0.0", "10.2.3.4" ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "masquerade": null
+ }
+]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "established",
+ "new"
+ ]
+ }
+ },
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ {
+ "drop": null
+ }
+ ],
+ [
+ 222,
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "masquerade": null
+ }
+]
+
diff --git a/tests/py/ip/masquerade.t.json.output b/tests/py/ip/masquerade.t.json.output
new file mode 100644
index 0000000..58e7e29
--- /dev/null
+++ b/tests/py/ip/masquerade.t.json.output
@@ -0,0 +1,123 @@
+# udp dport 53 masquerade random,persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
diff --git a/tests/py/ip/masquerade.t.payload b/tests/py/ip/masquerade.t.payload
new file mode 100644
index 0000000..79e5285
--- /dev/null
+++ b/tests/py/ip/masquerade.t.payload
@@ -0,0 +1,142 @@
+# udp dport 53 masquerade
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq ]
+
+# udp dport 53 masquerade random
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x4 ]
+
+# udp dport 53 masquerade random,persistent
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0xc ]
+
+# udp dport 53 masquerade random,persistent,fully-random
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# udp dport 53 masquerade random,fully-random
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x14 ]
+
+# udp dport 53 masquerade random,fully-random,persistent
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# udp dport 53 masquerade persistent
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x8 ]
+
+# udp dport 53 masquerade persistent,random
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0xc ]
+
+# udp dport 53 masquerade persistent,random,fully-random
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# udp dport 53 masquerade persistent,fully-random
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x18 ]
+
+# udp dport 53 masquerade persistent,fully-random,random
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# tcp dport { 1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} masquerade
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000100 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000400 : 0 [end] element 00000500 : 0 [end] element 00000600 : 0 [end] element 00000700 : 0 [end] element 00000800 : 0 [end] element 00006500 : 0 [end] element 0000ca00 : 0 [end] element 00002f01 : 0 [end] element 0000e903 : 0 [end] element 0000d207 : 0 [end] element 0000bb0b : 0 [end]
+ip test-ip4 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ masq ]
+
+# ip daddr 10.0.0.0-10.2.3.4 udp dport 53 counter masquerade
+ip test-ip4 postrouting
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0000000a ]
+ [ cmp lte reg 1 0x0403020a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ counter pkts 0 bytes 0 ]
+ [ masq ]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
+ip test-ip4 postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ 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 0 ]
+ [ masq ]
+
+# ip protocol 6 masquerade to :1024
+ip test-ip4 postrouting
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00000004 ]
+ [ masq proto_min reg 1 flags 0x2 ]
+
+# ip protocol 6 masquerade to :1024-2048
+ip test-ip4 postrouting
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00000004 ]
+ [ immediate reg 2 0x00000008 ]
+ [ masq proto_min reg 1 proto_max reg 2 flags 0x2 ]
+
diff --git a/tests/py/ip/meta.t b/tests/py/ip/meta.t
new file mode 100644
index 0000000..a88a614
--- /dev/null
+++ b/tests/py/ip/meta.t
@@ -0,0 +1,22 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+
+icmp type echo-request;ok
+meta l4proto icmp icmp type echo-request;ok;icmp type echo-request
+meta l4proto ipv6-icmp icmpv6 type nd-router-advert;ok;icmpv6 type nd-router-advert
+meta l4proto 58 icmpv6 type nd-router-advert;ok;icmpv6 type nd-router-advert
+icmpv6 type nd-router-advert;ok
+
+meta protocol ip udp dport 67;ok;udp dport 67
+
+meta ibrname "br0";fail
+meta obrname "br0";fail
+
+meta sdif "lo" accept;ok
+meta sdifname != "vrf1" accept;ok
+
+meta mark set ip dscp;ok
+
+meta mark set ip dscp << 2 | 0x10;ok
+meta mark set ip dscp << 26 | 0x10;ok
diff --git a/tests/py/ip/meta.t.json b/tests/py/ip/meta.t.json
new file mode 100644
index 0000000..25936db
--- /dev/null
+++ b/tests/py/ip/meta.t.json
@@ -0,0 +1,236 @@
+# icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta l4proto icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta l4proto ipv6-icmp icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": "ipv6-icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
+# meta l4proto 58 icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 58
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
+# icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
+# meta sdif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdif"
+ }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta sdifname != "vrf1" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdifname"
+ }
+ },
+ "op": "!=",
+ "right": "vrf1"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta mark set ip dscp
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+
+# meta mark set ip dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/ip/meta.t.json.output b/tests/py/ip/meta.t.json.output
new file mode 100644
index 0000000..091282b
--- /dev/null
+++ b/tests/py/ip/meta.t.json.output
@@ -0,0 +1,48 @@
+# meta l4proto icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta l4proto ipv6-icmp icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
+# meta l4proto 58 icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
diff --git a/tests/py/ip/meta.t.payload b/tests/py/ip/meta.t.payload
new file mode 100644
index 0000000..880ac5d
--- /dev/null
+++ b/tests/py/ip/meta.t.payload
@@ -0,0 +1,78 @@
+# icmp type echo-request
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta l4proto icmp icmp type echo-request
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta l4proto ipv6-icmp icmpv6 type nd-router-advert
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000086 ]
+
+# meta l4proto 58 icmpv6 type nd-router-advert
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000086 ]
+
+# icmpv6 type nd-router-advert
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000086 ]
+
+# meta sdif "lo" accept
+ip6 test-ip4 input
+ [ meta load sdif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta sdifname != "vrf1" accept
+ip6 test-ip4 input
+ [ meta load sdifname => reg 1 ]
+ [ cmp neq reg 1 0x31667276 0x00000000 0x00000000 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# meta protocol ip udp dport 67
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta mark set ip dscp
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip dscp << 2 | 0x10
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip dscp << 26 | 0x10
+ip
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/ip/numgen.t b/tests/py/ip/numgen.t
new file mode 100644
index 0000000..2a88146
--- /dev/null
+++ b/tests/py/ip/numgen.t
@@ -0,0 +1,9 @@
+:pre;type nat hook prerouting priority 0
+*ip;test-ip4;pre
+
+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
new file mode 100644
index 0000000..6cf6604
--- /dev/null
+++ b/tests/py/ip/numgen.t.json
@@ -0,0 +1,129 @@
+# ct mark set numgen inc mod 2
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "numgen": {
+ "mod": 2,
+ "mode": "inc"
+ }
+ }
+ }
+ }
+]
+
+# ct mark set numgen inc mod 2 offset 100
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "numgen": {
+ "mod": 2,
+ "mode": "inc",
+ "offset": 100
+ }
+ }
+ }
+ }
+]
+
+# dnat to numgen inc mod 2 map { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "numgen": {
+ "mod": 2,
+ "mode": "inc"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 0,
+ "192.168.10.100"
+ ],
+ [
+ 1,
+ "192.168.20.200"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# dnat to numgen inc mod 10 map { 0-5 : 192.168.10.100, 6-9 : 192.168.20.200}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "numgen": {
+ "mod": 10,
+ "mode": "inc"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ { "range": [ 0, 5 ] },
+ "192.168.10.100"
+ ],
+ [
+ { "range": [ 6, 9 ] },
+ "192.168.20.200"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# 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
new file mode 100644
index 0000000..06ad1ec
--- /dev/null
+++ b/tests/py/ip/numgen.t.json.output
@@ -0,0 +1,112 @@
+# ct mark set numgen inc mod 2
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "numgen": {
+ "mod": 2,
+ "mode": "inc",
+ "offset": 0
+ }
+ }
+ }
+ }
+]
+
+# dnat to numgen inc mod 2 map { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "numgen": {
+ "mod": 2,
+ "mode": "inc",
+ "offset": 0
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 0,
+ "192.168.10.100"
+ ],
+ [
+ 1,
+ "192.168.20.200"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# dnat to numgen inc mod 10 map { 0-5 : 192.168.10.100, 6-9 : 192.168.20.200}
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "numgen": {
+ "mod": 10,
+ "mode": "inc",
+ "offset": 0
+ }
+ },
+ "data": {
+ "set": [
+ [
+ { "range": [ 0, 5 ] },
+ "192.168.10.100"
+ ],
+ [
+ { "range": [ 6, 9 ] },
+ "192.168.20.200"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# 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
new file mode 100644
index 0000000..b4eadf8
--- /dev/null
+++ b/tests/py/ip/numgen.t.payload
@@ -0,0 +1,40 @@
+# ct mark set numgen inc mod 2
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 2 ]
+ [ ct set mark with reg 1 ]
+
+# dnat to numgen inc mod 2 map { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+__map%d x b
+__map%d x 0
+ element 00000000 : 640aa8c0 0 [end] element 00000001 : c814a8c0 0 [end]
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 2 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# dnat to numgen inc mod 10 map { 0-5 : 192.168.10.100, 6-9 : 192.168.20.200}
+__map%d test-ip4 f
+__map%d test-ip4 0
+ element 00000000 : 640aa8c0 0 [end] element 06000000 : c814a8c0 0 [end] element 0a000000 : 1 [end]
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 10 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# ct mark set numgen inc mod 2 offset 100
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 2 offset 100 ]
+ [ ct set mark with reg 1 ]
+
+# dnat to numgen inc mod 7 offset 167772161
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 7 offset 167772161 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# dnat to numgen inc mod 255 offset 167772161
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 255 offset 167772161 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ nat dnat ip addr_min reg 1 ]
diff --git a/tests/py/ip/objects.t b/tests/py/ip/objects.t
new file mode 100644
index 0000000..4fcde7c
--- /dev/null
+++ b/tests/py/ip/objects.t
@@ -0,0 +1,58 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+
+# counter
+%cnt1 type counter;ok
+%cnt2 type counter;ok
+
+ip saddr 192.168.1.3 counter name "cnt2";ok
+ip saddr 192.168.1.3 counter name "cnt3";fail
+counter name tcp dport map {443 : "cnt1", 80 : "cnt2", 22 : "cnt1"};ok
+
+# quota
+%qt1 type quota 25 mbytes;ok
+%qt2 type quota over 1 kbytes;ok
+
+ip saddr 192.168.1.3 quota name "qt1";ok
+ip saddr 192.168.1.3 quota name "qt3";fail
+quota name tcp dport map {443 : "qt1", 80 : "qt2", 22 : "qt1"};ok
+
+# ct helper
+%cthelp1 type ct helper { type "ftp" protocol tcp; };ok
+%cthelp2 type ct helper { type "ftp" protocol tcp; l3proto ip6; };fail
+
+ct helper set "cthelp1";ok
+ct helper set tcp dport map {21 : "cthelp1", 2121 : "cthelp1" };ok
+
+# limit
+%lim1 type limit rate 400/minute;ok
+%lim2 type limit rate over 1024 bytes/second burst 512 bytes;ok
+
+ip saddr 192.168.1.3 limit name "lim1";ok
+ip saddr 192.168.1.3 limit name "lim3";fail
+limit name tcp dport map {443 : "lim1", 80 : "lim2", 22 : "lim1"};ok
+
+# ct timeout
+%cttime1 type ct timeout { protocol tcp; policy = { established:122 } ;};ok
+%cttime2 type ct timeout { protocol udp; policy = { syn_sent:122 } ;};fail
+%cttime3 type ct timeout { protocol tcp; policy = { established:132, close:16, close_wait:16 } ; l3proto ip ;};ok
+%cttime4 type ct timeout { protocol udp; policy = { replied:14, unreplied:19 } ;};ok
+%cttime5 type ct timeout {protocol tcp; policy = { estalbished:100 } ;};fail
+
+ct timeout set "cttime1";ok
+
+# ct expectation
+%ctexpect1 type ct expectation { protocol tcp; dport 1234; timeout 2m; size 12; };ok
+%ctexpect2 type ct expectation { protocol udp; };fail
+%ctexpect3 type ct expectation { protocol tcp; dport 4321; };fail
+%ctexpect4 type ct expectation { protocol tcp; dport 4321; timeout 2m; };fail
+%ctexpect5 type ct expectation { protocol udp; dport 9876; timeout 2m; size 12; l3proto ip; };ok
+
+ct expectation set "ctexpect1";ok
+
+# synproxy
+%synproxy1 type synproxy mss 1460 wscale 7;ok
+%synproxy2 type synproxy mss 1460 wscale 7 timestamp sack-perm;ok
+
+synproxy name tcp dport map {443 : "synproxy1", 80 : "synproxy2"};ok
diff --git a/tests/py/ip/objects.t.json b/tests/py/ip/objects.t.json
new file mode 100644
index 0000000..a70dd9e
--- /dev/null
+++ b/tests/py/ip/objects.t.json
@@ -0,0 +1,229 @@
+# ip saddr 192.168.1.3 counter name "cnt2"
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.3"
+ }
+ },
+ {
+ "counter": "cnt2"
+ }
+]
+
+# counter name tcp dport map {443 : "cnt1", 80 : "cnt2", 22 : "cnt1"}
+[
+ {
+ "counter": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 443,
+ "cnt1"
+ ],
+ [
+ 80,
+ "cnt2"
+ ],
+ [
+ 22,
+ "cnt1"
+ ]
+ ]
+ }
+ }
+ }
+ }
+]
+
+# ip saddr 192.168.1.3 quota name "qt1"
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.3"
+ }
+ },
+ {
+ "quota": "qt1"
+ }
+]
+
+# quota name tcp dport map {443 : "qt1", 80 : "qt2", 22 : "qt1"}
+[
+ {
+ "quota": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 443,
+ "qt1"
+ ],
+ [
+ 80,
+ "qt2"
+ ],
+ [
+ 22,
+ "qt1"
+ ]
+ ]
+ }
+ }
+ }
+ }
+]
+
+# ct helper set "cthelp1"
+[
+ {
+ "ct helper": "cthelp1"
+ }
+]
+
+# ct helper set tcp dport map {21 : "cthelp1", 2121 : "cthelp1" }
+[
+ {
+ "ct helper": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 21,
+ "cthelp1"
+ ],
+ [
+ 2121,
+ "cthelp1"
+ ]
+ ]
+ }
+ }
+ }
+ }
+]
+
+# ip saddr 192.168.1.3 limit name "lim1"
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.3"
+ }
+ },
+ {
+ "limit": "lim1"
+ }
+]
+
+# limit name tcp dport map {443 : "lim1", 80 : "lim2", 22 : "lim1"}
+[
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ "lim1"
+ ],
+ [
+ 80,
+ "lim2"
+ ],
+ [
+ 443,
+ "lim1"
+ ]
+ ]
+ }
+ }
+ }
+ }
+]
+
+# ct timeout set "cttime1"
+[
+ {
+ "ct timeout": "cttime1"
+ }
+]
+
+# ct expectation set "ctexpect1"
+[
+ {
+ "ct expectation": "ctexpect1"
+ }
+]
+
+# synproxy name tcp dport map {443 : "synproxy1", 80 : "synproxy2"}
+[
+ {
+ "synproxy": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 80,
+ "synproxy2"
+ ],
+ [
+ 443,
+ "synproxy1"
+ ]
+ ]
+ }
+ }
+ }
+ }
+]
diff --git a/tests/py/ip/objects.t.json.output b/tests/py/ip/objects.t.json.output
new file mode 100644
index 0000000..ade195d
--- /dev/null
+++ b/tests/py/ip/objects.t.json.output
@@ -0,0 +1,64 @@
+# counter name tcp dport map {443 : "cnt1", 80 : "cnt2", 22 : "cnt1"}
+[
+ {
+ "counter": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ "cnt1"
+ ],
+ [
+ 80,
+ "cnt2"
+ ],
+ [
+ 443,
+ "cnt1"
+ ]
+ ]
+ }
+ }
+ }
+ }
+]
+
+# quota name tcp dport map {443 : "qt1", 80 : "qt2", 22 : "qt1"}
+[
+ {
+ "quota": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ "qt1"
+ ],
+ [
+ 80,
+ "qt2"
+ ],
+ [
+ 443,
+ "qt1"
+ ]
+ ]
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip/objects.t.payload b/tests/py/ip/objects.t.payload
new file mode 100644
index 0000000..5252724
--- /dev/null
+++ b/tests/py/ip/objects.t.payload
@@ -0,0 +1,79 @@
+# ip saddr 192.168.1.3 counter name "cnt2"
+ip test-ip4 output
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0301a8c0 ]
+ [ objref type 1 name cnt2 ]
+
+# counter name tcp dport map {443 : "cnt1", 80 : "cnt2", 22 : "cnt1"}
+__objmap%d test-ip4 43
+__objmap%d test-ip4 0
+ element 0000bb01 : 0 [end] element 00005000 : 0 [end] element 00001600 : 0 [end]
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ objref sreg 1 set __objmap%d ]
+
+# ip saddr 192.168.1.3 quota name "qt1"
+ip test-ip4 output
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0301a8c0 ]
+ [ objref type 2 name qt1 ]
+
+# quota name tcp dport map {443 : "qt1", 80 : "qt2", 22 : "qt1"}
+__objmap%d test-ip4 43
+__objmap%d test-ip4 0
+ element 0000bb01 : 0 [end] element 00005000 : 0 [end] element 00001600 : 0 [end]
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ objref sreg 1 set __objmap%d ]
+
+# ct helper set "cthelp1"
+ip test-ip4 output
+ [ objref type 3 name cthelp1 ]
+
+# ct helper set tcp dport map {21 : "cthelp1", 2121 : "cthelp1" }
+__objmap%d test-ip4 43
+__objmap%d test-ip4 0
+ element 00001500 : 0 [end] element 00004908 : 0 [end]
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ objref sreg 1 set __objmap%d ]
+
+# ip saddr 192.168.1.3 limit name "lim1"
+ip test-ip4 output
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0301a8c0 ]
+ [ objref type 4 name lim1 ]
+
+# limit name tcp dport map {443 : "lim1", 80 : "lim2", 22 : "lim1"}
+__objmap%d test-ip4 43 size 3
+__objmap%d test-ip4 0
+ element 0000bb01 : 0 [end] element 00005000 : 0 [end] element 00001600 : 0 [end]
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ objref sreg 1 set __objmap%d ]
+
+# ct timeout set "cttime1"
+ip test-ip4 output
+ [ objref type 7 name cttime1 ]
+
+# ct expectation set "ctexpect1"
+ip test-ip4 output
+ [ objref type 9 name ctexpect1 ]
+
+# synproxy name tcp dport map {443 : "synproxy1", 80 : "synproxy2"}
+__objmap%d test-ip4 43 size 2
+__objmap%d test-ip4 0
+ element 0000bb01 : 0 [end] element 00005000 : 0 [end]
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ objref sreg 1 set __objmap%d ]
diff --git a/tests/py/ip/redirect.t b/tests/py/ip/redirect.t
new file mode 100644
index 0000000..8c2b52f
--- /dev/null
+++ b/tests/py/ip/redirect.t
@@ -0,0 +1,51 @@
+:output;type nat hook output priority 0
+
+*ip;test-ip4;output
+
+# without arguments
+udp dport 53 redirect;ok
+
+# nf_nat flags combination
+udp dport 53 redirect random;ok
+udp dport 53 redirect random,persistent;ok
+udp dport 53 redirect random,persistent,fully-random;ok;udp dport 53 redirect random,fully-random,persistent
+udp dport 53 redirect random,fully-random;ok
+udp dport 53 redirect random,fully-random,persistent;ok
+udp dport 53 redirect persistent;ok
+udp dport 53 redirect persistent,random;ok;udp dport 53 redirect random,persistent
+udp dport 53 redirect persistent,random,fully-random;ok;udp dport 53 redirect random,fully-random,persistent
+udp dport 53 redirect persistent,fully-random;ok;udp dport 53 redirect fully-random,persistent
+udp dport 53 redirect persistent,fully-random,random;ok;udp dport 53 redirect random,fully-random,persistent
+
+# port specification
+tcp dport 22 redirect to :22;ok
+udp dport 1234 redirect to :4321;ok
+ip daddr 172.16.0.1 udp dport 9998 redirect to :6515;ok
+tcp dport 39128 redirect to :993;ok
+ip protocol tcp redirect to :100-200;ok;ip protocol 6 redirect to :100-200
+redirect to :1234;fail
+redirect to :12341111;fail
+
+# both port and nf_nat flags
+tcp dport 9128 redirect to :993 random;ok
+tcp dport 9128 redirect to :993 fully-random;ok
+tcp dport 9128 redirect to :123 persistent;ok
+tcp dport 9128 redirect to :123 random,persistent;ok
+
+# nf_nat flags is the last argument
+udp dport 1234 redirect random to 123;fail
+udp dport 21234 redirect persistent,fully-random to 431;fail
+
+# redirect is a terminal statement
+tcp dport 22 redirect counter packets 0 bytes 0 accept;fail
+tcp sport 22 redirect accept;fail
+ip saddr 10.1.1.1 redirect drop;fail
+
+# redirect with sets
+tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect;ok
+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
+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
new file mode 100644
index 0000000..2afdf9b
--- /dev/null
+++ b/tests/py/ip/redirect.t.json
@@ -0,0 +1,625 @@
+# udp dport 53 redirect
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": null
+ }
+]
+
+# udp dport 53 redirect random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": "random"
+ }
+ }
+]
+
+# udp dport 53 redirect random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect random,persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "persistent",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect random,fully-random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": "persistent"
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "fully-random",
+ "random"
+ ]
+ }
+ }
+]
+
+# tcp dport 22 redirect to :22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "redirect": {
+ "port": 22
+ }
+ }
+]
+
+# udp dport 1234 redirect to :4321
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 1234
+ }
+ },
+ {
+ "redirect": {
+ "port": 4321
+ }
+ }
+]
+
+# ip daddr 172.16.0.1 udp dport 9998 redirect to :6515
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "172.16.0.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 9998
+ }
+ },
+ {
+ "redirect": {
+ "port": 6515
+ }
+ }
+]
+
+# tcp dport 39128 redirect to :993
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 39128
+ }
+ },
+ {
+ "redirect": {
+ "port": 993
+ }
+ }
+]
+
+# ip protocol tcp redirect to :100-200
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "redirect": {
+ "port": {
+ "range": [ 100, 200 ]
+ }
+ }
+ }
+]
+
+# tcp dport 9128 redirect to :993 random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 9128
+ }
+ },
+ {
+ "redirect": {
+ "flags": "random",
+ "port": 993
+ }
+ }
+]
+
+# tcp dport 9128 redirect to :993 fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 9128
+ }
+ },
+ {
+ "redirect": {
+ "flags": "fully-random",
+ "port": 993
+ }
+ }
+]
+
+# tcp dport 9128 redirect to :123 persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 9128
+ }
+ },
+ {
+ "redirect": {
+ "flags": "persistent",
+ "port": 123
+ }
+ }
+]
+
+# tcp dport 9128 redirect to :123 random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 9128
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "persistent"
+ ],
+ "port": 123
+ }
+ }
+]
+
+# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 101,
+ 202,
+ 303,
+ 1001,
+ 2002,
+ 3003
+ ]
+ }
+ }
+ },
+ {
+ "redirect": null
+ }
+]
+
+# ip daddr 10.0.0.0-10.2.3.4 udp dport 53 counter redirect
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "10.0.0.0", "10.2.3.4" ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "redirect": null
+ }
+]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "established",
+ "new"
+ ]
+ }
+ },
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ {
+ "drop": null
+ }
+ ],
+ [
+ 222,
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "redirect": null
+ }
+]
+
+# redirect to :tcp dport map { 22 : 8000, 80 : 8080}
+[
+ {
+ "redirect": {
+ "port": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ 8000
+ ],
+ [
+ 80,
+ 8080
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip/redirect.t.json.output b/tests/py/ip/redirect.t.json.output
new file mode 100644
index 0000000..4646c60
--- /dev/null
+++ b/tests/py/ip/redirect.t.json.output
@@ -0,0 +1,146 @@
+# udp dport 53 redirect random,persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# ip protocol tcp redirect to :100-200
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "redirect": {
+ "port": {
+ "range": [ 100, 200 ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip/redirect.t.payload b/tests/py/ip/redirect.t.payload
new file mode 100644
index 0000000..4bed47c
--- /dev/null
+++ b/tests/py/ip/redirect.t.payload
@@ -0,0 +1,220 @@
+# udp dport 53 redirect
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir ]
+
+# udp dport 53 redirect random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x4 ]
+
+# udp dport 53 redirect random,persistent
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0xc ]
+
+# udp dport 53 redirect random,persistent,fully-random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# udp dport 53 redirect random,fully-random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x14 ]
+
+# udp dport 53 redirect random,fully-random,persistent
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# udp dport 53 redirect persistent
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x8 ]
+
+# udp dport 53 redirect persistent,random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0xc ]
+
+# udp dport 53 redirect persistent,random,fully-random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# udp dport 53 redirect persistent,fully-random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x18 ]
+
+# udp dport 53 redirect persistent,fully-random,random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# tcp dport 22 redirect to :22
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ immediate reg 1 0x00001600 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# udp dport 1234 redirect to :4321
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000d204 ]
+ [ immediate reg 1 0x0000e110 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# ip daddr 172.16.0.1 udp dport 9998 redirect to :6515
+ip test-ip4 output
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x010010ac ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000e27 ]
+ [ immediate reg 1 0x00007319 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# tcp dport 39128 redirect to :993
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000d898 ]
+ [ immediate reg 1 0x0000e103 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# ip protocol tcp redirect to :100-200
+ip test-ip4 output
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00006400 ]
+ [ immediate reg 2 0x0000c800 ]
+ [ redir proto_min reg 1 proto_max reg 2 flags 0x2 ]
+
+# tcp dport 9128 redirect to :993 random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000a823 ]
+ [ immediate reg 1 0x0000e103 ]
+ [ redir proto_min reg 1 flags 0x6 ]
+
+# tcp dport 9128 redirect to :993 fully-random
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000a823 ]
+ [ immediate reg 1 0x0000e103 ]
+ [ redir proto_min reg 1 flags 0x12 ]
+
+# tcp dport 9128 redirect to :123 persistent
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000a823 ]
+ [ immediate reg 1 0x00007b00 ]
+ [ redir proto_min reg 1 flags 0xa ]
+
+# tcp dport 9128 redirect to :123 random,persistent
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000a823 ]
+ [ immediate reg 1 0x00007b00 ]
+ [ redir proto_min reg 1 flags 0xe ]
+
+# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000100 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000400 : 0 [end] element 00000500 : 0 [end] element 00000600 : 0 [end] element 00000700 : 0 [end] element 00000800 : 0 [end] element 00006500 : 0 [end] element 0000ca00 : 0 [end] element 00002f01 : 0 [end] element 0000e903 : 0 [end] element 0000d207 : 0 [end] element 0000bb0b : 0 [end]
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ redir ]
+
+# ip daddr 10.0.0.0-10.2.3.4 udp dport 53 counter redirect
+ip test-ip4 output
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp gte reg 1 0x0000000a ]
+ [ cmp lte reg 1 0x0403020a ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ counter pkts 0 bytes 0 ]
+ [ redir ]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
+ip test-ip4 output
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ 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 0 ]
+ [ redir ]
+
+# 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
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
diff --git a/tests/py/ip/reject.t b/tests/py/ip/reject.t
new file mode 100644
index 0000000..ad00994
--- /dev/null
+++ b/tests/py/ip/reject.t
@@ -0,0 +1,17 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+
+reject;ok
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok;reject
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+reject with icmp 3;ok;reject
+mark 0x80000000 reject with tcp reset;ok;meta mark 0x80000000 reject with tcp reset
+
+reject with icmp no-route;fail
+reject with icmpv6 no-route;fail
diff --git a/tests/py/ip/reject.t.json b/tests/py/ip/reject.t.json
new file mode 100644
index 0000000..3e1d28d
--- /dev/null
+++ b/tests/py/ip/reject.t.json
@@ -0,0 +1,105 @@
+# reject
+[
+ {
+ "reject": null
+ }
+]
+
+# reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-unreachable
+[
+ {
+ "reject": {
+ "expr": "net-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp prot-unreachable
+[
+ {
+ "reject": {
+ "expr": "prot-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-prohibited
+[
+ {
+ "reject": {
+ "expr": "net-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp host-prohibited
+[
+ {
+ "reject": {
+ "expr": "host-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp 3
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# mark 0x80000000 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x80000000"
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
diff --git a/tests/py/ip/reject.t.json.output b/tests/py/ip/reject.t.json.output
new file mode 100644
index 0000000..3917413
--- /dev/null
+++ b/tests/py/ip/reject.t.json.output
@@ -0,0 +1,28 @@
+# reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# mark 0x80000000 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 2147483648
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
diff --git a/tests/py/ip/reject.t.payload b/tests/py/ip/reject.t.payload
new file mode 100644
index 0000000..5829065
--- /dev/null
+++ b/tests/py/ip/reject.t.payload
@@ -0,0 +1,44 @@
+# reject
+ip test-ip4 output
+ [ reject type 0 code 3 ]
+
+# reject with icmp host-unreachable
+ip test-ip4 output
+ [ reject type 0 code 1 ]
+
+# reject with icmp net-unreachable
+ip test-ip4 output
+ [ reject type 0 code 0 ]
+
+# reject with icmp prot-unreachable
+ip test-ip4 output
+ [ reject type 0 code 2 ]
+
+# reject with icmp port-unreachable
+ip test-ip4 output
+ [ reject type 0 code 3 ]
+
+# reject with icmp net-prohibited
+ip test-ip4 output
+ [ reject type 0 code 9 ]
+
+# reject with icmp host-prohibited
+ip test-ip4 output
+ [ reject type 0 code 10 ]
+
+# reject with icmp admin-prohibited
+ip test-ip4 output
+ [ reject type 0 code 13 ]
+
+# reject with icmp 3
+ip test-ip4 output
+ [ reject type 0 code 3 ]
+
+# mark 0x80000000 reject with tcp reset
+ip test-ip4 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x80000000 ]
+ [ reject type 1 code 0 ]
+
diff --git a/tests/py/ip/rt.t b/tests/py/ip/rt.t
new file mode 100644
index 0000000..986bf34
--- /dev/null
+++ b/tests/py/ip/rt.t
@@ -0,0 +1,7 @@
+:output;type filter hook input priority 0
+
+*ip;test-ip4;output
+
+rt nexthop 192.168.0.1;ok;rt ip nexthop 192.168.0.1
+rt nexthop fd00::1;fail
+rt ip6 nexthop fd00::1;fail
diff --git a/tests/py/ip/rt.t.json b/tests/py/ip/rt.t.json
new file mode 100644
index 0000000..41dbe34
--- /dev/null
+++ b/tests/py/ip/rt.t.json
@@ -0,0 +1,16 @@
+# rt nexthop 192.168.0.1
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "family": "ip",
+ "key": "nexthop"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ }
+]
+
diff --git a/tests/py/ip/rt.t.payload b/tests/py/ip/rt.t.payload
new file mode 100644
index 0000000..93eef4a
--- /dev/null
+++ b/tests/py/ip/rt.t.payload
@@ -0,0 +1,5 @@
+# rt nexthop 192.168.0.1
+ip test-ip4 output
+ [ rt load nexthop4 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+
diff --git a/tests/py/ip/sets.t b/tests/py/ip/sets.t
new file mode 100644
index 0000000..46d9686
--- /dev/null
+++ b/tests/py/ip/sets.t
@@ -0,0 +1,68 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+!w type ipv4_addr;ok
+!x type inet_proto;ok
+!y type inet_service;ok
+!z type time;ok
+
+!set1 type ipv4_addr;ok
+?set1 192.168.3.4;ok
+
+?set1 192.168.3.4;ok
+?set1 192.168.3.5, 192.168.3.6;ok
+?set1 192.168.3.5, 192.168.3.6;ok
+?set1 192.168.3.8, 192.168.3.9;ok
+?set1 192.168.3.10, 192.168.3.11;ok
+?set1 1234:1234:1234:1234:1234:1234:1234:1234;fail
+?set2 192.168.3.4;fail
+
+!set2 type ipv4_addr;ok
+?set2 192.168.3.4;ok
+?set2 192.168.3.5, 192.168.3.6;ok
+?set2 192.168.3.5, 192.168.3.6;ok
+?set2 192.168.3.8, 192.168.3.9;ok
+?set2 192.168.3.10, 192.168.3.11;ok
+
+ip saddr @set1 drop;ok
+ip saddr != @set1 drop;ok
+ip saddr @set2 drop;ok
+ip saddr != @set2 drop;ok
+ip saddr @set33 drop;fail
+ip saddr != @set33 drop;fail
+
+!set3 type ipv4_addr flags interval;ok
+?set3 192.168.0.0/16;ok
+?set3 172.16.0.0/12;ok
+?set3 10.0.0.0/8;ok
+
+!set4 type ipv4_addr flags interval;ok
+?set4 192.168.1.0/24;ok
+?set4 192.168.0.0/24;ok
+?set4 192.168.2.0/24;ok
+?set4 192.168.1.1;fail
+?set4 192.168.3.0/24;ok
+
+!set5 type ipv4_addr . ipv4_addr;ok
+ip saddr . ip daddr @set5 drop;ok
+add @set5 { ip saddr . ip daddr };ok
+
+!map1 type ipv4_addr . ipv4_addr : mark;ok
+add @map1 { ip saddr . ip daddr : meta mark };ok
+
+# test nested anonymous sets
+ip saddr { { 1.1.1.0, 3.3.3.0 }, 2.2.2.0 };ok;ip saddr { 1.1.1.0, 2.2.2.0, 3.3.3.0 }
+ip saddr { { 1.1.1.0/24, 3.3.3.0/24 }, 2.2.2.0/24 };ok;ip saddr { 1.1.1.0/24, 2.2.2.0/24, 3.3.3.0/24 }
+
+!set6 type ipv4_addr;ok
+?set6 192.168.3.5, *;ok
+ip saddr @set6 drop;ok
+
+ip saddr vmap { 1.1.1.1 : drop, * : accept };ok
+meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 };ok
+
diff --git a/tests/py/ip/sets.t.json b/tests/py/ip/sets.t.json
new file mode 100644
index 0000000..44ca152
--- /dev/null
+++ b/tests/py/ip/sets.t.json
@@ -0,0 +1,305 @@
+# ip saddr @set1 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "@set1"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip saddr != @set1 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "@set1"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip saddr @set2 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "@set2"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip saddr != @set2 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "@set2"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip saddr . ip daddr @set5 drop
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": "@set5"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# add @set5 { ip saddr . ip daddr }
+[
+ {
+ "set": {
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "op": "add",
+ "set": "@set5"
+ }
+ }
+]
+
+# ip saddr { { 1.1.1.0, 3.3.3.0 }, 2.2.2.0 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "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 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "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
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr @set6 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "@set6"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "*",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ 1
+ ],
+ [
+ "*",
+ 2
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+[
+ {
+ "map": {
+ "data": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "map": "@map1",
+ "op": "add"
+ }
+ }
+]
+
diff --git a/tests/py/ip/sets.t.json.got b/tests/py/ip/sets.t.json.got
new file mode 100644
index 0000000..8fae580
--- /dev/null
+++ b/tests/py/ip/sets.t.json.got
@@ -0,0 +1,62 @@
+# add @map1 { ip saddr . ip daddr : meta mark }
+[
+ {
+ "set": {
+ "data": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "map": "@map1",
+ "op": "add"
+ }
+ }
+]
+
+# 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.json.payload.got b/tests/py/ip/sets.t.json.payload.got
new file mode 100644
index 0000000..daf27aa
--- /dev/null
+++ b/tests/py/ip/sets.t.json.payload.got
@@ -0,0 +1,157 @@
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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.inet b/tests/py/ip/sets.t.payload.inet
new file mode 100644
index 0000000..fd6517a
--- /dev/null
+++ b/tests/py/ip/sets.t.payload.inet
@@ -0,0 +1,106 @@
+# ip saddr @set1 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr != @set1 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr @set2 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set2 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr != @set2 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr . ip daddr @set5 drop
+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 ]
+ [ lookup reg 1 set set5 ]
+ [ immediate reg 0 drop ]
+
+# add @set5 { ip saddr . ip daddr }
+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 ]
+ [ dynset add reg_key 1 set set5 ]
+
+# ip saddr { { 1.1.1.0, 3.3.3.0 }, 2.2.2.0 }
+__set%d t 3
+__set%d t 0
+ element 00010101 : 0 [end] element 00030303 : 0 [end] element 00020202 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr { { 1.1.1.0/24, 3.3.3.0/24 }, 2.2.2.0/24 }
+__set%d t 7
+__set%d t 0
+ element 00000000 : 1 [end] element 00010101 : 0 [end] element 00020101 : 1 [end] element 00020202 : 0 [end] element 00030202 : 1 [end] element 00030303 : 0 [end] element 00040303 : 1 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr @set6 drop
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set6 ]
+ [ immediate reg 0 drop ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ dynset add reg_key 1 set map1 sreg_data 10 ]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+__map%d test-inet b
+__map%d test-inet 0
+ element 01010101 : drop 0 [end] element : accept 2 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+__map%d test-inet b
+__map%d test-inet 0
+ element 01010101 : 00000001 0 [end] element : 00000002 2 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/ip/sets.t.payload.ip b/tests/py/ip/sets.t.payload.ip
new file mode 100644
index 0000000..d9cc32b
--- /dev/null
+++ b/tests/py/ip/sets.t.payload.ip
@@ -0,0 +1,83 @@
+# ip saddr @set1 drop
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr != @set1 drop
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr @set2 drop
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set2 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr != @set2 drop
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr . ip daddr @set5 drop
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set set5 ]
+ [ immediate reg 0 drop ]
+
+# add @set5 { ip saddr . ip daddr }
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ dynset add reg_key 1 set set5 ]
+
+# ip saddr { { 1.1.1.0, 3.3.3.0 }, 2.2.2.0 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00010101 : 0 [end] element 00030303 : 0 [end] element 00020202 : 0 [end]
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr { { 1.1.1.0/24, 3.3.3.0/24 }, 2.2.2.0/24 }
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00010101 : 0 [end] element 00020101 : 1 [end] element 00020202 : 0 [end] element 00030202 : 1 [end] element 00030303 : 0 [end] element 00040303 : 1 [end]
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr @set6 drop
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set6 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 : drop 0 [end] element : accept 2 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 : 00000001 0 [end] element : 00000002 2 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ dynset add reg_key 1 set map1 sreg_data 10 ]
+
diff --git a/tests/py/ip/sets.t.payload.ip.got b/tests/py/ip/sets.t.payload.ip.got
new file mode 100644
index 0000000..c43a0c5
--- /dev/null
+++ b/tests/py/ip/sets.t.payload.ip.got
@@ -0,0 +1,14 @@
+# add @map5 { 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 map5 sreg_data 10 ]
+
+# 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
new file mode 100644
index 0000000..d41b9e8
--- /dev/null
+++ b/tests/py/ip/sets.t.payload.netdev
@@ -0,0 +1,107 @@
+# ip saddr @set1 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr != @set1 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set1 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr @set2 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set2 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr != @set2 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr . ip daddr @set5 drop
+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 ]
+ [ lookup reg 1 set set5 ]
+ [ immediate reg 0 drop ]
+
+# add @set5 { ip saddr . ip daddr }
+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 ]
+ [ dynset add reg_key 1 set set5 ]
+
+# ip saddr { { 1.1.1.0, 3.3.3.0 }, 2.2.2.0 }
+__set%d test-netdev 3
+__set%d test-netdev 0
+ element 00010101 : 0 [end] element 00030303 : 0 [end] element 00020202 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr { { 1.1.1.0/24, 3.3.3.0/24 }, 2.2.2.0/24 }
+__set%d test-netdev 7
+__set%d test-netdev 0
+ element 00000000 : 1 [end] element 00010101 : 0 [end] element 00020101 : 1 [end] element 00020202 : 0 [end] element 00030202 : 1 [end] element 00030303 : 0 [end] element 00040303 : 1 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr @set6 drop
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set6 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 01010101 : drop 0 [end] element : accept 2 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 01010101 : 00000001 0 [end] element : 00000002 2 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ dynset add reg_key 1 set map1 sreg_data 10 ]
+
diff --git a/tests/py/ip/sets.t.payload.netdev.got b/tests/py/ip/sets.t.payload.netdev.got
new file mode 100644
index 0000000..4c80527
--- /dev/null
+++ b/tests/py/ip/sets.t.payload.netdev.got
@@ -0,0 +1,18 @@
+# add @map5 { 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 map5 sreg_data 10 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ dynset add reg_key 1 set map1 sreg_data 10 ]
+
diff --git a/tests/py/ip/snat.t b/tests/py/ip/snat.t
new file mode 100644
index 0000000..d4b0d2c
--- /dev/null
+++ b/tests/py/ip/snat.t
@@ -0,0 +1,21 @@
+:postrouting;type nat hook postrouting priority 0
+
+*ip;test-ip4;postrouting
+
+iifname "eth0" tcp dport 80-90 snat to 192.168.3.2;ok
+iifname "eth0" tcp dport != 80-90 snat to 192.168.3.2;ok
+iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2;ok
+iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2;ok
+iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255;ok;iifname "eth0" tcp dport 80-90 snat to 192.168.3.0/24
+iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240;ok
+
+iifname "eth0" tcp dport != 23-34 snat to 192.168.3.2;ok
+
+meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 };ok
+snat ip to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 };ok
+snat ip to ip saddr map { 10.141.12.14 : 192.168.2.0/24 };ok
+snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 };ok
+
+meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80};ok
+snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 };fail
+snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80 };fail
diff --git a/tests/py/ip/snat.t.json b/tests/py/ip/snat.t.json
new file mode 100644
index 0000000..967560e
--- /dev/null
+++ b/tests/py/ip/snat.t.json
@@ -0,0 +1,530 @@
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport != 80-90 snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 80,
+ 90,
+ 23
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 80,
+ 90,
+ 23
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport != 23-34 snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 23, 34 ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "prefix": {
+ "addr": "192.168.3.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "range": [
+ "192.168.3.15",
+ "192.168.3.240"
+ ]
+ }
+ }
+ }
+]
+
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "type_flags": "concat"
+ }
+ }
+]
+
+# snat ip interval to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "range": [
+ "192.168.2.2",
+ "192.168.2.4"
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "type_flags": "interval"
+ }
+ }
+]
+
+# snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "flags": "netmap",
+ "type_flags": [
+ "interval",
+ "prefix"
+ ]
+ }
+ }
+]
+
+# meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": "udp"
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "range": [
+ "192.168.2.2",
+ "192.168.2.4"
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# snat ip to ip saddr map { 10.141.12.14 : 192.168.2.0/24 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.12.14",
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80}
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "tcp",
+ "udp"
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "10.141.11.4",
+ 20
+ ]
+ },
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
diff --git a/tests/py/ip/snat.t.json.output b/tests/py/ip/snat.t.json.output
new file mode 100644
index 0000000..2a99780
--- /dev/null
+++ b/tests/py/ip/snat.t.json.output
@@ -0,0 +1,249 @@
+# iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 23,
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 23,
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": "192.168.3.2"
+ }
+ }
+]
+
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80}
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "10.141.11.4",
+ 20
+ ]
+ },
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "flags": "netmap",
+ "type_flags": "prefix"
+ }
+ }
+]
+
diff --git a/tests/py/ip/snat.t.payload b/tests/py/ip/snat.t.payload
new file mode 100644
index 0000000..71a5e2f
--- /dev/null
+++ b/tests/py/ip/snat.t.payload
@@ -0,0 +1,154 @@
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.2
+ip test-ip4 postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport != 80-90 snat to 192.168.3.2
+ip test-ip4 postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00005000 0x00005a00 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00005000 : 0 [end] element 00005a00 : 0 [end] element 00001700 : 0 [end]
+ip test-ip4 postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00005000 : 0 [end] element 00005a00 : 0 [end] element 00001700 : 0 [end]
+ip test-ip4 postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport != 23-34 snat to 192.168.3.2
+ip test-ip4 postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x00001700 0x00002200 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x0003a8c0 ]
+ [ immediate reg 2 0xff03a8c0 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 2 ]
+
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x0f03a8c0 ]
+ [ immediate reg 2 0xf003a8c0 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 2 ]
+
+# meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a : 0302a8c0 00005000 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 proto_min reg 9 ]
+
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a : 0202a8c0 0402a8c0 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 ]
+
+# snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+__map%d test-ip4 f size 3
+__map%d test-ip4 0
+ element 00000000 : 1 [end] element 000b8d0a : 0002a8c0 ff02a8c0 0 [end] element 000c8d0a : 1 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 flags 0x40 ]
+
+# snat ip to ip saddr map { 10.141.12.14 : 192.168.2.0/24 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0e0c8d0a : 0002a8c0 ff02a8c0 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 ]
+
+# meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a 00001400 : 0302a8c0 00005000 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 proto_min reg 9 ]
+
+# ip daddr 192.168.0.1 dnat to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 }
+__map%d x b size 2
+__map%d x 0
+ element 0000bb01 : 040a8d0a 0000fb20 0 [end] element 00005000 : 040a8d0a 0000901f 0 [end]
+ip
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 9 ]
+
diff --git a/tests/py/ip/tcp.t b/tests/py/ip/tcp.t
new file mode 100644
index 0000000..4dcfcb6
--- /dev/null
+++ b/tests/py/ip/tcp.t
@@ -0,0 +1,6 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip;input
+
+ip protocol tcp tcp dport ssh accept;ok;tcp dport 22 accept
+ip protocol ne tcp udp dport ssh accept;ok;ip protocol != 6 udp dport 22 accept
diff --git a/tests/py/ip/tcp.t.json b/tests/py/ip/tcp.t.json
new file mode 100644
index 0000000..d2c0915
--- /dev/null
+++ b/tests/py/ip/tcp.t.json
@@ -0,0 +1,62 @@
+# ip protocol tcp tcp dport ssh accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": "ssh"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip protocol ne tcp udp dport ssh accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": "tcp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": "ssh"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/ip/tcp.t.json.output b/tests/py/ip/tcp.t.json.output
new file mode 100644
index 0000000..7e89854
--- /dev/null
+++ b/tests/py/ip/tcp.t.json.output
@@ -0,0 +1,50 @@
+# ip protocol tcp tcp dport ssh accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip protocol ne tcp udp dport ssh accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "!=",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/ip/tcp.t.payload b/tests/py/ip/tcp.t.payload
new file mode 100644
index 0000000..58956d9
--- /dev/null
+++ b/tests/py/ip/tcp.t.payload
@@ -0,0 +1,18 @@
+# ip protocol tcp tcp dport ssh accept
+ip test-ip input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ immediate reg 0 accept ]
+
+# ip protocol ne tcp udp dport ssh accept
+ip test-ip input
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp neq reg 1 0x00000006 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ immediate reg 0 accept ]
+
diff --git a/tests/py/ip/tproxy.t b/tests/py/ip/tproxy.t
new file mode 100644
index 0000000..544c519
--- /dev/null
+++ b/tests/py/ip/tproxy.t
@@ -0,0 +1,14 @@
+:y;type filter hook prerouting priority -150
+
+*ip;x;y
+
+tproxy;fail
+tproxy to 192.0.2.1;fail
+tproxy to 192.0.2.1:50080;fail
+tproxy to :50080;fail
+meta l4proto 17 tproxy to 192.0.2.1;ok
+meta l4proto 6 tproxy to 192.0.2.1:50080;ok
+ip protocol 6 tproxy to :50080;ok
+meta l4proto 17 tproxy ip to 192.0.2.1;ok;meta l4proto 17 tproxy to 192.0.2.1
+meta l4proto 6 tproxy ip to 192.0.2.1:50080;ok;meta l4proto 6 tproxy to 192.0.2.1:50080
+ip protocol 6 tproxy ip to :50080;ok;ip protocol 6 tproxy to :50080
diff --git a/tests/py/ip/tproxy.t.json b/tests/py/ip/tproxy.t.json
new file mode 100644
index 0000000..4635fc1
--- /dev/null
+++ b/tests/py/ip/tproxy.t.json
@@ -0,0 +1,126 @@
+# meta l4proto 17 tproxy to 192.0.2.1
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1"
+ }
+ }
+]
+
+# meta l4proto 6 tproxy to 192.0.2.1:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1",
+ "port": 50080
+ }
+ }
+]
+
+# ip protocol 6 tproxy to :50080
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 17 tproxy ip to 192.0.2.1
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1",
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto 6 tproxy ip to 192.0.2.1:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1",
+ "family": "ip",
+ "port": 50080
+ }
+ }
+]
+
+# ip protocol 6 tproxy ip to :50080
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "family": "ip",
+ "port": 50080
+ }
+ }
+]
diff --git a/tests/py/ip/tproxy.t.json.output b/tests/py/ip/tproxy.t.json.output
new file mode 100644
index 0000000..2690f22
--- /dev/null
+++ b/tests/py/ip/tproxy.t.json.output
@@ -0,0 +1,61 @@
+# meta l4proto 17 tproxy ip to 192.0.2.1
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1"
+ }
+ }
+]
+
+# meta l4proto 6 tproxy ip to 192.0.2.1:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "192.0.2.1",
+ "port": 50080
+ }
+ }
+]
+
+# ip protocol 6 tproxy ip to :50080
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "port": 50080
+ }
+ }
+]
diff --git a/tests/py/ip/tproxy.t.payload b/tests/py/ip/tproxy.t.payload
new file mode 100644
index 0000000..dfe830e
--- /dev/null
+++ b/tests/py/ip/tproxy.t.payload
@@ -0,0 +1,44 @@
+# meta l4proto 17 tproxy to 192.0.2.1
+ip x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x010200c0 ]
+ [ tproxy ip addr reg 1 ]
+
+# meta l4proto 6 tproxy to 192.0.2.1:50080
+ip x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x010200c0 ]
+ [ immediate reg 2 0x0000a0c3 ]
+ [ tproxy ip addr reg 1 port reg 2 ]
+
+# ip protocol 6 tproxy to :50080
+ip x y
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x0000a0c3 ]
+ [ tproxy ip port reg 1 ]
+
+# meta l4proto 17 tproxy ip to 192.0.2.1
+ip x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0x010200c0 ]
+ [ tproxy ip addr reg 1 ]
+
+# meta l4proto 6 tproxy ip to 192.0.2.1:50080
+ip x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x010200c0 ]
+ [ immediate reg 2 0x0000a0c3 ]
+ [ tproxy ip addr reg 1 port reg 2 ]
+
+# ip protocol 6 tproxy ip to :50080
+ip x y
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x0000a0c3 ]
+ [ tproxy ip port reg 1 ]
+
diff --git a/tests/py/ip6/chains.t b/tests/py/ip6/chains.t
new file mode 100644
index 0000000..e78f9e0
--- /dev/null
+++ b/tests/py/ip6/chains.t
@@ -0,0 +1,17 @@
+# filter chains available are: input, output, forward, forward, prerouting and postrouting.
+:filter-input;type filter hook input priority 0
+:filter-prer;type filter hook prerouting priority 0
+:filter-forw-t;type filter hook forward priority 0
+:filter-out-t;type filter hook output priority 0
+:filter-post-t;type filter hook postrouting priority 0
+
+# nat chains available are: input, output, forward, prerouting and postrouting.
+:nat-input;type nat hook input priority 0
+:nat-prerouting;type nat hook prerouting priority 0
+:nat-output;type nat hook output priority 0
+:nat-postrou;type nat hook postrouting priority 0
+
+# route chain available is output.
+:route-out;type route hook output priority 0
+
+*ip6;test-ip6;filter-input,filter-prer,filter-forw-t,filter-out-t,filter-post-t,nat-input,nat-prerouting,nat-output,nat-postrou,route-out
diff --git a/tests/py/ip6/ct.t b/tests/py/ip6/ct.t
new file mode 100644
index 0000000..c06fd6a
--- /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 0000000..7d8c88b
--- /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 0000000..944208f
--- /dev/null
+++ b/tests/py/ip6/ct.t.payload
@@ -0,0 +1,46 @@
+# ct mark set ip6 dscp << 2 | 0x10
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp << 26 | 0x10
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp | 0x04
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffb ) ^ 0x00000004 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp | 0xff000000
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffffff ) ^ 0xff000000 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp & 0x0f << 2
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003c ) ^ 0x00000000 ]
+ [ ct set mark with reg 1 ]
diff --git a/tests/py/ip6/dnat.t b/tests/py/ip6/dnat.t
new file mode 100644
index 0000000..89d5a5f
--- /dev/null
+++ b/tests/py/ip6/dnat.t
@@ -0,0 +1,9 @@
+:prerouting;type nat hook prerouting priority 0
+
+*ip6;test-ip6;prerouting
+
+tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100;ok
+tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100;ok
+tcp dport 80-90 dnat to [2001:838:35f:1::]:80;ok
+dnat to [2001:838:35f:1::]/64;ok;dnat to 2001:838:35f:1::/64
+dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff;ok;dnat to 2001:838:35f:1::/64
diff --git a/tests/py/ip6/dnat.t.json b/tests/py/ip6/dnat.t.json
new file mode 100644
index 0000000..cbfdb68
--- /dev/null
+++ b/tests/py/ip6/dnat.t.json
@@ -0,0 +1,106 @@
+# tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "range": [ "2001:838:35f:1::", "2001:838:35f:2::" ]
+ },
+ "port": {
+ "range": [ 80, 100 ]
+ }
+ }
+ }
+]
+
+# tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "range": [ "2001:838:35f:1::", "2001:838:35f:2::" ]
+ },
+ "port": 100
+ }
+ }
+]
+
+# tcp dport 80-90 dnat to [2001:838:35f:1::]:80
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "2001:838:35f:1::",
+ "port": 80
+ }
+ }
+]
+
+# dnat to [2001:838:35f:1::]/64
+[
+ {
+ "dnat": {
+ "addr": {
+ "prefix": {
+ "addr": "2001:838:35f:1::",
+ "len": 64
+ }
+ }
+ }
+ }
+]
+
+# dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff
+[
+ {
+ "dnat": {
+ "addr": {
+ "prefix": {
+ "addr": "2001:838:35f:1::",
+ "len": 64
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/dnat.t.payload.ip6 b/tests/py/ip6/dnat.t.payload.ip6
new file mode 100644
index 0000000..004ffde
--- /dev/null
+++ b/tests/py/ip6/dnat.t.payload.ip6
@@ -0,0 +1,47 @@
+# tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100
+ip6 test-ip6 prerouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
+ [ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
+ [ immediate reg 3 0x00005000 ]
+ [ immediate reg 4 0x00006400 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
+
+# tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
+ip6 test-ip6 prerouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
+ [ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
+ [ immediate reg 3 0x00006400 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 flags 0x2 ]
+
+# tcp dport 80-90 dnat to [2001:838:35f:1::]:80
+ip6 test-ip6 prerouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
+ [ immediate reg 2 0x00005000 ]
+ [ nat dnat ip6 addr_min reg 1 proto_min reg 2 flags 0x2 ]
+
+# dnat to [2001:838:35f:1::]/64
+ip6 test-ip6 prerouting
+ [ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
+ [ immediate reg 2 0x38080120 0x01005f03 0xffffffff 0xffffffff ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 ]
+
+# dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff
+ip6 test-ip6 prerouting
+ [ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
+ [ immediate reg 2 0x38080120 0x01005f03 0xffffffff 0xffffffff ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 ]
diff --git a/tests/py/ip6/dst.t b/tests/py/ip6/dst.t
new file mode 100644
index 0000000..cd1fd3b
--- /dev/null
+++ b/tests/py/ip6/dst.t
@@ -0,0 +1,21 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+*inet;test-inet;input
+
+dst nexthdr 22;ok
+dst nexthdr != 233;ok
+dst nexthdr 33-45;ok
+dst nexthdr != 33-45;ok
+dst nexthdr { 33, 55, 67, 88};ok
+dst nexthdr != { 33, 55, 67, 88};ok
+dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp};ok;dst nexthdr { 51, 50, 17, 136, 58, 6, 33, 132, 108}
+dst nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp};ok;dst nexthdr != { 51, 50, 17, 136, 58, 6, 33, 132, 108}
+dst nexthdr icmp;ok;dst nexthdr 1
+dst nexthdr != icmp;ok;dst nexthdr != 1
+
+dst hdrlength 22;ok
+dst hdrlength != 233;ok
+dst hdrlength 33-45;ok
+dst hdrlength != 33-45;ok
+dst hdrlength { 33, 55, 67, 88};ok
diff --git a/tests/py/ip6/dst.t.json b/tests/py/ip6/dst.t.json
new file mode 100644
index 0000000..e947a76
--- /dev/null
+++ b/tests/py/ip6/dst.t.json
@@ -0,0 +1,315 @@
+# dst nexthdr 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# dst nexthdr != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# dst nexthdr 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# dst nexthdr != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# dst nexthdr { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# dst nexthdr != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "udplite",
+ "ipcomp",
+ "udp",
+ "ah",
+ "sctp",
+ "esp",
+ "dccp",
+ "tcp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ }
+]
+
+# dst nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "udplite",
+ "ipcomp",
+ "udp",
+ "ah",
+ "sctp",
+ "esp",
+ "dccp",
+ "tcp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ }
+]
+
+# dst nexthdr icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ }
+]
+
+# dst nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": "icmp"
+ }
+ }
+]
+
+# dst hdrlength 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# dst hdrlength != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# dst hdrlength 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# dst hdrlength != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# dst hdrlength { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# dst hdrlength != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/ip6/dst.t.json.output b/tests/py/ip6/dst.t.json.output
new file mode 100644
index 0000000..69d8f68
--- /dev/null
+++ b/tests/py/ip6/dst.t.json.output
@@ -0,0 +1,88 @@
+# dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 58,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# dst nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 58,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# dst nexthdr icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# dst nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "dst"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
diff --git a/tests/py/ip6/dst.t.payload.inet b/tests/py/ip6/dst.t.payload.inet
new file mode 100644
index 0000000..90d6bda
--- /dev/null
+++ b/tests/py/ip6/dst.t.payload.inet
@@ -0,0 +1,131 @@
+# dst nexthdr 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# dst nexthdr != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# dst nexthdr 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# dst nexthdr != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# dst nexthdr { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dst nexthdr != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dst nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# dst nexthdr icmp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# dst nexthdr != icmp
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# dst hdrlength 22
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# dst hdrlength != 233
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# dst hdrlength 33-45
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# dst hdrlength != 33-45
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# dst hdrlength { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dst hdrlength != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
diff --git a/tests/py/ip6/dst.t.payload.ip6 b/tests/py/ip6/dst.t.payload.ip6
new file mode 100644
index 0000000..941140d
--- /dev/null
+++ b/tests/py/ip6/dst.t.payload.ip6
@@ -0,0 +1,99 @@
+# dst nexthdr 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# dst nexthdr != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# dst nexthdr 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# dst nexthdr != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# dst nexthdr { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dst nexthdr != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dst nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# dst nexthdr icmp
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# dst nexthdr != icmp
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# dst hdrlength 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# dst hdrlength != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# dst hdrlength 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# dst hdrlength != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# dst hdrlength { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# dst hdrlength != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
diff --git a/tests/py/ip6/dup.t b/tests/py/ip6/dup.t
new file mode 100644
index 0000000..72cc5d5
--- /dev/null
+++ b/tests/py/ip6/dup.t
@@ -0,0 +1,7 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+
+dup to abcd::1;ok
+dup to abcd::1 device "lo";ok
+dup to ip6 saddr map { abcd::1 : cafe::cafe } device "lo";ok
diff --git a/tests/py/ip6/dup.t.json b/tests/py/ip6/dup.t.json
new file mode 100644
index 0000000..8a9493b
--- /dev/null
+++ b/tests/py/ip6/dup.t.json
@@ -0,0 +1,46 @@
+# dup to abcd::1
+[
+ {
+ "dup": {
+ "addr": "abcd::1"
+ }
+ }
+]
+
+# dup to abcd::1 device "lo"
+[
+ {
+ "dup": {
+ "addr": "abcd::1",
+ "dev": "lo"
+ }
+ }
+]
+
+# dup to ip6 saddr map { abcd::1 : cafe::cafe } device "lo"
+[
+ {
+ "dup": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "abcd::1",
+ "cafe::cafe"
+ ]
+ ]
+ }
+ }
+ },
+ "dev": "lo"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/dup.t.payload b/tests/py/ip6/dup.t.payload
new file mode 100644
index 0000000..c441d4b
--- /dev/null
+++ b/tests/py/ip6/dup.t.payload
@@ -0,0 +1,21 @@
+# dup to abcd::1
+ip6 test test
+ [ immediate reg 1 0x0000cdab 0x00000000 0x00000000 0x01000000 ]
+ [ dup sreg_addr 1 ]
+
+# dup to abcd::1 device "lo"
+ip6 test test
+ [ immediate reg 1 0x0000cdab 0x00000000 0x00000000 0x01000000 ]
+ [ immediate reg 2 0x00000001 ]
+ [ dup sreg_addr 1 sreg_dev 2 ]
+
+# dup to ip6 saddr map { abcd::1 : cafe::cafe } device "lo"
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 0000cdab 00000000 00000000 01000000 : 0000feca 00000000 00000000 feca0000 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ immediate reg 2 0x00000001 ]
+ [ dup sreg_addr 1 sreg_dev 2 ]
+
diff --git a/tests/py/ip6/ether.t b/tests/py/ip6/ether.t
new file mode 100644
index 0000000..49d7d06
--- /dev/null
+++ b/tests/py/ip6/ether.t
@@ -0,0 +1,8 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+
+tcp dport 22 iiftype ether ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04 accept
+tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04;ok
+tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2;ok
+ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2 accept;ok
diff --git a/tests/py/ip6/ether.t.json b/tests/py/ip6/ether.t.json
new file mode 100644
index 0000000..5e4b43b
--- /dev/null
+++ b/tests/py/ip6/ether.t.json
@@ -0,0 +1,163 @@
+# tcp dport 22 iiftype ether ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1::2"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1::2"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ }
+]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1::2"
+ }
+ }
+]
+
+# ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1::2"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/ip6/ether.t.json.output b/tests/py/ip6/ether.t.json.output
new file mode 100644
index 0000000..7ace627
--- /dev/null
+++ b/tests/py/ip6/ether.t.json.output
@@ -0,0 +1,43 @@
+# tcp dport 22 iiftype ether ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:4 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1::2"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:0f:54:0c:11:04"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/ip6/ether.t.payload b/tests/py/ip6/ether.t.payload
new file mode 100644
index 0000000..592b4ea
--- /dev/null
+++ b/tests/py/ip6/ether.t.payload
@@ -0,0 +1,49 @@
+# tcp dport 22 iiftype ether ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:4 accept
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 0x00000000 0x00000000 0x02000000 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ immediate reg 0 accept ]
+
+# tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 0x00000000 0x00000000 0x02000000 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 0x00000000 0x00000000 0x02000000 ]
+
+# ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2 accept
+ip6 test-ip6 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0c540f00 0x00000411 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 0x00000000 0x00000000 0x02000000 ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/ip6/exthdr.t b/tests/py/ip6/exthdr.t
new file mode 100644
index 0000000..a6c2d2b
--- /dev/null
+++ b/tests/py/ip6/exthdr.t
@@ -0,0 +1,19 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+
+exthdr hbh exists;ok
+exthdr rt exists;ok
+exthdr frag exists;ok
+exthdr dst exists;ok
+exthdr mh exists;ok
+
+exthdr hbh missing;ok
+
+exthdr hbh == exists;ok;exthdr hbh exists
+exthdr hbh == missing;ok;exthdr hbh missing
+exthdr hbh != exists;ok
+exthdr hbh != missing;ok
+
+exthdr hbh 1;ok;exthdr hbh exists
+exthdr hbh 0;ok;exthdr hbh missing
diff --git a/tests/py/ip6/exthdr.t.json b/tests/py/ip6/exthdr.t.json
new file mode 100644
index 0000000..4ca77d6
--- /dev/null
+++ b/tests/py/ip6/exthdr.t.json
@@ -0,0 +1,180 @@
+# exthdr hbh exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr rt exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr frag exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr dst exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "dst"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr mh exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr hbh missing
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# exthdr hbh == exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr hbh == missing
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# exthdr hbh != exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": true
+ }
+ }
+]
+
+# exthdr hbh != missing
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": false
+ }
+ }
+]
+
+# exthdr hbh 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# exthdr hbh 0
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
diff --git a/tests/py/ip6/exthdr.t.json.output b/tests/py/ip6/exthdr.t.json.output
new file mode 100644
index 0000000..c9f5b49
--- /dev/null
+++ b/tests/py/ip6/exthdr.t.json.output
@@ -0,0 +1,60 @@
+# exthdr hbh == exists
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr hbh == missing
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# exthdr hbh 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# exthdr hbh 0
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
diff --git a/tests/py/ip6/exthdr.t.payload.ip6 b/tests/py/ip6/exthdr.t.payload.ip6
new file mode 100644
index 0000000..be10d61
--- /dev/null
+++ b/tests/py/ip6/exthdr.t.payload.ip6
@@ -0,0 +1,60 @@
+# exthdr hbh exists
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# exthdr rt exists
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# exthdr frag exists
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 44 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# exthdr dst exists
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 60 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# exthdr mh exists
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# exthdr hbh missing
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# exthdr hbh == exists
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# exthdr hbh == missing
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# exthdr hbh != exists
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# exthdr hbh != missing
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# exthdr hbh 1
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# exthdr hbh 0
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
diff --git a/tests/py/ip6/flowtable.t b/tests/py/ip6/flowtable.t
new file mode 100644
index 0000000..e58d51b
--- /dev/null
+++ b/tests/py/ip6/flowtable.t
@@ -0,0 +1,6 @@
+: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
new file mode 100644
index 0000000..d0b3a95
--- /dev/null
+++ b/tests/py/ip6/flowtable.t.json
@@ -0,0 +1,62 @@
+# 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
new file mode 100644
index 0000000..d0b3a95
--- /dev/null
+++ b/tests/py/ip6/flowtable.t.json.output
@@ -0,0 +1,62 @@
+# 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
new file mode 100644
index 0000000..559475f
--- /dev/null
+++ b/tests/py/ip6/flowtable.t.payload
@@ -0,0 +1,16 @@
+# meter acct_out size 4096 { meta iif . ip6 saddr timeout 600s counter }
+acct_out test-ip6 31
+acct_out test-ip6 0
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ payload load 16b @ network header + 8 => reg 9 ]
+ [ dynset update reg_key 1 set acct_out timeout 600000ms expr [ counter pkts 0 bytes 0 ] ]
+
+# meter acct_out size 12345 { ip6 saddr . meta iif timeout 600s counter }
+acct_out test-ip6 31
+acct_out test-ip6 0
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ meta load iif => reg 2 ]
+ [ dynset update reg_key 1 set acct_out timeout 600000ms expr [ counter pkts 0 bytes 0 ] ]
+
diff --git a/tests/py/ip6/frag.t b/tests/py/ip6/frag.t
new file mode 100644
index 0000000..6bbd6ac
--- /dev/null
+++ b/tests/py/ip6/frag.t
@@ -0,0 +1,40 @@
+:output;type filter hook output priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip6;test-ip6;output
+*inet;test-inet;output
+*netdev;test-netdev;ingress,egress
+
+frag nexthdr tcp;ok;frag nexthdr 6
+frag nexthdr != icmp;ok;frag nexthdr != 1
+frag nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp};ok;frag nexthdr { 51, 136, 132, 6, 108, 50, 17, 33}
+frag nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp};ok;frag nexthdr != { 51, 136, 132, 6, 108, 50, 17, 33}
+frag nexthdr esp;ok;frag nexthdr 50
+frag nexthdr ah;ok;frag nexthdr 51
+
+frag reserved 22;ok
+frag reserved != 233;ok
+frag reserved 33-45;ok
+frag reserved != 33-45;ok
+frag reserved { 33, 55, 67, 88};ok
+frag reserved != { 33, 55, 67, 88};ok
+
+frag frag-off 22;ok
+frag frag-off != 233;ok
+frag frag-off 33-45;ok
+frag frag-off != 33-45;ok
+frag frag-off { 33, 55, 67, 88};ok
+frag frag-off != { 33, 55, 67, 88};ok
+
+frag reserved2 1;ok
+frag more-fragments 0;ok
+frag more-fragments 1;ok
+
+frag id 1;ok
+frag id 22;ok
+frag id != 33;ok
+frag id 33-45;ok
+frag id != 33-45;ok
+frag id { 33, 55, 67, 88};ok
+frag id != { 33, 55, 67, 88};ok
diff --git a/tests/py/ip6/frag.t.json b/tests/py/ip6/frag.t.json
new file mode 100644
index 0000000..b8c06df
--- /dev/null
+++ b/tests/py/ip6/frag.t.json
@@ -0,0 +1,644 @@
+# frag nexthdr tcp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ }
+]
+
+# frag nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": "icmp"
+ }
+ }
+]
+
+# frag nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp"
+ ]
+ }
+ }
+ }
+]
+
+# frag nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp"
+ ]
+ }
+ }
+ }
+]
+
+# frag nexthdr esp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": "esp"
+ }
+ }
+]
+
+# frag nexthdr ah
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": "ah"
+ }
+ }
+]
+
+# frag reserved 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# frag reserved != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# frag reserved 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# frag reserved != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# frag reserved { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# frag reserved != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# frag reserved { 33-55}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# frag reserved != { 33-55}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# frag frag-off 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# frag frag-off != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# frag frag-off 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# frag frag-off != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# frag frag-off { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# frag frag-off != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# frag frag-off { 33-55}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# frag frag-off != { 33-55}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "frag-off",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# frag reserved2 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved2",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# frag more-fragments 0
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "more-fragments",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# frag more-fragments 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "more-fragments",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# frag id 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# frag id 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# frag id != 33
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": 33
+ }
+ }
+]
+
+# frag id 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# frag id != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# frag id { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# frag id != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# frag id { 33-55}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# frag id != { 33-55}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "id",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/frag.t.json.output b/tests/py/ip6/frag.t.json.output
new file mode 100644
index 0000000..68d382b
--- /dev/null
+++ b/tests/py/ip6/frag.t.json.output
@@ -0,0 +1,118 @@
+# frag nexthdr tcp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ }
+]
+
+# frag nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# frag nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# frag nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# frag nexthdr esp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# frag nexthdr ah
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "frag"
+ }
+ },
+ "op": "==",
+ "right": 51
+ }
+ }
+]
+
diff --git a/tests/py/ip6/frag.t.payload.inet b/tests/py/ip6/frag.t.payload.inet
new file mode 100644
index 0000000..20334f4
--- /dev/null
+++ b/tests/py/ip6/frag.t.payload.inet
@@ -0,0 +1,232 @@
+# frag nexthdr tcp
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# frag nexthdr != icmp
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ 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-inet 3
+__set%d test-inet 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]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ 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-inet 3
+__set%d test-inet 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]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag nexthdr esp
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# frag nexthdr ah
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+
+# frag reserved 22
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# frag reserved != 233
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# frag reserved 33-45
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# frag reserved != 33-45
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# frag reserved { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag reserved != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag frag-off 22
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000b000 ]
+
+# frag frag-off != 233
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00004807 ]
+
+# frag frag-off 33-45
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp gte reg 1 0x00000801 ]
+ [ cmp lte reg 1 0x00006801 ]
+
+# frag frag-off != 33-45
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ range neq reg 1 0x00000801 0x00006801 ]
+
+# frag frag-off { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag frag-off != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag id 1
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# frag id 22
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# frag id != 33
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp neq reg 1 0x21000000 ]
+
+# frag id 33-45
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# frag id != 33-45
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# frag id { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag id != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag reserved2 1
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# frag more-fragments 0
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# frag more-fragments 1
+inet test-inet output
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
+
diff --git a/tests/py/ip6/frag.t.payload.ip6 b/tests/py/ip6/frag.t.payload.ip6
new file mode 100644
index 0000000..7c3e7a4
--- /dev/null
+++ b/tests/py/ip6/frag.t.payload.ip6
@@ -0,0 +1,176 @@
+# frag nexthdr tcp
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# frag nexthdr != icmp
+ip6 test-ip6 output
+ [ 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-ip6 3
+__set%d test-ip6 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]
+ip6 test-ip6 output
+ [ 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-ip6 3
+__set%d test-ip6 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]
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag nexthdr esp
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# frag nexthdr ah
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+
+# frag reserved 22
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# frag reserved != 233
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# frag reserved 33-45
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# frag reserved != 33-45
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# frag reserved { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag reserved != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag frag-off 22
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000b000 ]
+
+# frag frag-off != 233
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00004807 ]
+
+# frag frag-off 33-45
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp gte reg 1 0x00000801 ]
+ [ cmp lte reg 1 0x00006801 ]
+
+# frag frag-off != 33-45
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ range neq reg 1 0x00000801 0x00006801 ]
+
+# frag frag-off { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag frag-off != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag id 1
+ip6 test-ip6 output
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# frag id 22
+ip6 test-ip6 output
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# frag id != 33
+ip6 test-ip6 output
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp neq reg 1 0x21000000 ]
+
+# frag id 33-45
+ip6 test-ip6 output
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# frag id != 33-45
+ip6 test-ip6 output
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# frag id { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag id != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag reserved2 1
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# frag more-fragments 0
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# frag more-fragments 1
+ip6 test-ip6 output
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
+
diff --git a/tests/py/ip6/frag.t.payload.ip6.got b/tests/py/ip6/frag.t.payload.ip6.got
new file mode 100644
index 0000000..db439da
--- /dev/null
+++ b/tests/py/ip6/frag.t.payload.ip6.got
@@ -0,0 +1,43 @@
+# frag frag-off 0x16
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000b000 ]
+
+# frag frag-off != 0xe9
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00004807 ]
+
+# frag frag-off 0x21-0x2d
+ip6 test-ip6 output
+ [ 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 != 0x21-0x2d
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ range neq reg 1 0x00000801 0x00006801 ]
+
+# frag frag-off { 0x21, 0x37, 0x43, 0x58}
+__set%d test-ip6 3 size 4
+__set%d test-ip6 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag frag-off != { 0x21, 0x37, 0x43, 0x58}
+__set%d test-ip6 3 size 4
+__set%d test-ip6 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+ip6 test-ip6 output
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/ip6/frag.t.payload.netdev b/tests/py/ip6/frag.t.payload.netdev
new file mode 100644
index 0000000..0562075
--- /dev/null
+++ b/tests/py/ip6/frag.t.payload.netdev
@@ -0,0 +1,232 @@
+# frag nexthdr tcp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# frag nexthdr != icmp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# frag nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+__set%d test-netdev 3 size 8
+__set%d test-netdev 0
+ element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+__set%d test-netdev 3 size 8
+__set%d test-netdev 0
+ element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag nexthdr esp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# frag nexthdr ah
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+
+# frag reserved 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# frag reserved != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# frag reserved 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# frag reserved != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# frag reserved { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag reserved != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag frag-off 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000b000 ]
+
+# frag frag-off != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00004807 ]
+
+# frag frag-off 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp gte reg 1 0x00000801 ]
+ [ cmp lte reg 1 0x00006801 ]
+
+# frag frag-off != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ range neq reg 1 0x00000801 0x00006801 ]
+
+# frag frag-off { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag frag-off != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag reserved2 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# frag more-fragments 0
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# frag more-fragments 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# frag id 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# frag id 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# frag id != 33
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp neq reg 1 0x21000000 ]
+
+# frag id 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# frag id != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# frag id { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag id != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/ip6/frag.t.payload.netdev.got b/tests/py/ip6/frag.t.payload.netdev.got
new file mode 100644
index 0000000..0562075
--- /dev/null
+++ b/tests/py/ip6/frag.t.payload.netdev.got
@@ -0,0 +1,232 @@
+# frag nexthdr tcp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# frag nexthdr != icmp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# frag nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+__set%d test-netdev 3 size 8
+__set%d test-netdev 0
+ element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+__set%d test-netdev 3 size 8
+__set%d test-netdev 0
+ element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag nexthdr esp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# frag nexthdr ah
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+
+# frag reserved 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# frag reserved != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# frag reserved 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# frag reserved != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# frag reserved { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag reserved != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag frag-off 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000b000 ]
+
+# frag frag-off != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00004807 ]
+
+# frag frag-off 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp gte reg 1 0x00000801 ]
+ [ cmp lte reg 1 0x00006801 ]
+
+# frag frag-off != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ range neq reg 1 0x00000801 0x00006801 ]
+
+# frag frag-off { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag frag-off != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag reserved2 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# frag more-fragments 0
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# frag more-fragments 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# frag id 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# frag id 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# frag id != 33
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp neq reg 1 0x21000000 ]
+
+# frag id 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# frag id != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# frag id { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag id != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/ip6/hbh.t b/tests/py/ip6/hbh.t
new file mode 100644
index 0000000..fce5fea
--- /dev/null
+++ b/tests/py/ip6/hbh.t
@@ -0,0 +1,22 @@
+:filter-input;type filter hook input priority 0
+
+*ip6;test-ip6;filter-input
+*inet;test-inet;filter-input
+
+hbh hdrlength 22;ok
+hbh hdrlength != 233;ok
+hbh hdrlength 33-45;ok
+hbh hdrlength != 33-45;ok
+hbh hdrlength {33, 55, 67, 88};ok
+hbh hdrlength != {33, 55, 67, 88};ok
+
+hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;hbh nexthdr { 58, 136, 51, 50, 6, 17, 132, 33, 108}
+hbh nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;hbh nexthdr != { 58, 136, 51, 50, 6, 17, 132, 33, 108}
+hbh nexthdr 22;ok
+hbh nexthdr != 233;ok
+hbh nexthdr 33-45;ok
+hbh nexthdr != 33-45;ok
+hbh nexthdr {33, 55, 67, 88};ok
+hbh nexthdr != {33, 55, 67, 88};ok
+hbh nexthdr ip;ok;hbh nexthdr 0
+hbh nexthdr != ip;ok;hbh nexthdr != 0
diff --git a/tests/py/ip6/hbh.t.json b/tests/py/ip6/hbh.t.json
new file mode 100644
index 0000000..68670a3
--- /dev/null
+++ b/tests/py/ip6/hbh.t.json
@@ -0,0 +1,316 @@
+# hbh hdrlength 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# hbh hdrlength != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# hbh hdrlength 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# hbh hdrlength != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# hbh hdrlength {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# hbh hdrlength != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp",
+ "icmpv6"
+ ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp",
+ "icmpv6"
+ ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# hbh nexthdr != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# hbh nexthdr 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr ip
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ }
+]
+
+# hbh nexthdr != ip
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": "ip"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/hbh.t.json.output b/tests/py/ip6/hbh.t.json.output
new file mode 100644
index 0000000..190f0fc
--- /dev/null
+++ b/tests/py/ip6/hbh.t.json.output
@@ -0,0 +1,68 @@
+# hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [ 6, 17, 33, 50, 51, 58, 108, 132, 136 ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [ 6, 17, 33, 50, 51, 58, 108, 132, 136 ]
+ }
+ }
+ }
+]
+
+# hbh nexthdr ip
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# hbh nexthdr != ip
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "hbh"
+ }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
diff --git a/tests/py/ip6/hbh.t.payload.inet b/tests/py/ip6/hbh.t.payload.inet
new file mode 100644
index 0000000..63afd83
--- /dev/null
+++ b/tests/py/ip6/hbh.t.payload.inet
@@ -0,0 +1,132 @@
+# hbh hdrlength 22
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# hbh hdrlength != 233
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# hbh hdrlength 33-45
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# hbh hdrlength != 33-45
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# hbh hdrlength {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# hbh hdrlength != {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-inet 3
+__set%d test-inet 0
+ 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] element 0000003a : 0 [end]
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# hbh nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-inet 3
+__set%d test-inet 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] element 0000003a : 0 [end]
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# hbh nexthdr 22
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# hbh nexthdr != 233
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# hbh nexthdr 33-45
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# hbh nexthdr != 33-45
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# hbh nexthdr {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# hbh nexthdr != {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# hbh nexthdr ip
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# hbh nexthdr != ip
+inet test-inet filter-input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
diff --git a/tests/py/ip6/hbh.t.payload.ip6 b/tests/py/ip6/hbh.t.payload.ip6
new file mode 100644
index 0000000..913505a
--- /dev/null
+++ b/tests/py/ip6/hbh.t.payload.ip6
@@ -0,0 +1,100 @@
+# hbh hdrlength 22
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# hbh hdrlength != 233
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# hbh hdrlength 33-45
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# hbh hdrlength != 33-45
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# hbh hdrlength {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# hbh hdrlength != {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ 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] element 0000003a : 0 [end]
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# hbh nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-ip6 3
+__set%d test-ip6 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] element 0000003a : 0 [end]
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# hbh nexthdr 22
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# hbh nexthdr != 233
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# hbh nexthdr 33-45
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# hbh nexthdr != 33-45
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# hbh nexthdr {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# hbh nexthdr != {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# hbh nexthdr ip
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# hbh nexthdr != ip
+ip6 test-ip6 filter-input
+ [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
diff --git a/tests/py/ip6/icmpv6.t b/tests/py/ip6/icmpv6.t
new file mode 100644
index 0000000..35dad2b
--- /dev/null
+++ b/tests/py/ip6/icmpv6.t
@@ -0,0 +1,99 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+# BUG: There is a bug with icmpv6 and inet tables
+# *inet;test-inet;input
+
+icmpv6 type destination-unreachable accept;ok
+icmpv6 type packet-too-big accept;ok
+icmpv6 type time-exceeded accept;ok
+icmpv6 type echo-request accept;ok
+icmpv6 type echo-reply accept;ok
+icmpv6 type mld-listener-query accept;ok
+icmpv6 type mld-listener-report accept;ok
+icmpv6 type mld-listener-done accept;ok
+icmpv6 type mld-listener-reduction accept;ok;icmpv6 type mld-listener-done accept
+icmpv6 type nd-router-solicit accept;ok
+icmpv6 type nd-router-advert accept;ok
+icmpv6 type nd-neighbor-solicit accept;ok
+icmpv6 type nd-neighbor-advert accept;ok
+icmpv6 type nd-redirect accept;ok
+icmpv6 type parameter-problem accept;ok
+icmpv6 type router-renumbering accept;ok
+icmpv6 type ind-neighbor-solicit accept;ok
+icmpv6 type ind-neighbor-advert accept;ok
+icmpv6 type mld2-listener-report accept;ok
+icmpv6 type {destination-unreachable, time-exceeded, nd-router-solicit} accept;ok
+icmpv6 type {router-renumbering, mld-listener-done, time-exceeded, nd-router-solicit} accept;ok
+icmpv6 type {mld-listener-query, time-exceeded, nd-router-advert} accept;ok
+icmpv6 type != {mld-listener-query, time-exceeded, nd-router-advert} accept;ok
+
+icmpv6 code 4;ok;icmpv6 code port-unreachable
+icmpv6 code 3-66;ok
+icmpv6 code {5, 6, 7} accept;ok;icmpv6 code {policy-fail, reject-route, 7} accept
+icmpv6 code != {policy-fail, reject-route, 7} accept;ok
+
+icmpv6 checksum 2222 log;ok
+icmpv6 checksum != 2222 log;ok
+icmpv6 checksum 222-226;ok
+icmpv6 checksum != 222-226;ok
+icmpv6 checksum { 222, 226};ok
+icmpv6 checksum != { 222, 226};ok
+
+# BUG: icmpv6 parameter-problem, pptr
+# [ICMP6HDR_PPTR] = ICMP6HDR_FIELD("parameter-problem", icmp6_pptr),
+# $ sudo nft add rule ip6 test6 input icmpv6 parameter-problem 35
+# <cmdline>:1:53-53: Error: syntax error, unexpected end of file
+# add rule ip6 test6 input icmpv6 parameter-problem 35
+# ^
+# $ sudo nft add rule ip6 test6 input icmpv6 parameter-problem
+# <cmdline>:1:26-31: Error: Value 58 exceeds valid range 0-0
+# add rule ip6 test6 input icmpv6 parameter-problem
+# ^^^^^^
+# $ sudo nft add rule ip6 test6 input icmpv6 parameter-problem 2-4
+# <cmdline>:1:54-54: Error: syntax error, unexpected end of file
+# add rule ip6 test6 input icmpv6 parameter-problem 2-4
+
+icmpv6 mtu 22;ok
+icmpv6 mtu != 233;ok
+icmpv6 mtu 33-45;ok
+icmpv6 mtu != 33-45;ok
+icmpv6 mtu {33, 55, 67, 88};ok
+icmpv6 mtu != {33, 55, 67, 88};ok
+icmpv6 type packet-too-big icmpv6 mtu 1280;ok;icmpv6 mtu 1280
+
+icmpv6 id 33-45;ok;icmpv6 type { echo-request, echo-reply} icmpv6 id 33-45
+icmpv6 id != 33-45;ok;icmpv6 type { echo-request, echo-reply} icmpv6 id != 33-45
+icmpv6 id {33, 55, 67, 88};ok;icmpv6 type { echo-request, echo-reply} icmpv6 id { 33, 55, 67, 88}
+icmpv6 id != {33, 55, 67, 88};ok;icmpv6 type { echo-request, echo-reply} icmpv6 id != { 33, 55, 67, 88}
+
+icmpv6 id 1;ok;icmpv6 type { echo-request, echo-reply} icmpv6 id 1
+icmpv6 type echo-reply icmpv6 id 65534;ok
+
+icmpv6 sequence 2;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence 2
+icmpv6 sequence {3, 4, 5, 6, 7} accept;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence { 3, 4, 5, 6, 7} accept
+
+
+icmpv6 sequence {2, 4};ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence { 2, 4}
+icmpv6 sequence != {2, 4};ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence != { 2, 4}
+icmpv6 sequence 2-4;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence 2-4
+icmpv6 sequence != 2-4;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence != 2-4
+
+icmpv6 max-delay 33-45;ok
+icmpv6 max-delay != 33-45;ok
+icmpv6 max-delay {33, 55, 67, 88};ok
+icmpv6 max-delay != {33, 55, 67, 88};ok
+
+icmpv6 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
new file mode 100644
index 0000000..224a8e8
--- /dev/null
+++ b/tests/py/ip6/icmpv6.t.json
@@ -0,0 +1,1425 @@
+# icmpv6 type destination-unreachable accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "destination-unreachable"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type packet-too-big accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "packet-too-big"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type time-exceeded accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "time-exceeded"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type echo-request accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type echo-reply accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type mld-listener-query accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "mld-listener-query"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type mld-listener-report accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "mld-listener-report"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type mld-listener-done accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "mld-listener-done"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type mld-listener-reduction accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "mld-listener-reduction"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type nd-router-solicit accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-solicit"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type nd-router-advert accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type nd-neighbor-solicit accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-neighbor-solicit"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type nd-neighbor-advert accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-neighbor-advert"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type nd-redirect accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-redirect"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type parameter-problem accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "parameter-problem"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type router-renumbering accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "router-renumbering"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type ind-neighbor-solicit accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "ind-neighbor-solicit"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type ind-neighbor-advert accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "ind-neighbor-advert"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type mld2-listener-report accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "mld2-listener-report"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type {destination-unreachable, time-exceeded, nd-router-solicit} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "destination-unreachable",
+ "time-exceeded",
+ "nd-router-solicit"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type {router-renumbering, mld-listener-done, time-exceeded, nd-router-solicit} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "router-renumbering",
+ "mld-listener-done",
+ "time-exceeded",
+ "nd-router-solicit"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type {mld-listener-query, time-exceeded, nd-router-advert} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "mld-listener-query",
+ "time-exceeded",
+ "nd-router-advert"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type != {mld-listener-query, time-exceeded, nd-router-advert} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "mld-listener-query",
+ "time-exceeded",
+ "nd-router-advert"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 code 4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 4
+ }
+ }
+]
+
+# icmpv6 code 3-66
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 3, 66 ]
+ }
+ }
+ }
+]
+
+# icmpv6 code {5, 6, 7} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 5,
+ 6,
+ 7
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 code != {policy-fail, reject-route, 7} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "policy-fail",
+ "reject-route",
+ 7
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 checksum 2222 log
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 2222
+ }
+ },
+ {
+ "log": null
+ }
+]
+
+# icmpv6 checksum != 2222 log
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": 2222
+ }
+ },
+ {
+ "log": null
+ }
+]
+
+# icmpv6 checksum 222-226
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 222, 226 ]
+ }
+ }
+ }
+]
+
+# icmpv6 checksum != 222-226
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 222, 226 ]
+ }
+ }
+ }
+]
+
+# icmpv6 checksum { 222, 226}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 222,
+ 226
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 checksum != { 222, 226}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "checksum",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 222,
+ 226
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 mtu 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# icmpv6 mtu != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# icmpv6 mtu 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# icmpv6 mtu != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# icmpv6 mtu {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 mtu != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# icmpv6 id {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# icmpv6 type echo-reply icmpv6 id 65534
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 65534
+ }
+ }
+]
+
+# icmpv6 sequence 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# icmpv6 sequence {3, 4, 5, 6, 7} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 3,
+ 4,
+ 5,
+ 6,
+ 7
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 sequence {2, 4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != {2, 4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence 2-4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 2, 4 ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != 2-4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 2, 4 ]
+ }
+ }
+ }
+]
+
+# icmpv6 max-delay 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "max-delay",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# icmpv6 max-delay != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "max-delay",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# icmpv6 max-delay {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "max-delay",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 max-delay != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "max-delay",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 type packet-too-big icmpv6 mtu 1280
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "mtu",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 1280
+ }
+ }
+]
+
+# icmpv6 type parameter-problem icmpv6 code no-route
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "parameter-problem"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "no-route"
+ }
+ }
+]
+
+# 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.json.output b/tests/py/ip6/icmpv6.t.json.output
new file mode 100644
index 0000000..7b8f5c1
--- /dev/null
+++ b/tests/py/ip6/icmpv6.t.json.output
@@ -0,0 +1,760 @@
+# icmpv6 type mld-listener-reduction accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "mld-listener-done"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type {router-renumbering, mld-listener-done, time-exceeded, nd-router-solicit} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "time-exceeded",
+ "mld-listener-done",
+ "nd-router-solicit",
+ "router-renumbering"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type {mld-listener-query, time-exceeded, nd-router-advert} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "time-exceeded",
+ "mld-listener-query",
+ "nd-router-advert"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 type != {mld-listener-query, time-exceeded, nd-router-advert} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "time-exceeded",
+ "mld-listener-query",
+ "nd-router-advert"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 code 4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "port-unreachable"
+ }
+ }
+]
+
+# icmpv6 code 3-66
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ "addr-unreachable",
+ 66
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 code {5, 6, 7} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "policy-fail",
+ "reject-route",
+ 7
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 code { 3-66}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [
+ "addr-unreachable",
+ 66
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 code != { 3-66}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ {
+ "range": [
+ "addr-unreachable",
+ 66
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id {33-55}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != {33-55}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# icmpv6 sequence {3, 4, 5, 6, 7} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 3,
+ 4,
+ 5,
+ 6,
+ 7
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 sequence {2, 4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != {2, 4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence 2-4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != 2-4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence { 2-4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 2,
+ 4
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != { 2-4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 2,
+ 4
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/icmpv6.t.payload.ip6 b/tests/py/ip6/icmpv6.t.payload.ip6
new file mode 100644
index 0000000..fcaf481
--- /dev/null
+++ b/tests/py/ip6/icmpv6.t.payload.ip6
@@ -0,0 +1,643 @@
+# icmpv6 type destination-unreachable accept
+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 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type packet-too-big accept
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type time-exceeded accept
+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 0x00000003 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type echo-request accept
+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 0x00000080 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type echo-reply accept
+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 0x00000081 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type mld-listener-query accept
+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 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type mld-listener-report accept
+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 0x00000083 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type mld-listener-done accept
+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 0x00000084 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type mld-listener-reduction accept
+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 0x00000084 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type nd-router-solicit accept
+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 0x00000085 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type nd-router-advert accept
+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 0x00000086 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type nd-neighbor-solicit accept
+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 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type nd-neighbor-advert accept
+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 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type nd-redirect accept
+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 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type parameter-problem accept
+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 0x00000004 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type router-renumbering accept
+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 0x0000008a ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type ind-neighbor-solicit accept
+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 0x0000008d ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type ind-neighbor-advert accept
+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 0x0000008e ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type mld2-listener-report accept
+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 0x0000008f ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type {destination-unreachable, time-exceeded, nd-router-solicit} accept
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000001 : 0 [end] element 00000003 : 0 [end] element 00000085 : 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 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type {router-renumbering, mld-listener-done, time-exceeded, nd-router-solicit} accept
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 0000008a : 0 [end] element 00000084 : 0 [end] element 00000003 : 0 [end] element 00000085 : 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 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type {mld-listener-query, time-exceeded, nd-router-advert} accept
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000082 : 0 [end] element 00000003 : 0 [end] element 00000086 : 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 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type != {mld-listener-query, time-exceeded, nd-router-advert} accept
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000082 : 0 [end] element 00000003 : 0 [end] element 00000086 : 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 0x1 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 code 4
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+
+# icmpv6 code 3-66
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000003 ]
+ [ cmp lte reg 1 0x00000042 ]
+
+# icmpv6 code {5, 6, 7} accept
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 code != {policy-fail, reject-route, 7} accept
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 checksum 2222 log
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000ae08 ]
+ [ log ]
+
+# icmpv6 checksum != 2222 log
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000ae08 ]
+ [ log ]
+
+# icmpv6 checksum 222-226
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x0000de00 ]
+ [ cmp lte reg 1 0x0000e200 ]
+
+# icmpv6 checksum != 222-226
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ range neq reg 1 0x0000de00 0x0000e200 ]
+
+# icmpv6 checksum { 222, 226}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 0000de00 : 0 [end] element 0000e200 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmpv6 checksum != { 222, 226}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 0000de00 : 0 [end] element 0000e200 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmpv6 mtu 22
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# icmpv6 mtu != 233
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp neq reg 1 0xe9000000 ]
+
+# icmpv6 mtu 33-45
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# icmpv6 mtu != 33-45
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# icmpv6 mtu {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmpv6 mtu != {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmpv6 type packet-too-big icmpv6 mtu 1280
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00050000 ]
+
+# icmpv6 id 33-45
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# icmpv6 id != 33-45
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# icmpv6 id {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmpv6 id != {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmpv6 id 1
+__set%d test-ip6 3 size 2
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# icmpv6 type echo-reply icmpv6 id 65534
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x0000feff ]
+
+# icmpv6 sequence 2
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# icmpv6 sequence {3, 4, 5, 6, 7} accept
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000300 : 0 [end] element 00000400 : 0 [end] element 00000500 : 0 [end] element 00000600 : 0 [end] element 00000700 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 sequence {2, 4}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000200 : 0 [end] element 00000400 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmpv6 sequence != {2, 4}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000200 : 0 [end] element 00000400 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmpv6 sequence 2-4
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00000200 ]
+ [ cmp lte reg 1 0x00000400 ]
+
+# icmpv6 sequence != 2-4
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ range neq reg 1 0x00000200 0x00000400 ]
+
+# icmpv6 max-delay 33-45
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# icmpv6 max-delay != 33-45
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# icmpv6 max-delay {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# icmpv6 max-delay != {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# icmpv6 type parameter-problem icmpv6 code no-route
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+
+# icmpv6 type mld-listener-query icmpv6 taddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 type nd-neighbor-solicit icmpv6 taddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000087 ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 type nd-neighbor-advert icmpv6 taddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 taddr 2001:db8::133
+__set%d test-ip6 3 size 6
+__set%d test-ip6 0
+ element 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
new file mode 100644
index 0000000..2ffe318
--- /dev/null
+++ b/tests/py/ip6/ip6.t
@@ -0,0 +1,153 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+*inet;test-inet;input
+
+# BUG: Problem with version, priority
+# <cmdline>:1:1-38: Error: Could not process rule: Invalid argument
+# add rule ip6 test6 input ip6 version 1
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- ip6 version 6;ok
+
+ip6 dscp cs1;ok
+ip6 dscp != cs1;ok
+ip6 dscp 0x38;ok;ip6 dscp cs7
+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
+
+ip6 flowlabel 22;ok
+ip6 flowlabel != 233;ok
+- ip6 flowlabel 33-45;ok
+- ip6 flowlabel != 33-45;ok
+ip6 flowlabel { 33, 55, 67, 88};ok
+# BUG ip6 flowlabel { 5046528, 2883584, 13522432 }
+ip6 flowlabel != { 33, 55, 67, 88};ok
+ip6 flowlabel vmap { 0 : accept, 2 : continue };ok
+
+ip6 length 22;ok
+ip6 length != 233;ok
+ip6 length 33-45;ok
+ip6 length != 33-45;ok
+ip6 length { 33, 55, 67, 88};ok
+ip6 length != {33, 55, 67, 88};ok
+
+ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp};ok;ip6 nexthdr { 132, 51, 108, 136, 17, 33, 6}
+ip6 nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;ip6 nexthdr { 6, 136, 108, 33, 50, 17, 132, 58, 51}
+ip6 nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;ip6 nexthdr != { 6, 136, 108, 33, 50, 17, 132, 58, 51}
+ip6 nexthdr esp;ok;ip6 nexthdr 50
+ip6 nexthdr != esp;ok;ip6 nexthdr != 50
+ip6 nexthdr 33-44;ok
+ip6 nexthdr != 33-44;ok
+
+ip6 hoplimit 1;ok
+ip6 hoplimit != 233;ok
+ip6 hoplimit 33-45;ok
+ip6 hoplimit != 33-45;ok
+ip6 hoplimit {33, 55, 67, 88};ok
+ip6 hoplimit != {33, 55, 67, 88};ok
+
+# from src/scanner.l
+# v680 (({hex4}:){7}{hex4})
+ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234;ok
+# v670 ((:)(:{hex4}{7}))
+ip6 saddr ::1234:1234:1234:1234:1234:1234:1234;ok;ip6 saddr 0:1234:1234:1234:1234:1234:1234:1234
+# v671 ((({hex4}:){1})(:{hex4}{6}))
+ip6 saddr 1234::1234:1234:1234:1234:1234:1234;ok;ip6 saddr 1234:0:1234:1234:1234:1234:1234:1234
+# v672 ((({hex4}:){2})(:{hex4}{5}))
+ip6 saddr 1234:1234::1234:1234:1234:1234:1234;ok;ip6 saddr 1234:1234:0:1234:1234:1234:1234:1234
+ip6 saddr 1234:1234:0:1234:1234:1234:1234:1234;ok
+# v673 ((({hex4}:){3})(:{hex4}{4}))
+ip6 saddr 1234:1234:1234::1234:1234:1234:1234;ok;ip6 saddr 1234:1234:1234:0:1234:1234:1234:1234
+# v674 ((({hex4}:){4})(:{hex4}{3}))
+ip6 saddr 1234:1234:1234:1234:0:1234:1234:1234;ok
+# v675 ((({hex4}:){5})(:{hex4}{2}))
+ip6 saddr 1234:1234:1234:1234:1234::1234:1234;ok;ip6 saddr 1234:1234:1234:1234:1234:0:1234:1234
+# v676 ((({hex4}:){6})(:{hex4}{1}))
+ip6 saddr 1234:1234:1234:1234:1234:1234:0:1234;ok
+# v677 ((({hex4}:){7})(:))
+ip6 saddr 1234:1234:1234:1234:1234:1234:1234::;ok;ip6 saddr 1234:1234:1234:1234:1234:1234:1234:0
+# v67 ({v670}|{v671}|{v672}|{v673}|{v674}|{v675}|{v676}|{v677})
+# v660 ((:)(:{hex4}{6}))
+ip6 saddr ::1234:1234:1234:1234:1234:1234;ok
+# v661 ((({hex4}:){1})(:{hex4}{5}))
+ip6 saddr 1234::1234:1234:1234:1234:1234;ok
+# v662 ((({hex4}:){2})(:{hex4}{4}))
+ip6 saddr 1234:1234::1234:1234:1234:1234;ok
+# v663 ((({hex4}:){3})(:{hex4}{3}))
+ip6 saddr 1234:1234:1234::1234:1234:1234;ok
+# v664 ((({hex4}:){4})(:{hex4}{2}))
+ip6 saddr 1234:1234:1234:1234::1234:1234;ok
+# v665 ((({hex4}:){5})(:{hex4}{1}))
+ip6 saddr 1234:1234:1234:1234:1234::1234;ok
+# v666 ((({hex4}:){6})(:))
+ip6 saddr 1234:1234:1234:1234:1234:1234::;ok
+# v66 ({v660}|{v661}|{v662}|{v663}|{v664}|{v665}|{v666})
+# v650 ((:)(:{hex4}{5}))
+ip6 saddr ::1234:1234:1234:1234:1234;ok
+# v651 ((({hex4}:){1})(:{hex4}{4}))
+ip6 saddr 1234::1234:1234:1234:1234;ok
+# v652 ((({hex4}:){2})(:{hex4}{3}))
+ip6 saddr 1234:1234::1234:1234:1234;ok
+# v653 ((({hex4}:){3})(:{hex4}{2}))
+ip6 saddr 1234:1234:1234::1234:1234;ok
+# v654 ((({hex4}:){4})(:{hex4}{1}))
+ip6 saddr 1234:1234:1234:1234::1234;ok
+# v655 ((({hex4}:){5})(:))
+ip6 saddr 1234:1234:1234:1234:1234::;ok
+# v65 ({v650}|{v651}|{v652}|{v653}|{v654}|{v655})
+# v640 ((:)(:{hex4}{4}))
+ip6 saddr ::1234:1234:1234:1234;ok
+# v641 ((({hex4}:){1})(:{hex4}{3}))
+ip6 saddr 1234::1234:1234:1234;ok
+# v642 ((({hex4}:){2})(:{hex4}{2}))
+ip6 saddr 1234:1234::1234:1234;ok
+# v643 ((({hex4}:){3})(:{hex4}{1}))
+ip6 saddr 1234:1234:1234::1234;ok
+# v644 ((({hex4}:){4})(:))
+ip6 saddr 1234:1234:1234:1234::;ok
+# v64 ({v640}|{v641}|{v642}|{v643}|{v644})
+# v630 ((:)(:{hex4}{3}))
+ip6 saddr ::1234:1234:1234;ok
+# v631 ((({hex4}:){1})(:{hex4}{2}))
+ip6 saddr 1234::1234:1234;ok
+# v632 ((({hex4}:){2})(:{hex4}{1}))
+ip6 saddr 1234:1234::1234;ok
+# v633 ((({hex4}:){3})(:))
+ip6 saddr 1234:1234:1234::;ok
+# v63 ({v630}|{v631}|{v632}|{v633})
+# v620 ((:)(:{hex4}{2}))
+ip6 saddr ::1234:1234;ok;ip6 saddr ::18.52.18.52
+# v621 ((({hex4}:){1})(:{hex4}{1}))
+ip6 saddr 1234::1234;ok
+# v622 ((({hex4}:){2})(:))
+ip6 saddr 1234:1234::;ok
+# v62 ({v620}|{v621}|{v622})
+# v610 ((:)(:{hex4}{1}))
+ip6 saddr ::1234;ok
+# v611 ((({hex4}:){1})(:))
+ip6 saddr 1234::;ok
+# v61 ({v610}|{v611})
+# v60 (::)
+ip6 saddr ::/64;ok
+ip6 saddr ::1 ip6 daddr ::2;ok
+
+ip6 daddr != {::1234:1234:1234:1234:1234:1234:1234, 1234:1234::1234:1234:1234:1234:1234 };ok;ip6 daddr != {0:1234:1234:1234:1234:1234:1234:1234, 1234:1234:0:1234:1234:1234:1234:1234}
+ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234;ok;ip6 daddr != 0:1234:1234:1234:1234:1234:1234:1234-1234:1234:0:1234:1234:1234:1234:1234
+
+# limit impact to lo
+iif "lo" ip6 daddr set ::1;ok
+iif "lo" ip6 hoplimit set 1;ok
+iif "lo" ip6 dscp set af42;ok
+iif "lo" ip6 dscp set 63;ok;iif "lo" ip6 dscp set 0x3f
+iif "lo" ip6 ecn set ect0;ok
+iif "lo" ip6 ecn set ce;ok
+
+iif "lo" ip6 flowlabel set 0;ok
+iif "lo" ip6 flowlabel set 12345;ok
+iif "lo" ip6 flowlabel set 0xfffff;ok;iif "lo" ip6 flowlabel set 1048575
+
+iif "lo" ip6 ecn set 4;fail
+iif "lo" ip6 dscp set 64;fail
+iif "lo" ip6 flowlabel set 1048576;fail
diff --git a/tests/py/ip6/ip6.t.json b/tests/py/ip6/ip6.t.json
new file mode 100644
index 0000000..cf80217
--- /dev/null
+++ b/tests/py/ip6/ip6.t.json
@@ -0,0 +1,1559 @@
+# ip6 dscp cs1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "cs1"
+ }
+ }
+]
+
+# ip6 dscp != cs1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": "cs1"
+ }
+ }
+]
+
+# ip6 dscp 0x38
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "0x38"
+ }
+ }
+]
+
+# ip6 dscp != 0x20
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": "0x20"
+ }
+ }
+]
+
+# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "cs0",
+ "cs1",
+ "cs2",
+ "cs3",
+ "cs4",
+ "cs5",
+ "cs6",
+ "cs7",
+ "af11",
+ "af12",
+ "af13",
+ "af21",
+ "af22",
+ "af23",
+ "af31",
+ "af32",
+ "af33",
+ "af41",
+ "af42",
+ "af43",
+ "ef"
+ ]
+ }
+ }
+ }
+]
+
+# ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "0x04",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "0x3f",
+ {
+ "continue": null
+ }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "counter": null
+ }
+]
+
+# ip6 flowlabel 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip6 flowlabel != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ip6 flowlabel { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip6 flowlabel != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip6 flowlabel vmap { 0 : accept, 2 : continue }
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 0,
+ {
+ "accept": null
+ }
+ ],
+ [
+ 2,
+ {
+ "continue": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 length 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# ip6 length != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ip6 length 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip6 length != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip6 length { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip6 length != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "length",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "udp",
+ "ah",
+ "comp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp"
+ ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp",
+ "icmpv6"
+ ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "esp",
+ "ah",
+ "comp",
+ "udp",
+ "udplite",
+ "tcp",
+ "dccp",
+ "sctp",
+ "icmpv6"
+ ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr esp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "esp"
+ }
+ }
+]
+
+# ip6 nexthdr != esp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": "esp"
+ }
+ }
+]
+
+# ip6 nexthdr { 33-44}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 44 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr != { 33-44}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 44 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr 33-44
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 44 ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr != 33-44
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 44 ]
+ }
+ }
+ }
+]
+
+# ip6 hoplimit 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hoplimit",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ip6 hoplimit != 233
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hoplimit",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ip6 hoplimit 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hoplimit",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip6 hoplimit != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hoplimit",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ip6 hoplimit {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hoplimit",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip6 hoplimit != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "hoplimit",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234:1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1234:1234:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::1234:1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234::1234:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234::1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234::1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:0:1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:0:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234::1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234::1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:0:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:0:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234::1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:0:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234:1234:0:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234:1234:1234::"
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1234:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234::1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234::1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234::1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234::1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234::1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234::1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234::1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234::1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234:1234::"
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234::1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234::1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234::1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234::1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234::1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234::1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234::"
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234::1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234::1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234::1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234::1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234::"
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234::1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234::1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234::1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234::"
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234::1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234::"
+ }
+ }
+]
+
+# ip6 saddr ::1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234::"
+ }
+ }
+]
+
+# ip6 saddr ::/64
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "::",
+ "len": 64
+ }
+ }
+ }
+ }
+]
+
+# ip6 saddr ::1 ip6 daddr ::2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::2"
+ }
+ }
+]
+
+# ip6 daddr != {::1234:1234:1234:1234:1234:1234:1234, 1234:1234::1234:1234:1234:1234:1234 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "::1234:1234:1234:1234:1234:1234:1234",
+ "1234:1234::1234:1234:1234:1234:1234"
+ ]
+ }
+ }
+ }
+]
+
+# ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "::1234:1234:1234:1234:1234:1234:1234", "1234:1234::1234:1234:1234:1234:1234" ]
+ }
+ }
+ }
+]
+
+# iif "lo" ip6 daddr set ::1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "value": "::1"
+ }
+ }
+]
+
+# iif "lo" ip6 hoplimit set 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "hoplimit",
+ "protocol": "ip6"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# iif "lo" ip6 dscp set af42
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "value": "af42"
+ }
+ }
+]
+
+# iif "lo" ip6 dscp set 63
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "value": 63
+ }
+ }
+]
+
+# iif "lo" ip6 ecn set ect0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "ecn",
+ "protocol": "ip6"
+ }
+ },
+ "value": "ect0"
+ }
+ }
+]
+
+# iif "lo" ip6 ecn set ce
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "ecn",
+ "protocol": "ip6"
+ }
+ },
+ "value": "ce"
+ }
+ }
+]
+
+# iif "lo" ip6 flowlabel set 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "value": 0
+ }
+ }
+]
+
+# iif "lo" ip6 flowlabel set 12345
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "value": 12345
+ }
+ }
+]
+
+# iif "lo" ip6 flowlabel set 0xfffff
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "value": "0xfffff"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/ip6.t.json.output b/tests/py/ip6/ip6.t.json.output
new file mode 100644
index 0000000..6c20939
--- /dev/null
+++ b/tests/py/ip6/ip6.t.json.output
@@ -0,0 +1,374 @@
+# ip6 dscp 0x38
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "cs7"
+ }
+ }
+]
+
+# ip6 dscp != 0x20
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": "cs4"
+ }
+ }
+]
+
+# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "cs0",
+ "cs1",
+ "af11",
+ "af12",
+ "af13",
+ "cs2",
+ "af21",
+ "af22",
+ "af23",
+ "cs3",
+ "af31",
+ "af32",
+ "af33",
+ "cs4",
+ "af41",
+ "af42",
+ "af43",
+ "cs5",
+ "ef",
+ "cs6",
+ "cs7"
+ ]
+ }
+ }
+ }
+]
+
+# ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 4,
+ {
+ "accept": null
+ }
+ ],
+ [
+ 63,
+ {
+ "continue": null
+ }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "counter": null
+ }
+]
+
+# ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 51,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [ 6, 17, 33, 50, 51, 58, 108, 132, 136 ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [ 6, 17, 33, 50, 51, 58, 108, 132, 136 ]
+ }
+ }
+ }
+]
+
+# ip6 nexthdr esp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# ip6 nexthdr != esp
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": 50
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234:1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "0:1234:1234:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234::1234:1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:0:1234:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234::1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:0:1234:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234::1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:0:1234:1234:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234:0:1234:1234"
+ }
+ }
+]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:1234::
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "1234:1234:1234:1234:1234:1234:1234:0"
+ }
+ }
+]
+
+# ip6 saddr ::1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "::18.52.18.52"
+ }
+ }
+]
+
+# ip6 daddr != {::1234:1234:1234:1234:1234:1234:1234, 1234:1234::1234:1234:1234:1234:1234 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "0:1234:1234:1234:1234:1234:1234:1234",
+ "1234:1234:0:1234:1234:1234:1234:1234"
+ ]
+ }
+ }
+ }
+]
+
+# ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "0:1234:1234:1234:1234:1234:1234:1234", "1234:1234:0:1234:1234:1234:1234:1234" ]
+ }
+ }
+ }
+]
+
+# iif "lo" ip6 flowlabel set 0xfffff
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "flowlabel",
+ "protocol": "ip6"
+ }
+ },
+ "value": 1048575
+ }
+ }
+]
+
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
new file mode 100644
index 0000000..20dfe54
--- /dev/null
+++ b/tests/py/ip6/ip6.t.payload.inet
@@ -0,0 +1,641 @@
+# ip6 dscp cs1
+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 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# ip6 dscp != cs1
+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 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# ip6 dscp 0x38
+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 ]
+ [ cmp eq reg 1 0x0000000e ]
+
+# ip6 dscp != 0x20
+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 ]
+ [ cmp neq reg 1 0x00000008 ]
+
+# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000000 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000006 : 0 [end] element 00000008 : 0 [end] element 0000000a : 0 [end] element 0000000c : 0 [end] element 0000000e : 0 [end] element 00008002 : 0 [end] element 00000003 : 0 [end] element 00008003 : 0 [end] element 00008004 : 0 [end] element 00000005 : 0 [end] element 00008005 : 0 [end] element 00008006 : 0 [end] element 00000007 : 0 [end] element 00008007 : 0 [end] element 00008008 : 0 [end] element 00000009 : 0 [end] element 00008009 : 0 [end] element 0000800b : 0 [end]
+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 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter
+__map%d test-inet b size 2
+__map%d test-inet 0
+ element 00000001 : accept 0 [end] element 0000c00f : continue 0 [end]
+ip6 test-ip6 input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ip6 flowlabel 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00160000 ]
+
+# ip6 flowlabel != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00e90000 ]
+
+# ip6 flowlabel { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00210000 : 0 [end] element 00370000 : 0 [end] element 00430000 : 0 [end] element 00580000 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 flowlabel != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00210000 : 0 [end] element 00370000 : 0 [end] element 00430000 : 0 [end] element 00580000 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 flowlabel vmap { 0 : accept, 2 : continue }
+__map%d test-inet b size 2
+__map%d test-inet 0
+ element 00000000 : accept 0 [end] element 00020000 : continue 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 length 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip6 length != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip6 length 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip6 length != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip6 length { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 length != {33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000011 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-inet 3
+__set%d test-inet 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] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-inet 3
+__set%d test-inet 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] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 nexthdr esp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# ip6 nexthdr != esp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000032 ]
+
+# ip6 nexthdr 33-44
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002c ]
+
+# ip6 nexthdr != 33-44
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002c ]
+
+# ip6 hoplimit 1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ip6 hoplimit != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# ip6 hoplimit 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# ip6 hoplimit != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# ip6 hoplimit {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 hoplimit != {33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr ::1234:1234:1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34120000 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:0:1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:0:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234::1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00003412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:0:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:1234::
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x00003412 ]
+
+# ip6 saddr ::1234:1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234::1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234::1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00003412 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234::
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x00000000 ]
+
+# ip6 saddr ::1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234::1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234::
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00003412 0x00000000 ]
+
+# ip6 saddr ::1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234::
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234::
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234::1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234::
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234::
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x00000000 0x00000000 ]
+
+# ip6 saddr ::/64
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 8b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1 ip6 daddr ::2
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x02000000 ]
+
+# ip6 daddr != {::1234:1234:1234:1234:1234:1234:1234, 1234:1234::1234:1234:1234:1234:1234 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 34120000 34123412 34123412 34123412 : 0 [end] element 34123412 34120000 34123412 34123412 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ range neq reg 1 0x34120000 0x34123412 0x34123412 0x34123412 0x34123412 0x34120000 0x34123412 0x34123412 ]
+
+# iif "lo" ip6 daddr set ::1
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ immediate reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
+ [ payload write reg 1 => 16b @ network header + 24 csum_type 0 csum_off 0 csum_flags 0x1 ]
+
+# iif "lo" ip6 hoplimit set 1
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ immediate reg 1 0x00000001 ]
+ [ payload write reg 1 => 1b @ network header + 7 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 dscp set af42
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x00000009 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 dscp set 63
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x0000c00f ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 ecn set ect0
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000020 ]
+ [ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 ecn set ce
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000030 ]
+ [ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 flowlabel set 0
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 flowlabel set 12345
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00393000 ]
+ [ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 flowlabel set 0xfffff
+inet test-inet input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00ffff0f ]
+ [ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
new file mode 100644
index 0000000..f8e3ca3
--- /dev/null
+++ b/tests/py/ip6/ip6.t.payload.ip6
@@ -0,0 +1,481 @@
+# ip6 dscp cs1
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# ip6 dscp != cs1
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# ip6 dscp 0x38
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000000e ]
+
+# ip6 dscp != 0x20
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000008 ]
+
+# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000006 : 0 [end] element 00000008 : 0 [end] element 0000000a : 0 [end] element 0000000c : 0 [end] element 0000000e : 0 [end] element 00000000 : 0 [end] element 00008002 : 0 [end] element 00000003 : 0 [end] element 00008003 : 0 [end] element 00008004 : 0 [end] element 00000005 : 0 [end] element 00008005 : 0 [end] element 00008006 : 0 [end] element 00000007 : 0 [end] element 00008007 : 0 [end] element 00008008 : 0 [end] element 00000009 : 0 [end] element 00008009 : 0 [end] element 0000800b : 0 [end]
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter
+__map%d test-ip6 b size 2
+__map%d test-ip6 0
+ element 00000001 : accept 0 [end] element 0000c00f : continue 0 [end]
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ip6 flowlabel 22
+ip6 test-ip6 input
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00160000 ]
+
+# ip6 flowlabel != 233
+ip6 test-ip6 input
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00e90000 ]
+
+# ip6 flowlabel { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00210000 : 0 [end] element 00370000 : 0 [end] element 00430000 : 0 [end] element 00580000 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 flowlabel != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00210000 : 0 [end] element 00370000 : 0 [end] element 00430000 : 0 [end] element 00580000 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 flowlabel vmap { 0 : accept, 2 : continue }
+__map%d test-ip6 b size 2
+__map%d test-ip6 0
+ element 00000000 : accept 0 [end] element 00020000 : continue 0 [end]
+ip6 test-ip6 input
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 length 22
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# ip6 length != 233
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# ip6 length 33-45
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# ip6 length != 33-45
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# ip6 length { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 length != {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000011 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-ip6 3
+__set%d test-ip6 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] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
+__set%d test-ip6 3
+__set%d test-ip6 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] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 nexthdr esp
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# ip6 nexthdr != esp
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp neq reg 1 0x00000032 ]
+
+# ip6 nexthdr 33-44
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002c ]
+
+# ip6 nexthdr != 33-44
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002c ]
+
+# ip6 hoplimit 1
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ip6 hoplimit != 233
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# ip6 hoplimit 33-45
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# ip6 hoplimit != 33-45
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# ip6 hoplimit {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip6 hoplimit != {33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 7 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr ::1234:1234:1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34120000 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:0:1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:0:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234::1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00003412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:0:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234:1234::
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x00003412 ]
+
+# ip6 saddr ::1234:1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x34123412 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234::1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234::1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00003412 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234:1234::
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x34123412 0x00000000 ]
+
+# ip6 saddr ::1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x34120000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234:1234::1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234:1234::
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00003412 0x00000000 ]
+
+# ip6 saddr ::1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x34123412 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234:1234::1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234:1234::
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x34123412 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x34120000 0x34123412 ]
+
+# ip6 saddr 1234::1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234:1234::1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234:1234::
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00003412 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x34123412 ]
+
+# ip6 saddr 1234::1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234:1234::
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x34123412 0x00000000 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x34120000 ]
+
+# ip6 saddr 1234::
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003412 0x00000000 0x00000000 0x00000000 ]
+
+# ip6 saddr ::/64
+ip6 test-ip6 input
+ [ payload load 8b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
+
+# ip6 saddr ::1 ip6 daddr ::2
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x02000000 ]
+
+# ip6 daddr != {::1234:1234:1234:1234:1234:1234:1234, 1234:1234::1234:1234:1234:1234:1234 }
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 34120000 34123412 34123412 34123412 : 0 [end] element 34123412 34120000 34123412 34123412 : 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ip6 daddr != ::1234:1234:1234:1234:1234:1234:1234-1234:1234::1234:1234:1234:1234:1234
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ range neq reg 1 0x34120000 0x34123412 0x34123412 0x34123412 0x34123412 0x34120000 0x34123412 0x34123412 ]
+
+# iif "lo" ip6 daddr set ::1
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
+ [ payload write reg 1 => 16b @ network header + 24 csum_type 0 csum_off 0 csum_flags 0x1 ]
+
+# iif "lo" ip6 hoplimit set 1
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 1 0x00000001 ]
+ [ payload write reg 1 => 1b @ network header + 7 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 dscp set af42
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x00000009 ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 dscp set 63
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x0000c00f ]
+ [ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 ecn set ect0
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000020 ]
+ [ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 ecn set ce
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000030 ]
+ [ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 flowlabel set 0
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 flowlabel set 12345
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00393000 ]
+ [ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# iif "lo" ip6 flowlabel set 0xfffff
+ip6 test-ip6 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 3b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00ffff0f ]
+ [ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
diff --git a/tests/py/ip6/map.t b/tests/py/ip6/map.t
new file mode 100644
index 0000000..4d06e87
--- /dev/null
+++ b/tests/py/ip6/map.t
@@ -0,0 +1,5 @@
+:input;type filter hook input priority 0
+*ip6;test-ip6;input
+
+mark set ip6 saddr and ::ffff map { ::2 : 0x0000002a, ::ffff : 0x00000017};ok;meta mark set ip6 saddr & ::ffff map { ::2 : 0x0000002a, ::ffff : 0x00000017}
+
diff --git a/tests/py/ip6/map.t.json b/tests/py/ip6/map.t.json
new file mode 100644
index 0000000..78a01c6
--- /dev/null
+++ b/tests/py/ip6/map.t.json
@@ -0,0 +1,38 @@
+# mark set ip6 saddr and ::ffff map { ::2 : 0x0000002a, ::ffff : 0x00000017}
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "&": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "::ffff"
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ "::2",
+ "0x0000002a"
+ ],
+ [
+ "::ffff",
+ "0x00000017"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/map.t.json.output b/tests/py/ip6/map.t.json.output
new file mode 100644
index 0000000..9280d55
--- /dev/null
+++ b/tests/py/ip6/map.t.json.output
@@ -0,0 +1,38 @@
+# mark set ip6 saddr and ::ffff map { ::2 : 0x0000002a, ::ffff : 0x00000017}
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "&": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "::ffff"
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ "::2",
+ 42
+ ],
+ [
+ "::ffff",
+ 23
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/map.t.payload b/tests/py/ip6/map.t.payload
new file mode 100644
index 0000000..8e900c1
--- /dev/null
+++ b/tests/py/ip6/map.t.payload
@@ -0,0 +1,10 @@
+# mark set ip6 saddr and ::ffff map { ::2 : 0x0000002a, ::ffff : 0x00000017}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00000000 00000000 00000000 02000000 : 0000002a 0 [end] element 00000000 00000000 00000000 ffff0000 : 00000017 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000000 0x00000000 0x00000000 0xffff0000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
diff --git a/tests/py/ip6/masquerade.t b/tests/py/ip6/masquerade.t
new file mode 100644
index 0000000..4eb0467
--- /dev/null
+++ b/tests/py/ip6/masquerade.t
@@ -0,0 +1,30 @@
+:postrouting;type nat hook postrouting priority 0
+
+*ip6;test-ip6;postrouting
+
+# nf_nat flags combination
+udp dport 53 masquerade;ok
+udp dport 53 masquerade random;ok
+udp dport 53 masquerade random,persistent;ok
+udp dport 53 masquerade random,persistent,fully-random;ok;udp dport 53 masquerade random,fully-random,persistent
+udp dport 53 masquerade random,fully-random;ok
+udp dport 53 masquerade random,fully-random,persistent;ok
+udp dport 53 masquerade persistent;ok
+udp dport 53 masquerade persistent,random;ok;udp dport 53 masquerade random,persistent
+udp dport 53 masquerade persistent,random,fully-random;ok;udp dport 53 masquerade random,fully-random,persistent
+udp dport 53 masquerade persistent,fully-random;ok;udp dport 53 masquerade fully-random,persistent
+udp dport 53 masquerade persistent,fully-random,random;ok;udp dport 53 masquerade random,fully-random,persistent
+
+# using ports
+meta l4proto 6 masquerade to :1024;ok
+meta l4proto 6 masquerade to :1024-2048;ok
+
+# masquerade is a terminal statement
+tcp dport 22 masquerade counter packets 0 bytes 0 accept;fail
+tcp sport 22 masquerade accept;fail
+ip6 saddr ::1 masquerade drop;fail
+
+# masquerade with sets
+tcp dport { 1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} masquerade;ok
+ip6 daddr fe00::1-fe00::200 udp dport 53 counter masquerade;ok
+iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade;ok
diff --git a/tests/py/ip6/masquerade.t.json b/tests/py/ip6/masquerade.t.json
new file mode 100644
index 0000000..824b44f
--- /dev/null
+++ b/tests/py/ip6/masquerade.t.json
@@ -0,0 +1,423 @@
+# udp dport 53 masquerade
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": null
+ }
+]
+
+# udp dport 53 masquerade random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": "random"
+ }
+ }
+]
+
+# udp dport 53 masquerade random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade random,persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade random,fully-random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": "persistent"
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "persistent",
+ "fully-random",
+ "random"
+ ]
+ }
+ }
+]
+
+# meta l4proto 6 masquerade to :1024
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "masquerade": {
+ "port": 1024
+ }
+ }
+]
+
+# meta l4proto 6 masquerade to :1024-2048
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "masquerade": {
+ "port": {
+ "range": [ 1024, 2048 ]
+ }
+ }
+ }
+]
+
+# tcp dport { 1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} masquerade
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 101,
+ 202,
+ 303,
+ 1001,
+ 2002,
+ 3003
+ ]
+ }
+ }
+ },
+ {
+ "masquerade": null
+ }
+]
+
+# ip6 daddr fe00::1-fe00::200 udp dport 53 counter masquerade
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "fe00::1", "fe00::200" ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "masquerade": null
+ }
+]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "established",
+ "new"
+ ]
+ }
+ },
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ {
+ "drop": null
+ }
+ ],
+ [
+ 222,
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "masquerade": null
+ }
+]
+
diff --git a/tests/py/ip6/masquerade.t.json.output b/tests/py/ip6/masquerade.t.json.output
new file mode 100644
index 0000000..31d0cd9
--- /dev/null
+++ b/tests/py/ip6/masquerade.t.json.output
@@ -0,0 +1,98 @@
+# udp dport 53 masquerade persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 masquerade persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "masquerade": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
diff --git a/tests/py/ip6/masquerade.t.payload.ip6 b/tests/py/ip6/masquerade.t.payload.ip6
new file mode 100644
index 0000000..43ae2ae
--- /dev/null
+++ b/tests/py/ip6/masquerade.t.payload.ip6
@@ -0,0 +1,142 @@
+# udp dport 53 masquerade
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq ]
+
+# udp dport 53 masquerade random
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x4 ]
+
+# udp dport 53 masquerade random,persistent
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0xc ]
+
+# udp dport 53 masquerade random,persistent,fully-random
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# udp dport 53 masquerade random,fully-random
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x14 ]
+
+# udp dport 53 masquerade random,fully-random,persistent
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# udp dport 53 masquerade persistent
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x8 ]
+
+# udp dport 53 masquerade persistent,random
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0xc ]
+
+# udp dport 53 masquerade persistent,random,fully-random
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# udp dport 53 masquerade persistent,fully-random
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x18 ]
+
+# udp dport 53 masquerade persistent,fully-random,random
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ masq flags 0x1c ]
+
+# tcp dport { 1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} masquerade
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000100 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000400 : 0 [end] element 00000500 : 0 [end] element 00000600 : 0 [end] element 00000700 : 0 [end] element 00000800 : 0 [end] element 00006500 : 0 [end] element 0000ca00 : 0 [end] element 00002f01 : 0 [end] element 0000e903 : 0 [end] element 0000d207 : 0 [end] element 0000bb0b : 0 [end]
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ masq ]
+
+# ip6 daddr fe00::1-fe00::200 udp dport 53 counter masquerade
+ip6 test-ip6 postrouting
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp gte reg 1 0x000000fe 0x00000000 0x00000000 0x01000000 ]
+ [ cmp lte reg 1 0x000000fe 0x00000000 0x00000000 0x00020000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ counter pkts 0 bytes 0 ]
+ [ masq ]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
+ip6 test-ip6 postrouting
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ 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 0 ]
+ [ masq ]
+
+# meta l4proto 6 masquerade to :1024
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00000004 ]
+ [ masq proto_min reg 1 flags 0x2 ]
+
+# meta l4proto 6 masquerade to :1024-2048
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00000004 ]
+ [ immediate reg 2 0x00000008 ]
+ [ masq proto_min reg 1 proto_max reg 2 flags 0x2 ]
+
diff --git a/tests/py/ip6/meta.t b/tests/py/ip6/meta.t
new file mode 100644
index 0000000..c177b08
--- /dev/null
+++ b/tests/py/ip6/meta.t
@@ -0,0 +1,19 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+
+icmpv6 type nd-router-advert;ok
+meta l4proto ipv6-icmp icmpv6 type nd-router-advert;ok;icmpv6 type nd-router-advert
+
+meta l4proto icmp icmp type echo-request;ok;icmp type echo-request
+meta l4proto 1 icmp type echo-request;ok;icmp type echo-request
+icmp type echo-request;ok
+
+meta protocol ip udp dport 67;ok
+meta protocol ip6 udp dport 67;ok;udp dport 67
+
+meta sdif "lo" accept;ok
+meta sdifname != "vrf1" accept;ok
+
+meta mark set ip6 dscp << 2 | 0x10;ok
+meta mark set ip6 dscp << 26 | 0x10;ok
diff --git a/tests/py/ip6/meta.t.json b/tests/py/ip6/meta.t.json
new file mode 100644
index 0000000..1a2394d
--- /dev/null
+++ b/tests/py/ip6/meta.t.json
@@ -0,0 +1,313 @@
+# icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
+# meta l4proto ipv6-icmp icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": "ipv6-icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
+# meta l4proto icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta l4proto 1 icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta sdif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdif"
+ }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta sdifname != "vrf1" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdifname"
+ }
+ },
+ "op": "!=",
+ "right": "vrf1"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta mark set ip6 dscp lshift 2 or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp lshift 26 or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/meta.t.json.output b/tests/py/ip6/meta.t.json.output
new file mode 100644
index 0000000..61adf18
--- /dev/null
+++ b/tests/py/ip6/meta.t.json.output
@@ -0,0 +1,64 @@
+# meta l4proto ipv6-icmp icmpv6 type nd-router-advert
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-router-advert"
+ }
+ }
+]
+
+# meta l4proto icmp icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta l4proto 1 icmp type echo-request
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": "echo-request"
+ }
+ }
+]
+
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
diff --git a/tests/py/ip6/meta.t.payload b/tests/py/ip6/meta.t.payload
new file mode 100644
index 0000000..6a37f1d
--- /dev/null
+++ b/tests/py/ip6/meta.t.payload
@@ -0,0 +1,82 @@
+# icmpv6 type nd-router-advert
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000086 ]
+
+# meta l4proto ipv6-icmp icmpv6 type nd-router-advert
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000086 ]
+
+# meta l4proto icmp icmp type echo-request
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta l4proto 1 icmp type echo-request
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta sdif "lo" accept
+ip6 test-ip6 input
+ [ meta load sdif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta sdifname != "vrf1" accept
+ip6 test-ip6 input
+ [ meta load sdifname => reg 1 ]
+ [ cmp neq reg 1 0x31667276 0x00000000 0x00000000 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# meta protocol ip udp dport 67
+ip6 test-ip6 input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta protocol ip6 udp dport 67
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta mark set ip6 dscp << 2 | 0x10
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp << 26 | 0x10
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/ip6/mh.t b/tests/py/ip6/mh.t
new file mode 100644
index 0000000..46f4ba0
--- /dev/null
+++ b/tests/py/ip6/mh.t
@@ -0,0 +1,42 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+*inet;test-inet;input
+
+mh nexthdr 1;ok
+mh nexthdr != 1;ok
+mh nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp };ok;mh nexthdr { 58, 17, 108, 6, 51, 136, 50, 132, 33}
+mh nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp };ok;mh nexthdr != { 58, 17, 108, 6, 51, 136, 50, 132, 33}
+mh nexthdr icmp;ok;mh nexthdr 1
+mh nexthdr != icmp;ok;mh nexthdr != 1
+mh nexthdr 22;ok
+mh nexthdr != 233;ok
+mh nexthdr 33-45;ok
+mh nexthdr != 33-45;ok
+mh nexthdr { 33, 55, 67, 88 };ok
+mh nexthdr != { 33, 55, 67, 88 };ok
+
+mh hdrlength 22;ok
+mh hdrlength != 233;ok
+mh hdrlength 33-45;ok
+mh hdrlength != 33-45;ok
+mh hdrlength { 33, 55, 67, 88 };ok
+mh hdrlength != { 33, 55, 67, 88 };ok
+
+mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message};ok
+mh type home-agent-switch-message;ok
+mh type != home-agent-switch-message;ok
+
+mh reserved 22;ok
+mh reserved != 233;ok
+mh reserved 33-45;ok
+mh reserved != 33-45;ok
+mh reserved { 33, 55, 67, 88};ok
+mh reserved != { 33, 55, 67, 88};ok
+
+mh checksum 22;ok
+mh checksum != 233;ok
+mh checksum 33-45;ok
+mh checksum != 33-45;ok
+mh checksum { 33, 55, 67, 88};ok
+mh checksum != { 33, 55, 67, 88};ok
diff --git a/tests/py/ip6/mh.t.json b/tests/py/ip6/mh.t.json
new file mode 100644
index 0000000..3159b14
--- /dev/null
+++ b/tests/py/ip6/mh.t.json
@@ -0,0 +1,640 @@
+# mh nexthdr 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# mh nexthdr != 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# mh nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "udplite",
+ "ipcomp",
+ "udp",
+ "ah",
+ "sctp",
+ "esp",
+ "dccp",
+ "tcp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ }
+]
+
+# mh nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "udplite",
+ "ipcomp",
+ "udp",
+ "ah",
+ "sctp",
+ "esp",
+ "dccp",
+ "tcp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ }
+]
+
+# mh nexthdr icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ }
+]
+
+# mh nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": "icmp"
+ }
+ }
+]
+
+# mh nexthdr 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# mh nexthdr != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# mh nexthdr 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh nexthdr != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh nexthdr { 33, 55, 67, 88 }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# mh nexthdr != { 33, 55, 67, 88 }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# mh hdrlength 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# mh hdrlength != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# mh hdrlength 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh hdrlength != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh hdrlength { 33, 55, 67, 88 }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# mh hdrlength != { 33, 55, 67, 88 }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "binding-refresh-request",
+ "home-test-init",
+ "careof-test-init",
+ "home-test",
+ "careof-test",
+ "binding-update",
+ "binding-acknowledgement",
+ "binding-error",
+ "fast-binding-update",
+ "fast-binding-acknowledgement",
+ "fast-binding-advertisement",
+ "experimental-mobility-header",
+ "home-agent-switch-message"
+ ]
+ }
+ }
+ }
+]
+
+# mh type home-agent-switch-message
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": "home-agent-switch-message"
+ }
+ }
+]
+
+# mh type != home-agent-switch-message
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": "home-agent-switch-message"
+ }
+ }
+]
+
+# mh reserved 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# mh reserved != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# mh reserved 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh reserved != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh reserved { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# mh reserved != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "reserved",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# mh checksum 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "checksum",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# mh checksum != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "checksum",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# mh checksum 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "checksum",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh checksum != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "checksum",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# mh checksum { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "checksum",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# mh checksum != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "checksum",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/mh.t.json.output b/tests/py/ip6/mh.t.json.output
new file mode 100644
index 0000000..a851804
--- /dev/null
+++ b/tests/py/ip6/mh.t.json.output
@@ -0,0 +1,88 @@
+# mh nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 58,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# mh nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 58,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# mh nexthdr icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# mh nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "mh"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
diff --git a/tests/py/ip6/mh.t.payload.inet b/tests/py/ip6/mh.t.payload.inet
new file mode 100644
index 0000000..54eaa70
--- /dev/null
+++ b/tests/py/ip6/mh.t.payload.inet
@@ -0,0 +1,267 @@
+# mh nexthdr 1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# mh nexthdr != 1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# mh nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh nexthdr icmp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# mh nexthdr != icmp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# mh nexthdr 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# mh nexthdr != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# mh nexthdr 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# mh nexthdr != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# mh nexthdr { 33, 55, 67, 88 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh nexthdr != { 33, 55, 67, 88 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh hdrlength 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# mh hdrlength != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# mh hdrlength 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# mh hdrlength != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# mh hdrlength { 33, 55, 67, 88 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh hdrlength != { 33, 55, 67, 88 }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000000 : 0 [end] element 00000001 : 0 [end] element 00000002 : 0 [end] element 00000003 : 0 [end] element 00000004 : 0 [end] element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 0 [end] element 00000008 : 0 [end] element 00000009 : 0 [end] element 0000000a : 0 [end] element 0000000b : 0 [end] element 0000000c : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh type home-agent-switch-message
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000000c ]
+
+# mh type != home-agent-switch-message
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000000c ]
+
+# mh reserved 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# mh reserved != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# mh reserved 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# mh reserved != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# mh reserved { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh reserved != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh checksum 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# mh checksum != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# mh checksum 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# mh checksum != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# mh checksum { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh checksum != { 33, 55, 67, 88}
+__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]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
diff --git a/tests/py/ip6/mh.t.payload.ip6 b/tests/py/ip6/mh.t.payload.ip6
new file mode 100644
index 0000000..73bd422
--- /dev/null
+++ b/tests/py/ip6/mh.t.payload.ip6
@@ -0,0 +1,201 @@
+# mh nexthdr 1
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# mh nexthdr != 1
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# mh nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp }
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh nexthdr icmp
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# mh nexthdr != icmp
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# mh nexthdr 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# mh nexthdr != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# mh nexthdr 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# mh nexthdr != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# mh nexthdr { 33, 55, 67, 88 }
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh nexthdr != { 33, 55, 67, 88 }
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh hdrlength 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# mh hdrlength != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# mh hdrlength 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# mh hdrlength != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# mh hdrlength { 33, 55, 67, 88 }
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh hdrlength != { 33, 55, 67, 88 }
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000000 : 0 [end] element 00000001 : 0 [end] element 00000002 : 0 [end] element 00000003 : 0 [end] element 00000004 : 0 [end] element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 0 [end] element 00000008 : 0 [end] element 00000009 : 0 [end] element 0000000a : 0 [end] element 0000000b : 0 [end] element 0000000c : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh type home-agent-switch-message
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000000c ]
+
+# mh type != home-agent-switch-message
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 2 => reg 1 ]
+ [ cmp neq reg 1 0x0000000c ]
+
+# mh reserved 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# mh reserved != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# mh reserved 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# mh reserved != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# mh reserved { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh reserved != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# mh checksum 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# mh checksum != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ cmp neq reg 1 0x0000e900 ]
+
+# mh checksum 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ cmp gte reg 1 0x00002100 ]
+ [ cmp lte reg 1 0x00002d00 ]
+
+# mh checksum != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
+
+# mh checksum { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# mh checksum != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
diff --git a/tests/py/ip6/redirect.t b/tests/py/ip6/redirect.t
new file mode 100644
index 0000000..70ef7f9
--- /dev/null
+++ b/tests/py/ip6/redirect.t
@@ -0,0 +1,49 @@
+:output;type nat hook output priority 0
+
+*ip6;test-ip6;output
+
+# with no arguments
+redirect;ok
+udp dport 954 redirect;ok
+ip6 saddr fe00::cafe counter redirect;ok
+
+# nf_nat flags combination
+udp dport 53 redirect random;ok
+udp dport 53 redirect random,persistent;ok
+udp dport 53 redirect random,persistent,fully-random;ok;udp dport 53 redirect random,fully-random,persistent
+udp dport 53 redirect random,fully-random;ok
+udp dport 53 redirect random,fully-random,persistent;ok
+udp dport 53 redirect persistent;ok
+udp dport 53 redirect persistent,random;ok;udp dport 53 redirect random,persistent
+udp dport 53 redirect persistent,random,fully-random;ok;udp dport 53 redirect random,fully-random,persistent
+udp dport 53 redirect persistent,fully-random;ok;udp dport 53 redirect fully-random,persistent
+udp dport 53 redirect persistent,fully-random,random;ok;udp dport 53 redirect random,fully-random,persistent
+
+# port specification
+udp dport 1234 redirect to :1234;ok
+ip6 daddr fe00::cafe udp dport 9998 redirect to :6515;ok
+ip6 nexthdr tcp redirect to :100-200;ok;ip6 nexthdr 6 redirect to :100-200
+tcp dport 39128 redirect to :993;ok
+redirect to :1234;fail
+redirect to :12341111;fail
+
+# both port and nf_nat flags
+tcp dport 9128 redirect to :993 random;ok
+tcp dport 9128 redirect to :993 fully-random,persistent;ok
+
+# nf_nat flags are the last argument
+tcp dport 9128 redirect persistent to 123;fail
+tcp dport 9128 redirect random,persistent to 123;fail
+
+# redirect is a terminal statement
+tcp dport 22 redirect counter packets 0 bytes 0 accept;fail
+tcp sport 22 redirect accept;fail
+ip6 saddr ::1 redirect drop;fail
+
+# redirect with sets
+tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect;ok
+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
+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
new file mode 100644
index 0000000..c18223f
--- /dev/null
+++ b/tests/py/ip6/redirect.t.json
@@ -0,0 +1,589 @@
+# redirect
+[
+ {
+ "redirect": null
+ }
+]
+
+# udp dport 954 redirect
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 954
+ }
+ },
+ {
+ "redirect": null
+ }
+]
+
+# ip6 saddr fe00::cafe counter redirect
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "fe00::cafe"
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "redirect": null
+ }
+]
+
+# udp dport 53 redirect random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": "random"
+ }
+ }
+]
+
+# udp dport 53 redirect random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect random,persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "persistent",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect random,fully-random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": "persistent"
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "random",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "fully-random"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "persistent",
+ "fully-random",
+ "random"
+ ]
+ }
+ }
+]
+
+# udp dport 1234 redirect to :1234
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 1234
+ }
+ },
+ {
+ "redirect": {
+ "port": 1234
+ }
+ }
+]
+
+# ip6 daddr fe00::cafe udp dport 9998 redirect to :6515
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "fe00::cafe"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 9998
+ }
+ },
+ {
+ "redirect": {
+ "port": 6515
+ }
+ }
+]
+
+# ip6 nexthdr tcp redirect to :100-200
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "redirect": {
+ "port": {
+ "range": [ 100, 200 ]
+ }
+ }
+ }
+]
+
+# tcp dport 39128 redirect to :993
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 39128
+ }
+ },
+ {
+ "redirect": {
+ "port": 993
+ }
+ }
+]
+
+# tcp dport 9128 redirect to :993 random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 9128
+ }
+ },
+ {
+ "redirect": {
+ "flags": "random",
+ "port": 993
+ }
+ }
+]
+
+# tcp dport 9128 redirect to :993 fully-random,persistent
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 9128
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "fully-random",
+ "persistent"
+ ],
+ "port": 993
+ }
+ }
+]
+
+# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 101,
+ 202,
+ 303,
+ 1001,
+ 2002,
+ 3003
+ ]
+ }
+ }
+ },
+ {
+ "redirect": null
+ }
+]
+
+# ip6 daddr fe00::1-fe00::200 udp dport 53 counter redirect
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "fe00::1", "fe00::200" ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "redirect": null
+ }
+]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "established",
+ "new"
+ ]
+ }
+ },
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ {
+ "drop": null
+ }
+ ],
+ [
+ 222,
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ },
+ {
+ "redirect": null
+ }
+]
+
+# redirect to :tcp dport map { 22 : 8000, 80 : 8080}
+[
+ {
+ "redirect": {
+ "port": {
+ "map": {
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ 8000
+ ],
+ [
+ 80,
+ 8080
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/redirect.t.json.output b/tests/py/ip6/redirect.t.json.output
new file mode 100644
index 0000000..0174cc7
--- /dev/null
+++ b/tests/py/ip6/redirect.t.json.output
@@ -0,0 +1,146 @@
+# udp dport 53 redirect random,persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,random,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# udp dport 53 redirect persistent,fully-random,random
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 53
+ }
+ },
+ {
+ "redirect": {
+ "flags": [
+ "random",
+ "fully-random",
+ "persistent"
+ ]
+ }
+ }
+]
+
+# ip6 nexthdr tcp redirect to :100-200
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "nexthdr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "redirect": {
+ "port": {
+ "range": [ 100, 200 ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/redirect.t.payload.ip6 b/tests/py/ip6/redirect.t.payload.ip6
new file mode 100644
index 0000000..cfc2901
--- /dev/null
+++ b/tests/py/ip6/redirect.t.payload.ip6
@@ -0,0 +1,204 @@
+# redirect
+ip6 test-ip6 output
+ [ redir ]
+
+# udp dport 954 redirect
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000ba03 ]
+ [ redir ]
+
+# ip6 saddr fe00::cafe counter redirect
+ip6 test-ip6 output
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe 0x00000000 0x00000000 0xfeca0000 ]
+ [ counter pkts 0 bytes 0 ]
+ [ redir ]
+
+# udp dport 53 redirect random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x4 ]
+
+# udp dport 53 redirect random,persistent
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0xc ]
+
+# udp dport 53 redirect random,persistent,fully-random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# udp dport 53 redirect random,fully-random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x14 ]
+
+# udp dport 53 redirect random,fully-random,persistent
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# udp dport 53 redirect persistent
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x8 ]
+
+# udp dport 53 redirect persistent,random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0xc ]
+
+# udp dport 53 redirect persistent,random,fully-random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# udp dport 53 redirect persistent,fully-random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x18 ]
+
+# udp dport 53 redirect persistent,fully-random,random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ redir flags 0x1c ]
+
+# udp dport 1234 redirect to :1234
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000d204 ]
+ [ immediate reg 1 0x0000d204 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# ip6 daddr fe00::cafe udp dport 9998 redirect to :6515
+ip6 test-ip6 output
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe 0x00000000 0x00000000 0xfeca0000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000e27 ]
+ [ immediate reg 1 0x00007319 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# ip6 nexthdr tcp redirect to :100-200
+ip6 test-ip6 output
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00006400 ]
+ [ immediate reg 2 0x0000c800 ]
+ [ redir proto_min reg 1 proto_max reg 2 flags 0x2 ]
+
+# tcp dport 39128 redirect to :993
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000d898 ]
+ [ immediate reg 1 0x0000e103 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
+# tcp dport 9128 redirect to :993 random
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000a823 ]
+ [ immediate reg 1 0x0000e103 ]
+ [ redir proto_min reg 1 flags 0x6 ]
+
+# tcp dport 9128 redirect to :993 fully-random,persistent
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000a823 ]
+ [ immediate reg 1 0x0000e103 ]
+ [ redir proto_min reg 1 flags 0x1a ]
+
+# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000100 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000400 : 0 [end] element 00000500 : 0 [end] element 00000600 : 0 [end] element 00000700 : 0 [end] element 00000800 : 0 [end] element 00006500 : 0 [end] element 0000ca00 : 0 [end] element 00002f01 : 0 [end] element 0000e903 : 0 [end] element 0000d207 : 0 [end] element 0000bb0b : 0 [end]
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ redir ]
+
+# ip6 daddr fe00::1-fe00::200 udp dport 53 counter redirect
+ip6 test-ip6 output
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp gte reg 1 0x000000fe 0x00000000 0x00000000 0x01000000 ]
+ [ cmp lte reg 1 0x000000fe 0x00000000 0x00000000 0x00020000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00003500 ]
+ [ counter pkts 0 bytes 0 ]
+ [ redir ]
+
+# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
+ip6 test-ip6 output
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ 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 0 ]
+ [ redir ]
+
+# 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
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
+
diff --git a/tests/py/ip6/reject.t b/tests/py/ip6/reject.t
new file mode 100644
index 0000000..bfdd094
--- /dev/null
+++ b/tests/py/ip6/reject.t
@@ -0,0 +1,16 @@
+:output;type filter hook output priority 0
+
+*ip6;test-ip6;output
+
+reject;ok
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok;reject
+reject with icmpv6 policy-fail;ok
+reject with icmpv6 reject-route;ok
+reject with icmpv6 3;ok;reject with icmpv6 addr-unreachable
+mark 0x80000000 reject with tcp reset;ok;meta mark 0x80000000 reject with tcp reset
+
+reject with icmpv6 host-unreachable;fail
+reject with icmp host-unreachable;fail
diff --git a/tests/py/ip6/reject.t.json b/tests/py/ip6/reject.t.json
new file mode 100644
index 0000000..312a7da
--- /dev/null
+++ b/tests/py/ip6/reject.t.json
@@ -0,0 +1,95 @@
+# reject
+[
+ {
+ "reject": null
+ }
+]
+
+# reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 addr-unreachable
+[
+ {
+ "reject": {
+ "expr": "addr-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 policy-fail
+[
+ {
+ "reject": {
+ "expr": "policy-fail",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 reject-route
+[
+ {
+ "reject": {
+ "expr": "reject-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 3
+[
+ {
+ "reject": {
+ "expr": "addr-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# mark 0x80000000 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x80000000"
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/reject.t.json.output b/tests/py/ip6/reject.t.json.output
new file mode 100644
index 0000000..04f12f5
--- /dev/null
+++ b/tests/py/ip6/reject.t.json.output
@@ -0,0 +1,28 @@
+# reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# mark 0x80000000 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 2147483648
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/reject.t.payload.ip6 b/tests/py/ip6/reject.t.payload.ip6
new file mode 100644
index 0000000..3d4321b
--- /dev/null
+++ b/tests/py/ip6/reject.t.payload.ip6
@@ -0,0 +1,40 @@
+# reject
+ip6 test-ip6 output
+ [ reject type 0 code 4 ]
+
+# reject with icmpv6 no-route
+ip6 test-ip6 output
+ [ reject type 0 code 0 ]
+
+# reject with icmpv6 admin-prohibited
+ip6 test-ip6 output
+ [ reject type 0 code 1 ]
+
+# reject with icmpv6 addr-unreachable
+ip6 test-ip6 output
+ [ reject type 0 code 3 ]
+
+# reject with icmpv6 port-unreachable
+ip6 test-ip6 output
+ [ reject type 0 code 4 ]
+
+# reject with icmpv6 policy-fail
+ip6 test-ip6 output
+ [ reject type 0 code 5 ]
+
+# reject with icmpv6 reject-route
+ip6 test-ip6 output
+ [ reject type 0 code 6 ]
+
+# reject with icmpv6 3
+ip6 test-ip6 output
+ [ reject type 0 code 3 ]
+
+# mark 0x80000000 reject with tcp reset
+ip6 test-ip6 output
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x80000000 ]
+ [ reject type 1 code 0 ]
+
diff --git a/tests/py/ip6/rt.t b/tests/py/ip6/rt.t
new file mode 100644
index 0000000..c33d38a
--- /dev/null
+++ b/tests/py/ip6/rt.t
@@ -0,0 +1,38 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+*inet;test-inet;input
+
+rt nexthdr 1;ok
+rt nexthdr != 1;ok
+rt nexthdr {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp};ok;rt nexthdr { 33, 136, 50, 132, 51, 17, 108, 6, 58}
+rt nexthdr != {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp};ok;rt nexthdr != { 33, 136, 50, 132, 51, 17, 108, 6, 58}
+rt nexthdr icmp;ok;rt nexthdr 1
+rt nexthdr != icmp;ok;rt nexthdr != 1
+rt nexthdr 22;ok
+rt nexthdr != 233;ok
+rt nexthdr 33-45;ok
+rt nexthdr != 33-45;ok
+rt nexthdr { 33, 55, 67, 88};ok
+rt nexthdr != { 33, 55, 67, 88};ok
+
+rt hdrlength 22;ok
+rt hdrlength != 233;ok
+rt hdrlength 33-45;ok
+rt hdrlength != 33-45;ok
+rt hdrlength { 33, 55, 67, 88};ok
+rt hdrlength != { 33, 55, 67, 88};ok
+
+rt type 22;ok
+rt type != 233;ok
+rt type 33-45;ok
+rt type != 33-45;ok
+rt type { 33, 55, 67, 88};ok
+rt type != { 33, 55, 67, 88};ok
+
+rt seg-left 22;ok
+rt seg-left != 233;ok
+rt seg-left 33-45;ok
+rt seg-left != 33-45;ok
+rt seg-left { 33, 55, 67, 88};ok
+rt seg-left != { 33, 55, 67, 88};ok
diff --git a/tests/py/ip6/rt.t.json b/tests/py/ip6/rt.t.json
new file mode 100644
index 0000000..b12873d
--- /dev/null
+++ b/tests/py/ip6/rt.t.json
@@ -0,0 +1,576 @@
+# rt nexthdr 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# rt nexthdr != 1
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# rt nexthdr {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "udplite",
+ "ipcomp",
+ "udp",
+ "ah",
+ "sctp",
+ "esp",
+ "dccp",
+ "tcp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ }
+]
+
+# rt nexthdr != {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "udplite",
+ "ipcomp",
+ "udp",
+ "ah",
+ "sctp",
+ "esp",
+ "dccp",
+ "tcp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ }
+]
+
+# rt nexthdr icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": "icmp"
+ }
+ }
+]
+
+# rt nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": "icmp"
+ }
+ }
+]
+
+# rt nexthdr 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# rt nexthdr != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# rt nexthdr 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt nexthdr != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt nexthdr { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# rt nexthdr != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# rt hdrlength 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# rt hdrlength != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# rt hdrlength 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt hdrlength != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt hdrlength { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# rt hdrlength != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "hdrlength",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# rt type 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# rt type != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# rt type 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt type != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt type { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# rt type != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "type",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# rt seg-left 22
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "seg-left",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# rt seg-left != 233
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "seg-left",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# rt seg-left 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "seg-left",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt seg-left != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "seg-left",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# rt seg-left { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "seg-left",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# rt seg-left != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "seg-left",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/rt.t.json.output b/tests/py/ip6/rt.t.json.output
new file mode 100644
index 0000000..be5db0e
--- /dev/null
+++ b/tests/py/ip6/rt.t.json.output
@@ -0,0 +1,88 @@
+# rt nexthdr {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 58,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# rt nexthdr != {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 33,
+ 50,
+ 51,
+ 58,
+ 108,
+ 132,
+ 136
+ ]
+ }
+ }
+ }
+]
+
+# rt nexthdr icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# rt nexthdr != icmp
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "nexthdr",
+ "name": "rt"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
diff --git a/tests/py/ip6/rt.t.payload.inet b/tests/py/ip6/rt.t.payload.inet
new file mode 100644
index 0000000..864d311
--- /dev/null
+++ b/tests/py/ip6/rt.t.payload.inet
@@ -0,0 +1,244 @@
+# rt nexthdr 1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# rt nexthdr != 1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# rt nexthdr {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt nexthdr != {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt nexthdr icmp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# rt nexthdr != icmp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# rt nexthdr 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt nexthdr != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt nexthdr 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt nexthdr != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt nexthdr { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt nexthdr != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt hdrlength 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt hdrlength != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt hdrlength 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt hdrlength != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt hdrlength { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt hdrlength != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt type 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt type != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt type 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt type != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt type { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt type != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt seg-left 22
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt seg-left != 233
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt seg-left 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt seg-left != 33-45
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt seg-left { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt seg-left != { 33, 55, 67, 88}
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/ip6/rt.t.payload.ip6 b/tests/py/ip6/rt.t.payload.ip6
new file mode 100644
index 0000000..c7b52f8
--- /dev/null
+++ b/tests/py/ip6/rt.t.payload.ip6
@@ -0,0 +1,184 @@
+# rt nexthdr 1
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# rt nexthdr != 1
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# rt nexthdr {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt nexthdr != {udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000088 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000033 : 0 [end] element 00000084 : 0 [end] element 00000032 : 0 [end] element 00000021 : 0 [end] element 00000006 : 0 [end] element 0000003a : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt nexthdr icmp
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# rt nexthdr != icmp
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# rt nexthdr 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt nexthdr != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt nexthdr 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt nexthdr != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt nexthdr { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt nexthdr != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt hdrlength 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt hdrlength != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt hdrlength 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt hdrlength != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt hdrlength { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt hdrlength != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt type 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt type != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt type 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt type != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt type { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt type != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# rt seg-left 22
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# rt seg-left != 233
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# rt seg-left 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# rt seg-left != 33-45
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# rt seg-left { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# rt seg-left != { 33, 55, 67, 88}
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/ip6/rt0.t b/tests/py/ip6/rt0.t
new file mode 100644
index 0000000..1d50a89
--- /dev/null
+++ b/tests/py/ip6/rt0.t
@@ -0,0 +1,6 @@
+:output;type filter hook input priority 0
+
+*ip6;test-ip6;output
+
+rt nexthop 192.168.0.1;fail
+rt nexthop fd00::1;ok;rt ip6 nexthop fd00::1
diff --git a/tests/py/ip6/rt0.t.json b/tests/py/ip6/rt0.t.json
new file mode 100644
index 0000000..75ff923
--- /dev/null
+++ b/tests/py/ip6/rt0.t.json
@@ -0,0 +1,16 @@
+# rt nexthop fd00::1
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "family": "ip6",
+ "key": "nexthop"
+ }
+ },
+ "op": "==",
+ "right": "fd00::1"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/rt0.t.payload b/tests/py/ip6/rt0.t.payload
new file mode 100644
index 0000000..464b7f2
--- /dev/null
+++ b/tests/py/ip6/rt0.t.payload
@@ -0,0 +1,5 @@
+# rt nexthop fd00::1
+ip6 test-ip6 output
+ [ rt load nexthop6 => reg 1 ]
+ [ cmp eq reg 1 0x000000fd 0x00000000 0x00000000 0x01000000 ]
+
diff --git a/tests/py/ip6/sets.t b/tests/py/ip6/sets.t
new file mode 100644
index 0000000..17fd62f
--- /dev/null
+++ b/tests/py/ip6/sets.t
@@ -0,0 +1,48 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip6;test-ip6;input
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+!w type ipv6_addr;ok
+!x type inet_proto;ok
+!y type inet_service;ok
+!z type time;ok
+
+?set2 192.168.3.4;fail
+!set2 type ipv6_addr;ok
+?set2 1234:1234::1234:1234:1234:1234:1234;ok
+?set2 1234:1234::1234:1234:1234:1234:1234;ok
+?set2 1234::1234:1234:1234;ok
+?set2 1234:1234:1234:1234:1234::1234:1234, 1234:1234::123;ok
+?set2 192.168.3.8, 192.168.3.9;fail
+?set2 1234:1234::1234:1234:1234:1234;ok
+?set2 1234:1234::1234:1234:1234:1234;ok
+?set2 1234:1234:1234::1234;ok
+
+ip6 saddr @set2 drop;ok
+ip6 saddr != @set2 drop;ok
+ip6 saddr @set33 drop;fail
+ip6 saddr != @set33 drop;fail
+
+!set3 type ipv6_addr flags interval;ok
+?set3 1234:1234:1234:1234::/64;ok
+?set3 1324:1234:1234:1235::/64;ok
+?set3 1324:1234:1234:1233::/64;ok
+?set3 1234:1234:1234:1234:1234:1234:/96;fail
+?set3 1324:1234:1234:1236::/64;ok
+
+!set4 type ipv6_addr flags interval;ok
+?set4 1234:1234:1234:1234::/64,4321:1234:1234:1234::/64;ok
+?set4 4321:1234:1234:1234:1234:1234::/96;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
new file mode 100644
index 0000000..2029d2b
--- /dev/null
+++ b/tests/py/ip6/sets.t.json
@@ -0,0 +1,150 @@
+# ip6 saddr @set2 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "@set2"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip6 saddr != @set2 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "op": "!=",
+ "right": "@set2"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip6 saddr . ip6 daddr @set5 drop
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": "@set5"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# add @set5 { ip6 saddr . ip6 daddr }
+[
+ {
+ "set": {
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
+ },
+ "op": "add",
+ "set": "@set5"
+ }
+ }
+]
+
+# delete @set5 { ip6 saddr . ip6 daddr }
+[
+ {
+ "set": {
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
+ },
+ "op": "delete",
+ "set": "@set5"
+ }
+ }
+]
+
+# 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.json.got b/tests/py/ip6/sets.t.json.got
new file mode 100644
index 0000000..114b17c
--- /dev/null
+++ b/tests/py/ip6/sets.t.json.got
@@ -0,0 +1,31 @@
+# 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.json.payload.got b/tests/py/ip6/sets.t.json.payload.got
new file mode 100644
index 0000000..18ac33b
--- /dev/null
+++ b/tests/py/ip6/sets.t.json.payload.got
@@ -0,0 +1,107 @@
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 ]
+
+# 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 ]
+
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+netdev test-netdev egress
+ [ 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 ]
+
+# 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 b/tests/py/ip6/sets.t.payload
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/py/ip6/sets.t.payload
diff --git a/tests/py/ip6/sets.t.payload.inet b/tests/py/ip6/sets.t.payload.inet
new file mode 100644
index 0000000..2bbd557
--- /dev/null
+++ b/tests/py/ip6/sets.t.payload.inet
@@ -0,0 +1,49 @@
+# ip6 saddr @set2 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set set2 ]
+ [ immediate reg 0 drop ]
+
+# ip6 saddr != @set2 drop
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip6 saddr . ip6 daddr @set5 drop
+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 ]
+ [ lookup reg 1 set set5 ]
+ [ immediate reg 0 drop ]
+
+# add @set5 { ip6 saddr . ip6 daddr }
+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 ]
+ [ 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 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ payload load 16b @ network header + 24 => reg 2 ]
+ [ dynset delete reg_key 1 set set5 ]
diff --git a/tests/py/ip6/sets.t.payload.inet.got b/tests/py/ip6/sets.t.payload.inet.got
new file mode 100644
index 0000000..4cfa6a4
--- /dev/null
+++ b/tests/py/ip6/sets.t.payload.inet.got
@@ -0,0 +1,9 @@
+# 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 ]
+
diff --git a/tests/py/ip6/sets.t.payload.ip6 b/tests/py/ip6/sets.t.payload.ip6
new file mode 100644
index 0000000..c59f7b5
--- /dev/null
+++ b/tests/py/ip6/sets.t.payload.ip6
@@ -0,0 +1,38 @@
+# ip6 saddr @set2 drop
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set set2 ]
+ [ immediate reg 0 drop ]
+
+# ip6 saddr != @set2 drop
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip6 saddr . ip6 daddr @set5 drop
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ payload load 16b @ network header + 24 => reg 2 ]
+ [ lookup reg 1 set set5 ]
+ [ immediate reg 0 drop ]
+
+# add @set5 { ip6 saddr . ip6 daddr }
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ payload load 16b @ network header + 24 => reg 2 ]
+ [ dynset add reg_key 1 set set5 ]
+
+# delete @set5 { ip6 saddr . ip6 daddr }
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ 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.ip6.got b/tests/py/ip6/sets.t.payload.ip6.got
new file mode 100644
index 0000000..8c0ee0d
--- /dev/null
+++ b/tests/py/ip6/sets.t.payload.ip6.got
@@ -0,0 +1,7 @@
+# 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
new file mode 100644
index 0000000..1866d26
--- /dev/null
+++ b/tests/py/ip6/sets.t.payload.netdev
@@ -0,0 +1,50 @@
+# ip6 saddr @set2 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set set2 ]
+ [ immediate reg 0 drop ]
+
+# ip6 saddr != @set2 drop
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set set2 0x1 ]
+ [ immediate reg 0 drop ]
+
+# ip6 saddr . ip6 daddr @set5 drop
+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 ]
+ [ lookup reg 1 set set5 ]
+ [ immediate reg 0 drop ]
+
+# add @set5 { ip6 saddr . ip6 daddr }
+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 ]
+ [ dynset add reg_key 1 set set5 ]
+
+# delete @set5 { ip6 saddr . ip6 daddr }
+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 ]
+ [ 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/sets.t.payload.netdev.got b/tests/py/ip6/sets.t.payload.netdev.got
new file mode 100644
index 0000000..792d841
--- /dev/null
+++ b/tests/py/ip6/sets.t.payload.netdev.got
@@ -0,0 +1,9 @@
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ payload load 16b @ network header + 24 => reg 2 ]
+ [ meta load mark => reg 3 ]
+ [ dynset add reg_key 1 set map1 sreg_data 3 ]
+
diff --git a/tests/py/ip6/snat.t b/tests/py/ip6/snat.t
new file mode 100644
index 0000000..564f089
--- /dev/null
+++ b/tests/py/ip6/snat.t
@@ -0,0 +1,6 @@
+:postrouting;type nat hook postrouting priority 0
+
+*ip6;test-ip6;postrouting
+
+tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100;ok
+tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:100;ok
diff --git a/tests/py/ip6/snat.t.json b/tests/py/ip6/snat.t.json
new file mode 100644
index 0000000..58b0980
--- /dev/null
+++ b/tests/py/ip6/snat.t.json
@@ -0,0 +1,54 @@
+# tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "range": [ "2001:838:35f:1::", "2001:838:35f:2::" ]
+ },
+ "port": {
+ "range": [ 80, 100 ]
+ }
+ }
+ }
+]
+
+# tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 80, 90 ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "range": [ "2001:838:35f:1::", "2001:838:35f:2::" ]
+ },
+ "port": 100
+ }
+ }
+]
+
diff --git a/tests/py/ip6/snat.t.payload.ip6 b/tests/py/ip6/snat.t.payload.ip6
new file mode 100644
index 0000000..66a2967
--- /dev/null
+++ b/tests/py/ip6/snat.t.payload.ip6
@@ -0,0 +1,25 @@
+# tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
+ [ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
+ [ immediate reg 3 0x00005000 ]
+ [ immediate reg 4 0x00006400 ]
+ [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
+
+# tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
+ip6 test-ip6 postrouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
+ [ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
+ [ immediate reg 3 0x00006400 ]
+ [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 flags 0x2 ]
+
diff --git a/tests/py/ip6/srh.t b/tests/py/ip6/srh.t
new file mode 100644
index 0000000..fbaff41
--- /dev/null
+++ b/tests/py/ip6/srh.t
@@ -0,0 +1,22 @@
+:input;type filter hook input priority 0
+
+*ip6;test-ip6;input
+
+srh last-entry 0;ok
+srh last-entry 127;ok
+srh last-entry { 0, 4-127, 255 };ok
+
+srh flags 0;ok
+srh flags 127;ok
+srh flags { 0, 4-127, 255 };ok
+
+srh tag 0;ok
+srh tag 127;ok
+srh tag { 0, 4-127, 0xffff };ok;srh tag { 0, 4-127, 65535 }
+
+srh sid[1] dead::beef;ok
+srh sid[2] dead::beef;ok
+
+srh last-entry { 0, 4-127, 256 };fail
+srh flags { 0, 4-127, 256 };fail
+srh tag { 0, 4-127, 0x10000 };fail
diff --git a/tests/py/ip6/srh.t.json b/tests/py/ip6/srh.t.json
new file mode 100644
index 0000000..2d16f1c
--- /dev/null
+++ b/tests/py/ip6/srh.t.json
@@ -0,0 +1,194 @@
+# srh last-entry 0
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "last-entry",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# srh last-entry 127
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "last-entry",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": 127
+ }
+ }
+]
+
+# srh last-entry { 0, 4-127, 255 }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "last-entry",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 0,
+ { "range": [ 4, 127 ] },
+ 255
+ ]
+ }
+ }
+ }
+]
+
+# srh flags 0
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "flags",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# srh flags 127
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "flags",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": 127
+ }
+ }
+]
+
+# srh flags { 0, 4-127, 255 }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "flags",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 0,
+ { "range": [ 4, 127 ] },
+ 255
+ ]
+ }
+ }
+ }
+]
+
+# srh tag 0
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "tag",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# srh tag 127
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "tag",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": 127
+ }
+ }
+]
+
+# srh tag { 0, 4-127, 0xffff }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "tag",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 0,
+ { "range": [ 4, 127 ] },
+ "0xffff"
+ ]
+ }
+ }
+ }
+]
+
+# srh sid[1] dead::beef
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "sid[1]",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": "dead::beef"
+ }
+ }
+]
+
+# srh sid[2] dead::beef
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "sid[2]",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": "dead::beef"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/srh.t.json.output b/tests/py/ip6/srh.t.json.output
new file mode 100644
index 0000000..f801b81
--- /dev/null
+++ b/tests/py/ip6/srh.t.json.output
@@ -0,0 +1,22 @@
+# srh tag { 0, 4-127, 0xffff }
+[
+ {
+ "match": {
+ "left": {
+ "exthdr": {
+ "field": "tag",
+ "name": "srh"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 0,
+ { "range": [ 4, 127 ] },
+ 65535
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/srh.t.payload b/tests/py/ip6/srh.t.payload
new file mode 100644
index 0000000..364940a
--- /dev/null
+++ b/tests/py/ip6/srh.t.payload
@@ -0,0 +1,64 @@
+# srh last-entry 0
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# srh last-entry 127
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x0000007f ]
+
+# 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 = { \x01\x04\x01\x00\x00\x00 }
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# srh flags 0
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# srh flags 127
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 5 => reg 1 ]
+ [ cmp eq reg 1 0x0000007f ]
+
+# 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 = { \x01\x04\x01\x00\x00\x00 }
+ip6 test-ip6 input
+ [ exthdr load ipv6 1b @ 43 + 5 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# srh tag 0
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 43 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# srh tag 127
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 43 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x00007f00 ]
+
+# 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 = { \x01\x04\x01\x00\x00\x00 }
+ip6 test-ip6 input
+ [ exthdr load ipv6 2b @ 43 + 6 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# srh sid[1] dead::beef
+ip6 test-ip6 input
+ [ exthdr load ipv6 16b @ 43 + 8 => reg 1 ]
+ [ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
+
+# srh sid[2] dead::beef
+ip6 test-ip6 input
+ [ exthdr load ipv6 16b @ 43 + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
+
diff --git a/tests/py/ip6/tproxy.t b/tests/py/ip6/tproxy.t
new file mode 100644
index 0000000..d4c6bff
--- /dev/null
+++ b/tests/py/ip6/tproxy.t
@@ -0,0 +1,14 @@
+:y;type filter hook prerouting priority -150
+
+*ip6;x;y
+
+tproxy;fail
+tproxy to [2001:db8::1];fail
+tproxy to [2001:db8::1]:50080;fail
+tproxy to :50080;fail
+meta l4proto 6 tproxy to [2001:db8::1];ok
+meta l4proto 17 tproxy to [2001:db8::1]:50080;ok
+meta l4proto 6 tproxy to :50080;ok
+meta l4proto 6 tproxy ip6 to [2001:db8::1];ok;meta l4proto 6 tproxy to [2001:db8::1]
+meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080;ok;meta l4proto 17 tproxy to [2001:db8::1]:50080
+meta l4proto 6 tproxy ip6 to :50080;ok;meta l4proto 6 tproxy to :50080
diff --git a/tests/py/ip6/tproxy.t.json b/tests/py/ip6/tproxy.t.json
new file mode 100644
index 0000000..0e02d49
--- /dev/null
+++ b/tests/py/ip6/tproxy.t.json
@@ -0,0 +1,125 @@
+# meta l4proto 6 tproxy to [2001:db8::1]
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1"
+ }
+ }
+]
+
+# meta l4proto 17 tproxy to [2001:db8::1]:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1",
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 6 tproxy to :50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 6 tproxy ip6 to [2001:db8::1]
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1",
+ "family": "ip6"
+ }
+ }
+]
+
+# meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1",
+ "family": "ip6",
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 6 tproxy ip6 to :50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "family": "ip6",
+ "port": 50080
+ }
+ }
+]
+
diff --git a/tests/py/ip6/tproxy.t.json.output b/tests/py/ip6/tproxy.t.json.output
new file mode 100644
index 0000000..461738b
--- /dev/null
+++ b/tests/py/ip6/tproxy.t.json.output
@@ -0,0 +1,60 @@
+# meta l4proto 6 tproxy ip6 to [2001:db8::1]
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1"
+ }
+ }
+]
+
+# meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "2001:db8::1",
+ "port": 50080
+ }
+ }
+]
+
+# meta l4proto 6 tproxy ip6 to :50080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "port": 50080
+ }
+ }
+]
diff --git a/tests/py/ip6/tproxy.t.payload b/tests/py/ip6/tproxy.t.payload
new file mode 100644
index 0000000..9f28e80
--- /dev/null
+++ b/tests/py/ip6/tproxy.t.payload
@@ -0,0 +1,44 @@
+# meta l4proto 6 tproxy to [2001:db8::1]
+ip6 x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0xb80d0120 0x00000000 0x00000000 0x01000000 ]
+ [ tproxy ip6 addr reg 1 ]
+
+# meta l4proto 17 tproxy to [2001:db8::1]:50080
+ip6 x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0xb80d0120 0x00000000 0x00000000 0x01000000 ]
+ [ immediate reg 2 0x0000a0c3 ]
+ [ tproxy ip6 addr reg 1 port reg 2 ]
+
+# meta l4proto 6 tproxy to :50080
+ip6 x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x0000a0c3 ]
+ [ tproxy ip6 port reg 1 ]
+
+# meta l4proto 6 tproxy ip6 to [2001:db8::1]
+ip6 x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0xb80d0120 0x00000000 0x00000000 0x01000000 ]
+ [ tproxy ip6 addr reg 1 ]
+
+# meta l4proto 17 tproxy ip6 to [2001:db8::1]:50080
+ip6 x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ immediate reg 1 0xb80d0120 0x00000000 0x00000000 0x01000000 ]
+ [ immediate reg 2 0x0000a0c3 ]
+ [ tproxy ip6 addr reg 1 port reg 2 ]
+
+# meta l4proto 6 tproxy ip6 to :50080
+ip6 x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x0000a0c3 ]
+ [ tproxy ip6 port reg 1 ]
+
diff --git a/tests/py/ip6/vmap.t b/tests/py/ip6/vmap.t
new file mode 100644
index 0000000..2d54b82
--- /dev/null
+++ b/tests/py/ip6/vmap.t
@@ -0,0 +1,58 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip6;test-ip6;input
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+ip6 saddr vmap { abcd::3 : accept };ok
+ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234:1234;fail
+
+# Ipv6 address combinations
+# from src/scanner.l
+ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept};ok
+ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept};ok;ip6 saddr vmap { 0:1234:1234:1234:1234:1234:1234:1234 : accept}
+ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept};ok;ip6 saddr vmap { 1234:0:1234:1234:1234:1234:1234:1234 : accept}
+ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept};ok;ip6 saddr vmap { 1234:1234:0:1234:1234:1234:1234:1234 : accept}
+ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept};ok;ip6 saddr vmap { 1234:1234:1234:0:1234:1234:1234:1234 : accept}
+ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept};ok;ip6 saddr vmap { 1234:1234:1234:1234:0:1234:1234:1234 : accept}
+ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept};ok;ip6 saddr vmap { 1234:1234:1234:1234:1234:0:1234:1234 : accept}
+ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept};ok;ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:0:1234 : accept}
+ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept};ok;ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:0 : accept}
+ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept};ok
+ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept};ok
+ip6 saddr vmap { ::1234:1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234::1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234::1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234::1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234:1234:: : accept};ok
+ip6 saddr vmap { ::1234:1234:1234 : accept};ok
+ip6 saddr vmap { 1234::1234:1234 : accept};ok
+ip6 saddr vmap { 1234:1234::1234 : accept};ok
+ip6 saddr vmap { 1234:1234:1234:: : accept};ok
+ip6 saddr vmap { ::1234:1234 : accept};ok;ip6 saddr vmap { ::18.52.18.52 : accept}
+ip6 saddr vmap { 1234::1234 : accept};ok
+ip6 saddr vmap { 1234:1234:: : accept};ok
+ip6 saddr vmap { ::1234 : accept};ok
+ip6 saddr vmap { 1234:: : accept};ok
+ip6 saddr vmap { ::/64 : accept};ok
+
+ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop};ok;ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:0 : accept, ::aaaa : drop}
+ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop};ok;ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:0 : accept, ::bbbb : drop}
+ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop};ok;ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:0 : accept, ::cccc : drop}
+ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop};ok;ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:0 : accept, ::dddd: drop}
+
+# rule without comma:
+filter-input ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:bbbb:::accept::adda : drop};fail
diff --git a/tests/py/ip6/vmap.t.json b/tests/py/ip6/vmap.t.json
new file mode 100644
index 0000000..1b867ff
--- /dev/null
+++ b/tests/py/ip6/vmap.t.json
@@ -0,0 +1,1037 @@
+# ip6 saddr vmap { abcd::3 : accept }
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "abcd::3",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::1234:1234:1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234::1234:1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234::1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234::1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234::1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234::1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234::1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:1234::",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::1234:1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234::1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234::1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234::1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234::1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234::1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234::",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234::1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234::1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234::1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234::1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234::",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234::1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234::1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234::1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234::1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234::",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234::1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234::1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234::",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234::1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234::",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234::",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::/64 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "::",
+ "len": 64
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa::",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "::aaaa",
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa::",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "::bbbb",
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa::",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "::cccc",
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa::",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "::dddd",
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/vmap.t.json.output b/tests/py/ip6/vmap.t.json.output
new file mode 100644
index 0000000..affe383
--- /dev/null
+++ b/tests/py/ip6/vmap.t.json.output
@@ -0,0 +1,336 @@
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "0:1234:1234:1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:0:1234:1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:0:1234:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:0:1234:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:0:1234:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:0:1234:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:0:1234",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1234:1234:1234:1234:1234:1234:1234:0",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap { ::1234:1234 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::18.52.18.52",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::aaaa",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa:0",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::bbbb",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa:0",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::cccc",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa:0",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
+[
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "::dddd",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "1234:1234:1234:1234:1234:1234:aaaa:0",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/vmap.t.payload.inet b/tests/py/ip6/vmap.t.payload.inet
new file mode 100644
index 0000000..931cc6b
--- /dev/null
+++ b/tests/py/ip6/vmap.t.payload.inet
@@ -0,0 +1,420 @@
+# ip6 saddr vmap { abcd::3 : accept }
+__map%d test-inet b
+__map%d test-inet 0
+ element 0000cdab 00000000 00000000 03000000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34120000 34123412 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00003412 34123412 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34120000 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00003412 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34120000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 00003412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 34120000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 00003412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00000000 34123412 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00003412 34120000 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00000000 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00003412 34120000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 00000000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 00003412 34120000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 00000000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00000000 34120000 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00003412 00000000 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00000000 34120000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00003412 00000000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 00000000 34120000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 00003412 00000000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00000000 00000000 34123412 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00003412 00000000 34120000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00000000 00000000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00003412 00000000 34120000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:: : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 00000000 00000000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00000000 00000000 34120000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00003412 00000000 00000000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00000000 00000000 34120000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:: : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00003412 00000000 00000000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00000000 00000000 00000000 34123412 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00003412 00000000 00000000 34120000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:: : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 00000000 00000000 00000000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234 : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00000000 00000000 00000000 34120000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:: : accept}
+__map%d test-inet b
+__map%d test-inet 0
+ element 00003412 00000000 00000000 00000000 : accept 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::/64 : accept}
+__map%d test-inet f
+__map%d test-inet 0
+ element 00000000 00000000 00000000 00000000 : accept 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 aaaa0000 : drop 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 bbbb0000 : drop 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 cccc0000 : drop 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
+__map%d test-inet b
+__map%d test-inet 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 dddd0000 : drop 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
diff --git a/tests/py/ip6/vmap.t.payload.ip6 b/tests/py/ip6/vmap.t.payload.ip6
new file mode 100644
index 0000000..6e077b2
--- /dev/null
+++ b/tests/py/ip6/vmap.t.payload.ip6
@@ -0,0 +1,336 @@
+# ip6 saddr vmap { abcd::3 : accept }
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 0000cdab 00000000 00000000 03000000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34120000 34123412 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00003412 34123412 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34120000 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00003412 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34120000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 00003412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 34120000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 00003412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00000000 34123412 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00003412 34120000 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00000000 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00003412 34120000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 00000000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 00003412 34120000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 00000000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00000000 34120000 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00003412 00000000 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00000000 34120000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00003412 00000000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 00000000 34120000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 00003412 00000000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00000000 00000000 34123412 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00003412 00000000 34120000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00000000 00000000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00003412 00000000 34120000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:: : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 00000000 00000000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00000000 00000000 34120000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00003412 00000000 00000000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00000000 00000000 34120000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:: : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00003412 00000000 00000000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00000000 00000000 00000000 34123412 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00003412 00000000 00000000 34120000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:: : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 00000000 00000000 00000000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234 : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00000000 00000000 00000000 34120000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:: : accept}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 00003412 00000000 00000000 00000000 : accept 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::/64 : accept}
+__map%d test-ip6 f
+__map%d test-ip6 0
+ element 00000000 00000000 00000000 00000000 : accept 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 aaaa0000 : drop 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 bbbb0000 : drop 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 cccc0000 : drop 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
+__map%d test-ip6 b
+__map%d test-ip6 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 dddd0000 : drop 0 [end]
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
diff --git a/tests/py/ip6/vmap.t.payload.netdev b/tests/py/ip6/vmap.t.payload.netdev
new file mode 100644
index 0000000..45f2c0b
--- /dev/null
+++ b/tests/py/ip6/vmap.t.payload.netdev
@@ -0,0 +1,420 @@
+# ip6 saddr vmap { abcd::3 : accept }
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 0000cdab 00000000 00000000 03000000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34120000 34123412 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00003412 34123412 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34120000 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00003412 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34120000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 00003412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 34120000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 00003412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000000 34123412 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00003412 34120000 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00000000 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00003412 34120000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 00000000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 00003412 34120000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 00000000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000000 34120000 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00003412 00000000 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00000000 34120000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00003412 00000000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 00000000 34120000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 00003412 00000000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000000 00000000 34123412 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00003412 00000000 34120000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00000000 00000000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234::1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00003412 00000000 34120000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:1234:: : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 00000000 00000000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000000 00000000 34120000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00003412 00000000 00000000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234::1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00000000 00000000 34120000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:1234:: : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00003412 00000000 00000000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234:1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000000 00000000 00000000 34123412 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234::1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00003412 00000000 00000000 34120000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:1234:: : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 00000000 00000000 00000000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::1234 : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000000 00000000 00000000 34120000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { 1234:: : accept}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00003412 00000000 00000000 00000000 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap { ::/64 : accept}
+__map%d test-netdev f
+__map%d test-netdev 0
+ element 00000000 00000000 00000000 00000000 : accept 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 aaaa0000 : drop 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 bbbb0000 : drop 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 cccc0000 : drop 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 dddd0000 : drop 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
diff --git a/tests/py/log b/tests/py/log
new file mode 100644
index 0000000..aba5a15
--- /dev/null
+++ b/tests/py/log
@@ -0,0 +1,1004 @@
+INFO: Log will be available at /tmp/nftables-test.log
+any/last.t: ERROR: line 11: add rule ip test-ip4 input last: This rule should not have failed.
+any/last.t: ERROR: line 12: add rule ip test-ip4 input last used 300s: This rule should not have failed.
+any/meta.t: ERROR: line 3: I cannot create the chain 'egress'
+any/meta.t: ERROR: line 12: add rule netdev test-netdev egress meta length 1000: This rule should not have failed.
+any/meta.t: ERROR: line 13: add rule netdev test-netdev egress meta length 22: This rule should not have failed.
+any/meta.t: ERROR: line 14: add rule netdev test-netdev egress meta length != 233: This rule should not have failed.
+any/meta.t: ERROR: line 15: add rule netdev test-netdev egress meta length 33-45: This rule should not have failed.
+any/meta.t: ERROR: line 16: add rule netdev test-netdev egress meta length != 33-45: This rule should not have failed.
+any/meta.t: ERROR: line 17: add rule netdev test-netdev egress meta length { 33, 55, 67, 88}: This rule should not have failed.
+any/meta.t: ERROR: line 18: add rule netdev test-netdev egress meta length { 33-55, 67-88}: This rule should not have failed.
+any/meta.t: ERROR: line 19: add rule netdev test-netdev egress meta length { 33-55, 56-88, 100-120}: This rule should not have failed.
+any/meta.t: ERROR: line 20: add rule netdev test-netdev egress meta length != { 33, 55, 67, 88}: This rule should not have failed.
+any/meta.t: ERROR: line 21: add rule netdev test-netdev egress meta length { 33-55, 66-88}: This rule should not have failed.
+any/meta.t: ERROR: line 22: add rule netdev test-netdev egress meta length != { 33-55, 66-88}: This rule should not have failed.
+any/meta.t: ERROR: line 24: add rule netdev test-netdev egress meta protocol { ip, arp, ip6, vlan }: This rule should not have failed.
+any/meta.t: ERROR: line 25: add rule netdev test-netdev egress meta protocol != {ip, arp, ip6, 8021q}: This rule should not have failed.
+any/meta.t: ERROR: line 26: add rule netdev test-netdev egress meta protocol ip: This rule should not have failed.
+any/meta.t: ERROR: line 27: add rule netdev test-netdev egress meta protocol != ip: This rule should not have failed.
+any/meta.t: ERROR: line 29: add rule netdev test-netdev egress meta l4proto 22: This rule should not have failed.
+any/meta.t: ERROR: line 30: add rule netdev test-netdev egress meta l4proto != 233: This rule should not have failed.
+any/meta.t: ERROR: line 31: add rule netdev test-netdev egress meta l4proto 33-45: This rule should not have failed.
+any/meta.t: ERROR: line 32: add rule netdev test-netdev egress meta l4proto != 33-45: This rule should not have failed.
+any/meta.t: ERROR: line 33: add rule netdev test-netdev egress meta l4proto { 33, 55, 67, 88}: This rule should not have failed.
+any/meta.t: ERROR: line 34: add rule netdev test-netdev egress meta l4proto != { 33, 55, 67, 88}: This rule should not have failed.
+any/meta.t: ERROR: line 35: add rule netdev test-netdev egress meta l4proto { 33-55, 66-88}: This rule should not have failed.
+any/meta.t: ERROR: line 36: add rule netdev test-netdev egress meta l4proto != { 33-55, 66-88}: This rule should not have failed.
+any/meta.t: ERROR: line 38: add rule netdev test-netdev egress meta priority root: This rule should not have failed.
+any/meta.t: ERROR: line 39: add rule netdev test-netdev egress meta priority none: This rule should not have failed.
+any/meta.t: ERROR: line 40: add rule netdev test-netdev egress meta priority 0x87654321: This rule should not have failed.
+any/meta.t: ERROR: line 41: add rule netdev test-netdev egress meta priority 2271560481: This rule should not have failed.
+any/meta.t: ERROR: line 42: add rule netdev test-netdev egress meta priority 1:1234: This rule should not have failed.
+any/meta.t: ERROR: line 43: add rule netdev test-netdev egress meta priority bcad:dadc: This rule should not have failed.
+any/meta.t: ERROR: line 44: add rule netdev test-netdev egress meta priority aabb:0: This rule should not have failed.
+any/meta.t: ERROR: line 45: add rule netdev test-netdev egress meta priority != bcad:dadc: This rule should not have failed.
+any/meta.t: ERROR: line 46: add rule netdev test-netdev egress meta priority != aabb:0: This rule should not have failed.
+any/meta.t: ERROR: line 47: add rule netdev test-netdev egress meta priority bcad:dada-bcad:dadc: This rule should not have failed.
+any/meta.t: ERROR: line 48: add rule netdev test-netdev egress meta priority != bcad:dada-bcad:dadc: This rule should not have failed.
+any/meta.t: ERROR: line 49: add rule netdev test-netdev egress meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}: This rule should not have failed.
+any/meta.t: ERROR: line 50: add rule netdev test-netdev egress meta priority set cafe:beef: This rule should not have failed.
+any/meta.t: ERROR: line 51: add rule netdev test-netdev egress meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb}: This rule should not have failed.
+any/meta.t: ERROR: line 53: add rule netdev test-netdev egress meta mark 0x4: This rule should not have failed.
+any/meta.t: ERROR: line 54: add rule netdev test-netdev egress meta mark 0x32: This rule should not have failed.
+any/meta.t: ERROR: line 55: add rule netdev test-netdev egress meta mark and 0x03 == 0x01: This rule should not have failed.
+any/meta.t: ERROR: line 56: add rule netdev test-netdev egress meta mark and 0x03 != 0x01: This rule should not have failed.
+any/meta.t: ERROR: line 57: add rule netdev test-netdev egress meta mark 0x10: This rule should not have failed.
+any/meta.t: ERROR: line 58: add rule netdev test-netdev egress meta mark != 0x10: This rule should not have failed.
+any/meta.t: ERROR: line 59: add rule netdev test-netdev egress meta mark 0xffffff00/24: This rule should not have failed.
+any/meta.t: ERROR: line 61: add rule netdev test-netdev egress meta mark or 0x03 == 0x01: This rule should not have failed.
+any/meta.t: ERROR: line 62: add rule netdev test-netdev egress meta mark or 0x03 != 0x01: This rule should not have failed.
+any/meta.t: ERROR: line 63: add rule netdev test-netdev egress meta mark xor 0x03 == 0x01: This rule should not have failed.
+any/meta.t: ERROR: line 64: add rule netdev test-netdev egress meta mark xor 0x03 != 0x01: This rule should not have failed.
+any/meta.t: ERROR: line 66: add rule netdev test-netdev egress meta iif "lo" accept: This rule should not have failed.
+any/meta.t: ERROR: line 67: add rule netdev test-netdev egress meta iif != "lo" accept: This rule should not have failed.
+any/meta.t: ERROR: line 69: add rule netdev test-netdev egress meta iifname "dummy0": This rule should not have failed.
+any/meta.t: ERROR: line 70: add rule netdev test-netdev egress meta iifname != "dummy0": This rule should not have failed.
+any/meta.t: ERROR: line 71: add rule netdev test-netdev egress meta iifname {"dummy0", "lo"}: This rule should not have failed.
+any/meta.t: ERROR: line 72: add rule netdev test-netdev egress meta iifname != {"dummy0", "lo"}: This rule should not have failed.
+any/meta.t: ERROR: line 73: add rule netdev test-netdev egress meta iifname "dummy*": This rule should not have failed.
+any/meta.t: ERROR: line 74: add rule netdev test-netdev egress meta iifname "dummy\*": This rule should not have failed.
+any/meta.t: ERROR: line 77: add rule netdev test-netdev egress meta iiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}: This rule should not have failed.
+any/meta.t: ERROR: line 78: add rule netdev test-netdev egress meta iiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}: This rule should not have failed.
+any/meta.t: ERROR: line 79: add rule netdev test-netdev egress meta iiftype != ether: This rule should not have failed.
+any/meta.t: ERROR: line 80: add rule netdev test-netdev egress meta iiftype ether: This rule should not have failed.
+any/meta.t: ERROR: line 81: add rule netdev test-netdev egress meta iiftype != ppp: This rule should not have failed.
+any/meta.t: ERROR: line 82: add rule netdev test-netdev egress meta iiftype ppp: This rule should not have failed.
+any/meta.t: ERROR: line 84: add rule netdev test-netdev egress meta oif "lo" accept: This rule should not have failed.
+any/meta.t: ERROR: line 85: add rule netdev test-netdev egress meta oif != "lo" accept: This rule should not have failed.
+any/meta.t: ERROR: line 87: add rule netdev test-netdev egress meta oifname "dummy0": This rule should not have failed.
+any/meta.t: ERROR: line 88: add rule netdev test-netdev egress meta oifname != "dummy0": This rule should not have failed.
+any/meta.t: ERROR: line 89: add rule netdev test-netdev egress meta oifname { "dummy0", "lo"}: This rule should not have failed.
+any/meta.t: ERROR: line 90: add rule netdev test-netdev egress meta oifname "dummy*": This rule should not have failed.
+any/meta.t: ERROR: line 91: add rule netdev test-netdev egress meta oifname "dummy\*": This rule should not have failed.
+any/meta.t: ERROR: line 94: add rule netdev test-netdev egress meta oiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}: This rule should not have failed.
+any/meta.t: ERROR: line 95: add rule netdev test-netdev egress meta oiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}: This rule should not have failed.
+any/meta.t: ERROR: line 96: add rule netdev test-netdev egress meta oiftype != ether: This rule should not have failed.
+any/meta.t: ERROR: line 97: add rule netdev test-netdev egress meta oiftype ether: This rule should not have failed.
+any/meta.t: ERROR: line 99: add rule netdev test-netdev egress meta skuid {"bin", "root", "daemon"} accept: This rule should not have failed.
+any/meta.t: ERROR: line 100: add rule netdev test-netdev egress meta skuid != {"bin", "root", "daemon"} accept: This rule should not have failed.
+any/meta.t: ERROR: line 101: add rule netdev test-netdev egress meta skuid "root": This rule should not have failed.
+any/meta.t: ERROR: line 102: add rule netdev test-netdev egress meta skuid != "root": This rule should not have failed.
+any/meta.t: ERROR: line 103: add rule netdev test-netdev egress meta skuid lt 3000 accept: This rule should not have failed.
+any/meta.t: ERROR: line 104: add rule netdev test-netdev egress meta skuid gt 3000 accept: This rule should not have failed.
+any/meta.t: ERROR: line 105: add rule netdev test-netdev egress meta skuid eq 3000 accept: This rule should not have failed.
+any/meta.t: ERROR: line 106: add rule netdev test-netdev egress meta skuid 3001-3005 accept: This rule should not have failed.
+any/meta.t: ERROR: line 107: add rule netdev test-netdev egress meta skuid != 2001-2005 accept: This rule should not have failed.
+any/meta.t: ERROR: line 108: add rule netdev test-netdev egress meta skuid { 2001-2005, 3001-3005} accept: This rule should not have failed.
+any/meta.t: ERROR: line 109: add rule netdev test-netdev egress meta skuid != { 2001-2005, 3001-3005} accept: This rule should not have failed.
+any/meta.t: ERROR: line 111: add rule netdev test-netdev egress meta skgid {"bin", "root", "daemon"} accept: This rule should not have failed.
+any/meta.t: ERROR: line 112: add rule netdev test-netdev egress meta skgid != {"bin", "root", "daemon"} accept: This rule should not have failed.
+any/meta.t: ERROR: line 113: add rule netdev test-netdev egress meta skgid "root": This rule should not have failed.
+any/meta.t: ERROR: line 114: add rule netdev test-netdev egress meta skgid != "root": This rule should not have failed.
+any/meta.t: ERROR: line 115: add rule netdev test-netdev egress meta skgid lt 3000 accept: This rule should not have failed.
+any/meta.t: ERROR: line 116: add rule netdev test-netdev egress meta skgid gt 3000 accept: This rule should not have failed.
+any/meta.t: ERROR: line 117: add rule netdev test-netdev egress meta skgid eq 3000 accept: This rule should not have failed.
+any/meta.t: ERROR: line 118: add rule netdev test-netdev egress meta skgid 2001-2005 accept: This rule should not have failed.
+any/meta.t: ERROR: line 119: add rule netdev test-netdev egress meta skgid != 2001-2005 accept: This rule should not have failed.
+any/meta.t: ERROR: line 131: add rule netdev test-netdev egress meta mark set 0xffffffc8 xor 0x16: This rule should not have failed.
+any/meta.t: ERROR: line 132: add rule netdev test-netdev egress meta mark set 0x16 and 0x16: This rule should not have failed.
+any/meta.t: ERROR: line 133: add rule netdev test-netdev egress meta mark set 0xffffffe9 or 0x16: This rule should not have failed.
+any/meta.t: ERROR: line 134: add rule netdev test-netdev egress meta mark set 0xffffffde and 0x16: This rule should not have failed.
+any/meta.t: ERROR: line 135: add rule netdev test-netdev egress meta mark set 0xf045ffde or 0x10: This rule should not have failed.
+any/meta.t: ERROR: line 136: add rule netdev test-netdev egress meta mark set 0xffffffde or 0x16: This rule should not have failed.
+any/meta.t: ERROR: line 137: add rule netdev test-netdev egress meta mark set 0x32 or 0xfffff: This rule should not have failed.
+any/meta.t: ERROR: line 138: add rule netdev test-netdev egress meta mark set 0xfffe xor 0x16: This rule should not have failed.
+any/meta.t: ERROR: line 143: add rule netdev test-netdev egress meta iif "lo": This rule should not have failed.
+any/meta.t: ERROR: line 144: add rule netdev test-netdev egress meta oif "lo": This rule should not have failed.
+any/meta.t: ERROR: line 145: add rule netdev test-netdev egress meta oifname "dummy2" accept: This rule should not have failed.
+any/meta.t: ERROR: line 146: add rule netdev test-netdev egress meta skuid 3000: This rule should not have failed.
+any/meta.t: ERROR: line 147: add rule netdev test-netdev egress meta skgid 3000: This rule should not have failed.
+any/meta.t: ERROR: line 151: add rule netdev test-netdev egress meta rtclassid "cosmos": This rule should not have failed.
+any/meta.t: ERROR: line 153: add rule netdev test-netdev egress meta pkttype broadcast: This rule should not have failed.
+any/meta.t: ERROR: line 154: add rule netdev test-netdev egress meta pkttype host: This rule should not have failed.
+any/meta.t: ERROR: line 155: add rule netdev test-netdev egress meta pkttype multicast: This rule should not have failed.
+any/meta.t: ERROR: line 156: add rule netdev test-netdev egress meta pkttype != broadcast: This rule should not have failed.
+any/meta.t: ERROR: line 157: add rule netdev test-netdev egress meta pkttype != host: This rule should not have failed.
+any/meta.t: ERROR: line 158: add rule netdev test-netdev egress meta pkttype != multicast: This rule should not have failed.
+any/meta.t: ERROR: line 160: add rule netdev test-netdev egress pkttype { broadcast, multicast} accept: This rule should not have failed.
+any/meta.t: ERROR: line 162: add rule netdev test-netdev egress meta cpu 1: This rule should not have failed.
+any/meta.t: ERROR: line 163: add rule netdev test-netdev egress meta cpu != 1: This rule should not have failed.
+any/meta.t: ERROR: line 164: add rule netdev test-netdev egress meta cpu 1-3: This rule should not have failed.
+any/meta.t: ERROR: line 165: add rule netdev test-netdev egress meta cpu != 1-2: This rule should not have failed.
+any/meta.t: ERROR: line 166: add rule netdev test-netdev egress meta cpu { 2,3}: This rule should not have failed.
+any/meta.t: ERROR: line 167: add rule netdev test-netdev egress meta cpu { 2-3, 5-7}: This rule should not have failed.
+any/meta.t: ERROR: line 168: add rule netdev test-netdev egress meta cpu != { 2,3}: This rule should not have failed.
+any/meta.t: ERROR: line 170: add rule netdev test-netdev egress meta iifgroup 0: This rule should not have failed.
+any/meta.t: ERROR: line 171: add rule netdev test-netdev egress meta iifgroup != 0: This rule should not have failed.
+any/meta.t: ERROR: line 172: add rule netdev test-netdev egress meta iifgroup "default": This rule should not have failed.
+any/meta.t: ERROR: line 173: add rule netdev test-netdev egress meta iifgroup != "default": This rule should not have failed.
+any/meta.t: ERROR: line 174: add rule netdev test-netdev egress meta iifgroup {"default", 11}: This rule should not have failed.
+any/meta.t: ERROR: line 175: add rule netdev test-netdev egress meta iifgroup != {"default", 11}: This rule should not have failed.
+any/meta.t: ERROR: line 176: add rule netdev test-netdev egress meta iifgroup { 11,33}: This rule should not have failed.
+any/meta.t: ERROR: line 177: add rule netdev test-netdev egress meta iifgroup {11-33, 44-55}: This rule should not have failed.
+any/meta.t: ERROR: line 178: add rule netdev test-netdev egress meta iifgroup != { 11,33}: This rule should not have failed.
+any/meta.t: ERROR: line 179: add rule netdev test-netdev egress meta iifgroup != {11-33, 44-55}: This rule should not have failed.
+any/meta.t: ERROR: line 180: add rule netdev test-netdev egress meta oifgroup 0: This rule should not have failed.
+any/meta.t: ERROR: line 181: add rule netdev test-netdev egress meta oifgroup != 0: This rule should not have failed.
+any/meta.t: ERROR: line 182: add rule netdev test-netdev egress meta oifgroup "default": This rule should not have failed.
+any/meta.t: ERROR: line 183: add rule netdev test-netdev egress meta oifgroup != "default": This rule should not have failed.
+any/meta.t: ERROR: line 184: add rule netdev test-netdev egress meta oifgroup {"default", 11}: This rule should not have failed.
+any/meta.t: ERROR: line 185: add rule netdev test-netdev egress meta oifgroup != {"default", 11}: This rule should not have failed.
+any/meta.t: ERROR: line 186: add rule netdev test-netdev egress meta oifgroup { 11,33}: This rule should not have failed.
+any/meta.t: ERROR: line 187: add rule netdev test-netdev egress meta oifgroup {11-33, 44-55}: This rule should not have failed.
+any/meta.t: ERROR: line 188: add rule netdev test-netdev egress meta oifgroup != { 11,33}: This rule should not have failed.
+any/meta.t: ERROR: line 189: add rule netdev test-netdev egress meta oifgroup != {11-33, 44-55}: This rule should not have failed.
+any/meta.t: ERROR: line 191: add rule netdev test-netdev egress meta cgroup 1048577: This rule should not have failed.
+any/meta.t: ERROR: line 192: add rule netdev test-netdev egress meta cgroup != 1048577: This rule should not have failed.
+any/meta.t: ERROR: line 193: add rule netdev test-netdev egress meta cgroup { 1048577, 1048578 }: This rule should not have failed.
+any/meta.t: ERROR: line 194: add rule netdev test-netdev egress meta cgroup != { 1048577, 1048578}: This rule should not have failed.
+any/meta.t: ERROR: line 195: add rule netdev test-netdev egress meta cgroup 1048577-1048578: This rule should not have failed.
+any/meta.t: ERROR: line 196: add rule netdev test-netdev egress meta cgroup != 1048577-1048578: This rule should not have failed.
+any/meta.t: ERROR: line 198: add rule netdev test-netdev egress meta iif . meta oif { "lo" . "lo" }: This rule should not have failed.
+any/meta.t: ERROR: line 199: add rule netdev test-netdev egress meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a }: This rule should not have failed.
+any/meta.t: ERROR: line 200: add rule netdev test-netdev egress meta iif . meta oif vmap { "lo" . "lo" : drop }: This rule should not have failed.
+any/meta.t: ERROR: line 202: add rule netdev test-netdev egress meta random eq 1: This rule should not have failed.
+any/meta.t: ERROR: line 203: add rule netdev test-netdev egress meta random gt 1000000: This rule should not have failed.
+any/meta.t: ERROR: line 205: add rule netdev test-netdev egress meta time "1970-05-23 21:07:14" drop: This rule should not have failed.
+any/meta.t: ERROR: line 206: add rule netdev test-netdev egress meta time 12341234 drop: This rule should not have failed.
+any/meta.t: ERROR: line 207: add rule netdev test-netdev egress meta time "2019-06-21 17:00:00" drop: This rule should not have failed.
+any/meta.t: ERROR: line 208: add rule netdev test-netdev egress meta time "2019-07-01 00:00:00" drop: This rule should not have failed.
+any/meta.t: ERROR: line 209: add rule netdev test-netdev egress meta time "2019-07-01 00:01:00" drop: This rule should not have failed.
+any/meta.t: ERROR: line 210: add rule netdev test-netdev egress meta time "2019-07-01 00:00:01" drop: This rule should not have failed.
+any/meta.t: ERROR: line 211: add rule netdev test-netdev egress meta time < "2022-07-01 11:00:00" accept: This rule should not have failed.
+any/meta.t: ERROR: line 212: add rule netdev test-netdev egress meta time > "2022-07-01 11:00:00" accept: This rule should not have failed.
+any/meta.t: ERROR: line 213: add rule netdev test-netdev egress meta day "Saturday" drop: This rule should not have failed.
+any/meta.t: ERROR: line 214: add rule netdev test-netdev egress meta day 6 drop: This rule should not have failed.
+any/meta.t: ERROR: line 216: add rule netdev test-netdev egress meta hour "17:00" drop: This rule should not have failed.
+any/meta.t: ERROR: line 217: add rule netdev test-netdev egress meta hour "17:00:00" drop: This rule should not have failed.
+any/meta.t: ERROR: line 218: add rule netdev test-netdev egress meta hour "17:00:01" drop: This rule should not have failed.
+any/meta.t: ERROR: line 219: add rule netdev test-netdev egress meta hour "00:00" drop: This rule should not have failed.
+any/meta.t: ERROR: line 220: add rule netdev test-netdev egress meta hour "00:01" drop: This rule should not have failed.
+any/meta.t: ERROR: line 221: add rule netdev test-netdev egress time < "2022-07-01 11:00:00" accept: This rule should not have failed.
+any/meta.t: ERROR: line 222: add rule netdev test-netdev egress time > "2022-07-01 11:00:00" accept: This rule should not have failed.
+any/meta.t: ERROR: line 226: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+any/rawpayload.t: ERROR: line 3: I cannot create the chain 'egress'
+any/rawpayload.t: ERROR: line 8: add rule netdev test-netdev egress meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 }: This rule should not have failed.
+any/rawpayload.t: ERROR: line 9: add rule netdev test-netdev egress meta l4proto tcp @th,16,16 { 22, 23, 80}: This rule should not have failed.
+any/rawpayload.t: ERROR: line 10: add rule netdev test-netdev egress @nh,8,8 0xff: This rule should not have failed.
+any/rawpayload.t: ERROR: line 11: add rule netdev test-netdev egress @nh,8,16 0x0: This rule should not have failed.
+any/rawpayload.t: ERROR: line 18: add rule netdev test-netdev egress @ll,0,1 1: This rule should not have failed.
+any/rawpayload.t: ERROR: line 19: add rule netdev test-netdev egress @ll,0,8 & 0x80 == 0x80: This rule should not have failed.
+any/rawpayload.t: ERROR: line 20: add rule netdev test-netdev egress @ll,0,128 0xfedcba987654321001234567890abcde: This rule should not have failed.
+any/rawpayload.t: ERROR: line 22: add rule netdev test-netdev egress meta l4proto 91 @th,400,16 0x0 accept: This rule should not have failed.
+any/rawpayload.t: ERROR: line 24: add rule inet test-inet input @ih,32,32 0x14000000: This rule should not have failed.
+any/rawpayload.t: ERROR: line 24: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+any/rt.t: OK
+any/ct.t: OK
+any/log.t: OK
+any/queue.t: OK
+any/objects.t: ERROR: line 3: I cannot create the chain 'egress'
+any/objects.t: ERROR: line 16: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+any/objects.t: OK
+any/counter.t: OK
+any/quota.t: ERROR: line 3: I cannot create the chain 'egress'
+any/quota.t: ERROR: line 12: add rule netdev test-netdev egress quota 1025 bytes: This rule should not have failed.
+any/quota.t: ERROR: line 13: add rule netdev test-netdev egress quota 1 kbytes: This rule should not have failed.
+any/quota.t: ERROR: line 14: add rule netdev test-netdev egress quota 2 kbytes: This rule should not have failed.
+any/quota.t: ERROR: line 15: add rule netdev test-netdev egress quota 1025 kbytes: This rule should not have failed.
+any/quota.t: ERROR: line 16: add rule netdev test-netdev egress quota 1023 mbytes: This rule should not have failed.
+any/quota.t: ERROR: line 17: add rule netdev test-netdev egress quota 10230 mbytes: This rule should not have failed.
+any/quota.t: ERROR: line 18: add rule netdev test-netdev egress quota 1023000 mbytes: This rule should not have failed.
+any/quota.t: ERROR: line 20: add rule netdev test-netdev egress quota over 1 kbytes: This rule should not have failed.
+any/quota.t: ERROR: line 21: add rule netdev test-netdev egress quota over 2 kbytes: This rule should not have failed.
+any/quota.t: ERROR: line 22: add rule netdev test-netdev egress quota over 1025 kbytes: This rule should not have failed.
+any/quota.t: ERROR: line 23: add rule netdev test-netdev egress quota over 1023 mbytes: This rule should not have failed.
+any/quota.t: ERROR: line 24: add rule netdev test-netdev egress quota over 10230 mbytes: This rule should not have failed.
+any/quota.t: ERROR: line 25: add rule netdev test-netdev egress quota over 1023000 mbytes: This rule should not have failed.
+any/quota.t: ERROR: line 25: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+any/limit.t: ERROR: line 3: I cannot create the chain 'egress'
+any/limit.t: ERROR: line 12: add rule netdev test-netdev egress limit rate 400/minute: This rule should not have failed.
+any/limit.t: ERROR: line 13: add rule netdev test-netdev egress limit rate 20/second: This rule should not have failed.
+any/limit.t: ERROR: line 14: add rule netdev test-netdev egress limit rate 400/hour: This rule should not have failed.
+any/limit.t: ERROR: line 15: add rule netdev test-netdev egress limit rate 40/day: This rule should not have failed.
+any/limit.t: ERROR: line 16: add rule netdev test-netdev egress limit rate 400/week: This rule should not have failed.
+any/limit.t: ERROR: line 17: add rule netdev test-netdev egress limit rate 1023/second burst 10 packets: This rule should not have failed.
+any/limit.t: ERROR: line 20: add rule netdev test-netdev egress limit rate 1 kbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 21: add rule netdev test-netdev egress limit rate 2 kbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 22: add rule netdev test-netdev egress limit rate 1025 kbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 23: add rule netdev test-netdev egress limit rate 1023 mbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 24: add rule netdev test-netdev egress limit rate 10230 mbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 25: add rule netdev test-netdev egress limit rate 1023000 mbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 28: add rule netdev test-netdev egress limit rate 1 bytes / second: This rule should not have failed.
+any/limit.t: ERROR: line 29: add rule netdev test-netdev egress limit rate 1 kbytes / second: This rule should not have failed.
+any/limit.t: ERROR: line 30: add rule netdev test-netdev egress limit rate 1 mbytes / second: This rule should not have failed.
+any/limit.t: ERROR: line 33: add rule netdev test-netdev egress limit rate 1025 bytes/second burst 512 bytes: This rule should not have failed.
+any/limit.t: ERROR: line 34: add rule netdev test-netdev egress limit rate 1025 kbytes/second burst 1023 kbytes: This rule should not have failed.
+any/limit.t: ERROR: line 35: add rule netdev test-netdev egress limit rate 1025 mbytes/second burst 1025 kbytes: This rule should not have failed.
+any/limit.t: ERROR: line 36: add rule netdev test-netdev egress limit rate 1025000 mbytes/second burst 1023 mbytes: This rule should not have failed.
+any/limit.t: ERROR: line 38: add rule netdev test-netdev egress limit rate over 400/minute: This rule should not have failed.
+any/limit.t: ERROR: line 39: add rule netdev test-netdev egress limit rate over 20/second: This rule should not have failed.
+any/limit.t: ERROR: line 40: add rule netdev test-netdev egress limit rate over 400/hour: This rule should not have failed.
+any/limit.t: ERROR: line 41: add rule netdev test-netdev egress limit rate over 40/day: This rule should not have failed.
+any/limit.t: ERROR: line 42: add rule netdev test-netdev egress limit rate over 400/week: This rule should not have failed.
+any/limit.t: ERROR: line 43: add rule netdev test-netdev egress limit rate over 1023/second burst 10 packets: This rule should not have failed.
+any/limit.t: ERROR: line 45: add rule netdev test-netdev egress limit rate over 1 kbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 46: add rule netdev test-netdev egress limit rate over 2 kbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 47: add rule netdev test-netdev egress limit rate over 1025 kbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 48: add rule netdev test-netdev egress limit rate over 1023 mbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 49: add rule netdev test-netdev egress limit rate over 10230 mbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 50: add rule netdev test-netdev egress limit rate over 1023000 mbytes/second: This rule should not have failed.
+any/limit.t: ERROR: line 52: add rule netdev test-netdev egress limit rate over 1025 bytes/second burst 512 bytes: This rule should not have failed.
+any/limit.t: ERROR: line 53: add rule netdev test-netdev egress limit rate over 1025 kbytes/second burst 1023 kbytes: This rule should not have failed.
+any/limit.t: ERROR: line 54: add rule netdev test-netdev egress limit rate over 1025 mbytes/second burst 1025 kbytes: This rule should not have failed.
+any/limit.t: ERROR: line 55: add rule netdev test-netdev egress limit rate over 1025000 mbytes/second burst 1023 mbytes: This rule should not have failed.
+any/limit.t: ERROR: line 55: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+any/tcpopt.t: ERROR: line 58: add rule ip test-ip4 input reset tcp option mptcp: This rule should not have failed.
+any/tcpopt.t: ERROR: line 59: add rule ip test-ip4 input reset tcp option 2: This rule should not have failed.
+any/tcpopt.t: ERROR: line 60: add rule ip test-ip4 input reset tcp option 123: This rule should not have failed.
+arp/arp.t: ERROR: line 4: I cannot create the chain 'egress'
+arp/arp.t: ERROR: line 9: add rule netdev test-netdev egress arp htype 1: This rule should not have failed.
+arp/arp.t: ERROR: line 10: add rule netdev test-netdev egress arp htype != 1: This rule should not have failed.
+arp/arp.t: ERROR: line 11: add rule netdev test-netdev egress arp htype 22: This rule should not have failed.
+arp/arp.t: ERROR: line 12: add rule netdev test-netdev egress arp htype != 233: This rule should not have failed.
+arp/arp.t: ERROR: line 13: add rule netdev test-netdev egress arp htype 33-45: This rule should not have failed.
+arp/arp.t: ERROR: line 14: add rule netdev test-netdev egress arp htype != 33-45: This rule should not have failed.
+arp/arp.t: ERROR: line 15: add rule netdev test-netdev egress arp htype { 33, 55, 67, 88}: This rule should not have failed.
+arp/arp.t: ERROR: line 16: add rule netdev test-netdev egress arp htype != { 33, 55, 67, 88}: This rule should not have failed.
+arp/arp.t: ERROR: line 18: add rule netdev test-netdev egress arp ptype 0x0800: This rule should not have failed.
+arp/arp.t: ERROR: line 20: add rule netdev test-netdev egress arp hlen 22: This rule should not have failed.
+arp/arp.t: ERROR: line 21: add rule netdev test-netdev egress arp hlen != 233: This rule should not have failed.
+arp/arp.t: ERROR: line 22: add rule netdev test-netdev egress arp hlen 33-45: This rule should not have failed.
+arp/arp.t: ERROR: line 23: add rule netdev test-netdev egress arp hlen != 33-45: This rule should not have failed.
+arp/arp.t: ERROR: line 24: add rule netdev test-netdev egress arp hlen { 33, 55, 67, 88}: This rule should not have failed.
+arp/arp.t: ERROR: line 25: add rule netdev test-netdev egress arp hlen != { 33, 55, 67, 88}: This rule should not have failed.
+arp/arp.t: ERROR: line 27: add rule netdev test-netdev egress arp plen 22: This rule should not have failed.
+arp/arp.t: ERROR: line 28: add rule netdev test-netdev egress arp plen != 233: This rule should not have failed.
+arp/arp.t: ERROR: line 29: add rule netdev test-netdev egress arp plen 33-45: This rule should not have failed.
+arp/arp.t: ERROR: line 30: add rule netdev test-netdev egress arp plen != 33-45: This rule should not have failed.
+arp/arp.t: ERROR: line 31: add rule netdev test-netdev egress arp plen { 33, 55, 67, 88}: This rule should not have failed.
+arp/arp.t: ERROR: line 32: add rule netdev test-netdev egress arp plen != { 33, 55, 67, 88}: This rule should not have failed.
+arp/arp.t: ERROR: line 34: add rule netdev test-netdev egress arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}: This rule should not have failed.
+arp/arp.t: ERROR: line 35: add rule netdev test-netdev egress arp operation != {nak, inreply, inrequest, rreply, rrequest, reply, request}: This rule should not have failed.
+arp/arp.t: ERROR: line 36: add rule netdev test-netdev egress arp operation 1-2: This rule should not have failed.
+arp/arp.t: ERROR: line 37: add rule netdev test-netdev egress arp operation request: This rule should not have failed.
+arp/arp.t: ERROR: line 38: add rule netdev test-netdev egress arp operation reply: This rule should not have failed.
+arp/arp.t: ERROR: line 39: add rule netdev test-netdev egress arp operation rrequest: This rule should not have failed.
+arp/arp.t: ERROR: line 40: add rule netdev test-netdev egress arp operation rreply: This rule should not have failed.
+arp/arp.t: ERROR: line 41: add rule netdev test-netdev egress arp operation inrequest: This rule should not have failed.
+arp/arp.t: ERROR: line 42: add rule netdev test-netdev egress arp operation inreply: This rule should not have failed.
+arp/arp.t: ERROR: line 43: add rule netdev test-netdev egress arp operation nak: This rule should not have failed.
+arp/arp.t: ERROR: line 44: add rule netdev test-netdev egress arp operation != request: This rule should not have failed.
+arp/arp.t: ERROR: line 45: add rule netdev test-netdev egress arp operation != reply: This rule should not have failed.
+arp/arp.t: ERROR: line 46: add rule netdev test-netdev egress arp operation != rrequest: This rule should not have failed.
+arp/arp.t: ERROR: line 47: add rule netdev test-netdev egress arp operation != rreply: This rule should not have failed.
+arp/arp.t: ERROR: line 48: add rule netdev test-netdev egress arp operation != inrequest: This rule should not have failed.
+arp/arp.t: ERROR: line 49: add rule netdev test-netdev egress arp operation != inreply: This rule should not have failed.
+arp/arp.t: ERROR: line 50: add rule netdev test-netdev egress arp operation != nak: This rule should not have failed.
+arp/arp.t: ERROR: line 52: add rule netdev test-netdev egress arp saddr ip 1.2.3.4: This rule should not have failed.
+arp/arp.t: ERROR: line 53: add rule netdev test-netdev egress arp daddr ip 4.3.2.1: This rule should not have failed.
+arp/arp.t: ERROR: line 54: add rule netdev test-netdev egress arp saddr ether aa:bb:cc:aa:bb:cc: This rule should not have failed.
+arp/arp.t: ERROR: line 55: add rule netdev test-netdev egress arp daddr ether aa:bb:cc:aa:bb:cc: This rule should not have failed.
+arp/arp.t: ERROR: line 57: add rule netdev test-netdev egress arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee: This rule should not have failed.
+arp/arp.t: ERROR: line 58: add rule netdev test-netdev egress arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1: This rule should not have failed.
+arp/arp.t: ERROR: line 60: add rule netdev test-netdev egress meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566: This rule should not have failed.
+arp/arp.t: ERROR: line 60: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+bridge/meta.t: OK
+bridge/redirect.t: ERROR: line 5: add rule bridge test-bridge prerouting meta broute set 1: This rule should not have failed.
+bridge/icmpX.t: OK
+bridge/vlan.t: ERROR: line 3: I cannot create the chain 'egress'
+bridge/vlan.t: ERROR: line 8: add rule netdev test-netdev egress vlan id 4094: This rule should not have failed.
+bridge/vlan.t: ERROR: line 9: add rule netdev test-netdev egress vlan id 0: This rule should not have failed.
+bridge/vlan.t: ERROR: line 12: add rule netdev test-netdev egress vlan id 4094 vlan dei 0: This rule should not have failed.
+bridge/vlan.t: ERROR: line 13: add rule netdev test-netdev egress vlan id 4094 vlan dei 1: This rule should not have failed.
+bridge/vlan.t: ERROR: line 14: add rule netdev test-netdev egress vlan id 4094 vlan dei != 1: This rule should not have failed.
+bridge/vlan.t: ERROR: line 15: add rule netdev test-netdev egress vlan id 4094 vlan cfi 1: This rule should not have failed.
+bridge/vlan.t: ERROR: line 19: add rule netdev test-netdev egress vlan id 4094 vlan dei 1 vlan pcp 7: This rule should not have failed.
+bridge/vlan.t: ERROR: line 20: add rule netdev test-netdev egress vlan id 4094 vlan dei 1 vlan pcp 3: This rule should not have failed.
+bridge/vlan.t: ERROR: line 22: add rule netdev test-netdev egress ether type vlan vlan id 4094: This rule should not have failed.
+bridge/vlan.t: ERROR: line 23: add rule netdev test-netdev egress ether type vlan vlan id 0: This rule should not have failed.
+bridge/vlan.t: ERROR: line 24: add rule netdev test-netdev egress ether type vlan vlan id 4094 vlan dei 0: This rule should not have failed.
+bridge/vlan.t: ERROR: line 25: add rule netdev test-netdev egress ether type vlan vlan id 4094 vlan dei 1: This rule should not have failed.
+bridge/vlan.t: ERROR: line 28: add rule netdev test-netdev egress vlan id 4094 tcp dport 22: This rule should not have failed.
+bridge/vlan.t: ERROR: line 29: add rule netdev test-netdev egress vlan id 1 ip saddr 10.0.0.1: This rule should not have failed.
+bridge/vlan.t: ERROR: line 30: add rule netdev test-netdev egress vlan id 1 ip saddr 10.0.0.0/23: This rule should not have failed.
+bridge/vlan.t: ERROR: line 31: add rule netdev test-netdev egress vlan id 1 ip saddr 10.0.0.0/23 udp dport 53: This rule should not have failed.
+bridge/vlan.t: ERROR: line 32: add rule netdev test-netdev egress ether type vlan vlan id 1 ip saddr 10.0.0.0/23 udp dport 53: This rule should not have failed.
+bridge/vlan.t: ERROR: line 34: add rule netdev test-netdev egress vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3: This rule should not have failed.
+bridge/vlan.t: ERROR: line 37: add rule netdev test-netdev egress ether type vlan ip protocol 1 accept: This rule should not have failed.
+bridge/vlan.t: ERROR: line 40: add rule netdev test-netdev egress ether type 8021ad vlan id 1 ip protocol 6 accept: This rule should not have failed.
+bridge/vlan.t: ERROR: line 41: add rule netdev test-netdev egress ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter: This rule should not have failed.
+bridge/vlan.t: ERROR: line 42: add rule netdev test-netdev egress ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6: This rule should not have failed.
+bridge/vlan.t: ERROR: line 49: add rule netdev test-netdev egress vlan id 1 vlan id set 2: This rule should not have failed.
+bridge/vlan.t: ERROR: line 51: add rule netdev test-netdev egress ether saddr 00:01:02:03:04:05 vlan id 1: This rule should not have failed.
+bridge/vlan.t: ERROR: line 52: add rule netdev test-netdev egress vlan id 2 ether saddr 0:1:2:3:4:6: This rule should not have failed.
+bridge/vlan.t: ERROR: line 54: add rule netdev test-netdev egress ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }: This rule should not have failed.
+bridge/vlan.t: ERROR: line 54: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+bridge/ether.t: OK
+bridge/reject.t: OK
+inet/ipsec.t: OK
+inet/vmap.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/vmap.t: ERROR: line 8: add rule netdev test-netdev egress iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }: This rule should not have failed.
+inet/vmap.t: ERROR: line 9: add rule inet test-inet input ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }: This rule should not have failed.
+inet/vmap.t: ERROR: line 10: add rule netdev test-netdev egress udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }: This rule should not have failed.
+inet/vmap.t: ERROR: line 10: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/meta.t: OK
+inet/snat.t: OK
+inet/ether-ip.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/ether-ip.t: ERROR: line 8: add rule netdev test-netdev egress tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept: This rule should not have failed.
+inet/ether-ip.t: ERROR: line 9: add rule netdev test-netdev egress tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04: This rule should not have failed.
+inet/ether-ip.t: ERROR: line 9: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/rt.t: OK
+inet/ct.t: OK
+inet/ip.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/ip.t: ERROR: line 10: add rule netdev test-netdev egress ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe }: This rule should not have failed.
+inet/ip.t: ERROR: line 12: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/icmpX.t: OK
+inet/tcp.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/tcp.t: ERROR: line 12: add rule netdev test-netdev egress tcp dport 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 13: add rule netdev test-netdev egress tcp dport != 233: This rule should not have failed.
+inet/tcp.t: ERROR: line 14: add rule netdev test-netdev egress tcp dport 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 15: add rule netdev test-netdev egress tcp dport != 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 16: add rule netdev test-netdev egress tcp dport { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 17: add rule netdev test-netdev egress tcp dport != { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 18: add rule netdev test-netdev egress tcp dport {telnet, http, https} accept: This rule should not have failed.
+inet/tcp.t: ERROR: line 19: add rule netdev test-netdev egress tcp dport vmap { 22 : accept, 23 : drop }: This rule should not have failed.
+inet/tcp.t: ERROR: line 20: add rule netdev test-netdev egress tcp dport vmap { 25:accept, 28:drop }: This rule should not have failed.
+inet/tcp.t: ERROR: line 21: add rule netdev test-netdev egress tcp dport { 22, 53, 80, 110 }: This rule should not have failed.
+inet/tcp.t: ERROR: line 22: add rule netdev test-netdev egress tcp dport != { 22, 53, 80, 110 }: This rule should not have failed.
+inet/tcp.t: ERROR: line 26: add rule netdev test-netdev egress tcp sport 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 27: add rule netdev test-netdev egress tcp sport != 233: This rule should not have failed.
+inet/tcp.t: ERROR: line 28: add rule netdev test-netdev egress tcp sport 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 29: add rule netdev test-netdev egress tcp sport != 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 30: add rule netdev test-netdev egress tcp sport { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 31: add rule netdev test-netdev egress tcp sport != { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 32: add rule netdev test-netdev egress tcp sport vmap { 25:accept, 28:drop }: This rule should not have failed.
+inet/tcp.t: ERROR: line 34: add rule netdev test-netdev egress tcp sport 8080 drop: This rule should not have failed.
+inet/tcp.t: ERROR: line 35: add rule netdev test-netdev egress tcp sport 1024 tcp dport 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 36: add rule netdev test-netdev egress tcp sport 1024 tcp dport 22 tcp sequence 0: This rule should not have failed.
+inet/tcp.t: ERROR: line 38: add rule netdev test-netdev egress tcp sequence 0 tcp sport 1024 tcp dport 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 39: add rule netdev test-netdev egress tcp sequence 0 tcp sport { 1024, 1022} tcp dport 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 41: add rule netdev test-netdev egress tcp sequence 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 42: add rule netdev test-netdev egress tcp sequence != 233: This rule should not have failed.
+inet/tcp.t: ERROR: line 43: add rule netdev test-netdev egress tcp sequence 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 44: add rule netdev test-netdev egress tcp sequence != 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 45: add rule netdev test-netdev egress tcp sequence { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 46: add rule netdev test-netdev egress tcp sequence != { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 48: add rule netdev test-netdev egress tcp ackseq 42949672 drop: This rule should not have failed.
+inet/tcp.t: ERROR: line 49: add rule netdev test-netdev egress tcp ackseq 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 50: add rule netdev test-netdev egress tcp ackseq != 233: This rule should not have failed.
+inet/tcp.t: ERROR: line 51: add rule netdev test-netdev egress tcp ackseq 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 52: add rule netdev test-netdev egress tcp ackseq != 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 53: add rule netdev test-netdev egress tcp ackseq { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 54: add rule netdev test-netdev egress tcp ackseq != { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 66: add rule netdev test-netdev egress tcp flags { fin, syn, rst, psh, ack, urg, ecn, cwr} drop: This rule should not have failed.
+inet/tcp.t: ERROR: line 67: add rule netdev test-netdev egress tcp flags != { fin, urg, ecn, cwr} drop: This rule should not have failed.
+inet/tcp.t: ERROR: line 68: add rule netdev test-netdev egress tcp flags cwr: This rule should not have failed.
+inet/tcp.t: ERROR: line 69: add rule netdev test-netdev egress tcp flags != cwr: This rule should not have failed.
+inet/tcp.t: ERROR: line 70: add rule netdev test-netdev egress tcp flags == syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 71: add rule netdev test-netdev egress tcp flags fin,syn / fin,syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 72: add rule netdev test-netdev egress tcp flags != syn / fin,syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 73: add rule netdev test-netdev egress tcp flags & syn != 0: This rule should not have failed.
+inet/tcp.t: ERROR: line 74: add rule netdev test-netdev egress tcp flags & syn == 0: This rule should not have failed.
+inet/tcp.t: ERROR: line 75: add rule netdev test-netdev egress tcp flags & (syn | ack) != 0: This rule should not have failed.
+inet/tcp.t: ERROR: line 76: add rule netdev test-netdev egress tcp flags & (syn | ack) == 0: This rule should not have failed.
+inet/tcp.t: ERROR: line 78: add rule netdev test-netdev egress tcp flags & syn == syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 79: add rule netdev test-netdev egress tcp flags & syn != syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 80: add rule netdev test-netdev egress tcp flags & (fin | syn | rst | ack) syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 81: add rule netdev test-netdev egress tcp flags & (fin | syn | rst | ack) == syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 82: add rule netdev test-netdev egress tcp flags & (fin | syn | rst | ack) != syn: This rule should not have failed.
+inet/tcp.t: ERROR: line 83: add rule netdev test-netdev egress tcp flags & (fin | syn | rst | ack) == (syn | ack): This rule should not have failed.
+inet/tcp.t: ERROR: line 84: add rule netdev test-netdev egress tcp flags & (fin | syn | rst | ack) != (syn | ack): This rule should not have failed.
+inet/tcp.t: ERROR: line 85: add rule netdev test-netdev egress tcp flags & (syn | ack) == (syn | ack): This rule should not have failed.
+inet/tcp.t: ERROR: line 86: add rule netdev test-netdev egress tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr: This rule should not have failed.
+inet/tcp.t: ERROR: line 87: add rule netdev test-netdev egress tcp flags { syn, syn | ack }: This rule should not have failed.
+inet/tcp.t: ERROR: line 88: add rule netdev test-netdev egress tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }: This rule should not have failed.
+inet/tcp.t: ERROR: line 89: add rule netdev test-netdev egress tcp flags ! fin,rst: This rule should not have failed.
+inet/tcp.t: ERROR: line 92: add rule netdev test-netdev egress tcp window 22222: This rule should not have failed.
+inet/tcp.t: ERROR: line 93: add rule netdev test-netdev egress tcp window 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 94: add rule netdev test-netdev egress tcp window != 233: This rule should not have failed.
+inet/tcp.t: ERROR: line 95: add rule netdev test-netdev egress tcp window 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 96: add rule netdev test-netdev egress tcp window != 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 97: add rule netdev test-netdev egress tcp window { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 98: add rule netdev test-netdev egress tcp window != { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 100: add rule netdev test-netdev egress tcp checksum 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 101: add rule netdev test-netdev egress tcp checksum != 233: This rule should not have failed.
+inet/tcp.t: ERROR: line 102: add rule netdev test-netdev egress tcp checksum 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 103: add rule netdev test-netdev egress tcp checksum != 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 104: add rule netdev test-netdev egress tcp checksum { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 105: add rule netdev test-netdev egress tcp checksum != { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 107: add rule netdev test-netdev egress tcp urgptr 1234 accept: This rule should not have failed.
+inet/tcp.t: ERROR: line 108: add rule netdev test-netdev egress tcp urgptr 22: This rule should not have failed.
+inet/tcp.t: ERROR: line 109: add rule netdev test-netdev egress tcp urgptr != 233: This rule should not have failed.
+inet/tcp.t: ERROR: line 110: add rule netdev test-netdev egress tcp urgptr 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 111: add rule netdev test-netdev egress tcp urgptr != 33-45: This rule should not have failed.
+inet/tcp.t: ERROR: line 112: add rule netdev test-netdev egress tcp urgptr { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 113: add rule netdev test-netdev egress tcp urgptr != { 33, 55, 67, 88}: This rule should not have failed.
+inet/tcp.t: ERROR: line 115: add rule netdev test-netdev egress tcp doff 8: This rule should not have failed.
+inet/tcp.t: ERROR: line 115: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/icmp.t: OK
+inet/socket.t: OK
+inet/udplite.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/udplite.t: ERROR: line 10: add rule netdev test-netdev egress udplite sport 80 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 11: add rule netdev test-netdev egress udplite sport != 60 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 12: add rule netdev test-netdev egress udplite sport 50-70 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 13: add rule netdev test-netdev egress udplite sport != 50-60 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 14: add rule netdev test-netdev egress udplite sport { 49, 50} drop: This rule should not have failed.
+inet/udplite.t: ERROR: line 15: add rule netdev test-netdev egress udplite sport != { 49, 50} accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 17: add rule netdev test-netdev egress udplite dport 80 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 18: add rule netdev test-netdev egress udplite dport != 60 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 19: add rule netdev test-netdev egress udplite dport 70-75 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 20: add rule netdev test-netdev egress udplite dport != 50-60 accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 21: add rule netdev test-netdev egress udplite dport { 49, 50} drop: This rule should not have failed.
+inet/udplite.t: ERROR: line 22: add rule netdev test-netdev egress udplite dport != { 49, 50} accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 31: add rule netdev test-netdev egress udplite checksum 6666 drop: This rule should not have failed.
+inet/udplite.t: ERROR: line 32: add rule netdev test-netdev egress udplite checksum != { 444, 555} accept: This rule should not have failed.
+inet/udplite.t: ERROR: line 33: add rule netdev test-netdev egress udplite checksum 22: This rule should not have failed.
+inet/udplite.t: ERROR: line 34: add rule netdev test-netdev egress udplite checksum != 233: This rule should not have failed.
+inet/udplite.t: ERROR: line 35: add rule netdev test-netdev egress udplite checksum 33-45: This rule should not have failed.
+inet/udplite.t: ERROR: line 36: add rule netdev test-netdev egress udplite checksum != 33-45: This rule should not have failed.
+inet/udplite.t: ERROR: line 37: add rule netdev test-netdev egress udplite checksum { 33, 55, 67, 88}: This rule should not have failed.
+inet/udplite.t: ERROR: line 38: add rule netdev test-netdev egress udplite checksum != { 33, 55, 67, 88}: This rule should not have failed.
+inet/udplite.t: ERROR: line 38: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/dccp.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/dccp.t: ERROR: line 10: add rule netdev test-netdev egress dccp sport 21-35: This rule should not have failed.
+inet/dccp.t: ERROR: line 11: add rule netdev test-netdev egress dccp sport != 21-35: This rule should not have failed.
+inet/dccp.t: ERROR: line 12: add rule netdev test-netdev egress dccp sport {23, 24, 25}: This rule should not have failed.
+inet/dccp.t: ERROR: line 13: add rule netdev test-netdev egress dccp sport != {23, 24, 25}: This rule should not have failed.
+inet/dccp.t: ERROR: line 15: add rule netdev test-netdev egress dccp sport 20-50: This rule should not have failed.
+inet/dccp.t: ERROR: line 19: add rule netdev test-netdev egress dccp dport {23, 24, 25}: This rule should not have failed.
+inet/dccp.t: ERROR: line 20: add rule netdev test-netdev egress dccp dport != {23, 24, 25}: This rule should not have failed.
+inet/dccp.t: ERROR: line 22: add rule netdev test-netdev egress dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}: This rule should not have failed.
+inet/dccp.t: ERROR: line 23: add rule netdev test-netdev egress dccp type != {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}: This rule should not have failed.
+inet/dccp.t: ERROR: line 24: add rule netdev test-netdev egress dccp type request: This rule should not have failed.
+inet/dccp.t: ERROR: line 25: add rule netdev test-netdev egress dccp type != request: This rule should not have failed.
+inet/dccp.t: ERROR: line 27: add rule ip test-ip4 input dccp option 0 exists: This rule should not have failed.
+inet/dccp.t: ERROR: line 28: add rule ip test-ip4 input dccp option 43 missing: This rule should not have failed.
+inet/dccp.t: ERROR: line 29: add rule ip test-ip4 input dccp option 255 exists: This rule should not have failed.
+inet/dccp.t: ERROR: line 30: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/tproxy.t: OK
+inet/ether.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/ether.t: ERROR: line 11: add rule netdev test-netdev egress tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept: This rule should not have failed.
+inet/ether.t: ERROR: line 12: add rule netdev test-netdev egress tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept: This rule should not have failed.
+inet/ether.t: ERROR: line 14: add rule netdev test-netdev egress ether saddr 00:0f:54:0c:11:04 accept: This rule should not have failed.
+inet/ether.t: ERROR: line 16: add rule netdev test-netdev egress vlan id 1: This rule should not have failed.
+inet/ether.t: ERROR: line 17: add rule netdev test-netdev egress ether type vlan vlan id 2: This rule should not have failed.
+inet/ether.t: ERROR: line 20: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/synproxy.t: OK
+inet/sctp.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/sctp.t: ERROR: line 10: add rule netdev test-netdev egress sctp sport 23: This rule should not have failed.
+inet/sctp.t: ERROR: line 11: add rule netdev test-netdev egress sctp sport != 23: This rule should not have failed.
+inet/sctp.t: ERROR: line 12: add rule netdev test-netdev egress sctp sport 23-44: This rule should not have failed.
+inet/sctp.t: ERROR: line 13: add rule netdev test-netdev egress sctp sport != 23-44: This rule should not have failed.
+inet/sctp.t: ERROR: line 14: add rule netdev test-netdev egress sctp sport { 23, 24, 25}: This rule should not have failed.
+inet/sctp.t: ERROR: line 15: add rule netdev test-netdev egress sctp sport != { 23, 24, 25}: This rule should not have failed.
+inet/sctp.t: ERROR: line 17: add rule netdev test-netdev egress sctp dport 23: This rule should not have failed.
+inet/sctp.t: ERROR: line 18: add rule netdev test-netdev egress sctp dport != 23: This rule should not have failed.
+inet/sctp.t: ERROR: line 19: add rule netdev test-netdev egress sctp dport 23-44: This rule should not have failed.
+inet/sctp.t: ERROR: line 20: add rule netdev test-netdev egress sctp dport != 23-44: This rule should not have failed.
+inet/sctp.t: ERROR: line 21: add rule netdev test-netdev egress sctp dport { 23, 24, 25}: This rule should not have failed.
+inet/sctp.t: ERROR: line 22: add rule netdev test-netdev egress sctp dport != { 23, 24, 25}: This rule should not have failed.
+inet/sctp.t: ERROR: line 24: add rule netdev test-netdev egress sctp checksum 1111: This rule should not have failed.
+inet/sctp.t: ERROR: line 25: add rule netdev test-netdev egress sctp checksum != 11: This rule should not have failed.
+inet/sctp.t: ERROR: line 26: add rule netdev test-netdev egress sctp checksum 21-333: This rule should not have failed.
+inet/sctp.t: ERROR: line 27: add rule netdev test-netdev egress sctp checksum != 32-111: This rule should not have failed.
+inet/sctp.t: ERROR: line 28: add rule netdev test-netdev egress sctp checksum { 22, 33, 44}: This rule should not have failed.
+inet/sctp.t: ERROR: line 29: add rule netdev test-netdev egress sctp checksum != { 22, 33, 44}: This rule should not have failed.
+inet/sctp.t: ERROR: line 31: add rule netdev test-netdev egress sctp vtag 22: This rule should not have failed.
+inet/sctp.t: ERROR: line 32: add rule netdev test-netdev egress sctp vtag != 233: This rule should not have failed.
+inet/sctp.t: ERROR: line 33: add rule netdev test-netdev egress sctp vtag 33-45: This rule should not have failed.
+inet/sctp.t: ERROR: line 34: add rule netdev test-netdev egress sctp vtag != 33-45: This rule should not have failed.
+inet/sctp.t: ERROR: line 35: add rule netdev test-netdev egress sctp vtag {33, 55, 67, 88}: This rule should not have failed.
+inet/sctp.t: ERROR: line 36: add rule netdev test-netdev egress sctp vtag != {33, 55, 67, 88}: This rule should not have failed.
+inet/sctp.t: ERROR: line 39: add rule ip test-ip4 input sctp chunk data exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 40: add rule ip test-ip4 input sctp chunk init exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 41: add rule ip test-ip4 input sctp chunk init-ack exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 42: add rule ip test-ip4 input sctp chunk sack exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 43: add rule ip test-ip4 input sctp chunk heartbeat exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 44: add rule ip test-ip4 input sctp chunk heartbeat-ack exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 45: add rule ip test-ip4 input sctp chunk abort exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 46: add rule ip test-ip4 input sctp chunk shutdown exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 47: add rule ip test-ip4 input sctp chunk shutdown-ack exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 48: add rule ip test-ip4 input sctp chunk error exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 49: add rule ip test-ip4 input sctp chunk cookie-echo exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 50: add rule ip test-ip4 input sctp chunk cookie-ack exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 51: add rule ip test-ip4 input sctp chunk ecne exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 52: add rule ip test-ip4 input sctp chunk cwr exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 53: add rule ip test-ip4 input sctp chunk shutdown-complete exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 54: add rule ip test-ip4 input sctp chunk asconf-ack exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 55: add rule ip test-ip4 input sctp chunk forward-tsn exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 56: add rule ip test-ip4 input sctp chunk asconf exists: This rule should not have failed.
+inet/sctp.t: ERROR: line 59: add rule ip test-ip4 input sctp chunk data type 0: This rule should not have failed.
+inet/sctp.t: ERROR: line 60: add rule ip test-ip4 input sctp chunk init flags 23: This rule should not have failed.
+inet/sctp.t: ERROR: line 61: add rule ip test-ip4 input sctp chunk init-ack length 42: This rule should not have failed.
+inet/sctp.t: ERROR: line 64: add rule ip test-ip4 input sctp chunk data stream 1337: This rule should not have failed.
+inet/sctp.t: ERROR: line 65: add rule ip test-ip4 input sctp chunk init initial-tsn 5: This rule should not have failed.
+inet/sctp.t: ERROR: line 66: add rule ip test-ip4 input sctp chunk init-ack num-outbound-streams 3: This rule should not have failed.
+inet/sctp.t: ERROR: line 67: add rule ip test-ip4 input sctp chunk sack a-rwnd 1: This rule should not have failed.
+inet/sctp.t: ERROR: line 68: add rule ip test-ip4 input sctp chunk shutdown cum-tsn-ack 65535: This rule should not have failed.
+inet/sctp.t: ERROR: line 69: add rule ip test-ip4 input sctp chunk ecne lowest-tsn 5: This rule should not have failed.
+inet/sctp.t: ERROR: line 70: add rule ip test-ip4 input sctp chunk cwr lowest-tsn 8: This rule should not have failed.
+inet/sctp.t: ERROR: line 71: add rule ip test-ip4 input sctp chunk asconf-ack seqno 12345: This rule should not have failed.
+inet/sctp.t: ERROR: line 72: add rule ip test-ip4 input sctp chunk forward-tsn new-cum-tsn 31337: This rule should not have failed.
+inet/sctp.t: ERROR: line 73: add rule ip test-ip4 input sctp chunk asconf seqno 12345: This rule should not have failed.
+inet/sctp.t: ERROR: line 73: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/map.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/map.t: ERROR: line 9: add rule netdev test-netdev egress mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017}: This rule should not have failed.
+inet/map.t: ERROR: line 10: add rule netdev test-netdev egress mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001}: This rule should not have failed.
+inet/map.t: ERROR: line 10: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/ip_tcp.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/ip_tcp.t: ERROR: line 10: add rule netdev test-netdev egress ip protocol tcp tcp dport 22: This rule should not have failed.
+inet/ip_tcp.t: ERROR: line 13: add rule netdev test-netdev egress ip protocol tcp ip saddr 1.2.3.4 tcp dport 22: This rule should not have failed.
+inet/ip_tcp.t: ERROR: line 16: add rule netdev test-netdev egress ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22: This rule should not have failed.
+inet/ip_tcp.t: ERROR: line 19: add rule netdev test-netdev egress ip protocol tcp counter tcp dport 22: This rule should not have failed.
+inet/ip_tcp.t: ERROR: line 21: add rule netdev test-netdev egress ether type ip tcp dport 22: This rule should not have failed.
+inet/ip_tcp.t: ERROR: line 21: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/fib.t: OK
+inet/vxlan.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/vxlan.t: ERROR: line 11: add rule ip test-ip4 input udp dport 4789 vxlan vni 10: This rule should not have failed.
+inet/vxlan.t: ERROR: line 12: add rule ip test-ip4 input udp dport 4789 vxlan ip saddr 10.141.11.2: This rule should not have failed.
+inet/vxlan.t: ERROR: line 13: add rule ip test-ip4 input udp dport 4789 vxlan ip saddr 10.141.11.0/24: This rule should not have failed.
+inet/vxlan.t: ERROR: line 14: add rule ip test-ip4 input udp dport 4789 vxlan ip protocol 1: This rule should not have failed.
+inet/vxlan.t: ERROR: line 15: add rule ip test-ip4 input udp dport 4789 vxlan udp sport 8888: This rule should not have failed.
+inet/vxlan.t: ERROR: line 16: add rule ip test-ip4 input udp dport 4789 vxlan icmp type echo-reply: This rule should not have failed.
+inet/vxlan.t: ERROR: line 17: add rule ip test-ip4 input udp dport 4789 vxlan ether saddr 62:87:4d:d6:19:05: This rule should not have failed.
+inet/vxlan.t: ERROR: line 18: add rule ip test-ip4 input udp dport 4789 vxlan vlan id 10: This rule should not have failed.
+inet/vxlan.t: ERROR: line 19: add rule ip test-ip4 input udp dport 4789 vxlan ip dscp 0x02: This rule should not have failed.
+inet/vxlan.t: ERROR: line 20: add rule ip test-ip4 input udp dport 4789 vxlan ip dscp 0x02: This rule should not have failed.
+inet/vxlan.t: ERROR: line 21: add rule ip test-ip4 input udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.2.3.4 . 4.3.2.1 }: This rule should not have failed.
+inet/vxlan.t: ERROR: line 23: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/ah.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/ah.t: ERROR: line 22: add rule netdev test-netdev egress ah hdrlength 11-23: This rule should not have failed.
+inet/ah.t: ERROR: line 23: add rule netdev test-netdev egress ah hdrlength != 11-23: This rule should not have failed.
+inet/ah.t: ERROR: line 24: add rule netdev test-netdev egress ah hdrlength {11, 23, 44 }: This rule should not have failed.
+inet/ah.t: ERROR: line 25: add rule netdev test-netdev egress ah hdrlength != {11, 23, 44 }: This rule should not have failed.
+inet/ah.t: ERROR: line 27: add rule netdev test-netdev egress ah reserved 22: This rule should not have failed.
+inet/ah.t: ERROR: line 28: add rule netdev test-netdev egress ah reserved != 233: This rule should not have failed.
+inet/ah.t: ERROR: line 29: add rule netdev test-netdev egress ah reserved 33-45: This rule should not have failed.
+inet/ah.t: ERROR: line 30: add rule netdev test-netdev egress ah reserved != 33-45: This rule should not have failed.
+inet/ah.t: ERROR: line 31: add rule netdev test-netdev egress ah reserved {23, 100}: This rule should not have failed.
+inet/ah.t: ERROR: line 32: add rule netdev test-netdev egress ah reserved != {23, 100}: This rule should not have failed.
+inet/ah.t: ERROR: line 34: add rule netdev test-netdev egress ah spi 111: This rule should not have failed.
+inet/ah.t: ERROR: line 35: add rule netdev test-netdev egress ah spi != 111: This rule should not have failed.
+inet/ah.t: ERROR: line 36: add rule netdev test-netdev egress ah spi 111-222: This rule should not have failed.
+inet/ah.t: ERROR: line 37: add rule netdev test-netdev egress ah spi != 111-222: This rule should not have failed.
+inet/ah.t: ERROR: line 38: add rule netdev test-netdev egress ah spi {111, 122}: This rule should not have failed.
+inet/ah.t: ERROR: line 39: add rule netdev test-netdev egress ah spi != {111, 122}: This rule should not have failed.
+inet/ah.t: ERROR: line 42: add rule netdev test-netdev egress ah sequence 123: This rule should not have failed.
+inet/ah.t: ERROR: line 43: add rule netdev test-netdev egress ah sequence != 123: This rule should not have failed.
+inet/ah.t: ERROR: line 44: add rule netdev test-netdev egress ah sequence {23, 25, 33}: This rule should not have failed.
+inet/ah.t: ERROR: line 45: add rule netdev test-netdev egress ah sequence != {23, 25, 33}: This rule should not have failed.
+inet/ah.t: ERROR: line 46: add rule netdev test-netdev egress ah sequence 23-33: This rule should not have failed.
+inet/ah.t: ERROR: line 47: add rule netdev test-netdev egress ah sequence != 23-33: This rule should not have failed.
+inet/ah.t: ERROR: line 47: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/dnat.t: OK
+inet/esp.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/esp.t: ERROR: line 10: add rule netdev test-netdev egress esp spi 100: This rule should not have failed.
+inet/esp.t: ERROR: line 11: add rule netdev test-netdev egress esp spi != 100: This rule should not have failed.
+inet/esp.t: ERROR: line 12: add rule netdev test-netdev egress esp spi 111-222: This rule should not have failed.
+inet/esp.t: ERROR: line 13: add rule netdev test-netdev egress esp spi != 111-222: This rule should not have failed.
+inet/esp.t: ERROR: line 14: add rule netdev test-netdev egress esp spi { 100, 102}: This rule should not have failed.
+inet/esp.t: ERROR: line 15: add rule netdev test-netdev egress esp spi != { 100, 102}: This rule should not have failed.
+inet/esp.t: ERROR: line 17: add rule netdev test-netdev egress esp sequence 22: This rule should not have failed.
+inet/esp.t: ERROR: line 18: add rule netdev test-netdev egress esp sequence 22-24: This rule should not have failed.
+inet/esp.t: ERROR: line 19: add rule netdev test-netdev egress esp sequence != 22-24: This rule should not have failed.
+inet/esp.t: ERROR: line 20: add rule netdev test-netdev egress esp sequence { 22, 24}: This rule should not have failed.
+inet/esp.t: ERROR: line 21: add rule netdev test-netdev egress esp sequence != { 22, 24}: This rule should not have failed.
+inet/esp.t: ERROR: line 21: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/geneve.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/geneve.t: ERROR: line 11: add rule ip test-ip4 input udp dport 6081 geneve vni 10: This rule should not have failed.
+inet/geneve.t: ERROR: line 12: add rule ip test-ip4 input udp dport 6081 geneve ip saddr 10.141.11.2: This rule should not have failed.
+inet/geneve.t: ERROR: line 13: add rule ip test-ip4 input udp dport 6081 geneve ip saddr 10.141.11.0/24: This rule should not have failed.
+inet/geneve.t: ERROR: line 14: add rule ip test-ip4 input udp dport 6081 geneve ip protocol 1: This rule should not have failed.
+inet/geneve.t: ERROR: line 15: add rule ip test-ip4 input udp dport 6081 geneve udp sport 8888: This rule should not have failed.
+inet/geneve.t: ERROR: line 16: add rule ip test-ip4 input udp dport 6081 geneve icmp type echo-reply: This rule should not have failed.
+inet/geneve.t: ERROR: line 17: add rule ip test-ip4 input udp dport 6081 geneve ether saddr 62:87:4d:d6:19:05: This rule should not have failed.
+inet/geneve.t: ERROR: line 18: add rule ip test-ip4 input udp dport 6081 geneve vlan id 10: This rule should not have failed.
+inet/geneve.t: ERROR: line 19: add rule ip test-ip4 input udp dport 6081 geneve ip dscp 0x02: This rule should not have failed.
+inet/geneve.t: ERROR: line 20: add rule ip test-ip4 input udp dport 6081 geneve ip dscp 0x02: This rule should not have failed.
+inet/geneve.t: ERROR: line 21: add rule ip test-ip4 input udp dport 6081 geneve ip saddr . geneve ip daddr { 1.2.3.4 . 4.3.2.1 }: This rule should not have failed.
+inet/geneve.t: ERROR: line 23: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/udp.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/udp.t: ERROR: line 10: add rule netdev test-netdev egress udp sport 80 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 11: add rule netdev test-netdev egress udp sport != 60 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 12: add rule netdev test-netdev egress udp sport 50-70 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 13: add rule netdev test-netdev egress udp sport != 50-60 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 14: add rule netdev test-netdev egress udp sport { 49, 50} drop: This rule should not have failed.
+inet/udp.t: ERROR: line 15: add rule netdev test-netdev egress udp sport != { 50, 60} accept: This rule should not have failed.
+inet/udp.t: ERROR: line 19: add rule netdev test-netdev egress udp dport 80 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 20: add rule netdev test-netdev egress udp dport != 60 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 21: add rule netdev test-netdev egress udp dport 70-75 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 22: add rule netdev test-netdev egress udp dport != 50-60 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 23: add rule netdev test-netdev egress udp dport { 49, 50} drop: This rule should not have failed.
+inet/udp.t: ERROR: line 24: add rule netdev test-netdev egress udp dport != { 50, 60} accept: This rule should not have failed.
+inet/udp.t: ERROR: line 26: add rule netdev test-netdev egress udp length 6666: This rule should not have failed.
+inet/udp.t: ERROR: line 27: add rule netdev test-netdev egress udp length != 6666: This rule should not have failed.
+inet/udp.t: ERROR: line 28: add rule netdev test-netdev egress udp length 50-65 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 29: add rule netdev test-netdev egress udp length != 50-65 accept: This rule should not have failed.
+inet/udp.t: ERROR: line 30: add rule netdev test-netdev egress udp length { 50, 65} accept: This rule should not have failed.
+inet/udp.t: ERROR: line 31: add rule netdev test-netdev egress udp length != { 50, 65} accept: This rule should not have failed.
+inet/udp.t: ERROR: line 33: add rule netdev test-netdev egress udp checksum 6666 drop: This rule should not have failed.
+inet/udp.t: ERROR: line 34: add rule netdev test-netdev egress udp checksum != { 444, 555} accept: This rule should not have failed.
+inet/udp.t: ERROR: line 36: add rule netdev test-netdev egress udp checksum 22: This rule should not have failed.
+inet/udp.t: ERROR: line 37: add rule netdev test-netdev egress udp checksum != 233: This rule should not have failed.
+inet/udp.t: ERROR: line 38: add rule netdev test-netdev egress udp checksum 33-45: This rule should not have failed.
+inet/udp.t: ERROR: line 39: add rule netdev test-netdev egress udp checksum != 33-45: This rule should not have failed.
+inet/udp.t: ERROR: line 40: add rule netdev test-netdev egress udp checksum { 33, 55, 67, 88}: This rule should not have failed.
+inet/udp.t: ERROR: line 41: add rule netdev test-netdev egress udp checksum != { 33, 55, 67, 88}: This rule should not have failed.
+inet/udp.t: ERROR: line 44: add rule netdev test-netdev egress iif "lo" udp checksum set 0: This rule should not have failed.
+inet/udp.t: ERROR: line 45: add rule netdev test-netdev egress iif "lo" udp dport set 65535: This rule should not have failed.
+inet/udp.t: ERROR: line 45: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/sets.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/sets.t: ERROR: line 15: add rule netdev test-netdev egress ip saddr @set1 drop: This rule should not have failed.
+inet/sets.t: ERROR: line 18: add rule netdev test-netdev egress ip6 daddr != @set2 accept: This rule should not have failed.
+inet/sets.t: ERROR: line 24: add rule netdev test-netdev egress ip saddr . ip daddr . tcp dport @set3 accept: This rule should not have failed.
+inet/sets.t: ERROR: line 25: add rule netdev test-netdev egress ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept: This rule should not have failed.
+inet/sets.t: ERROR: line 25: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/gretap.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/gretap.t: ERROR: line 10: add rule ip test-ip4 input gretap ip saddr 10.141.11.2: This rule should not have failed.
+inet/gretap.t: ERROR: line 11: add rule ip test-ip4 input gretap ip saddr 10.141.11.0/24: This rule should not have failed.
+inet/gretap.t: ERROR: line 12: add rule ip test-ip4 input gretap ip protocol 1: This rule should not have failed.
+inet/gretap.t: ERROR: line 13: add rule ip test-ip4 input gretap udp sport 8888: This rule should not have failed.
+inet/gretap.t: ERROR: line 14: add rule ip test-ip4 input gretap icmp type echo-reply: This rule should not have failed.
+inet/gretap.t: ERROR: line 15: add rule ip test-ip4 input gretap ether saddr 62:87:4d:d6:19:05: This rule should not have failed.
+inet/gretap.t: ERROR: line 16: add rule ip test-ip4 input gretap vlan id 10: This rule should not have failed.
+inet/gretap.t: ERROR: line 17: add rule ip test-ip4 input gretap ip dscp 0x02: This rule should not have failed.
+inet/gretap.t: ERROR: line 18: add rule ip test-ip4 input gretap ip dscp 0x02: This rule should not have failed.
+inet/gretap.t: ERROR: line 19: add rule ip test-ip4 input gretap ip saddr . gretap ip daddr { 1.2.3.4 . 4.3.2.1 }: This rule should not have failed.
+inet/gretap.t: ERROR: line 21: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/osf.t: OK
+inet/gre.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/gre.t: ERROR: line 10: add rule netdev test-netdev egress gre version 0: This rule should not have failed.
+inet/gre.t: ERROR: line 11: add rule ip test-ip4 input gre ip saddr 10.141.11.2: This rule should not have failed.
+inet/gre.t: ERROR: line 12: add rule ip test-ip4 input gre ip saddr 10.141.11.0/24: This rule should not have failed.
+inet/gre.t: ERROR: line 13: add rule ip test-ip4 input gre ip protocol 1: This rule should not have failed.
+inet/gre.t: ERROR: line 14: add rule ip test-ip4 input gre udp sport 8888: This rule should not have failed.
+inet/gre.t: ERROR: line 15: add rule ip test-ip4 input gre icmp type echo-reply: This rule should not have failed.
+inet/gre.t: ERROR: line 18: add rule ip test-ip4 input gre ip dscp 0x02: This rule should not have failed.
+inet/gre.t: ERROR: line 19: add rule ip test-ip4 input gre ip dscp 0x02: This rule should not have failed.
+inet/gre.t: ERROR: line 20: add rule ip test-ip4 input gre ip saddr . gre ip daddr { 1.2.3.4 . 4.3.2.1 }: This rule should not have failed.
+inet/gre.t: ERROR: line 22: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/comp.t: ERROR: line 3: I cannot create the chain 'egress'
+inet/comp.t: ERROR: line 12: add rule netdev test-netdev egress comp nexthdr != esp: This rule should not have failed.
+inet/comp.t: ERROR: line 18: add rule netdev test-netdev egress comp flags 0x0: This rule should not have failed.
+inet/comp.t: ERROR: line 19: add rule netdev test-netdev egress comp flags != 0x23: This rule should not have failed.
+inet/comp.t: ERROR: line 20: add rule netdev test-netdev egress comp flags 0x33-0x45: This rule should not have failed.
+inet/comp.t: ERROR: line 21: add rule netdev test-netdev egress comp flags != 0x33-0x45: This rule should not have failed.
+inet/comp.t: ERROR: line 22: add rule netdev test-netdev egress comp flags {0x33, 0x55, 0x67, 0x88}: This rule should not have failed.
+inet/comp.t: ERROR: line 23: add rule netdev test-netdev egress comp flags != {0x33, 0x55, 0x67, 0x88}: This rule should not have failed.
+inet/comp.t: ERROR: line 25: add rule netdev test-netdev egress comp cpi 22: This rule should not have failed.
+inet/comp.t: ERROR: line 26: add rule netdev test-netdev egress comp cpi != 233: This rule should not have failed.
+inet/comp.t: ERROR: line 27: add rule netdev test-netdev egress comp cpi 33-45: This rule should not have failed.
+inet/comp.t: ERROR: line 28: add rule netdev test-netdev egress comp cpi != 33-45: This rule should not have failed.
+inet/comp.t: ERROR: line 29: add rule netdev test-netdev egress comp cpi {33, 55, 67, 88}: This rule should not have failed.
+inet/comp.t: ERROR: line 30: add rule netdev test-netdev egress comp cpi != {33, 55, 67, 88}: This rule should not have failed.
+inet/comp.t: ERROR: line 30: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+inet/reject.t: OK
+ip/meta.t: OK
+ip/snat.t: OK
+ip/masquerade.t: OK
+ip/redirect.t: OK
+ip/rt.t: OK
+ip/ct.t: OK
+ip/hash.t: OK
+ip/ip.t: ERROR: line 3: I cannot create the chain 'egress'
+ip/ip.t: ERROR: line 28: add rule netdev test-netdev egress ip dscp cs1: This rule should not have failed.
+ip/ip.t: ERROR: line 29: add rule netdev test-netdev egress ip dscp != cs1: This rule should not have failed.
+ip/ip.t: ERROR: line 30: add rule netdev test-netdev egress ip dscp 0x38: This rule should not have failed.
+ip/ip.t: ERROR: line 31: add rule netdev test-netdev egress ip dscp != 0x20: This rule should not have failed.
+ip/ip.t: ERROR: line 32: add rule netdev test-netdev egress ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}: This rule should not have failed.
+ip/ip.t: ERROR: line 34: add rule netdev test-netdev egress ip dscp != {cs0, cs3}: This rule should not have failed.
+ip/ip.t: ERROR: line 35: add rule netdev test-netdev egress ip dscp vmap { cs1 : continue , cs4 : accept } counter: This rule should not have failed.
+ip/ip.t: ERROR: line 37: add rule netdev test-netdev egress ip length 232: This rule should not have failed.
+ip/ip.t: ERROR: line 38: add rule netdev test-netdev egress ip length != 233: This rule should not have failed.
+ip/ip.t: ERROR: line 39: add rule netdev test-netdev egress ip length 333-435: This rule should not have failed.
+ip/ip.t: ERROR: line 40: add rule netdev test-netdev egress ip length != 333-453: This rule should not have failed.
+ip/ip.t: ERROR: line 41: add rule netdev test-netdev egress ip length { 333, 553, 673, 838}: This rule should not have failed.
+ip/ip.t: ERROR: line 42: add rule netdev test-netdev egress ip length != { 333, 553, 673, 838}: This rule should not have failed.
+ip/ip.t: ERROR: line 44: add rule netdev test-netdev egress ip id 22: This rule should not have failed.
+ip/ip.t: ERROR: line 45: add rule netdev test-netdev egress ip id != 233: This rule should not have failed.
+ip/ip.t: ERROR: line 46: add rule netdev test-netdev egress ip id 33-45: This rule should not have failed.
+ip/ip.t: ERROR: line 47: add rule netdev test-netdev egress ip id != 33-45: This rule should not have failed.
+ip/ip.t: ERROR: line 48: add rule netdev test-netdev egress ip id { 33, 55, 67, 88}: This rule should not have failed.
+ip/ip.t: ERROR: line 49: add rule netdev test-netdev egress ip id != { 33, 55, 67, 88}: This rule should not have failed.
+ip/ip.t: ERROR: line 51: add rule netdev test-netdev egress ip frag-off 222 accept: This rule should not have failed.
+ip/ip.t: ERROR: line 52: add rule netdev test-netdev egress ip frag-off != 233: This rule should not have failed.
+ip/ip.t: ERROR: line 53: add rule netdev test-netdev egress ip frag-off 33-45: This rule should not have failed.
+ip/ip.t: ERROR: line 54: add rule netdev test-netdev egress ip frag-off != 33-45: This rule should not have failed.
+ip/ip.t: ERROR: line 55: add rule netdev test-netdev egress ip frag-off { 33, 55, 67, 88}: This rule should not have failed.
+ip/ip.t: ERROR: line 56: add rule netdev test-netdev egress ip frag-off != { 33, 55, 67, 88}: This rule should not have failed.
+ip/ip.t: ERROR: line 58: add rule netdev test-netdev egress ip ttl 0 drop: This rule should not have failed.
+ip/ip.t: ERROR: line 59: add rule netdev test-netdev egress ip ttl 233: This rule should not have failed.
+ip/ip.t: ERROR: line 60: add rule netdev test-netdev egress ip ttl 33-55: This rule should not have failed.
+ip/ip.t: ERROR: line 61: add rule netdev test-netdev egress ip ttl != 45-50: This rule should not have failed.
+ip/ip.t: ERROR: line 62: add rule netdev test-netdev egress ip ttl {43, 53, 45 }: This rule should not have failed.
+ip/ip.t: ERROR: line 63: add rule netdev test-netdev egress ip ttl != {43, 53, 45 }: This rule should not have failed.
+ip/ip.t: ERROR: line 65: add rule netdev test-netdev egress ip protocol tcp: This rule should not have failed.
+ip/ip.t: ERROR: line 66: add rule netdev test-netdev egress ip protocol != tcp: This rule should not have failed.
+ip/ip.t: ERROR: line 67: add rule netdev test-netdev egress ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept: This rule should not have failed.
+ip/ip.t: ERROR: line 68: add rule netdev test-netdev egress ip protocol != { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept: This rule should not have failed.
+ip/ip.t: ERROR: line 70: add rule netdev test-netdev egress ip protocol 255: This rule should not have failed.
+ip/ip.t: ERROR: line 73: add rule netdev test-netdev egress ip checksum 13172 drop: This rule should not have failed.
+ip/ip.t: ERROR: line 74: add rule netdev test-netdev egress ip checksum 22: This rule should not have failed.
+ip/ip.t: ERROR: line 75: add rule netdev test-netdev egress ip checksum != 233: This rule should not have failed.
+ip/ip.t: ERROR: line 76: add rule netdev test-netdev egress ip checksum 33-45: This rule should not have failed.
+ip/ip.t: ERROR: line 77: add rule netdev test-netdev egress ip checksum != 33-45: This rule should not have failed.
+ip/ip.t: ERROR: line 78: add rule netdev test-netdev egress ip checksum { 33, 55, 67, 88}: This rule should not have failed.
+ip/ip.t: ERROR: line 79: add rule netdev test-netdev egress ip checksum != { 33, 55, 67, 88}: This rule should not have failed.
+ip/ip.t: ERROR: line 83: add rule netdev test-netdev egress ip saddr 192.168.2.0/24: This rule should not have failed.
+ip/ip.t: ERROR: line 84: add rule netdev test-netdev egress ip saddr != 192.168.2.0/24: This rule should not have failed.
+ip/ip.t: ERROR: line 85: add rule netdev test-netdev egress ip saddr 192.168.3.1 ip daddr 192.168.3.100: This rule should not have failed.
+ip/ip.t: ERROR: line 86: add rule netdev test-netdev egress ip saddr != 1.1.1.1: This rule should not have failed.
+ip/ip.t: ERROR: line 87: add rule netdev test-netdev egress ip saddr 1.1.1.1: This rule should not have failed.
+ip/ip.t: ERROR: line 88: add rule netdev test-netdev egress ip daddr 192.168.0.1-192.168.0.250: This rule should not have failed.
+ip/ip.t: ERROR: line 89: add rule netdev test-netdev egress ip daddr 10.0.0.0-10.255.255.255: This rule should not have failed.
+ip/ip.t: ERROR: line 90: add rule netdev test-netdev egress ip daddr 172.16.0.0-172.31.255.255: This rule should not have failed.
+ip/ip.t: ERROR: line 91: add rule netdev test-netdev egress ip daddr 192.168.3.1-192.168.4.250: This rule should not have failed.
+ip/ip.t: ERROR: line 92: add rule netdev test-netdev egress ip daddr != 192.168.0.1-192.168.0.250: This rule should not have failed.
+ip/ip.t: ERROR: line 93: add rule netdev test-netdev egress ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept: This rule should not have failed.
+ip/ip.t: ERROR: line 94: add rule netdev test-netdev egress ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept: This rule should not have failed.
+ip/ip.t: ERROR: line 96: add rule netdev test-netdev egress ip daddr 192.168.1.2-192.168.1.55: This rule should not have failed.
+ip/ip.t: ERROR: line 97: add rule netdev test-netdev egress ip daddr != 192.168.1.2-192.168.1.55: This rule should not have failed.
+ip/ip.t: ERROR: line 98: add rule netdev test-netdev egress ip saddr 192.168.1.3-192.168.33.55: This rule should not have failed.
+ip/ip.t: ERROR: line 99: add rule netdev test-netdev egress ip saddr != 192.168.1.3-192.168.33.55: This rule should not have failed.
+ip/ip.t: ERROR: line 101: add rule netdev test-netdev egress ip daddr 192.168.0.1: This rule should not have failed.
+ip/ip.t: ERROR: line 102: add rule netdev test-netdev egress ip daddr 192.168.0.1 drop: This rule should not have failed.
+ip/ip.t: ERROR: line 103: add rule netdev test-netdev egress ip daddr 192.168.0.2: This rule should not have failed.
+ip/ip.t: ERROR: line 105: add rule netdev test-netdev egress ip saddr & 0xff == 1: This rule should not have failed.
+ip/ip.t: ERROR: line 106: add rule netdev test-netdev egress ip saddr & 0.0.0.255 < 0.0.0.127: This rule should not have failed.
+ip/ip.t: ERROR: line 108: add rule netdev test-netdev egress ip saddr & 0xffff0000 == 0xffff0000: This rule should not have failed.
+ip/ip.t: ERROR: line 110: add rule netdev test-netdev egress ip version 4 ip hdrlength 5: This rule should not have failed.
+ip/ip.t: ERROR: line 111: add rule netdev test-netdev egress ip hdrlength 0: This rule should not have failed.
+ip/ip.t: ERROR: line 112: add rule netdev test-netdev egress ip hdrlength 15: This rule should not have failed.
+ip/ip.t: ERROR: line 113: add rule netdev test-netdev egress ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter: This rule should not have failed.
+ip/ip.t: ERROR: line 117: add rule netdev test-netdev egress iif "lo" ip daddr set 127.0.0.1: This rule should not have failed.
+ip/ip.t: ERROR: line 118: add rule netdev test-netdev egress iif "lo" ip checksum set 0: This rule should not have failed.
+ip/ip.t: ERROR: line 119: add rule netdev test-netdev egress iif "lo" ip id set 0: This rule should not have failed.
+ip/ip.t: ERROR: line 120: add rule netdev test-netdev egress iif "lo" ip ecn set 1: This rule should not have failed.
+ip/ip.t: ERROR: line 121: add rule netdev test-netdev egress iif "lo" ip ecn set ce: This rule should not have failed.
+ip/ip.t: ERROR: line 122: add rule netdev test-netdev egress iif "lo" ip ttl set 23: This rule should not have failed.
+ip/ip.t: ERROR: line 123: add rule netdev test-netdev egress iif "lo" ip protocol set 1: This rule should not have failed.
+ip/ip.t: ERROR: line 125: add rule netdev test-netdev egress iif "lo" ip dscp set af23: This rule should not have failed.
+ip/ip.t: ERROR: line 126: add rule netdev test-netdev egress iif "lo" ip dscp set cs0: This rule should not have failed.
+ip/ip.t: ERROR: line 128: add rule netdev test-netdev egress ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }: This rule should not have failed.
+ip/ip.t: ERROR: line 129: add rule netdev test-netdev egress ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }: This rule should not have failed.
+ip/ip.t: ERROR: line 129: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+ip/igmp.t: OK
+ip/tcp.t: OK
+ip/icmp.t: OK
+ip/flowtable.t: OK
+ip/dup.t: OK
+ip/tproxy.t: OK
+ip/ether.t: OK
+ip/objects.t: OK
+ip/ip_tcp.t: OK
+ip/dnat.t: OK
+ip/sets.t: ERROR: line 3: I cannot create the chain 'egress'
+ip/sets.t: ERROR: line 32: add rule netdev test-netdev egress ip saddr @set1 drop: This rule should not have failed.
+ip/sets.t: ERROR: line 33: add rule netdev test-netdev egress ip saddr != @set1 drop: This rule should not have failed.
+ip/sets.t: ERROR: line 34: add rule netdev test-netdev egress ip saddr @set2 drop: This rule should not have failed.
+ip/sets.t: ERROR: line 35: add rule netdev test-netdev egress ip saddr != @set2 drop: This rule should not have failed.
+ip/sets.t: ERROR: line 52: add rule netdev test-netdev egress ip saddr . ip daddr @set5 drop: This rule should not have failed.
+ip/sets.t: ERROR: line 53: add rule netdev test-netdev egress add @set5 { ip saddr . ip daddr }: This rule should not have failed.
+ip/sets.t: ERROR: line 56: add rule netdev test-netdev egress ip saddr { { 1.1.1.0, 3.3.3.0 }, 2.2.2.0 }: This rule should not have failed.
+ip/sets.t: ERROR: line 57: add rule netdev test-netdev egress ip saddr { { 1.1.1.0/24, 3.3.3.0/24 }, 2.2.2.0/24 }: This rule should not have failed.
+ip/sets.t: ERROR: line 60: add element ip test-ip4 set6 { 192.168.3.5, * }: This rule should not have failed.
+ip/sets.t: ERROR: line 61: add rule netdev test-netdev egress ip saddr @set6 drop: This rule should not have failed.
+ip/sets.t: ERROR: line 63: add rule ip test-ip4 input ip saddr vmap { 1.1.1.1 : drop, * : accept }: This rule should not have failed.
+ip/sets.t: ERROR: line 64: add rule ip test-ip4 input meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }: This rule should not have failed.
+ip/sets.t: ERROR: line 65: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+ip/numgen.t: OK
+ip/reject.t: OK
+ip6/vmap.t: ERROR: line 3: I cannot create the chain 'egress'
+ip6/vmap.t: ERROR: line 9: add rule netdev test-netdev egress ip6 saddr vmap { abcd::3 : accept }: This rule should not have failed.
+ip6/vmap.t: ERROR: line 14: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 15: add rule netdev test-netdev egress ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 16: add rule netdev test-netdev egress ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 17: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 18: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 19: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 20: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 21: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 22: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 23: add rule netdev test-netdev egress ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 24: add rule netdev test-netdev egress ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 25: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 26: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 27: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 28: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 29: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 30: add rule netdev test-netdev egress ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 31: add rule netdev test-netdev egress ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 32: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 33: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 34: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 35: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 36: add rule netdev test-netdev egress ip6 saddr vmap { ::1234:1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 37: add rule netdev test-netdev egress ip6 saddr vmap { 1234::1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 38: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234::1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 39: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234::1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 40: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:1234:: : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 41: add rule netdev test-netdev egress ip6 saddr vmap { ::1234:1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 42: add rule netdev test-netdev egress ip6 saddr vmap { 1234::1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 43: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234::1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 44: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:1234:: : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 45: add rule netdev test-netdev egress ip6 saddr vmap { ::1234:1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 46: add rule netdev test-netdev egress ip6 saddr vmap { 1234::1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 47: add rule netdev test-netdev egress ip6 saddr vmap { 1234:1234:: : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 48: add rule netdev test-netdev egress ip6 saddr vmap { ::1234 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 49: add rule netdev test-netdev egress ip6 saddr vmap { 1234:: : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 50: add rule netdev test-netdev egress ip6 saddr vmap { ::/64 : accept}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 52: add rule netdev test-netdev egress ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 53: add rule netdev test-netdev egress ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 54: add rule netdev test-netdev egress ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 55: add rule netdev test-netdev egress ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}: This rule should not have failed.
+ip6/vmap.t: ERROR: line 58: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+ip6/rt0.t: OK
+ip6/meta.t: OK
+ip6/snat.t: OK
+ip6/srh.t: OK
+ip6/masquerade.t: OK
+ip6/redirect.t: OK
+ip6/rt.t: OK
+ip6/icmpv6.t: OK
+ip6/ct.t: OK
+ip6/flowtable.t: OK
+ip6/dst.t: OK
+ip6/ip6.t: OK
+ip6/dup.t: OK
+ip6/tproxy.t: OK
+ip6/ether.t: OK
+ip6/hbh.t: OK
+ip6/map.t: OK
+ip6/frag.t: ERROR: line 3: I cannot create the chain 'egress'
+ip6/frag.t: ERROR: line 9: add rule netdev test-netdev egress frag nexthdr tcp: This rule should not have failed.
+ip6/frag.t: ERROR: line 10: add rule netdev test-netdev egress frag nexthdr != icmp: This rule should not have failed.
+ip6/frag.t: ERROR: line 11: add rule netdev test-netdev egress frag nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp}: This rule should not have failed.
+ip6/frag.t: ERROR: line 12: add rule netdev test-netdev egress frag nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp}: This rule should not have failed.
+ip6/frag.t: ERROR: line 13: add rule netdev test-netdev egress frag nexthdr esp: This rule should not have failed.
+ip6/frag.t: ERROR: line 14: add rule netdev test-netdev egress frag nexthdr ah: This rule should not have failed.
+ip6/frag.t: ERROR: line 16: add rule netdev test-netdev egress frag reserved 22: This rule should not have failed.
+ip6/frag.t: ERROR: line 17: add rule netdev test-netdev egress frag reserved != 233: This rule should not have failed.
+ip6/frag.t: ERROR: line 18: add rule netdev test-netdev egress frag reserved 33-45: This rule should not have failed.
+ip6/frag.t: ERROR: line 19: add rule netdev test-netdev egress frag reserved != 33-45: This rule should not have failed.
+ip6/frag.t: ERROR: line 20: add rule netdev test-netdev egress frag reserved { 33, 55, 67, 88}: This rule should not have failed.
+ip6/frag.t: ERROR: line 21: add rule netdev test-netdev egress frag reserved != { 33, 55, 67, 88}: This rule should not have failed.
+ip6/frag.t: ERROR: line 23: add rule netdev test-netdev egress frag frag-off 22: This rule should not have failed.
+ip6/frag.t: ERROR: line 24: add rule netdev test-netdev egress frag frag-off != 233: This rule should not have failed.
+ip6/frag.t: ERROR: line 25: add rule netdev test-netdev egress frag frag-off 33-45: This rule should not have failed.
+ip6/frag.t: ERROR: line 26: add rule netdev test-netdev egress frag frag-off != 33-45: This rule should not have failed.
+ip6/frag.t: ERROR: line 27: add rule netdev test-netdev egress frag frag-off { 33, 55, 67, 88}: This rule should not have failed.
+ip6/frag.t: ERROR: line 28: add rule netdev test-netdev egress frag frag-off != { 33, 55, 67, 88}: This rule should not have failed.
+ip6/frag.t: ERROR: line 30: add rule netdev test-netdev egress frag reserved2 1: This rule should not have failed.
+ip6/frag.t: ERROR: line 31: add rule netdev test-netdev egress frag more-fragments 0: This rule should not have failed.
+ip6/frag.t: ERROR: line 32: add rule netdev test-netdev egress frag more-fragments 1: This rule should not have failed.
+ip6/frag.t: ERROR: line 34: add rule netdev test-netdev egress frag id 1: This rule should not have failed.
+ip6/frag.t: ERROR: line 35: add rule netdev test-netdev egress frag id 22: This rule should not have failed.
+ip6/frag.t: ERROR: line 36: add rule netdev test-netdev egress frag id != 33: This rule should not have failed.
+ip6/frag.t: ERROR: line 37: add rule netdev test-netdev egress frag id 33-45: This rule should not have failed.
+ip6/frag.t: ERROR: line 38: add rule netdev test-netdev egress frag id != 33-45: This rule should not have failed.
+ip6/frag.t: ERROR: line 39: add rule netdev test-netdev egress frag id { 33, 55, 67, 88}: This rule should not have failed.
+ip6/frag.t: ERROR: line 40: add rule netdev test-netdev egress frag id != { 33, 55, 67, 88}: This rule should not have failed.
+ip6/frag.t: ERROR: line 40: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+ip6/exthdr.t: OK
+ip6/dnat.t: OK
+ip6/sets.t: ERROR: line 3: I cannot create the chain 'egress'
+ip6/sets.t: ERROR: line 25: add rule netdev test-netdev egress ip6 saddr @set2 drop: This rule should not have failed.
+ip6/sets.t: ERROR: line 26: add rule netdev test-netdev egress ip6 saddr != @set2 drop: This rule should not have failed.
+ip6/sets.t: ERROR: line 42: add rule netdev test-netdev egress ip6 saddr . ip6 daddr @set5 drop: This rule should not have failed.
+ip6/sets.t: ERROR: line 43: add rule netdev test-netdev egress add @set5 { ip6 saddr . ip6 daddr }: This rule should not have failed.
+ip6/sets.t: ERROR: line 44: add rule netdev test-netdev egress delete @set5 { ip6 saddr . ip6 daddr }: This rule should not have failed.
+ip6/sets.t: ERROR: line 44: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+ip6/mh.t: OK
+ip6/reject.t: OK
+netdev/dup.t: ERROR: line 2: I cannot create the chain 'egress'
+netdev/dup.t: ERROR: line 6: add rule netdev test-netdev egress dup to "lo": This rule should not have failed.
+netdev/dup.t: ERROR: line 7: add rule netdev test-netdev egress dup to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"}: This rule should not have failed.
+netdev/dup.t: ERROR: line 8: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+netdev/fwd.t: ERROR: line 2: I cannot create the chain 'egress'
+netdev/fwd.t: ERROR: line 6: add rule netdev test-netdev egress fwd to "lo": This rule should not have failed.
+netdev/fwd.t: ERROR: line 7: add rule netdev test-netdev egress fwd to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"}: This rule should not have failed.
+netdev/fwd.t: ERROR: line 9: add rule netdev test-netdev egress fwd ip to 192.168.2.200 device "lo": This rule should not have failed.
+netdev/fwd.t: ERROR: line 9: The chain egress does not exist in netdev test-netdev. I cannot delete it.
+netdev/reject.t: ERROR: line 5: add rule netdev test-netdev ingress reject with icmp host-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 6: add rule netdev test-netdev ingress reject with icmp net-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 7: add rule netdev test-netdev ingress reject with icmp prot-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 8: add rule netdev test-netdev ingress reject with icmp port-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 9: add rule netdev test-netdev ingress reject with icmp net-prohibited: This rule should not have failed.
+netdev/reject.t: ERROR: line 10: add rule netdev test-netdev ingress reject with icmp host-prohibited: This rule should not have failed.
+netdev/reject.t: ERROR: line 11: add rule netdev test-netdev ingress reject with icmp admin-prohibited: This rule should not have failed.
+netdev/reject.t: ERROR: line 13: add rule netdev test-netdev ingress reject with icmpv6 no-route: This rule should not have failed.
+netdev/reject.t: ERROR: line 14: add rule netdev test-netdev ingress reject with icmpv6 admin-prohibited: This rule should not have failed.
+netdev/reject.t: ERROR: line 15: add rule netdev test-netdev ingress reject with icmpv6 addr-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 16: add rule netdev test-netdev ingress reject with icmpv6 port-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 17: add rule netdev test-netdev ingress reject with icmpv6 policy-fail: This rule should not have failed.
+netdev/reject.t: ERROR: line 18: add rule netdev test-netdev ingress reject with icmpv6 reject-route: This rule should not have failed.
+netdev/reject.t: ERROR: line 20: add rule netdev test-netdev ingress mark 12345 reject with tcp reset: This rule should not have failed.
+netdev/reject.t: ERROR: line 22: add rule netdev test-netdev ingress reject: This rule should not have failed.
+netdev/reject.t: ERROR: line 23: add rule netdev test-netdev ingress meta protocol ip reject: This rule should not have failed.
+netdev/reject.t: ERROR: line 24: add rule netdev test-netdev ingress meta protocol ip6 reject: This rule should not have failed.
+netdev/reject.t: ERROR: line 26: add rule netdev test-netdev ingress reject with icmpx host-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 27: add rule netdev test-netdev ingress reject with icmpx no-route: This rule should not have failed.
+netdev/reject.t: ERROR: line 28: add rule netdev test-netdev ingress reject with icmpx admin-prohibited: This rule should not have failed.
+netdev/reject.t: ERROR: line 29: add rule netdev test-netdev ingress reject with icmpx port-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 31: add rule netdev test-netdev ingress meta protocol ip reject with icmp host-unreachable: This rule should not have failed.
+netdev/reject.t: ERROR: line 32: add rule netdev test-netdev ingress meta protocol ip6 reject with icmpv6 no-route: This rule should not have failed.
+netdev/reject.t: ERROR: line 39: add rule netdev test-netdev ingress meta protocol ip reject with icmpx admin-prohibited: This rule should not have failed.
+netdev/reject.t: ERROR: line 40: add rule netdev test-netdev ingress meta protocol ip6 reject with icmpx admin-prohibited: This rule should not have failed.
+104 test files, 68 files passed, 1988 unit tests,
+805 error, 0 warning
+
+=================================================================
+==67823==ERROR: LeakSanitizer: detected memory leaks
+
+Direct leak of 464608 byte(s) in 116 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4f1cca in PyObject_Malloc (/usr/bin/python3.9+0x4f1cca)
+
+Direct leak of 17699 byte(s) in 20 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x50ee7b (/usr/bin/python3.9+0x50ee7b)
+
+Direct leak of 6256 byte(s) in 9 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x50c092 in PyDict_Copy (/usr/bin/python3.9+0x50c092)
+
+Direct leak of 5892 byte(s) in 8 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4f2b1d (/usr/bin/python3.9+0x4f2b1d)
+
+Direct leak of 4628 byte(s) in 6 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4fcaef in PyMem_Malloc (/usr/bin/python3.9+0x4fcaef)
+
+Direct leak of 2656 byte(s) in 5 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4f1b05 (/usr/bin/python3.9+0x4f1b05)
+
+Direct leak of 1226 byte(s) in 2 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x50ea16 in PyBytes_FromStringAndSize (/usr/bin/python3.9+0x50ea16)
+
+Direct leak of 1056 byte(s) in 2 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4f1db2 (/usr/bin/python3.9+0x4f1db2)
+
+Direct leak of 936 byte(s) in 1 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4fa38d in PyType_GenericAlloc (/usr/bin/python3.9+0x4fa38d)
+
+Direct leak of 96 byte(s) in 3 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x540d66 (/usr/bin/python3.9+0x540d66)
+
+Direct leak of 32 byte(s) in 1 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4f00d3 in PyThread_allocate_lock (/usr/bin/python3.9+0x4f00d3)
+
+Indirect leak of 54968 byte(s) in 57 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4fa38d in PyType_GenericAlloc (/usr/bin/python3.9+0x4fa38d)
+
+Indirect leak of 4963 byte(s) in 5 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x50ee7b (/usr/bin/python3.9+0x50ee7b)
+
+Indirect leak of 4779 byte(s) in 5 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4f2b1d (/usr/bin/python3.9+0x4f2b1d)
+
+Indirect leak of 576 byte(s) in 1 object(s) allocated from:
+ #0 0x7f739491de8f in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
+ #1 0x4f1cca in PyObject_Malloc (/usr/bin/python3.9+0x4f1cca)
+
+SUMMARY: AddressSanitizer: 570371 byte(s) leaked in 241 allocation(s).
diff --git a/tests/py/netdev/dup.t b/tests/py/netdev/dup.t
new file mode 100644
index 0000000..5632802
--- /dev/null
+++ b/tests/py/netdev/dup.t
@@ -0,0 +1,8 @@
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*netdev;test-netdev;ingress,egress
+
+dup to "lo";ok
+dup to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"};ok
+
diff --git a/tests/py/netdev/dup.t.json b/tests/py/netdev/dup.t.json
new file mode 100644
index 0000000..dc56f64
--- /dev/null
+++ b/tests/py/netdev/dup.t.json
@@ -0,0 +1,30 @@
+# dup to "lo"
+[
+ {
+ "dup": {
+ "addr": "lo"
+ }
+ }
+]
+
+# dup to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"}
+[
+ {
+ "dup": {
+ "addr": {
+ "map": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "data": {
+ "set": [
+ [ 1, "lo" ],
+ [ 2, "lo" ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/netdev/dup.t.payload b/tests/py/netdev/dup.t.payload
new file mode 100644
index 0000000..51ff782
--- /dev/null
+++ b/tests/py/netdev/dup.t.payload
@@ -0,0 +1,14 @@
+# dup to "lo"
+netdev test-netdev ingress
+ [ immediate reg 1 0x00000001 ]
+ [ dup sreg_dev 1 ]
+
+# dup to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000001 : 00000001 0 [end] element 00000002 : 00000001 0 [end]
+netdev test-netdev ingress
+ [ meta load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ dup sreg_dev 1 ]
+
diff --git a/tests/py/netdev/fwd.t b/tests/py/netdev/fwd.t
new file mode 100644
index 0000000..6051560
--- /dev/null
+++ b/tests/py/netdev/fwd.t
@@ -0,0 +1,9 @@
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*netdev;test-netdev;ingress,egress
+
+fwd to "lo";ok
+fwd to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"};ok
+
+fwd ip to 192.168.2.200 device "lo";ok
diff --git a/tests/py/netdev/fwd.t.json b/tests/py/netdev/fwd.t.json
new file mode 100644
index 0000000..583606c
--- /dev/null
+++ b/tests/py/netdev/fwd.t.json
@@ -0,0 +1,47 @@
+# fwd to "lo"
+[
+ {
+ "fwd": {
+ "dev": "lo"
+ }
+ }
+]
+
+# fwd to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"}
+[
+ {
+ "fwd": {
+ "dev": {
+ "map": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "data": {
+ "set": [
+ [
+ "0x00000001",
+ "lo"
+ ],
+ [
+ "0x00000002",
+ "lo"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# fwd ip to 192.168.2.200 device "lo"
+[
+ {
+ "fwd": {
+ "addr": "192.168.2.200",
+ "dev": "lo",
+ "family": "ip"
+ }
+ }
+]
+
diff --git a/tests/py/netdev/fwd.t.json.output b/tests/py/netdev/fwd.t.json.output
new file mode 100644
index 0000000..8433e49
--- /dev/null
+++ b/tests/py/netdev/fwd.t.json.output
@@ -0,0 +1,27 @@
+# fwd to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"}
+[
+ {
+ "fwd": {
+ "dev": {
+ "map": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "data": {
+ "set": [
+ [
+ 1,
+ "lo"
+ ],
+ [
+ 2,
+ "lo"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/netdev/fwd.t.payload b/tests/py/netdev/fwd.t.payload
new file mode 100644
index 0000000..f03077a
--- /dev/null
+++ b/tests/py/netdev/fwd.t.payload
@@ -0,0 +1,20 @@
+# fwd to "lo"
+netdev test-netdev ingress
+ [ immediate reg 1 0x00000001 ]
+ [ fwd sreg_dev 1 ]
+
+# fwd to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"}
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 00000001 : 00000001 0 [end] element 00000002 : 00000001 0 [end]
+netdev test-netdev ingress
+ [ meta load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ fwd sreg_dev 1 ]
+
+# fwd ip to 192.168.2.200 device "lo"
+netdev test-netdev ingress
+ [ immediate reg 1 0x00000001 ]
+ [ immediate reg 2 0xc802a8c0 ]
+ [ fwd sreg_dev 1 sreg_addr 2 nfproto 2 ]
+
diff --git a/tests/py/netdev/reject.t b/tests/py/netdev/reject.t
new file mode 100644
index 0000000..c66e649
--- /dev/null
+++ b/tests/py/netdev/reject.t
@@ -0,0 +1,40 @@
+:ingress;type filter hook ingress device lo priority 0
+
+*netdev;test-netdev;ingress
+
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok
+reject with icmpv6 policy-fail;ok
+reject with icmpv6 reject-route;ok
+
+mark 12345 reject with tcp reset;ok;meta l4proto 6 meta mark 0x00003039 reject with tcp reset
+
+reject;ok
+meta protocol ip reject;ok;reject with icmp port-unreachable
+meta protocol ip6 reject;ok;reject with icmpv6 port-unreachable
+
+reject with icmpx host-unreachable;ok
+reject with icmpx no-route;ok
+reject with icmpx admin-prohibited;ok
+reject with icmpx port-unreachable;ok;reject
+
+meta protocol ip reject with icmp host-unreachable;ok;reject with icmp host-unreachable
+meta protocol ip6 reject with icmpv6 no-route;ok;reject with icmpv6 no-route
+
+meta protocol ip6 reject with icmp host-unreachable;fail
+meta protocol ip ip protocol icmp reject with icmpv6 no-route;fail
+meta protocol ip6 ip protocol icmp reject with icmp host-unreachable;fail
+meta l4proto udp reject with tcp reset;fail
+
+meta protocol ip reject with icmpx admin-prohibited;ok
+meta protocol ip6 reject with icmpx admin-prohibited;ok
diff --git a/tests/py/netdev/reject.t.json b/tests/py/netdev/reject.t.json
new file mode 100644
index 0000000..9968aaf
--- /dev/null
+++ b/tests/py/netdev/reject.t.json
@@ -0,0 +1,293 @@
+# reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-unreachable
+[
+ {
+ "reject": {
+ "expr": "net-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp prot-unreachable
+[
+ {
+ "reject": {
+ "expr": "prot-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-prohibited
+[
+ {
+ "reject": {
+ "expr": "net-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp host-prohibited
+[
+ {
+ "reject": {
+ "expr": "host-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 addr-unreachable
+[
+ {
+ "reject": {
+ "expr": "addr-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 policy-fail
+[
+ {
+ "reject": {
+ "expr": "policy-fail",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 reject-route
+[
+ {
+ "reject": {
+ "expr": "reject-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# mark 12345 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta protocol ip reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# meta protocol ip6 reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpx host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta protocol ip reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# meta protocol ip6 reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# meta protocol ip reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta protocol ip6 reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
diff --git a/tests/py/netdev/reject.t.payload b/tests/py/netdev/reject.t.payload
new file mode 100644
index 0000000..d014ada
--- /dev/null
+++ b/tests/py/netdev/reject.t.payload
@@ -0,0 +1,142 @@
+# reject with icmp host-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 1 ]
+
+# reject with icmp net-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 0 ]
+
+# reject with icmp prot-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 2 ]
+
+# reject with icmp port-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 3 ]
+
+# reject with icmp net-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 9 ]
+
+# reject with icmp host-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 10 ]
+
+# reject with icmp admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 13 ]
+
+# reject with icmpv6 no-route
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 0 ]
+
+# reject with icmpv6 admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 1 ]
+
+# reject with icmpv6 addr-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 3 ]
+
+# reject with icmpv6 port-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 4 ]
+
+# reject with icmpv6 policy-fail
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 5 ]
+
+# reject with icmpv6 reject-route
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 6 ]
+
+# mark 12345 reject with tcp reset
+netdev
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00003039 ]
+ [ reject type 1 code 0 ]
+
+# reject
+netdev
+ [ reject type 2 code 1 ]
+
+# meta protocol ip reject
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 3 ]
+
+# meta protocol ip6 reject
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 4 ]
+
+# reject with icmpx host-unreachable
+netdev
+ [ reject type 2 code 2 ]
+
+# reject with icmpx no-route
+netdev
+ [ reject type 2 code 0 ]
+
+# reject with icmpx admin-prohibited
+netdev
+ [ reject type 2 code 3 ]
+
+# reject with icmpx port-unreachable
+netdev
+ [ reject type 2 code 1 ]
+
+# meta protocol ip reject with icmp host-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 1 ]
+
+# meta protocol ip6 reject with icmpv6 no-route
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 0 ]
+
+# meta protocol ip reject with icmpx admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 2 code 3 ]
+
+# meta protocol ip6 reject with icmpx admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 2 code 3 ]
+
diff --git a/tests/py/nft-test.py b/tests/py/nft-test.py
new file mode 100755
index 0000000..9a25503
--- /dev/null
+++ b/tests/py/nft-test.py
@@ -0,0 +1,1586 @@
+#!/usr/bin/env python
+#
+# (C) 2014 by Ana Rey Botello <anarey@gmail.com>
+#
+# Based on iptables-test.py:
+# (C) 2012 by 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 as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# Thanks to the Outreach Program for Women (OPW) for sponsoring this test
+# infrastructure.
+
+from __future__ import print_function
+import sys
+import os
+import argparse
+import signal
+import json
+import traceback
+import tempfile
+
+TESTS_PATH = os.path.dirname(os.path.abspath(__file__))
+sys.path.insert(0, os.path.join(TESTS_PATH, '../../py/'))
+os.environ['TZ'] = 'UTC-2'
+
+from nftables import Nftables
+
+TESTS_DIRECTORY = ["any", "arp", "bridge", "inet", "ip", "ip6", "netdev"]
+LOGFILE = "/tmp/nftables-test.log"
+log_file = None
+table_list = []
+chain_list = []
+all_set = dict()
+obj_list = []
+signal_received = 0
+
+
+class Colors:
+ if sys.stdout.isatty() and sys.stderr.isatty():
+ HEADER = '\033[95m'
+ GREEN = '\033[92m'
+ YELLOW = '\033[93m'
+ RED = '\033[91m'
+ ENDC = '\033[0m'
+ else:
+ HEADER = ''
+ GREEN = ''
+ YELLOW = ''
+ RED = ''
+ ENDC = ''
+
+
+class Chain:
+ """Class that represents a chain"""
+
+ def __init__(self, name, config, lineno):
+ self.name = name
+ self.config = config
+ self.lineno = lineno
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+ def __str__(self):
+ return "%s" % self.name
+
+
+class Table:
+ """Class that represents a table"""
+
+ def __init__(self, family, name, chains):
+ self.family = family
+ self.name = name
+ self.chains = chains
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+ def __str__(self):
+ return "%s %s" % (self.family, self.name)
+
+
+class Set:
+ """Class that represents a set"""
+
+ 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
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+
+class Obj:
+ """Class that represents an object"""
+
+ def __init__(self, table, family, name, type, spcf):
+ self.table = table
+ self.family = family
+ self.name = name
+ self.type = type
+ self.spcf = spcf
+
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
+
+
+def print_msg(reason, errstr, filename=None, lineno=None, color=None):
+ '''
+ Prints a message with nice colors, indicating file and line number.
+ '''
+ color_errstr = "%s%s%s" % (color, errstr, Colors.ENDC)
+ if filename and lineno:
+ sys.stderr.write("%s: %s line %d: %s\n" %
+ (filename, color_errstr, lineno + 1, reason))
+ else:
+ sys.stderr.write("%s %s\n" % (color_errstr, reason))
+ sys.stderr.flush() # So that the message stay in the right place.
+
+
+def print_error(reason, filename=None, lineno=None):
+ print_msg(reason, "ERROR:", filename, lineno, Colors.RED)
+
+
+def print_warning(reason, filename=None, lineno=None):
+ print_msg(reason, "WARNING:", filename, lineno, Colors.YELLOW)
+
+def print_info(reason, filename=None, lineno=None):
+ print_msg(reason, "INFO:", filename, lineno, Colors.GREEN)
+
+def color_differences(rule, other, color):
+ rlen = len(rule)
+ olen = len(other)
+ out = ""
+ i = 0
+
+ # find equal part at start
+ for i in range(rlen):
+ if i >= olen or rule[i] != other[i]:
+ break
+ if i > 0:
+ out += rule[:i]
+ rule = rule[i:]
+ other = other[i:]
+ rlen = len(rule)
+ olen = len(other)
+
+ # find equal part at end
+ for i in range(1, rlen + 1):
+ if i > olen or rule[rlen - i] != other[olen - i]:
+ i -= 1
+ break
+ if rlen > i:
+ out += color + rule[:rlen - i] + Colors.ENDC
+ rule = rule[rlen - i:]
+
+ out += rule
+ return out
+
+def print_differences_warning(filename, lineno, rule1, rule2, cmd):
+ colored_rule1 = color_differences(rule1, rule2, Colors.YELLOW)
+ colored_rule2 = color_differences(rule2, rule1, Colors.YELLOW)
+ reason = "'%s': '%s' mismatches '%s'" % (cmd, colored_rule1, colored_rule2)
+ print_warning(reason, filename, lineno)
+
+
+def print_differences_error(filename, lineno, cmd):
+ reason = "'%s': Listing is broken." % cmd
+ print_error(reason, filename, lineno)
+
+
+def table_exist(table, filename, lineno):
+ '''
+ Exists a table.
+ '''
+ cmd = "list table %s" % table
+ ret = execute_cmd(cmd, filename, lineno)
+
+ return True if (ret == 0) else False
+
+
+def table_flush(table, filename, lineno):
+ '''
+ Flush a table.
+ '''
+ cmd = "flush table %s" % table
+ execute_cmd(cmd, filename, lineno)
+
+ return cmd
+
+
+def table_create(table, filename, lineno):
+ '''
+ Adds a table.
+ '''
+ # We check if table exists.
+ if table_exist(table, filename, lineno):
+ reason = "Table %s already exists" % table
+ print_error(reason, filename, lineno)
+ return -1
+
+ table_list.append(table)
+
+ # We add a new table
+ cmd = "add table %s" % table
+ ret = execute_cmd(cmd, filename, lineno)
+
+ if ret != 0:
+ reason = "Cannot " + cmd
+ print_error(reason, filename, lineno)
+ table_list.remove(table)
+ return -1
+
+ # We check if table was added correctly.
+ if not table_exist(table, filename, lineno):
+ table_list.remove(table)
+ reason = "I have just added the table %s " \
+ "but it does not exist. Giving up!" % table
+ print_error(reason, filename, lineno)
+ return -1
+
+ for table_chain in table.chains:
+ chain = chain_get_by_name(table_chain)
+ if chain is None:
+ reason = "The chain %s requested by table %s " \
+ "does not exist." % (table_chain, table)
+ print_error(reason, filename, lineno)
+ else:
+ chain_create(chain, table, filename)
+
+ return 0
+
+
+def table_delete(table, filename=None, lineno=None):
+ '''
+ Deletes a table.
+ '''
+ if not table_exist(table, filename, lineno):
+ reason = "Table %s does not exist but I added it before." % table
+ print_error(reason, filename, lineno)
+ return -1
+
+ cmd = "delete table %s" % table
+ ret = execute_cmd(cmd, filename, lineno)
+ if ret != 0:
+ reason = "%s: I cannot delete table %s. Giving up!" % (cmd, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+ if table_exist(table, filename, lineno):
+ reason = "I have just deleted the table %s " \
+ "but it still exists." % table
+ print_error(reason, filename, lineno)
+ return -1
+
+ return 0
+
+
+def chain_exist(chain, table, filename):
+ '''
+ Checks a chain
+ '''
+ cmd = "list chain %s %s" % (table, chain)
+ ret = execute_cmd(cmd, filename, chain.lineno)
+
+ return True if (ret == 0) else False
+
+
+def chain_create(chain, table, filename):
+ '''
+ Adds a chain
+ '''
+ if chain_exist(chain, table, filename):
+ reason = "This chain '%s' exists in %s. I cannot create " \
+ "two chains with same name." % (chain, table)
+ print_error(reason, filename, chain.lineno)
+ return -1
+
+ cmd = "add chain %s %s" % (table, chain)
+ if chain.config:
+ cmd += " { %s; }" % chain.config
+
+ ret = execute_cmd(cmd, filename, chain.lineno)
+ if ret != 0:
+ reason = "I cannot create the chain '%s'" % chain
+ print_error(reason, filename, chain.lineno)
+ return -1
+
+ if not chain_exist(chain, table, filename):
+ reason = "I have added the chain '%s' " \
+ "but it does not exist in %s" % (chain, table)
+ print_error(reason, filename, chain.lineno)
+ return -1
+
+ return 0
+
+
+def chain_delete(chain, table, filename=None, lineno=None):
+ '''
+ Flushes and deletes a chain.
+ '''
+ if not chain_exist(chain, table, filename):
+ reason = "The chain %s does not exist in %s. " \
+ "I cannot delete it." % (chain, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+ cmd = "flush chain %s %s" % (table, chain)
+ ret = execute_cmd(cmd, filename, lineno)
+ if ret != 0:
+ reason = "I cannot " + cmd
+ print_error(reason, filename, lineno)
+ return -1
+
+ cmd = "delete chain %s %s" % (table, chain)
+ ret = execute_cmd(cmd, filename, lineno)
+ if ret != 0:
+ reason = "I cannot " + cmd
+ print_error(reason, filename, lineno)
+ return -1
+
+ if chain_exist(chain, table, filename):
+ reason = "The chain %s exists in %s. " \
+ "I cannot delete this chain" % (chain, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+ return 0
+
+
+def chain_get_by_name(name):
+ for chain in chain_list:
+ if chain.name == name:
+ break
+ else:
+ chain = None
+
+ return chain
+
+
+def set_add(s, test_result, filename, lineno):
+ '''
+ Adds a set.
+ '''
+ 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 _set_exist(s, filename, lineno):
+ reason = "Set %s already exists in %s" % (s.name, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+ flags = s.flags
+ if flags != "":
+ flags = "flags %s; " % flags
+
+ if s.data == "":
+ cmd = "add set %s %s { type %s;%s %s}" % (table, s.name, s.type, s.timeout, flags)
+ else:
+ cmd = "add map %s %s { type %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 _set_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
+
+ 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 { type %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.
+ '''
+ if not table_list:
+ reason = "Missing table to add rules"
+ print_error(reason, filename, lineno)
+ return -1
+
+ for table in table_list:
+ # Check if set exists.
+ if (not set_exist(set_name, table, filename, lineno) or
+ set_name not in all_set) and state == "ok":
+ reason = "I cannot add an element to the set %s " \
+ "since it does not exist." % set_name
+ print_error(reason, filename, lineno)
+ return -1
+
+ element = ", ".join(set_element)
+ cmd = "add element %s %s { %s }" % (table, set_name, element)
+ ret = execute_cmd(cmd, filename, lineno)
+
+ if (state == "fail" and ret == 0) or (state == "ok" and ret != 0):
+ if state == "fail":
+ test_state = "This rule should have failed."
+ else:
+ test_state = "This rule should not have failed."
+
+ reason = cmd + ": " + test_state
+ print_error(reason, filename, lineno)
+ return -1
+
+ # Add element into all_set.
+ if ret == 0 and state == "ok":
+ for e in set_element:
+ all_set[set_name].add(e)
+
+ return 0
+
+
+def set_delete_elements(set_element, set_name, table, filename=None,
+ lineno=None):
+ '''
+ Deletes elements in a set.
+ '''
+ for element in set_element:
+ cmd = "delete element %s %s { %s }" % (table, set_name, element)
+ ret = execute_cmd(cmd, filename, lineno)
+ if ret != 0:
+ reason = "I cannot delete element %s " \
+ "from the set %s" % (element, set_name)
+ print_error(reason, filename, lineno)
+ return -1
+
+ return 0
+
+
+def set_delete(table, filename=None, lineno=None):
+ '''
+ Deletes set and its content.
+ '''
+ for set_name in all_set.keys():
+ # Check if exists the set
+ if not set_exist(set_name, table, filename, lineno):
+ reason = "The set %s does not exist, " \
+ "I cannot delete it" % set_name
+ print_error(reason, filename, lineno)
+ return -1
+
+ # We delete all elements in the set
+ set_delete_elements(all_set[set_name], set_name, table, filename,
+ lineno)
+
+ # We delete the set.
+ cmd = "delete set %s %s" % (table, set_name)
+ ret = execute_cmd(cmd, filename, lineno)
+
+ # Check if the set still exists after I deleted it.
+ if ret != 0 or set_exist(set_name, table, filename, lineno):
+ reason = "Cannot remove the set " + set_name
+ print_error(reason, filename, lineno)
+ return -1
+
+ return 0
+
+
+def set_exist(set_name, table, filename, lineno):
+ '''
+ Check if the set exists.
+ '''
+ cmd = "list set %s %s" % (table, set_name)
+ ret = execute_cmd(cmd, filename, lineno)
+
+ return True if (ret == 0) else False
+
+
+def _set_exist(s, filename, lineno):
+ '''
+ Check if the set exists.
+ '''
+ cmd = "list set %s %s %s" % (s.family, s.table, s.name)
+ ret = execute_cmd(cmd, 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.
+ '''
+ pos1 = rule1.find("{")
+ pos2 = rule2.find("{")
+
+ if (rule1[:pos1] != rule2[:pos2]):
+ return False
+
+ end1 = rule1.find("}")
+ end2 = rule2.find("}")
+
+ if (pos1 != -1) and (pos2 != -1) and (end1 != -1) and (end2 != -1):
+ list1 = (rule1[pos1 + 1:end1].replace(" ", "")).split(",")
+ list2 = (rule2[pos2 + 1:end2].replace(" ", "")).split(",")
+ list1.sort()
+ list2.sort()
+ if list1 != list2:
+ return False
+
+ return rule1[end1:] == rule2[end2:]
+
+ return False
+
+
+def obj_add(o, test_result, filename, lineno):
+ '''
+ Adds an object.
+ '''
+ if not table_list:
+ reason = "Missing table to add rule"
+ print_error(reason, filename, lineno)
+ return -1
+
+ for table in table_list:
+ o.table = table.name
+ o.family = table.family
+ obj_handle = o.type + " " + o.name
+ if _obj_exist(o, filename, lineno):
+ reason = "The %s already exists in %s" % (obj_handle, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+ cmd = "add %s %s %s %s" % (o.type, table, o.name, o.spcf)
+ 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 %s" % (cmd, obj_handle)
+ print_error(reason, filename, lineno)
+ return -1
+
+ exist = _obj_exist(o, filename, lineno)
+
+ if exist:
+ if test_result == "ok":
+ return 0
+ reason = "I added the %s to the table %s " \
+ "but it should have failed" % (obj_handle, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+ if test_result == "fail":
+ return 0
+
+ reason = "I have just added the %s to " \
+ "the table %s but it does not exist" % (obj_handle, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+def obj_delete(table, filename=None, lineno=None):
+ '''
+ Deletes object.
+ '''
+ for o in obj_list:
+ obj_handle = o.type + " " + o.name
+ # Check if exists the obj
+ if not obj_exist(o, table, filename, lineno):
+ reason = "The %s does not exist, I cannot delete it" % obj_handle
+ print_error(reason, filename, lineno)
+ return -1
+
+ # We delete the object.
+ cmd = "delete %s %s %s" % (o.type, table, o.name)
+ ret = execute_cmd(cmd, filename, lineno)
+
+ # Check if the object still exists after I deleted it.
+ if ret != 0 or obj_exist(o, table, filename, lineno):
+ reason = "Cannot remove the " + obj_handle
+ print_error(reason, filename, lineno)
+ return -1
+
+ return 0
+
+
+def obj_exist(o, table, filename, lineno):
+ '''
+ Check if the object exists.
+ '''
+ cmd = "list %s %s %s" % (o.type, table, o.name)
+ ret = execute_cmd(cmd, filename, lineno)
+
+ return True if (ret == 0) else False
+
+
+def _obj_exist(o, filename, lineno):
+ '''
+ Check if the object exists.
+ '''
+ cmd = "list %s %s %s %s" % (o.type, o.family, o.table, o.name)
+ ret = execute_cmd(cmd, filename, lineno)
+
+ return True if (ret == 0) else False
+
+
+def output_clean(pre_output, chain):
+ pos_chain = pre_output.find(chain.name)
+ if pos_chain == -1:
+ return ""
+ output_intermediate = pre_output[pos_chain:]
+ brace_start = output_intermediate.find("{")
+ brace_end = output_intermediate.find("}")
+ pre_rule = output_intermediate[brace_start:brace_end]
+ if pre_rule[1:].find("{") > -1: # this rule has a set.
+ set = pre_rule[1:].replace("\t", "").replace("\n", "").strip()
+ set = set.split(";")[2].strip() + "}"
+ remainder = output_clean(chain.name + " {;;" + output_intermediate[brace_end+1:], chain)
+ if len(remainder) <= 0:
+ return set
+ return set + " " + remainder
+ else:
+ rule = pre_rule.split(";")[2].replace("\t", "").replace("\n", "").\
+ strip()
+ if len(rule) < 0:
+ return ""
+ return rule
+
+
+def payload_check_elems_to_set(elems):
+ newset = set()
+
+ for n, line in enumerate(elems.split('[end]')):
+ e = line.strip()
+ if e in newset:
+ print_error("duplicate", e, n)
+ return newset
+
+ newset.add(e)
+
+ return newset
+
+
+def payload_check_set_elems(want, got):
+ if want.find('element') < 0 or want.find('[end]') < 0:
+ return 0
+
+ if got.find('element') < 0 or got.find('[end]') < 0:
+ return 0
+
+ set_want = payload_check_elems_to_set(want)
+ set_got = payload_check_elems_to_set(got)
+
+ return set_want == set_got
+
+
+def payload_check(payload_buffer, file, cmd):
+ file.seek(0, 0)
+ i = 0
+
+ if not payload_buffer:
+ return False
+
+ for lineno, want_line in enumerate(payload_buffer):
+ line = file.readline()
+
+ if want_line == line:
+ i += 1
+ continue
+
+ if want_line.find('[') < 0 and line.find('[') < 0:
+ continue
+ if want_line.find(']') < 0 and line.find(']') < 0:
+ continue
+
+ if payload_check_set_elems(want_line, line):
+ continue
+
+ print_differences_warning(file.name, lineno, want_line.strip(),
+ line.strip(), cmd)
+ return 0
+
+ return i > 0
+
+
+def json_dump_normalize(json_string, human_readable = False):
+ json_obj = json.loads(json_string)
+
+ if human_readable:
+ return json.dumps(json_obj, sort_keys = True,
+ indent = 4, separators = (',', ': '))
+ else:
+ return json.dumps(json_obj, sort_keys = True)
+
+def json_validate(json_string):
+ json_obj = json.loads(json_string)
+ try:
+ nftables.json_validate(json_obj)
+ except Exception:
+ print_error("schema validation failed for input '%s'" % json_string)
+ print_error(traceback.format_exc())
+
+def rule_add(rule, filename, lineno, force_all_family_option, filename_path):
+ '''
+ Adds a rule
+ '''
+ # TODO Check if a rule is added correctly.
+ ret = warning = error = unit_tests = 0
+
+ if not table_list or not chain_list:
+ reason = "Missing table or chain to add rule."
+ print_error(reason, filename, lineno)
+ return [-1, warning, error, unit_tests]
+
+ if rule[1].strip() == "ok":
+ payload_expected = None
+ payload_path = None
+ try:
+ payload_log = open("%s.payload" % filename_path)
+ payload_path = payload_log.name
+ payload_expected = payload_find_expected(payload_log, rule[0])
+ except:
+ payload_log = None
+
+ if enable_json_option:
+ try:
+ json_log = open("%s.json" % filename_path)
+ json_input = json_find_expected(json_log, rule[0])
+ except:
+ json_input = None
+
+ if not json_input:
+ print_error("did not find JSON equivalent for rule '%s'"
+ % rule[0])
+ else:
+ try:
+ json_input = json_dump_normalize(json_input)
+ except ValueError:
+ reason = "Invalid JSON syntax in rule: %s" % json_input
+ print_error(reason)
+ return [-1, warning, error, unit_tests]
+
+ try:
+ json_log = open("%s.json.output" % filename_path)
+ json_expected = json_find_expected(json_log, rule[0])
+ except:
+ # will use json_input for comparison
+ json_expected = None
+
+ if json_expected:
+ try:
+ json_expected = json_dump_normalize(json_expected)
+ except ValueError:
+ reason = "Invalid JSON syntax in expected output: %s" % json_expected
+ print_error(reason)
+ return [-1, warning, error, unit_tests]
+
+ for table in table_list:
+ if rule[1].strip() == "ok":
+ table_payload_expected = None
+ try:
+ payload_log = open("%s.payload.%s" % (filename_path, table.family))
+ payload_path = payload_log.name
+ table_payload_expected = payload_find_expected(payload_log, rule[0])
+ except:
+ if not payload_log:
+ print_error("did not find any payload information",
+ filename_path)
+ elif not payload_expected:
+ print_error("did not find payload information for "
+ "rule '%s'" % rule[0], payload_log.name, 1)
+ if not table_payload_expected:
+ table_payload_expected = payload_expected
+
+ for table_chain in table.chains:
+ chain = chain_get_by_name(table_chain)
+ unit_tests += 1
+ table_flush(table, filename, lineno)
+
+ payload_log = tempfile.TemporaryFile(mode="w+")
+
+ # Add rule and check return code
+ cmd = "add rule %s %s %s" % (table, chain, rule[0])
+ ret = execute_cmd(cmd, filename, lineno, payload_log, debug="netlink")
+
+ state = rule[1].rstrip()
+ if (ret in [0,134] and state == "fail") or (ret != 0 and state == "ok"):
+ if state == "fail":
+ test_state = "This rule should have failed."
+ else:
+ test_state = "This rule should not have failed."
+ reason = cmd + ": " + test_state
+ print_error(reason, filename, lineno)
+ ret = -1
+ error += 1
+ if not force_all_family_option:
+ return [ret, warning, error, unit_tests]
+
+ if state == "fail" and ret != 0:
+ ret = 0
+ continue
+
+ if ret != 0:
+ continue
+
+ # Check for matching payload
+ if state == "ok" and not payload_check(table_payload_expected,
+ payload_log, cmd):
+ error += 1
+
+ try:
+ gotf = open("%s.got" % payload_path)
+ gotf_payload_expected = payload_find_expected(gotf, rule[0])
+ gotf.close()
+ except:
+ gotf_payload_expected = None
+ payload_log.seek(0, 0)
+ if not payload_check(gotf_payload_expected, payload_log, cmd):
+ gotf = open("%s.got" % payload_path, 'a')
+ payload_log.seek(0, 0)
+ gotf.write("# %s\n" % rule[0])
+ while True:
+ line = payload_log.readline()
+ if line == "":
+ break
+ gotf.write(line)
+ gotf.close()
+ print_warning("Wrote payload for rule %s" % rule[0],
+ gotf.name, 1)
+
+ # Check for matching ruleset listing
+ numeric_proto_old = nftables.set_numeric_proto_output(True)
+ stateless_old = nftables.set_stateless_output(True)
+ list_cmd = 'list table %s' % table
+ rc, pre_output, err = nftables.cmd(list_cmd)
+ nftables.set_numeric_proto_output(numeric_proto_old)
+ nftables.set_stateless_output(stateless_old)
+
+ output = pre_output.split(";")
+ if len(output) < 2:
+ reason = cmd + ": Listing is broken."
+ print_error(reason, filename, lineno)
+ ret = -1
+ error += 1
+ if not force_all_family_option:
+ return [ret, warning, error, unit_tests]
+ continue
+
+ rule_output = output_clean(pre_output, chain)
+ retest_output = False
+ if len(rule) == 3:
+ teoric_exit = rule[2]
+ retest_output = True
+ else:
+ teoric_exit = rule[0]
+
+ if rule_output.rstrip() != teoric_exit.rstrip():
+ if rule[0].find("{") != -1: # anonymous sets
+ if not set_check_element(teoric_exit.rstrip(),
+ rule_output.rstrip()):
+ warning += 1
+ retest_output = True
+ print_differences_warning(filename, lineno,
+ teoric_exit.rstrip(),
+ rule_output, cmd)
+ if not force_all_family_option:
+ return [ret, warning, error, unit_tests]
+ else:
+ if len(rule_output) <= 0:
+ error += 1
+ print_differences_error(filename, lineno, cmd)
+ if not force_all_family_option:
+ return [ret, warning, error, unit_tests]
+
+ warning += 1
+ retest_output = True
+ print_differences_warning(filename, lineno,
+ teoric_exit.rstrip(),
+ rule_output, cmd)
+
+ if not force_all_family_option:
+ return [ret, warning, error, unit_tests]
+
+ if retest_output:
+ table_flush(table, filename, lineno)
+
+ # Add rule and check return code
+ cmd = "add rule %s %s %s" % (table, chain, rule_output.rstrip())
+ ret = execute_cmd(cmd, filename, lineno, payload_log, debug="netlink")
+
+ if ret != 0:
+ test_state = "Replaying rule failed."
+ reason = cmd + ": " + test_state
+ print_warning(reason, filename, lineno)
+ ret = -1
+ error += 1
+ if not force_all_family_option:
+ return [ret, warning, error, unit_tests]
+ # Check for matching payload
+ elif not payload_check(table_payload_expected,
+ payload_log, cmd):
+ error += 1
+
+ if not enable_json_option:
+ continue
+
+ # Generate JSON equivalent for rule if not found
+ if not json_input:
+ json_old = nftables.set_json_output(True)
+ rc, json_output, err = nftables.cmd(list_cmd)
+ nftables.set_json_output(json_old)
+
+ json_output = json.loads(json_output)
+ for item in json_output["nftables"]:
+ if "rule" in item:
+ del(item["rule"]["handle"])
+ json_output = item["rule"]
+ break
+ json_input = json.dumps(json_output["expr"], sort_keys = True)
+
+ gotf = open("%s.json.got" % filename_path, 'a')
+ jdump = json_dump_normalize(json_input, True)
+ gotf.write("# %s\n%s\n\n" % (rule[0], jdump))
+ gotf.close()
+ print_warning("Wrote JSON equivalent for rule %s" % rule[0],
+ gotf.name, 1)
+
+ table_flush(table, filename, lineno)
+ payload_log = tempfile.TemporaryFile(mode="w+")
+
+ # Add rule in JSON format
+ cmd = json.dumps({ "nftables": [{ "add": { "rule": {
+ "family": table.family,
+ "table": table.name,
+ "chain": chain.name,
+ "expr": json.loads(json_input),
+ }}}]})
+
+ if enable_json_schema:
+ json_validate(cmd)
+
+ json_old = nftables.set_json_output(True)
+ ret = execute_cmd(cmd, filename, lineno, payload_log, debug="netlink")
+ nftables.set_json_output(json_old)
+
+ if ret != 0:
+ reason = "Failed to add JSON equivalent rule"
+ print_error(reason, filename, lineno)
+ continue
+
+ # Check for matching payload
+ if not payload_check(table_payload_expected, payload_log, cmd):
+ error += 1
+ gotf = open("%s.json.payload.got" % filename_path, 'a')
+ payload_log.seek(0, 0)
+ gotf.write("# %s\n" % rule[0])
+ while True:
+ line = payload_log.readline()
+ if line == "":
+ break
+ gotf.write(line)
+ gotf.close()
+ print_warning("Wrote JSON payload for rule %s" % rule[0],
+ gotf.name, 1)
+
+ # Check for matching ruleset listing
+ numeric_proto_old = nftables.set_numeric_proto_output(True)
+ stateless_old = nftables.set_stateless_output(True)
+ json_old = nftables.set_json_output(True)
+ rc, json_output, err = nftables.cmd(list_cmd)
+ nftables.set_json_output(json_old)
+ nftables.set_numeric_proto_output(numeric_proto_old)
+ nftables.set_stateless_output(stateless_old)
+
+ if enable_json_schema:
+ json_validate(json_output)
+
+ json_output = json.loads(json_output)
+ for item in json_output["nftables"]:
+ if "rule" in item:
+ del(item["rule"]["handle"])
+ json_output = item["rule"]
+ break
+ json_output = json.dumps(json_output["expr"], sort_keys = True)
+
+ if not json_expected and json_output != json_input:
+ print_differences_warning(filename, lineno,
+ json_input, json_output, cmd)
+ error += 1
+ gotf = open("%s.json.output.got" % filename_path, 'a')
+ jdump = json_dump_normalize(json_output, True)
+ gotf.write("# %s\n%s\n\n" % (rule[0], jdump))
+ gotf.close()
+ print_warning("Wrote JSON output for rule %s" % rule[0],
+ gotf.name, 1)
+ # prevent further warnings and .got file updates
+ json_expected = json_output
+ elif json_expected and json_output != json_expected:
+ print_differences_warning(filename, lineno,
+ json_expected, json_output, cmd)
+ error += 1
+
+ return [ret, warning, error, unit_tests]
+
+
+def cleanup_on_exit():
+ for table in table_list:
+ for table_chain in table.chains:
+ chain = chain_get_by_name(table_chain)
+ chain_delete(chain, table, "", "")
+ if all_set:
+ set_delete(table)
+ if obj_list:
+ obj_delete(table)
+ table_delete(table)
+
+
+def signal_handler(signal, frame):
+ global signal_received
+ signal_received = 1
+
+
+def execute_cmd(cmd, filename, lineno, stdout_log=False, debug=False):
+ '''
+ Executes a command, checks for segfaults and returns the command exit
+ code.
+
+ :param cmd: string with the command to be executed
+ :param filename: name of the file tested (used for print_error purposes)
+ :param lineno: line number being tested (used for print_error purposes)
+ :param stdout_log: redirect stdout to this file instead of global log_file
+ :param debug: temporarily set these debug flags
+ '''
+ global log_file
+ print("command: {}".format(cmd), file=log_file)
+ if debug_option:
+ print(cmd)
+
+ log_file.flush()
+
+ if debug:
+ debug_old = nftables.get_debug()
+ nftables.set_debug(debug)
+
+ ret, out, err = nftables.cmd(cmd)
+
+ if not stdout_log:
+ stdout_log = log_file
+
+ stdout_log.write(out)
+ stdout_log.flush()
+ log_file.write(err)
+ log_file.flush()
+
+ if debug:
+ nftables.set_debug(debug_old)
+
+ return ret
+
+
+def print_result(filename, tests, warning, error):
+ return str(filename) + ": " + str(tests) + " unit tests, " + str(error) + \
+ " error, " + str(warning) + " warning"
+
+
+def print_result_all(filename, tests, warning, error, unit_tests):
+ return str(filename) + ": " + str(tests) + " unit tests, " + \
+ str(unit_tests) + " total test executed, " + str(error) + \
+ " error, " + str(warning) + " warning"
+
+
+def table_process(table_line, filename, lineno):
+ table_info = table_line.split(";")
+ table = Table(table_info[0], table_info[1], table_info[2].split(","))
+
+ return table_create(table, filename, lineno)
+
+
+def chain_process(chain_line, lineno):
+ chain_info = chain_line.split(";")
+ chain_list.append(Chain(chain_info[0], chain_info[1], lineno))
+
+ return 0
+
+
+def set_process(set_line, filename, lineno):
+ test_result = set_line[1]
+ timeout=""
+
+ tokens = set_line[0].split(" ")
+ set_name = tokens[0]
+ set_type = tokens[2]
+ set_data = ""
+ set_flags = ""
+
+ i = 3
+ 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 len(tokens) == i+2 and tokens[i] == "timeout":
+ timeout = "timeout " + tokens[i+1] + ";"
+ i += 2
+
+ if len(tokens) == i+2 and tokens[i] == "flags":
+ set_flags = tokens[i+1]
+ elif len(tokens) != i:
+ print_error(set_name + " bad flag: " + tokens[i], filename, lineno)
+
+ 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)
+
+ if ret == 0:
+ all_set[set_name] = set()
+
+ return ret
+
+
+def set_element_process(element_line, filename, lineno):
+ rule_state = element_line[1]
+ element_line = element_line[0]
+ space = element_line.find(" ")
+ set_name = element_line[:space]
+ set_element = element_line[space:].split(",")
+
+ return set_add_elements(set_element, set_name, rule_state, filename, lineno)
+
+
+def obj_process(obj_line, filename, lineno):
+ test_result = obj_line[1]
+
+ tokens = obj_line[0].split(" ")
+ obj_name = tokens[0]
+ obj_type = tokens[2]
+ obj_spcf = ""
+
+ if obj_type == "ct" and tokens[3] == "helper":
+ obj_type = "ct helper"
+ tokens[3] = ""
+
+ if obj_type == "ct" and tokens[3] == "timeout":
+ obj_type = "ct timeout"
+ tokens[3] = ""
+
+ if obj_type == "ct" and tokens[3] == "expectation":
+ obj_type = "ct expectation"
+ tokens[3] = ""
+
+ if len(tokens) > 3:
+ obj_spcf = " ".join(tokens[3:])
+
+ o = Obj("", "", obj_name, obj_type, obj_spcf)
+
+ ret = obj_add(o, test_result, filename, lineno)
+ if ret == 0:
+ obj_list.append(o)
+
+ return ret
+
+
+def payload_find_expected(payload_log, rule):
+ '''
+ Find the netlink payload that should be generated by given rule in
+ payload_log
+
+ :param payload_log: open file handle of the payload data
+ :param rule: nft rule we are going to add
+ '''
+ found = 0
+ payload_buffer = []
+
+ while True:
+ line = payload_log.readline()
+ if not line:
+ break
+
+ if line[0] == "#": # rule start
+ rule_line = line.strip()[2:]
+
+ if rule_line == rule.strip():
+ found = 1
+ continue
+
+ if found == 1:
+ payload_buffer.append(line)
+ if line.isspace():
+ return payload_buffer
+
+ payload_log.seek(0, 0)
+ return payload_buffer
+
+
+def json_find_expected(json_log, rule):
+ '''
+ Find the corresponding JSON for given rule
+
+ :param json_log: open file handle of the json data
+ :param rule: nft rule we are going to add
+ '''
+ found = 0
+ json_buffer = ""
+
+ while True:
+ line = json_log.readline()
+ if not line:
+ break
+
+ if line[0] == "#": # rule start
+ rule_line = line.strip()[2:]
+
+ if rule_line == rule.strip():
+ found = 1
+ continue
+
+ if found == 1:
+ json_buffer += line.rstrip("\n").strip()
+ if line.isspace():
+ return json_buffer
+
+ json_log.seek(0, 0)
+ return json_buffer
+
+
+def run_test_file(filename, force_all_family_option, specific_file):
+ '''
+ Runs a test file
+
+ :param filename: name of the file with the test rules
+ '''
+ filename_path = os.path.join(TESTS_PATH, filename)
+ f = open(filename_path)
+ tests = passed = total_unit_run = total_warning = total_error = 0
+
+ for lineno, line in enumerate(f):
+ sys.stdout.flush()
+
+ if signal_received == 1:
+ print("\nSignal received. Cleaning up and Exitting...")
+ cleanup_on_exit()
+ sys.exit(0)
+
+ if line.isspace():
+ continue
+
+ if line[0] == "#": # Command-line
+ continue
+
+ if line[0] == '*': # Table
+ table_line = line.rstrip()[1:]
+ ret = table_process(table_line, filename, lineno)
+ if ret != 0:
+ break
+ continue
+
+ if line[0] == ":": # Chain
+ chain_line = line.rstrip()[1:]
+ ret = chain_process(chain_line, lineno)
+ if ret != 0:
+ break
+ continue
+
+ if line[0] == "!": # Adds this set
+ set_line = line.rstrip()[1:].split(";")
+ ret = set_process(set_line, filename, lineno)
+ tests += 1
+ if ret == -1:
+ continue
+ passed += 1
+ continue
+
+ if line[0] == "?": # Adds elements in a set
+ element_line = line.rstrip()[1:].split(";")
+ ret = set_element_process(element_line, filename, lineno)
+ tests += 1
+ if ret == -1:
+ continue
+
+ passed += 1
+ continue
+
+ if line[0] == "%": # Adds this object
+ brace = line.rfind("}")
+ if brace < 0:
+ obj_line = line.rstrip()[1:].split(";")
+ else:
+ obj_line = (line[1:brace+1], line[brace+2:].rstrip())
+
+ ret = obj_process(obj_line, filename, lineno)
+ tests += 1
+ if ret == -1:
+ continue
+ passed += 1
+ continue
+
+ # Rule
+ rule = line.split(';') # rule[1] Ok or FAIL
+ if len(rule) == 1 or len(rule) > 3 or rule[1].rstrip() \
+ not in {"ok", "fail"}:
+ reason = "Skipping malformed rule test. (%s)" % line.rstrip('\n')
+ print_warning(reason, filename, lineno)
+ continue
+
+ if line[0] == "-": # Run omitted lines
+ if need_fix_option:
+ rule[0] = rule[0].rstrip()[1:].strip()
+ else:
+ continue
+ elif need_fix_option:
+ continue
+
+ result = rule_add(rule, filename, lineno, force_all_family_option,
+ filename_path)
+ tests += 1
+ ret = result[0]
+ warning = result[1]
+ total_warning += warning
+ total_error += result[2]
+ total_unit_run += result[3]
+
+ if ret != 0:
+ continue
+
+ if warning == 0: # All ok.
+ passed += 1
+
+ # Delete rules, sets, chains and tables
+ for table in table_list:
+ # We delete chains
+ for table_chain in table.chains:
+ chain = chain_get_by_name(table_chain)
+ chain_delete(chain, table, filename, lineno)
+
+ # We delete sets.
+ if all_set:
+ ret = set_delete(table, filename, lineno)
+ if ret != 0:
+ reason = "There is a problem when we delete a set"
+ print_error(reason, filename, lineno)
+
+ # We delete tables.
+ table_delete(table, filename, lineno)
+
+ if specific_file:
+ if force_all_family_option:
+ print(print_result_all(filename, tests, total_warning, total_error,
+ total_unit_run))
+ else:
+ print(print_result(filename, tests, total_warning, total_error))
+ else:
+ if tests == passed and tests > 0:
+ print(filename + ": " + Colors.GREEN + "OK" + Colors.ENDC)
+
+ f.close()
+ del table_list[:]
+ del chain_list[:]
+ all_set.clear()
+
+ return [tests, passed, total_warning, total_error, total_unit_run]
+
+def spawn_netns():
+ # prefer unshare module
+ try:
+ import unshare
+ unshare.unshare(unshare.CLONE_NEWNET)
+ return True
+ except:
+ pass
+
+ # sledgehammer style:
+ # - call ourselves prefixed by 'unshare -n' if found
+ # - pass extra --no-netns parameter to avoid another recursion
+ try:
+ import shutil
+
+ unshare = shutil.which("unshare")
+ if unshare is None:
+ return False
+
+ sys.argv.append("--no-netns")
+ if debug_option:
+ print("calling: ", [unshare, "-n", sys.executable] + sys.argv)
+ os.execv(unshare, [unshare, "-n", sys.executable] + sys.argv)
+ except:
+ pass
+
+ return False
+
+def main():
+ parser = argparse.ArgumentParser(description='Run nft tests')
+
+ parser.add_argument('filenames', nargs='*', metavar='path/to/file.t',
+ help='Run only these tests')
+
+ parser.add_argument('-d', '--debug', action='store_true', dest='debug',
+ help='enable debugging mode')
+
+ parser.add_argument('-e', '--need-fix', action='store_true',
+ dest='need_fix_line', help='run rules that need a fix')
+
+ parser.add_argument('-f', '--force-family', action='store_true',
+ dest='force_all_family',
+ help='keep testing all families on error')
+
+ parser.add_argument('-H', '--host', action='store_true',
+ help='run tests against installed libnftables.so.1')
+
+ parser.add_argument('-j', '--enable-json', action='store_true',
+ dest='enable_json',
+ help='test JSON functionality as well')
+
+ parser.add_argument('-l', '--library', default=None,
+ help='path to libntables.so.1, overrides --host')
+
+ parser.add_argument('-N', '--no-netns', action='store_true',
+ dest='no_netns',
+ help='Do not run in own network namespace')
+
+ parser.add_argument('-s', '--schema', action='store_true',
+ dest='enable_schema',
+ help='verify json input/output against schema')
+
+ parser.add_argument('-v', '--version', action='version',
+ version='1.0',
+ help='Print the version information')
+
+ args = parser.parse_args()
+ global debug_option, need_fix_option, enable_json_option, enable_json_schema
+ debug_option = args.debug
+ need_fix_option = args.need_fix_line
+ force_all_family_option = args.force_all_family
+ enable_json_option = args.enable_json
+ enable_json_schema = args.enable_schema
+ specific_file = False
+
+ signal.signal(signal.SIGINT, signal_handler)
+ signal.signal(signal.SIGTERM, signal_handler)
+
+ if os.getuid() != 0:
+ print("You need to be root to run this, sorry")
+ return
+
+ if not args.no_netns and not spawn_netns():
+ print_warning("cannot run in own namespace, connectivity might break")
+
+ # Change working directory to repository root
+ os.chdir(TESTS_PATH + "/../..")
+
+ check_lib_path = True
+ if args.library is None:
+ if args.host:
+ args.library = 'libnftables.so.1'
+ check_lib_path = False
+ else:
+ args.library = 'src/.libs/libnftables.so.1'
+
+ if check_lib_path and not os.path.exists(args.library):
+ print("The nftables library at '%s' does not exist. "
+ "You need to build the project." % args.library)
+ return
+
+ if args.enable_schema and not args.enable_json:
+ print_error("Option --schema requires option --json")
+ return
+
+ global nftables
+ nftables = Nftables(sofile = args.library)
+
+ test_files = files_ok = run_total = 0
+ tests = passed = warnings = errors = 0
+ global log_file
+ try:
+ log_file = open(LOGFILE, 'w')
+ print_info("Log will be available at %s" % LOGFILE)
+ except IOError:
+ print_error("Cannot open log file %s" % LOGFILE)
+ return
+
+ file_list = []
+ if args.filenames:
+ file_list = args.filenames
+ if len(args.filenames) == 1:
+ specific_file = True
+ else:
+ for directory in TESTS_DIRECTORY:
+ path = os.path.join(TESTS_PATH, directory)
+ for root, dirs, files in os.walk(path):
+ for f in files:
+ if f.endswith(".t"):
+ file_list.append(os.path.join(directory, f))
+
+ for filename in file_list:
+ result = run_test_file(filename, force_all_family_option, specific_file)
+ file_tests = result[0]
+ file_passed = result[1]
+ file_warnings = result[2]
+ file_errors = result[3]
+ file_unit_run = result[4]
+
+ test_files += 1
+
+ if file_warnings == 0 and file_tests == file_passed:
+ files_ok += 1
+ if file_tests:
+ tests += file_tests
+ passed += file_passed
+ errors += file_errors
+ warnings += file_warnings
+ if force_all_family_option:
+ run_total += file_unit_run
+
+ if test_files == 0:
+ print("No test files to run")
+ else:
+ if not specific_file:
+ if force_all_family_option:
+ print("%d test files, %d files passed, %d unit tests, " % (test_files, files_ok, tests))
+ print("%d total executed, %d error, %d warning" % (run_total, errors,warnings))
+ else:
+ print("%d test files, %d files passed, %d unit tests, " % (test_files, files_ok, tests))
+ print("%d error, %d warning" % (errors, warnings))
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/py/tools/test-sanitizer.sh b/tests/py/tools/test-sanitizer.sh
new file mode 100755
index 0000000..92354d2
--- /dev/null
+++ b/tests/py/tools/test-sanitizer.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+# Do some simple sanity checks on tests:
+# - Report tests where reply matches command
+# - Report tests with non-ok exit but reply
+# - Check for duplicate test commands in *.t files
+# - Check for duplicate or stale payload records in *.t.payload* files
+# - Check for duplicate or stale json equivalents in *.t.json files
+
+cd $(dirname $0)/../
+
+[[ $1 ]] && tests="$@" || tests="*/*.t"
+
+reportfile=""
+report() { # (file, msg)
+ [[ "$reportfile" == "$1" ]] || {
+ reportfile="$1"
+ echo ""
+ echo "In $reportfile:"
+ }
+ shift
+ echo "$@"
+}
+
+for t in $tests; do
+ [[ -f $t ]] || continue
+
+ readarray -t cmdlines <<< $(grep -v -e '^ *[:*#-?]' -e '^ *$' $t)
+
+ cmds=""
+ for cmdline in "${cmdlines[@]}"; do
+ readarray -t -d ';' cmdparts <<< "$cmdline"
+ cmd="${cmdparts[0]}"
+ rc="${cmdparts[1]}"
+ out="${cmdparts[2]}"
+
+ [[ -n $cmd ]] || continue
+
+ #echo "cmdline: $cmdline"
+ #echo "cmd: $cmd"
+ #echo "rc: $rc"
+ #echo "out: $out"
+
+ [[ "$cmd" != "$out" ]] || \
+ report $t "reply matches cmd: $cmd"
+ [[ "$rc" != "ok" && "$out" ]] && \
+ report $t "output record with non-ok exit: $cmd"
+
+ cmds+="${cmd}\n"
+ done
+
+ readarray -t dups <<< $(echo -e "$cmds" | sort | uniq -d)
+ for dup in "${dups[@]}"; do
+ [[ -n $dup ]] || continue
+ report $t "duplicate command: $dup"
+ done
+
+ for p in $t.payload* $t.json; do
+ [[ -f $p ]] || continue
+ [[ $p == *.got ]] && continue
+ [[ $p == *.json ]] && t="json" || t="payload"
+
+ pcmds=$(grep '^#' $p)
+ readarray -t dups <<< $(echo "$pcmds" | sort | uniq -d)
+ readarray -t stales <<< $(echo "$pcmds" | while read hash pcmd; do
+ echo -e "$cmds" | grep -qxF "${pcmd}" || echo "# ${pcmd}"
+ done)
+
+ for stale in "${stales[@]}"; do
+ [[ -n $stale ]] || continue
+ report $p "stale $t record: $stale"
+ done
+ for dup in "${dups[@]}"; do
+ [[ -n $dup ]] || continue
+ report $p "duplicate $t record: $dup"
+ done
+ done
+done
diff --git a/tests/py/y b/tests/py/y
new file mode 100644
index 0000000..3ac1e95
--- /dev/null
+++ b/tests/py/y
@@ -0,0 +1,14 @@
+diff --git a/tests/py/ip/sets.t b/tests/py/ip/sets.t
+index a224d0fef13d..46d9686b7ddd 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/shell/README b/tests/shell/README
new file mode 100644
index 0000000..3af17a9
--- /dev/null
+++ b/tests/shell/README
@@ -0,0 +1,35 @@
+This test suite is intended to perform tests on a higher level
+than the other regression test suites.
+
+It can run arbitrary executables which can perform any test, not
+limited to testing the nft syntax or netlink code (which is what
+the regression tests do).
+
+To run the test suite (as root):
+ $ cd tests/shell
+ # ./run-tests.sh
+
+Test files are executable files matching the pattern <<name_N>>,
+where N should be 0 in all new tests. All tests should return 0 on
+success.
+
+Since they are located with `find', test files can be put in any
+subdirectory.
+
+You can turn on a verbose execution by calling:
+ # ./run-tests.sh -v
+
+And generate missing dump files with:
+ # ./run-tests.sh -g <TESTFILE>
+
+Before each test file invocation, `nft flush ruleset' will be called.
+Also, test file process environment will include the variable $NFT
+which contains the nft command being tested.
+
+You can pass an arbitrary $NFT value as well:
+ # NFT=/usr/local/sbin/nft ./run-tests.sh
+
+Note that, to support usage such as NFT='valgrind nft', tests must
+invoke $NFT unquoted.
+
+By default, the tests are run with the nft binary at '../../src/nft'
diff --git a/tests/shell/features/bitshift.nft b/tests/shell/features/bitshift.nft
new file mode 100644
index 0000000..7f9ccb6
--- /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 0000000..1a02fd6
--- /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 0000000..b381ec5
--- /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/ctexpect.nft b/tests/shell/features/ctexpect.nft
new file mode 100644
index 0000000..02c3dfd
--- /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 0000000..4be58cd
--- /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 0000000..b97242e
--- /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/inet_ingress.nft b/tests/shell/features/inet_ingress.nft
new file mode 100644
index 0000000..944a5c7
--- /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/inner_matching.nft b/tests/shell/features/inner_matching.nft
new file mode 100644
index 0000000..6c86fd3
--- /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 0000000..d811570
--- /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 0000000..06c4c9d
--- /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/netdev_chain_without_device.nft b/tests/shell/features/netdev_chain_without_device.nft
new file mode 100644
index 0000000..25eb200
--- /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 0000000..67d706d
--- /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/osf.nft b/tests/shell/features/osf.nft
new file mode 100644
index 0000000..dbb6b4c
--- /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/reset_rule.sh b/tests/shell/features/reset_rule.sh
new file mode 100755
index 0000000..567ee2f
--- /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 0000000..3d03417
--- /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 0000000..520afd6
--- /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/set_with_two_expressions.nft b/tests/shell/features/set_with_two_expressions.nft
new file mode 100644
index 0000000..97632a7
--- /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/table_flag_owner.nft b/tests/shell/features/table_flag_owner.nft
new file mode 100644
index 0000000..aef122a
--- /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/nft-valgrind-wrapper.sh b/tests/shell/helpers/nft-valgrind-wrapper.sh
new file mode 100755
index 0000000..98bbdf4
--- /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 0000000..91a8248
--- /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 0000000..13b918f
--- /dev/null
+++ b/tests/shell/helpers/test-wrapper.sh
@@ -0,0 +1,223 @@
+#!/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
+}
+
+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 "/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
+ "$TEST" &>> "$NFT_TEST_TESTTMPDIR/testout.log" || rc_test=$?
+fi
+
+$NFT list ruleset > "$NFT_TEST_TESTTMPDIR/ruleset-after"
+
+read tainted_after < /proc/sys/kernel/tainted
+
+DUMPPATH="$TESTDIR/dumps"
+DUMPFILE="$DUMPPATH/$TESTBASE.nft"
+NODUMPFILE="$DUMPPATH/$TESTBASE.nodump"
+
+dump_written=
+
+# The caller can request a re-geneating of the dumps, by setting
+# DUMPGEN=y.
+#
+# This only will happen if the command completed with success.
+#
+# It also will only happen for tests, that have a "$DUMPPATH" directory. There
+# might be tests, that don't want to have dumps created. The existence of the
+# directory controls that. Tests that have a "$NODUMPFILE" file, don't get a dump generated.
+if [ "$rc_test" -eq 0 -a "$DUMPGEN" = y -a -d "$DUMPPATH" -a ! -f "$NODUMPFILE" ] ; then
+ dump_written=y
+ if [ ! -f "$DUMPFILE" ] ; then
+ # No dumpfile exists yet. We generate both a .nft and a .nodump
+ # file. The user can pick which one to commit to git.
+ : > "$NODUMPFILE"
+ fi
+ cat "$NFT_TEST_TESTTMPDIR/ruleset-after" > "$DUMPFILE"
+fi
+
+rc_dump=0
+if [ "$rc_test" -ne 77 -a -f "$DUMPFILE" ] ; then
+ if [ "$dump_written" != y ] ; then
+ if ! $DIFF -u "$DUMPFILE" "$NFT_TEST_TESTTMPDIR/ruleset-after" &> "$NFT_TEST_TESTTMPDIR/ruleset-diff" ; then
+ rc_dump=1
+ else
+ rm -f "$NFT_TEST_TESTTMPDIR/ruleset-diff"
+ fi
+ fi
+fi
+if [ "$rc_dump" -ne 0 ] ; then
+ echo "$DUMPFILE" > "$NFT_TEST_TESTTMPDIR/rc-failed-dump"
+fi
+
+rc_chkdump=0
+# check that a flush after the test succeeds. We anyway need a clean ruleset
+# for the `nft --check` next.
+$NFT flush ruleset &> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump" || rc_chkdump=1
+if [ -f "$DUMPFILE" ] ; then
+ # We have a dumpfile. Call `nft --check` to possibly cover new code
+ # paths.
+ if [ "$rc_test" -eq 77 ] ; then
+ # The test was skipped. Possibly we don't have the required
+ # features to process this file. Ignore any output and exit
+ # code, but still call the program (for valgrind or sanitizer
+ # issue we hope to find).
+ $NFT --check -f "$DUMPFILE" &>/dev/null || :
+ else
+ $NFT --check -f "$DUMPFILE" &>> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump" || rc_chkdump=1
+ fi
+fi
+if [ -s "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump" ] ; then
+ # Non-empty output? That is wrong.
+ rc_chkdump=1
+elif [ "$rc_chkdump" -eq 0 ] ; then
+ rm -rf "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+fi
+if [ "$rc_chkdump" -ne 0 ] ; then
+ # Ensure we don't have empty output files. Always write something, so
+ # that `grep ^ -R` lists the file.
+ echo -e "<<<<<\n\nCalling \`nft --check\` (or \`nft flush ruleset\`) failed for \"$DUMPFILE\"" >> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+fi
+
+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/log b/tests/shell/log
new file mode 100644
index 0000000..dd8204a
--- /dev/null
+++ b/tests/shell/log
@@ -0,0 +1,41 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: NFT_TEST_FAIL_ON_SKIP=n
+I: conf: NFT_TEST_RANDOM_SEED=975674303
+I: conf: NFT_TEST_SHUFFLE_TESTS=y
+I: conf: TMPDIR=/tmp
+
+I: conf: NFT_TEST_SKIP_slow=n
+I: conf: NFT_TEST_HAVE_bitshift=y
+I: conf: NFT_TEST_HAVE_catchall_element=y
+I: conf: NFT_TEST_HAVE_chain_binding=y
+I: conf: NFT_TEST_HAVE_ctexpect=y
+I: conf: NFT_TEST_HAVE_cttimeout=y
+I: conf: NFT_TEST_HAVE_destroy=y
+I: conf: NFT_TEST_HAVE_inet_ingress=y
+I: conf: NFT_TEST_HAVE_inner_matching=y
+I: conf: NFT_TEST_HAVE_json=y
+I: conf: NFT_TEST_HAVE_map_lookup=y
+I: conf: NFT_TEST_HAVE_netdev_chain_without_device=y
+I: conf: NFT_TEST_HAVE_netdev_egress=y
+I: conf: NFT_TEST_HAVE_osf=y
+I: conf: NFT_TEST_HAVE_reset_rule=y
+I: conf: NFT_TEST_HAVE_reset_set=y
+I: conf: NFT_TEST_HAVE_sctp_chunks=y
+I: conf: NFT_TEST_HAVE_set_with_two_expressions=y
+I: conf: NFT_TEST_HAVE_table_flag_owner=y
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20231013-172649.494.0MPMPC
+
diff --git a/tests/shell/log-0 b/tests/shell/log-0
new file mode 100644
index 0000000..3b5cc2e
--- /dev/null
+++ b/tests/shell/log-0
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-034240.938.Qsx0OT
+
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-1 b/tests/shell/log-1
new file mode 100644
index 0000000..d2790d8
--- /dev/null
+++ b/tests/shell/log-1
@@ -0,0 +1,395 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-040313.211.hBf9Yz
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+./helpers/test-wrapper.sh: línea 46: /tmp/nft-test.20230908-040227.551.9oVD5e/test-.-testcases-chains-0020depth_1.41/ruleset-after: No existe el fichero o el directorio
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+./helpers/test-wrapper.sh: línea 46: /tmp/nft-test.20230908-040227.551.9oVD5e/test-.-testcases-chains-0021prio_0.42/ruleset-after: No existe el fichero o el directorio
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-10 b/tests/shell/log-10
new file mode 100644
index 0000000..048215f
--- /dev/null
+++ b/tests/shell/log-10
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-065520.315.73c1aF
+
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-11 b/tests/shell/log-11
new file mode 100644
index 0000000..6ec6e03
--- /dev/null
+++ b/tests/shell/log-11
@@ -0,0 +1,394 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-071422.873.Iqesdi
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0014objects_0
+./run-tests.sh: línea 417: echo: error de escritura: Llamada al sistema interrumpida
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-12 b/tests/shell/log-12
new file mode 100644
index 0000000..cbaab14
--- /dev/null
+++ b/tests/shell/log-12
@@ -0,0 +1,394 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-073337.934.U6SWhK
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+./run-tests.sh: línea 417: echo: error de escritura: Llamada al sistema interrumpida
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-13 b/tests/shell/log-13
new file mode 100644
index 0000000..0f7960b
--- /dev/null
+++ b/tests/shell/log-13
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-075245.323.jrYR8p
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-14 b/tests/shell/log-14
new file mode 100644
index 0000000..b7fbfe6
--- /dev/null
+++ b/tests/shell/log-14
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-081152.369.B4cloZ
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-15 b/tests/shell/log-15
new file mode 100644
index 0000000..b0ec056
--- /dev/null
+++ b/tests/shell/log-15
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-083048.644.V73BFi
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-16 b/tests/shell/log-16
new file mode 100644
index 0000000..19f44f1
--- /dev/null
+++ b/tests/shell/log-16
@@ -0,0 +1,395 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-085003.385.6jawWe
+
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+W: [FAILED] kmemleak detected 2 memory leaks
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0046set_0
+W: [FAILED] kmemleak detected 0 memory leaks
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-17 b/tests/shell/log-17
new file mode 100644
index 0000000..7856993
--- /dev/null
+++ b/tests/shell/log-17
@@ -0,0 +1,396 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-090913.763.7JmqSw
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+W: [FAILED] ./testcases/transactions/30s-stress: got 123
+W: [FAILED] ./testcases/sets/0043concatenated_ranges_1: got 123
+W: [FAILED] ./testcases/maps/vmap_timeout: got 123
+W: [FAILED] ./testcases/sets/automerge_0: got 123
+W: [FAILED] ./testcases/sets/0044interval_overlap_1: got 123
+W: [FAILED] ./testcases/sets/0044interval_overlap_0: got 123
+W: [FAILED] ./testcases/sets/0043concatenated_ranges_0: got 123
+
+I: results: [OK] 366 [SKIPPED] 0 [FAILED] 7 [TOTAL] 373
+I: check the temp directory "/tmp/nft-test.20230908-090913.763.7JmqSw" ("/tmp/nft-test.latest.root")
+I: ls -lad "/tmp/nft-test.latest.root"/*/*
+I: grep -R ^ "/tmp/nft-test.latest.root"/
diff --git a/tests/shell/log-18 b/tests/shell/log-18
new file mode 100644
index 0000000..c94430e
--- /dev/null
+++ b/tests/shell/log-18
@@ -0,0 +1,394 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-092813.735.QfPduO
+
+W: [FAILED] kernel is tainted
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-19 b/tests/shell/log-19
new file mode 100644
index 0000000..0d1dde7
--- /dev/null
+++ b/tests/shell/log-19
@@ -0,0 +1,395 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-094709.304.3MOhCT
+
+W: [FAILED] kernel is tainted
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_non_eq
+./run-tests.sh: línea 417: echo: error de escritura: Llamada al sistema interrumpida
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-2 b/tests/shell/log-2
new file mode 100644
index 0000000..a21ad8b
--- /dev/null
+++ b/tests/shell/log-2
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-042224.066.0IULfA
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-3 b/tests/shell/log-3
new file mode 100644
index 0000000..c671908
--- /dev/null
+++ b/tests/shell/log-3
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-044118.092.gRCtxw
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-4 b/tests/shell/log-4
new file mode 100644
index 0000000..cbbe138
--- /dev/null
+++ b/tests/shell/log-4
@@ -0,0 +1,394 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-050031.108.TYKrPN
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+./run-tests.sh: línea 417: echo: error de escritura: Llamada al sistema interrumpida
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-5 b/tests/shell/log-5
new file mode 100644
index 0000000..093ced7
--- /dev/null
+++ b/tests/shell/log-5
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-051942.497.rZkwem
+
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-6 b/tests/shell/log-6
new file mode 100644
index 0000000..2e91549
--- /dev/null
+++ b/tests/shell/log-6
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-053846.566.vmUD0F
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-7 b/tests/shell/log-7
new file mode 100644
index 0000000..880f7e5
--- /dev/null
+++ b/tests/shell/log-7
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-055748.021.YK3a5b
+
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/log-8 b/tests/shell/log-8
new file mode 100644
index 0000000..ba61aa1
--- /dev/null
+++ b/tests/shell/log-8
@@ -0,0 +1,397 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-061702.084.69Rom6
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+W: [FAILED] ./testcases/sets/reset_command_0: got 1
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+./run-tests.sh: línea 417: echo: error de escritura: Llamada al sistema interrumpida
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 372 [SKIPPED] 0 [FAILED] 1 [TOTAL] 373
+I: check the temp directory "/tmp/nft-test.20230908-061702.084.69Rom6" ("/tmp/nft-test.latest.root")
+I: ls -lad "/tmp/nft-test.latest.root"/*/*
+I: grep -R ^ "/tmp/nft-test.latest.root"/
diff --git a/tests/shell/log-9 b/tests/shell/log-9
new file mode 100644
index 0000000..17c9ca2
--- /dev/null
+++ b/tests/shell/log-9
@@ -0,0 +1,393 @@
+I: conf: NFT=./../../src/nft
+I: conf: NFT_REAL=./../../src/nft
+I: conf: VERBOSE=n
+I: conf: DUMPGEN=n
+I: conf: VALGRIND=n
+I: conf: KMEMLEAK=n
+I: conf: NFT_TEST_HAS_REALROOT=y
+I: conf: NFT_TEST_HAS_SOCKET_LIMITS=n
+I: conf: NFT_TEST_UNSHARE_CMD=unshare\ -f\ -n\ -m
+I: conf: NFT_TEST_HAS_UNSHARED=y
+I: conf: NFT_TEST_HAS_UNSHARED_MOUNT=y
+I: conf: NFT_TEST_KEEP_LOGS=n
+I: conf: NFT_TEST_JOBS=12
+I: conf: TMPDIR=/tmp
+
+I: info: NFT_TEST_BASEDIR=.
+I: info: NFT_TEST_TMPDIR=/tmp/nft-test.20230908-063609.833.1uFcfR
+
+I: [OK] ./testcases/bitwise/0040mark_binop_0
+I: [OK] ./testcases/bitwise/0040mark_binop_2
+I: [OK] ./testcases/bitwise/0040mark_binop_1
+I: [OK] ./testcases/bitwise/0040mark_binop_3
+I: [OK] ./testcases/bitwise/0040mark_binop_4
+I: [OK] ./testcases/bitwise/0040mark_binop_5
+I: [OK] ./testcases/bitwise/0040mark_binop_6
+I: [OK] ./testcases/bitwise/0040mark_binop_7
+I: [OK] ./testcases/bitwise/0040mark_binop_8
+I: [OK] ./testcases/bitwise/0040mark_binop_9
+I: [OK] ./testcases/cache/0004_cache_update_0
+I: [OK] ./testcases/cache/0002_interval_0
+I: [OK] ./testcases/bogons/assert_failures
+I: [OK] ./testcases/cache/0005_cache_chain_flush
+I: [OK] ./testcases/cache/0006_cache_table_flush
+I: [OK] ./testcases/cache/0011_index_0
+I: [OK] ./testcases/cache/0010_implicit_chain_0
+I: [OK] ./testcases/cache/0007_echo_cache_init_0
+I: [OK] ./testcases/cache/0001_cache_handling_0
+I: [OK] ./testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ./testcases/cache/0003_cache_update_0
+I: [OK] ./testcases/chains/0006masquerade_0
+I: [OK] ./testcases/chains/0007masquerade_1
+I: [OK] ./testcases/chains/0004busy_1
+I: [OK] ./testcases/chains/0005busy_map_1
+I: [OK] ./testcases/chains/0008masquerade_jump_1
+I: [OK] ./testcases/chains/0010endless_jump_loop_1
+I: [OK] ./testcases/chains/0009masquerade_jump_1
+I: [OK] ./testcases/chains/0013rename_0
+I: [OK] ./testcases/chains/0014rename_0
+I: [OK] ./testcases/cache/0008_delete_by_handle_0
+I: [OK] ./testcases/chains/0011endless_jump_loop_1
+I: [OK] ./testcases/chains/0015check_jump_loop_1
+I: [OK] ./testcases/chains/0017masquerade_jump_1
+I: [OK] ./testcases/chains/0019masquerade_jump_1
+I: [OK] ./testcases/chains/0018check_jump_loop_1
+I: [OK] ./testcases/chains/0016delete_handle_0
+I: [OK] ./testcases/chains/0022prio_dummy_1
+I: [OK] ./testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ./testcases/chains/0028prio_bridge_out_1
+I: [OK] ./testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ./testcases/chains/0001jumps_0
+I: [OK] ./testcases/chains/0030create_0
+I: [OK] ./testcases/chains/0031priority_variable_0
+I: [OK] ./testcases/chains/0032priority_variable_0
+I: [OK] ./testcases/chains/0003jump_loop_1
+I: [OK] ./testcases/chains/0033priority_variable_1
+I: [OK] ./testcases/chains/0002jumps_1
+I: [OK] ./testcases/chains/0034priority_variable_1
+I: [OK] ./testcases/chains/0035policy_variable_0
+I: [OK] ./testcases/chains/0037policy_variable_1
+I: [OK] ./testcases/chains/0036policy_variable_0
+I: [OK] ./testcases/chains/0038policy_variable_1
+I: [OK] ./testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ./testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ./testcases/chains/0039negative_priority_0
+I: [OK] ./testcases/chains/0025prio_arp_1
+I: [OK] ./testcases/chains/0026prio_netdev_1
+I: [OK] ./testcases/flowtable/0001flowtable_0
+I: [OK] ./testcases/comments/comments_0
+I: [OK] ./testcases/chains/0041chain_binding_0
+I: [OK] ./testcases/chains/0042chain_variable_0
+I: [OK] ./testcases/chains/0043chain_ingress_0
+I: [OK] ./testcases/chains/0044chain_destroy_0
+I: [OK] ./testcases/chains/netdev_chain_0
+I: [OK] ./testcases/flowtable/0004delete_after_add_0
+I: [OK] ./testcases/flowtable/0002create_flowtable_0
+I: [OK] ./testcases/flowtable/0005delete_in_use_1
+I: [OK] ./testcases/flowtable/0003add_after_flush_0
+I: [OK] ./testcases/flowtable/0006segfault_0
+I: [OK] ./testcases/flowtable/0012flowtable_variable_0
+I: [OK] ./testcases/flowtable/0013addafterdelete_0
+I: [OK] ./testcases/flowtable/0010delete_handle_0
+I: [OK] ./testcases/flowtable/0014addafterdelete_0
+I: [OK] ./testcases/include/0001absolute_0
+I: [OK] ./testcases/flowtable/0009deleteafterflush_0
+I: [OK] ./testcases/include/0002relative_0
+I: [OK] ./testcases/chains/0020depth_1
+I: [OK] ./testcases/include/0003includepath_0
+I: [OK] ./testcases/flowtable/0015destroy_0
+I: [OK] ./testcases/flowtable/0011deleteafterflush_0
+I: [OK] ./testcases/flowtable/0008prio_1
+I: [OK] ./testcases/include/0004endlessloop_1
+I: [OK] ./testcases/include/0005glob_empty_0
+I: [OK] ./testcases/include/0006glob_single_0
+I: [OK] ./testcases/include/0007glob_double_0
+I: [OK] ./testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ./testcases/include/0009glob_nofile_1
+I: [OK] ./testcases/include/0010glob_broken_file_1
+I: [OK] ./testcases/flowtable/0007prio_0
+I: [OK] ./testcases/chains/0021prio_0
+I: [OK] ./testcases/include/0011glob_dependency_0
+I: [OK] ./testcases/include/0012glob_dependency_1
+I: [OK] ./testcases/include/0013glob_dotfile_0
+I: [OK] ./testcases/include/0013input_descriptors_included_files_0
+I: [OK] ./testcases/include/0014glob_directory_0
+I: [OK] ./testcases/include/0015doubleincludepath_0
+I: [OK] ./testcases/include/0016maxdepth_0
+I: [OK] ./testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ./testcases/include/0018include_error_0
+I: [OK] ./testcases/include/0019include_error_0
+I: [OK] ./testcases/include/0020include_chain_0
+I: [OK] ./testcases/listing/0002ruleset_0
+I: [OK] ./testcases/json/0002table_map_0
+I: [OK] ./testcases/listing/0001ruleset_0
+I: [OK] ./testcases/json/0001set_statements_0
+I: [OK] ./testcases/json/0003json_schema_version_0
+I: [OK] ./testcases/json/0004json_schema_version_1
+I: [OK] ./testcases/json/0005secmark_objref_0
+I: [OK] ./testcases/json/0006obj_comment_0
+I: [OK] ./testcases/listing/0003table_0
+I: [OK] ./testcases/listing/0004table_0
+I: [OK] ./testcases/json/netdev
+I: [OK] ./testcases/listing/0005ruleset_ip_0
+I: [OK] ./testcases/listing/0006ruleset_ip6_0
+I: [OK] ./testcases/listing/0015dynamic_0
+I: [OK] ./testcases/listing/0008ruleset_arp_0
+I: [OK] ./testcases/listing/0007ruleset_inet_0
+I: [OK] ./testcases/listing/0009ruleset_bridge_0
+I: [OK] ./testcases/listing/0014objects_0
+I: [OK] ./testcases/listing/0013objects_0
+I: [OK] ./testcases/listing/0016anonymous_0
+I: [OK] ./testcases/listing/0017objects_0
+I: [OK] ./testcases/listing/0018data_0
+I: [OK] ./testcases/listing/0019set_0
+I: [OK] ./testcases/listing/0021ruleset_json_terse_0
+I: [OK] ./testcases/listing/0022terse_0
+I: [OK] ./testcases/listing/0020flowtable_0
+I: [OK] ./testcases/listing/0010sets_0
+I: [OK] ./testcases/listing/0012sets_0
+I: [OK] ./testcases/listing/0011sets_0
+I: [OK] ./testcases/maps/0007named_ifname_dtype_0
+I: [OK] ./testcases/maps/0009vmap_0
+I: [OK] ./testcases/maps/0010concat_map_0
+I: [OK] ./testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ./testcases/maps/0006interval_map_overlap_0
+I: [OK] ./testcases/maps/0013map_0
+I: [OK] ./testcases/maps/0011vmap_0
+I: [OK] ./testcases/maps/0012map_0
+I: [OK] ./testcases/maps/0017_map_variable_0
+I: [OK] ./testcases/maps/0003map_add_many_elements_0
+I: [OK] ./testcases/maps/anon_objmap_concat
+I: [OK] ./testcases/maps/0008interval_map_delete_0
+I: [OK] ./testcases/maps/0014destroy_0
+I: [OK] ./testcases/maps/different_map_types_1
+I: [OK] ./testcases/maps/anonymous_snat_map_0
+I: [OK] ./testcases/maps/map_with_flags_0
+I: [OK] ./testcases/maps/map_catchall_double_deactivate
+I: [OK] ./testcases/maps/0016map_leak_0
+I: [OK] ./testcases/maps/typeof_maps_0
+I: [OK] ./testcases/maps/named_snat_map_0
+I: [OK] ./testcases/maps/typeof_integer_0
+I: [OK] ./testcases/maps/typeof_maps_concat
+I: [OK] ./testcases/maps/typeof_maps_concat_update_0
+I: [OK] ./testcases/maps/typeof_maps_update_0
+I: [OK] ./testcases/maps/typeof_maps_add_delete
+I: [OK] ./testcases/maps/typeof_raw_0
+I: [OK] ./testcases/nft-f/0001define_slash_0
+I: [OK] ./testcases/netns/0001nft-f_0
+I: [OK] ./testcases/nft-f/0002rollback_rule_0
+I: [OK] ./testcases/nft-f/0003rollback_jump_0
+I: [OK] ./testcases/nft-f/0004rollback_set_0
+I: [OK] ./testcases/nft-f/0005rollback_map_0
+I: [OK] ./testcases/maps/0018map_leak_timeout_0
+I: [OK] ./testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ./testcases/nft-f/0008split_tables_0
+I: [OK] ./testcases/nft-f/0006action_object_0
+I: [OK] ./testcases/nft-f/0009variable_0
+I: [OK] ./testcases/nft-f/0010variable_0
+I: [OK] ./testcases/nft-f/0012different_defines_0
+I: [OK] ./testcases/nft-f/0013defines_1
+I: [OK] ./testcases/nft-f/0014defines_1
+I: [OK] ./testcases/nft-f/0015defines_1
+I: [OK] ./testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ./testcases/nft-f/0016redefines_1
+I: [OK] ./testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ./testcases/nft-f/0018jump_variable_0
+I: [OK] ./testcases/netns/0002loosecommands_0
+I: [OK] ./testcases/nft-f/0019jump_variable_1
+I: [OK] ./testcases/nft-f/0020jump_variable_1
+I: [OK] ./testcases/maps/nat_addr_port
+I: [OK] ./testcases/nft-f/0021list_ruleset_0
+I: [OK] ./testcases/nft-f/0022variables_0
+I: [OK] ./testcases/nft-f/0024priority_0
+I: [OK] ./testcases/nft-f/0025empty_dynset_0
+I: [OK] ./testcases/nft-f/0026listing_0
+I: [OK] ./testcases/nft-f/0023check_1
+I: [OK] ./testcases/nft-f/0027split_chains_0
+I: [OK] ./testcases/nft-f/0031vmap_string_0
+I: [OK] ./testcases/nft-f/0030variable_reuse_0
+I: [OK] ./testcases/maps/0004interval_map_create_once_0
+I: [OK] ./testcases/nft-f/0029split_file_0
+I: [OK] ./testcases/nft-f/0032pknock_0
+I: [OK] ./testcases/optimizations/dependency_kill
+I: [OK] ./testcases/nft-f/0028variable_cmdline_0
+I: [OK] ./testcases/nft-i/0001define_0
+I: [OK] ./testcases/optimizations/merge_stmts
+I: [OK] ./testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ./testcases/optimizations/merge_stmts_vmap
+I: [OK] ./testcases/optimizations/merge_vmap_raw
+I: [OK] ./testcases/optimizations/merge_reject
+I: [OK] ./testcases/optimizations/merge_stmts_concat
+I: [OK] ./testcases/optimizations/not_mergeable
+I: [OK] ./testcases/optimizations/merge_vmaps
+I: [OK] ./testcases/optimizations/single_anon_set
+I: [OK] ./testcases/optimizations/skip_merge
+I: [OK] ./testcases/optimizations/skip_non_eq
+I: [OK] ./testcases/optimizations/merge_nat
+I: [OK] ./testcases/optimizations/variables
+I: [OK] ./testcases/optimizations/skip_unsupported
+I: [OK] ./testcases/optimizations/ruleset
+I: [OK] ./testcases/optionals/comments_0
+I: [OK] ./testcases/optionals/comments_chain_0
+I: [OK] ./testcases/optionals/comments_objects_0
+I: [OK] ./testcases/optionals/comments_table_0
+I: [OK] ./testcases/optionals/comments_handles_0
+I: [OK] ./testcases/optionals/comments_objects_dup_0
+I: [OK] ./testcases/optionals/log_prefix_0
+I: [OK] ./testcases/parsing/describe
+I: [OK] ./testcases/parsing/large_rule_pipe
+I: [OK] ./testcases/owner/0001-flowtable-uaf
+I: [OK] ./testcases/optionals/handles_0
+I: [OK] ./testcases/optionals/handles_1
+I: [OK] ./testcases/optionals/update_object_handles_0
+I: [OK] ./testcases/parsing/log
+I: [OK] ./testcases/optionals/delete_object_handles_0
+I: [OK] ./testcases/parsing/octal
+I: [OK] ./testcases/rule_management/0005replace_1
+I: [OK] ./testcases/rule_management/0004replace_0
+I: [OK] ./testcases/rule_management/0003insert_0
+I: [OK] ./testcases/rule_management/0002addinsertlocation_1
+I: [OK] ./testcases/rule_management/0006replace_1
+I: [OK] ./testcases/rule_management/0008delete_1
+I: [OK] ./testcases/rule_management/0009delete_1
+I: [OK] ./testcases/rule_management/0007delete_0
+I: [OK] ./testcases/sets/0001named_interval_0
+I: [OK] ./testcases/sets/0002named_interval_automerging_0
+I: [OK] ./testcases/rule_management/0010replace_0
+I: [OK] ./testcases/rule_management/0012destroy_0
+I: [OK] ./testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ./testcases/rule_management/0011reset_0
+I: [OK] ./testcases/sets/0004named_interval_shadow_0
+I: [OK] ./testcases/sets/0005named_interval_shadow_0
+I: [OK] ./testcases/sets/0006create_set_0
+I: [OK] ./testcases/sets/0008comments_interval_0
+I: [OK] ./testcases/sets/0008create_verdict_map_0
+I: [OK] ./testcases/netns/0003many_0
+I: [OK] ./testcases/sets/0007create_element_0
+I: [OK] ./testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ./testcases/nft-f/0011manydefines_0
+I: [OK] ./testcases/sets/0015rulesetflush_0
+I: [OK] ./testcases/sets/0010comments_0
+I: [OK] ./testcases/sets/0009comments_timeout_0
+I: [OK] ./testcases/sets/0016element_leak_0
+I: [OK] ./testcases/sets/0021nesting_0
+I: [OK] ./testcases/sets/0018set_check_size_1
+I: [OK] ./testcases/sets/0017add_after_flush_0
+I: [OK] ./testcases/sets/0020comments_0
+I: [OK] ./testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ./testcases/sets/0019set_check_size_0
+I: [OK] ./testcases/sets/0024named_objects_0
+I: [OK] ./testcases/sets/0026named_limit_0
+I: [OK] ./testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ./testcases/sets/0022type_selective_flush_0
+I: [OK] ./testcases/sets/0025anonymous_set_0
+I: [OK] ./testcases/rule_management/0001addinsertposition_0
+I: [OK] ./testcases/sets/0031set_timeout_size_0
+I: [OK] ./testcases/sets/0032restore_set_simple_0
+I: [OK] ./testcases/sets/0033add_set_simple_flat_0
+I: [OK] ./testcases/sets/0028autoselect_0
+I: [OK] ./testcases/sets/0028delete_handle_0
+I: [OK] ./testcases/sets/0035add_set_elements_flat_0
+I: [OK] ./testcases/sets/0036add_set_element_expiration_0
+I: [OK] ./testcases/sets/0037_set_with_inet_service_0
+I: [OK] ./testcases/sets/0029named_ifname_dtype_0
+I: [OK] ./testcases/sets/0042update_set_0
+I: [OK] ./testcases/sets/0039delete_interval_0
+I: [OK] ./testcases/sets/0038meter_list_0
+I: [OK] ./testcases/sets/0040get_host_endian_elements_0
+I: [OK] ./testcases/sets/0045concat_ipv4_service
+I: [OK] ./testcases/sets/0041interval_0
+I: [OK] ./testcases/sets/0046netmap_0
+I: [OK] ./testcases/sets/0047nat_0
+I: [OK] ./testcases/sets/0011add_many_elements_0
+I: [OK] ./testcases/sets/0048set_counters_0
+I: [OK] ./testcases/sets/0049set_define_0
+I: [OK] ./testcases/sets/0050set_define_1
+I: [OK] ./testcases/sets/0051set_interval_counter_0
+I: [OK] ./testcases/sets/0012add_delete_many_elements_0
+I: [OK] ./testcases/sets/0053echo_0
+I: [OK] ./testcases/sets/0013add_delete_many_elements_0
+I: [OK] ./testcases/sets/0052overlap_0
+I: [OK] ./testcases/sets/0054comments_set_0
+I: [OK] ./testcases/sets/0055tcpflags_0
+I: [OK] ./testcases/sets/0034get_element_0
+I: [OK] ./testcases/sets/0056dynamic_limit_0
+I: [OK] ./testcases/sets/0058_setupdate_timeout_0
+I: [OK] ./testcases/sets/0057set_create_fails_0
+I: [OK] ./testcases/sets/0059set_update_multistmt_0
+I: [OK] ./testcases/sets/0061anonymous_automerge_0
+I: [OK] ./testcases/sets/0060set_multistmt_0
+I: [OK] ./testcases/sets/0060set_multistmt_1
+I: [OK] ./testcases/sets/0062set_connlimit_0
+I: [OK] ./testcases/sets/0063set_catchall_0
+I: [OK] ./testcases/sets/0064map_catchall_0
+I: [OK] ./testcases/sets/0065_icmp_postprocessing
+I: [OK] ./testcases/sets/0070stacked_l2_headers
+I: [OK] ./testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ./testcases/sets/0069interval_merge_0
+I: [OK] ./testcases/sets/collapse_elem_0
+I: [OK] ./testcases/sets/0067nat_concat_interval_0
+I: [OK] ./testcases/sets/0072destroy_0
+I: [OK] ./testcases/sets/concat_interval_0
+I: [OK] ./testcases/sets/inner_0
+I: [OK] ./testcases/sets/exact_overlap_0
+I: [OK] ./testcases/sets/errors_0
+I: [OK] ./testcases/sets/dynset_missing
+I: [OK] ./testcases/sets/set_eval_0
+I: [OK] ./testcases/sets/typeof_raw_0
+I: [OK] ./testcases/sets/typeof_sets_0
+I: [OK] ./testcases/sets/typeof_sets_1
+I: [OK] ./testcases/sets/typeof_sets_concat
+I: [OK] ./testcases/sets/type_set_symbol
+I: [OK] ./testcases/transactions/0001table_0
+I: [OK] ./testcases/transactions/0002table_0
+I: [OK] ./testcases/sets/reset_command_0
+I: [OK] ./testcases/transactions/0010chain_0
+I: [OK] ./testcases/transactions/0011chain_0
+I: [OK] ./testcases/transactions/0003table_0
+I: [OK] ./testcases/transactions/0012chain_0
+I: [OK] ./testcases/sets/0030add_many_elements_interval_0
+I: [OK] ./testcases/transactions/0013chain_0
+I: [OK] ./testcases/transactions/0014chain_1
+I: [OK] ./testcases/transactions/0021rule_0
+I: [OK] ./testcases/transactions/0020rule_0
+I: [OK] ./testcases/transactions/0022rule_1
+I: [OK] ./testcases/transactions/0015chain_0
+I: [OK] ./testcases/transactions/0023rule_1
+I: [OK] ./testcases/transactions/0030set_0
+I: [OK] ./testcases/transactions/0025rule_0
+I: [OK] ./testcases/transactions/0024rule_0
+I: [OK] ./testcases/transactions/0031set_0
+I: [OK] ./testcases/transactions/0032set_0
+I: [OK] ./testcases/transactions/0033set_0
+I: [OK] ./testcases/transactions/0034set_0
+I: [OK] ./testcases/transactions/0035set_0
+I: [OK] ./testcases/transactions/0036set_1
+I: [OK] ./testcases/transactions/0037set_0
+I: [OK] ./testcases/transactions/0038set_0
+I: [OK] ./testcases/transactions/0039set_0
+I: [OK] ./testcases/sets/0068interval_stack_overflow_0
+I: [OK] ./testcases/transactions/0041nat_restore_0
+I: [OK] ./testcases/transactions/0042_stateful_expr_0
+I: [OK] ./testcases/transactions/0040set_0
+I: [OK] ./testcases/transactions/0043set_1
+I: [OK] ./testcases/transactions/0044rule_0
+I: [OK] ./testcases/transactions/0045anon-unbind_0
+I: [OK] ./testcases/transactions/0046set_0
+I: [OK] ./testcases/transactions/0047set_0
+I: [OK] ./testcases/transactions/0048helpers_0
+I: [OK] ./testcases/transactions/0050rule_1
+I: [OK] ./testcases/transactions/anon_chain_loop
+I: [OK] ./testcases/transactions/bad_expression
+I: [OK] ./testcases/sets/sets_with_ifnames
+I: [OK] ./testcases/transactions/0049huge_0
+I: [OK] ./testcases/transactions/0051map_0
+I: [OK] ./testcases/transactions/30s-stress
+I: [OK] ./testcases/sets/0043concatenated_ranges_1
+I: [OK] ./testcases/maps/vmap_timeout
+I: [OK] ./testcases/sets/automerge_0
+I: [OK] ./testcases/sets/0044interval_overlap_1
+I: [OK] ./testcases/sets/0044interval_overlap_0
+I: [OK] ./testcases/sets/0043concatenated_ranges_0
+
+I: results: [OK] 373 [SKIPPED] 0 [FAILED] 0 [TOTAL] 373
diff --git a/tests/shell/overlap-interval.txt b/tests/shell/overlap-interval.txt
new file mode 100644
index 0000000..578c7f8
--- /dev/null
+++ b/tests/shell/overlap-interval.txt
@@ -0,0 +1,430 @@
+testcases/transactions/0050rule_1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+Error: Could not process rule: File exists
+add element t s { 0 - 2 }
+ ^^^^^^
+Failed to insert 0 - 2 given:
+table ip t {
+ set s {
+ type inet_service
+ flags interval,timeout
+ timeout 1m22s
+ gc-interval 1m22s
+ }
+
+ set c {
+ type inet_service . inet_service
+ flags interval,timeout
+ timeout 1m22s
+ gc-interval 1m22s
+ }
+}
+
+I: results: [OK] 0 [FAILED] 1 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+Error: Could not process rule: File exists
+add element t s { 0 - 2 }
+ ^^^^^^
+Failed to insert 0 - 2 given:
+table ip t {
+ set s {
+ type inet_service
+ flags interval,timeout
+ timeout 1m22s
+ gc-interval 1m22s
+ }
+
+ set c {
+ type inet_service . inet_service
+ flags interval,timeout
+ timeout 1m22s
+ gc-interval 1m22s
+ }
+}
+
+I: results: [OK] 0 [FAILED] 1 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
+I: [OK] testcases/sets/0044interval_overlap_0
+
+I: results: [OK] 1 [FAILED] 0 [TOTAL] 1
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] testcases/sets/0044interval_overlap_0
diff --git a/tests/shell/run-tests-kmemleak.sh b/tests/shell/run-tests-kmemleak.sh
new file mode 100644
index 0000000..16e6cfd
--- /dev/null
+++ b/tests/shell/run-tests-kmemleak.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+rm -f leak.txt
+
+cat x | while read line
+do
+ echo "running $line..."
+ sh -c 'echo clear > /sys/kernel/debug/kmemleak'
+ ./run-tests.sh $line
+ echo "... checking for leaks"
+ sh -c 'echo scan > /sys/kernel/debug/kmemleak'
+ LINES=`cat /sys/kernel/debug/kmemleak | grep nfnetlink | wc -l | cut -d' ' -f 1`
+ echo $LINES
+ if [ $LINES -ne 0 ]
+ then
+ echo "POSSIBLE LEAK!!!!!!!!!"
+ echo "$line" >> leak.txt
+ fi
+done
diff --git a/tests/shell/run-tests.sh b/tests/shell/run-tests.sh
new file mode 100755
index 0000000..22105c2
--- /dev/null
+++ b/tests/shell/run-tests.sh
@@ -0,0 +1,945 @@
+#!/bin/bash
+
+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
+}
+
+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() {
+ _msg E "$@"
+}
+
+msg_warn() {
+ _msg W "$@"
+}
+
+msg_info() {
+ _msg I "$@"
+}
+
+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 " -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 " DUMPGEN=*|y : Regenerate dump files. Dump files are only recreated if the"
+ echo " test completes successfully and the \"dumps\" directory for the"
+ echo " test exits."
+ 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")"
+DUMPGEN="$(bool_y "$DUMPGEN")"
+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 [ -z "$NFT_TEST_RANDOM_SEED" ] ; then
+ # Choose a random value.
+ n="$SRANDOM"
+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
+fi
+# Limit a 31 bit decimal so tests can rely on this being in a certain
+# restricted form.
+NFT_TEST_RANDOM_SEED="$(( $n % 0x80000000 ))"
+export NFT_TEST_RANDOM_SEED
+
+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
+ ;;
+ -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
+ NFT_TEST_HAS_REALROOT="$(bool_y "$NFT_TEST_HAS_REALROOT")"
+fi
+export NFT_TEST_HAS_REALROOT
+
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = "" ] ; then
+ if [ "$NFT_TEST_HAS_REALROOT" = y ] ; then
+ NFT_TEST_HAS_SOCKET_LIMITS=n
+ elif [ "$(cat /proc/sys/net/core/wmem_max 2>/dev/null)" -ge $((4000*1024)) ] 2>/dev/null && \
+ [ "$(cat /proc/sys/net/core/rmem_max 2>/dev/null)" -ge $((4000*1024)) ] 2>/dev/null ; then
+ NFT_TEST_HAS_SOCKET_LIMITS=n
+ else
+ NFT_TEST_HAS_SOCKET_LIMITS=y
+ fi
+else
+ NFT_TEST_HAS_SOCKET_LIMITS="$(bool_n "$NFT_TEST_HAS_SOCKET_LIMITS")"
+fi
+export NFT_TEST_HAS_SOCKET_LIMITS
+
+detect_unshare() {
+ if ! $1 true &>/dev/null ; then
+ return 1
+ fi
+ NFT_TEST_UNSHARE_CMD="$1"
+ return 0
+}
+
+if [ -n "${NFT_TEST_UNSHARE_CMD+x}" ] ; then
+ # User overrides the unshare command.
+ if ! detect_unshare "$NFT_TEST_UNSHARE_CMD" ; then
+ msg_error "Cannot unshare via NFT_TEST_UNSHARE_CMD=$(printf '%q' "$NFT_TEST_UNSHARE_CMD")"
+ fi
+ if [ -z "${NFT_TEST_HAS_UNSHARED+x}" ] ; then
+ # Autodetect NFT_TEST_HAS_UNSHARED based one whether
+ # $NFT_TEST_UNSHARE_CMD is set.
+ if [ -n "$NFT_TEST_UNSHARE_CMD" ] ; then
+ NFT_TEST_HAS_UNSHARED="y"
+ else
+ NFT_TEST_HAS_UNSHARED="n"
+ fi
+ else
+ NFT_TEST_HAS_UNSHARED="$(bool_y "$NFT_TEST_HAS_UNSHARED")"
+ fi
+ if [ -z "${NFT_TEST_HAS_UNSHARED_MOUNT+x}" ] ; then
+ NFT_TEST_HAS_UNSHARED_MOUNT=n
+ if [ "$NFT_TEST_HAS_UNSHARED" == y ] ; then
+ case "$NFT_TEST_UNSHARE_CMD" in
+ unshare*-m*|unshare*--mount-proc*)
+ NFT_TEST_HAS_UNSHARED_MOUNT=y
+ ;;
+ esac
+ fi
+ else
+ NFT_TEST_HAS_UNSHARED_MOUNT="$(bool_y "$NFT_TEST_HAS_UNSHARED_MOUNT")"
+ fi
+else
+ NFT_TEST_HAS_UNSHARED_MOUNT=n
+ if [ "$NFT_TEST_HAS_REALROOT" = y ] ; then
+ # We appear to have real root. So try to unshare
+ # without a separate USERNS. CLONE_NEWUSER will break
+ # tests that are limited by
+ # /proc/sys/net/core/{wmem_max,rmem_max}. With real
+ # root, we want to test that.
+ if detect_unshare "unshare -f -n -m" ; then
+ NFT_TEST_HAS_UNSHARED_MOUNT=y
+ else
+ detect_unshare "unshare -f -n" ||
+ detect_unshare "unshare -f -p -m --mount-proc -U --map-root-user -n" ||
+ detect_unshare "unshare -f -U --map-root-user -n"
+ fi
+ else
+ if detect_unshare "unshare -f -p -m --mount-proc -U --map-root-user -n" ; then
+ NFT_TEST_HAS_UNSHARED_MOUNT=y
+ else
+ detect_unshare "unshare -f -U --map-root-user -n"
+ fi
+ fi
+ if [ -z "$NFT_TEST_UNSHARE_CMD" ] ; then
+ msg_error "Unshare does not work. Run as root with -U/--no-unshare or set NFT_TEST_UNSHARE_CMD"
+ fi
+ NFT_TEST_HAS_UNSHARED=y
+fi
+# If tests wish, they can know whether they are unshared via this variable.
+export NFT_TEST_HAS_UNSHARED
+export NFT_TEST_HAS_UNSHARED_MOUNT
+
+# normalize the jobs number to be an integer.
+case "$NFT_TEST_JOBS" in
+ ''|*[!0-9]*) NFT_TEST_JOBS=_NFT_TEST_JOBS_DEFAULT ;;
+esac
+if [ -z "$NFT_TEST_UNSHARE_CMD" -a "$NFT_TEST_JOBS" -gt 1 ] ; then
+ NFT_TEST_JOBS=1
+fi
+
+[ -z "$NFT" ] && NFT="$NFT_TEST_BASEDIR/../../src/nft"
+${NFT} > /dev/null 2>&1
+ret=$?
+if [ ${ret} -eq 126 ] || [ ${ret} -eq 127 ]; then
+ msg_error "cannot execute nft command: $NFT"
+fi
+
+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"
+done
+
+if [ "$NFT_TEST_JOBS" -eq 0 ] ; then
+ MODPROBE="$(which modprobe)"
+ if [ ! -x "$MODPROBE" ] ; then
+ msg_error "no modprobe binary found"
+ fi
+fi
+
+DIFF="$(which diff)"
+if [ ! -x "$DIFF" ] ; then
+ DIFF=true
+fi
+
+declare -A JOBS_PIDLIST
+
+_NFT_TEST_VALGRIND_VGDB_PREFIX=
+
+cleanup_on_exit() {
+ pids_search=''
+ for pid in "${!JOBS_PIDLIST[@]}" ; do
+ kill -- "-$pid" &>/dev/null
+ pids_search="$pids_search\\|\\<$pid\\>"
+ done
+ if [ -n "$pids_search" ] ; then
+ pids_search="${pids_search:2}"
+ for i in {1..100}; do
+ ps xh -o pgrp | grep -q "$pids_search" || break
+ sleep 0.01
+ done
+ fi
+ if [ "$NFT_TEST_KEEP_LOGS" != y -a -n "$NFT_TEST_TMPDIR" ] ; then
+ rm -rf "$NFT_TEST_TMPDIR"
+ fi
+ if [ -n "$_NFT_TEST_VALGRIND_VGDB_PREFIX" ] ; then
+ rm -rf "$_NFT_TEST_VALGRIND_VGDB_PREFIX"* &>/dev/null
+ fi
+}
+
+trap 'exit 130' SIGINT
+trap 'exit 143' SIGTERM
+trap 'rc=$?; cleanup_on_exit; exit $rc' EXIT
+
+TIMESTAMP=$(date '+%Y%m%d-%H%M%S.%3N')
+NFT_TEST_TMPDIR="$(mktemp --tmpdir="$_TMPDIR" -d "nft-test.$TIMESTAMP$NFT_TEST_TMPDIR_TAG.XXXXXX")" ||
+ msg_error "Failure to create temp directory in \"$_TMPDIR\""
+chmod 755 "$NFT_TEST_TMPDIR"
+
+exec &> >(tee "$NFT_TEST_TMPDIR/test.log")
+
+msg_info "conf: NFT=$(printf '%q' "$NFT")"
+msg_info "conf: NFT_REAL=$(printf '%q' "$NFT_REAL")"
+msg_info "conf: VERBOSE=$(printf '%q' "$VERBOSE")"
+msg_info "conf: 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() {
+ 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 \
+ nft_dup_ipv4 nft_dup_ipv6 nft_dup nft_nat \
+ nft_masq_ipv4 nft_masq_ipv6 nft_masq \
+ nft_exthdr nft_payload nft_cmp nft_range \
+ nft_quota nft_queue nft_numgen nft_osf nft_socket nft_tproxy \
+ nft_meta nft_meta_bridge nft_counter nft_log nft_limit \
+ nft_fib nft_fib_ipv4 nft_fib_ipv6 nft_fib_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 \
+ nft_reject nft_reject_inet nft_reject_netdev \
+ nf_tables_set nf_tables \
+ nf_flow_table nf_flow_table_ipv4 nf_flow_tables_ipv6 \
+ nf_flow_table_inet nft_flow_offload \
+ nft_xfrm
+}
+
+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
+
+ 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
+}
+
+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"
+
+ 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
+ ((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
+
+ print_test_header "$result_msg_level" "$testfile" "$((ok + skipped + failed))" "$result_msg_status"
+
+ 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
+ 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_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"
+}
+
+job_wait()
+{
+ local num_jobs="$1"
+
+ while [ "$JOBS_N_RUNNING" -gt 0 -a "$JOBS_N_RUNNING" -ge "$num_jobs" ] ; do
+ wait -n -p JOBCOMPLETED
+ local rc_got="$?"
+ local testfile2="${JOBS_PIDLIST[$JOBCOMPLETED]}"
+ unset JOBS_PIDLIST[$JOBCOMPLETED]
+ print_test_result "${JOBS_TEMPDIR["$testfile2"]}" "$testfile2" "$rc_got"
+ ((JOBS_N_RUNNING--))
+ 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
+JOBS_N_RUNNING=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_N_RUNNING++))
+done
+
+job_wait 0
+
+echo ""
+
+# 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
+
+# ( \
+# 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/stable-log/log-4.14 b/tests/shell/stable-log/log-4.14
new file mode 100644
index 0000000..2424f9a
--- /dev/null
+++ b/tests/shell/stable-log/log-4.14
@@ -0,0 +1,750 @@
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_0
+W: [FAILED] ././testcases/bitwise/0040mark_binop_0
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_1
+W: [FAILED] ././testcases/bitwise/0040mark_binop_1
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_2
+W: [FAILED] ././testcases/bitwise/0040mark_binop_2
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_3
+W: [FAILED] ././testcases/bitwise/0040mark_binop_3
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_4
+W: [FAILED] ././testcases/bitwise/0040mark_binop_4
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_5
+W: [FAILED] ././testcases/bitwise/0040mark_binop_5
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_6
+W: [FAILED] ././testcases/bitwise/0040mark_binop_6
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_7
+W: [FAILED] ././testcases/bitwise/0040mark_binop_7
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_8
+W: [FAILED] ././testcases/bitwise/0040mark_binop_8
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_9
+W: [FAILED] ././testcases/bitwise/0040mark_binop_9
+I: [EXECUTING] ././testcases/bogons/assert_failures
+I: [OK] ././testcases/bogons/assert_failures
+I: [EXECUTING] ././testcases/cache/0001_cache_handling_0
+I: [OK] ././testcases/cache/0001_cache_handling_0
+I: [EXECUTING] ././testcases/cache/0002_interval_0
+I: [OK] ././testcases/cache/0002_interval_0
+I: [EXECUTING] ././testcases/cache/0003_cache_update_0
+I: [OK] ././testcases/cache/0003_cache_update_0
+I: [EXECUTING] ././testcases/cache/0004_cache_update_0
+I: [OK] ././testcases/cache/0004_cache_update_0
+I: [EXECUTING] ././testcases/cache/0005_cache_chain_flush
+I: [OK] ././testcases/cache/0005_cache_chain_flush
+I: [EXECUTING] ././testcases/cache/0006_cache_table_flush
+I: [OK] ././testcases/cache/0006_cache_table_flush
+I: [EXECUTING] ././testcases/cache/0007_echo_cache_init_0
+I: [OK] ././testcases/cache/0007_echo_cache_init_0
+I: [EXECUTING] ././testcases/cache/0008_delete_by_handle_0
+W: [FAILED] ././testcases/cache/0008_delete_by_handle_0
+I: [EXECUTING] ././testcases/cache/0009_delete_by_handle_incorrect_0
+W: [FAILED] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [EXECUTING] ././testcases/cache/0010_implicit_chain_0
+W: [FAILED] ././testcases/cache/0010_implicit_chain_0
+I: [EXECUTING] ././testcases/cache/0011_index_0
+W: [DUMP FAIL] ././testcases/cache/0011_index_0
+I: [EXECUTING] ././testcases/chains/0001jumps_0
+I: [OK] ././testcases/chains/0001jumps_0
+I: [EXECUTING] ././testcases/chains/0002jumps_1
+I: [OK] ././testcases/chains/0002jumps_1
+I: [EXECUTING] ././testcases/chains/0003jump_loop_1
+I: [OK] ././testcases/chains/0003jump_loop_1
+I: [EXECUTING] ././testcases/chains/0004busy_1
+I: [OK] ././testcases/chains/0004busy_1
+I: [EXECUTING] ././testcases/chains/0005busy_map_1
+I: [OK] ././testcases/chains/0005busy_map_1
+I: [EXECUTING] ././testcases/chains/0006masquerade_0
+I: [OK] ././testcases/chains/0006masquerade_0
+I: [EXECUTING] ././testcases/chains/0007masquerade_1
+I: [OK] ././testcases/chains/0007masquerade_1
+I: [EXECUTING] ././testcases/chains/0008masquerade_jump_1
+I: [OK] ././testcases/chains/0008masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0009masquerade_jump_1
+I: [OK] ././testcases/chains/0009masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0010endless_jump_loop_1
+I: [OK] ././testcases/chains/0010endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0011endless_jump_loop_1
+I: [OK] ././testcases/chains/0011endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0013rename_0
+I: [OK] ././testcases/chains/0013rename_0
+I: [EXECUTING] ././testcases/chains/0014rename_0
+I: [OK] ././testcases/chains/0014rename_0
+I: [EXECUTING] ././testcases/chains/0015check_jump_loop_1
+I: [OK] ././testcases/chains/0015check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0016delete_handle_0
+W: [FAILED] ././testcases/chains/0016delete_handle_0
+I: [EXECUTING] ././testcases/chains/0017masquerade_jump_1
+W: [FAILED] ././testcases/chains/0017masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0018check_jump_loop_1
+I: [OK] ././testcases/chains/0018check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0019masquerade_jump_1
+W: [FAILED] ././testcases/chains/0019masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0020depth_1
+W: [FAILED] ././testcases/chains/0020depth_1
+I: [EXECUTING] ././testcases/chains/0021prio_0
+W: [FAILED] ././testcases/chains/0021prio_0
+I: [EXECUTING] ././testcases/chains/0022prio_dummy_1
+I: [OK] ././testcases/chains/0022prio_dummy_1
+I: [EXECUTING] ././testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ././testcases/chains/0023prio_inet_srcnat_1
+I: [EXECUTING] ././testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ././testcases/chains/0024prio_inet_dstnat_1
+I: [EXECUTING] ././testcases/chains/0025prio_arp_1
+I: [OK] ././testcases/chains/0025prio_arp_1
+I: [EXECUTING] ././testcases/chains/0026prio_netdev_1
+I: [OK] ././testcases/chains/0026prio_netdev_1
+I: [EXECUTING] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [EXECUTING] ././testcases/chains/0028prio_bridge_out_1
+I: [OK] ././testcases/chains/0028prio_bridge_out_1
+I: [EXECUTING] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [EXECUTING] ././testcases/chains/0030create_0
+I: [OK] ././testcases/chains/0030create_0
+I: [EXECUTING] ././testcases/chains/0031priority_variable_0
+I: [OK] ././testcases/chains/0031priority_variable_0
+I: [EXECUTING] ././testcases/chains/0032priority_variable_0
+I: [OK] ././testcases/chains/0032priority_variable_0
+I: [EXECUTING] ././testcases/chains/0033priority_variable_1
+I: [OK] ././testcases/chains/0033priority_variable_1
+I: [EXECUTING] ././testcases/chains/0034priority_variable_1
+I: [OK] ././testcases/chains/0034priority_variable_1
+I: [EXECUTING] ././testcases/chains/0035policy_variable_0
+I: [OK] ././testcases/chains/0035policy_variable_0
+I: [EXECUTING] ././testcases/chains/0036policy_variable_0
+I: [OK] ././testcases/chains/0036policy_variable_0
+I: [EXECUTING] ././testcases/chains/0037policy_variable_1
+I: [OK] ././testcases/chains/0037policy_variable_1
+I: [EXECUTING] ././testcases/chains/0038policy_variable_1
+I: [OK] ././testcases/chains/0038policy_variable_1
+I: [EXECUTING] ././testcases/chains/0039negative_priority_0
+I: [OK] ././testcases/chains/0039negative_priority_0
+I: [EXECUTING] ././testcases/chains/0041chain_binding_0
+W: [FAILED] ././testcases/chains/0041chain_binding_0
+I: [EXECUTING] ././testcases/chains/0042chain_variable_0
+W: [FAILED] ././testcases/chains/0042chain_variable_0
+I: [EXECUTING] ././testcases/chains/0043chain_ingress_0
+W: [FAILED] ././testcases/chains/0043chain_ingress_0
+I: [EXECUTING] ././testcases/chains/0044chain_destroy_0
+W: [FAILED] ././testcases/chains/0044chain_destroy_0
+I: [EXECUTING] ././testcases/chains/netdev_chain_0
+W: [FAILED] ././testcases/chains/netdev_chain_0
+I: [EXECUTING] ././testcases/comments/comments_0
+I: [OK] ././testcases/comments/comments_0
+I: [EXECUTING] ././testcases/flowtable/0001flowtable_0
+W: [FAILED] ././testcases/flowtable/0001flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0002create_flowtable_0
+W: [FAILED] ././testcases/flowtable/0002create_flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0003add_after_flush_0
+W: [FAILED] ././testcases/flowtable/0003add_after_flush_0
+I: [EXECUTING] ././testcases/flowtable/0004delete_after_add_0
+W: [FAILED] ././testcases/flowtable/0004delete_after_add_0
+I: [EXECUTING] ././testcases/flowtable/0005delete_in_use_1
+W: [FAILED] ././testcases/flowtable/0005delete_in_use_1
+I: [EXECUTING] ././testcases/flowtable/0006segfault_0
+I: [OK] ././testcases/flowtable/0006segfault_0
+I: [EXECUTING] ././testcases/flowtable/0007prio_0
+W: [FAILED] ././testcases/flowtable/0007prio_0
+I: [EXECUTING] ././testcases/flowtable/0008prio_1
+I: [OK] ././testcases/flowtable/0008prio_1
+I: [EXECUTING] ././testcases/flowtable/0009deleteafterflush_0
+W: [FAILED] ././testcases/flowtable/0009deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0010delete_handle_0
+W: [FAILED] ././testcases/flowtable/0010delete_handle_0
+I: [EXECUTING] ././testcases/flowtable/0011deleteafterflush_0
+W: [FAILED] ././testcases/flowtable/0011deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0012flowtable_variable_0
+W: [FAILED] ././testcases/flowtable/0012flowtable_variable_0
+I: [EXECUTING] ././testcases/flowtable/0013addafterdelete_0
+W: [FAILED] ././testcases/flowtable/0013addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0014addafterdelete_0
+W: [FAILED] ././testcases/flowtable/0014addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0015destroy_0
+W: [FAILED] ././testcases/flowtable/0015destroy_0
+I: [EXECUTING] ././testcases/include/0001absolute_0
+I: [OK] ././testcases/include/0001absolute_0
+I: [EXECUTING] ././testcases/include/0002relative_0
+I: [OK] ././testcases/include/0002relative_0
+I: [EXECUTING] ././testcases/include/0003includepath_0
+I: [OK] ././testcases/include/0003includepath_0
+I: [EXECUTING] ././testcases/include/0004endlessloop_1
+I: [OK] ././testcases/include/0004endlessloop_1
+I: [EXECUTING] ././testcases/include/0005glob_empty_0
+I: [OK] ././testcases/include/0005glob_empty_0
+I: [EXECUTING] ././testcases/include/0006glob_single_0
+I: [OK] ././testcases/include/0006glob_single_0
+I: [EXECUTING] ././testcases/include/0007glob_double_0
+I: [OK] ././testcases/include/0007glob_double_0
+I: [EXECUTING] ././testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ././testcases/include/0008glob_nofile_wildcard_0
+I: [EXECUTING] ././testcases/include/0009glob_nofile_1
+I: [OK] ././testcases/include/0009glob_nofile_1
+I: [EXECUTING] ././testcases/include/0010glob_broken_file_1
+I: [OK] ././testcases/include/0010glob_broken_file_1
+I: [EXECUTING] ././testcases/include/0011glob_dependency_0
+I: [OK] ././testcases/include/0011glob_dependency_0
+I: [EXECUTING] ././testcases/include/0012glob_dependency_1
+I: [OK] ././testcases/include/0012glob_dependency_1
+I: [EXECUTING] ././testcases/include/0013glob_dotfile_0
+I: [OK] ././testcases/include/0013glob_dotfile_0
+I: [EXECUTING] ././testcases/include/0013input_descriptors_included_files_0
+I: [OK] ././testcases/include/0013input_descriptors_included_files_0
+I: [EXECUTING] ././testcases/include/0014glob_directory_0
+I: [OK] ././testcases/include/0014glob_directory_0
+I: [EXECUTING] ././testcases/include/0015doubleincludepath_0
+I: [OK] ././testcases/include/0015doubleincludepath_0
+I: [EXECUTING] ././testcases/include/0016maxdepth_0
+I: [OK] ././testcases/include/0016maxdepth_0
+I: [EXECUTING] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [EXECUTING] ././testcases/include/0018include_error_0
+I: [OK] ././testcases/include/0018include_error_0
+I: [EXECUTING] ././testcases/include/0019include_error_0
+I: [OK] ././testcases/include/0019include_error_0
+I: [EXECUTING] ././testcases/include/0020include_chain_0
+I: [OK] ././testcases/include/0020include_chain_0
+I: [EXECUTING] ././testcases/json/0001set_statements_0
+W: [FAILED] ././testcases/json/0001set_statements_0
+I: [EXECUTING] ././testcases/json/0002table_map_0
+W: [DUMP FAIL] ././testcases/json/0002table_map_0
+I: [EXECUTING] ././testcases/json/0003json_schema_version_0
+I: [OK] ././testcases/json/0003json_schema_version_0
+I: [EXECUTING] ././testcases/json/0004json_schema_version_1
+I: [OK] ././testcases/json/0004json_schema_version_1
+I: [EXECUTING] ././testcases/json/0005secmark_objref_0
+W: [FAILED] ././testcases/json/0005secmark_objref_0
+I: [EXECUTING] ././testcases/json/0006obj_comment_0
+W: [DUMP FAIL] ././testcases/json/0006obj_comment_0
+I: [EXECUTING] ././testcases/json/netdev
+I: [OK] ././testcases/json/netdev
+I: [EXECUTING] ././testcases/listing/0001ruleset_0
+I: [OK] ././testcases/listing/0001ruleset_0
+I: [EXECUTING] ././testcases/listing/0002ruleset_0
+I: [OK] ././testcases/listing/0002ruleset_0
+I: [EXECUTING] ././testcases/listing/0003table_0
+I: [OK] ././testcases/listing/0003table_0
+I: [EXECUTING] ././testcases/listing/0004table_0
+I: [OK] ././testcases/listing/0004table_0
+I: [EXECUTING] ././testcases/listing/0005ruleset_ip_0
+I: [OK] ././testcases/listing/0005ruleset_ip_0
+I: [EXECUTING] ././testcases/listing/0006ruleset_ip6_0
+I: [OK] ././testcases/listing/0006ruleset_ip6_0
+I: [EXECUTING] ././testcases/listing/0007ruleset_inet_0
+I: [OK] ././testcases/listing/0007ruleset_inet_0
+I: [EXECUTING] ././testcases/listing/0008ruleset_arp_0
+I: [OK] ././testcases/listing/0008ruleset_arp_0
+I: [EXECUTING] ././testcases/listing/0009ruleset_bridge_0
+I: [OK] ././testcases/listing/0009ruleset_bridge_0
+I: [EXECUTING] ././testcases/listing/0010sets_0
+W: [FAILED] ././testcases/listing/0010sets_0
+I: [EXECUTING] ././testcases/listing/0011sets_0
+W: [FAILED] ././testcases/listing/0011sets_0
+I: [EXECUTING] ././testcases/listing/0012sets_0
+I: [OK] ././testcases/listing/0012sets_0
+I: [EXECUTING] ././testcases/listing/0013objects_0
+W: [FAILED] ././testcases/listing/0013objects_0
+I: [EXECUTING] ././testcases/listing/0014objects_0
+I: [OK] ././testcases/listing/0014objects_0
+I: [EXECUTING] ././testcases/listing/0015dynamic_0
+W: [FAILED] ././testcases/listing/0015dynamic_0
+I: [EXECUTING] ././testcases/listing/0016anonymous_0
+I: [OK] ././testcases/listing/0016anonymous_0
+I: [EXECUTING] ././testcases/listing/0017objects_0
+I: [OK] ././testcases/listing/0017objects_0
+I: [EXECUTING] ././testcases/listing/0018data_0
+I: [OK] ././testcases/listing/0018data_0
+I: [EXECUTING] ././testcases/listing/0019set_0
+I: [OK] ././testcases/listing/0019set_0
+I: [EXECUTING] ././testcases/listing/0020flowtable_0
+I: [OK] ././testcases/listing/0020flowtable_0
+I: [EXECUTING] ././testcases/listing/0021ruleset_json_terse_0
+I: [OK] ././testcases/listing/0021ruleset_json_terse_0
+I: [EXECUTING] ././testcases/listing/0022terse_0
+I: [OK] ././testcases/listing/0022terse_0
+I: [EXECUTING] ././testcases/maps/0003map_add_many_elements_0
+I: [OK] ././testcases/maps/0003map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0004interval_map_create_once_0
+I: [OK] ././testcases/maps/0004interval_map_create_once_0
+I: [EXECUTING] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0006interval_map_overlap_0
+I: [OK] ././testcases/maps/0006interval_map_overlap_0
+I: [EXECUTING] ././testcases/maps/0007named_ifname_dtype_0
+I: [OK] ././testcases/maps/0007named_ifname_dtype_0
+I: [EXECUTING] ././testcases/maps/0008interval_map_delete_0
+I: [OK] ././testcases/maps/0008interval_map_delete_0
+I: [EXECUTING] ././testcases/maps/0009vmap_0
+W: [DUMP FAIL] ././testcases/maps/0009vmap_0
+I: [EXECUTING] ././testcases/maps/0010concat_map_0
+W: [FAILED] ././testcases/maps/0010concat_map_0
+I: [EXECUTING] ././testcases/maps/0011vmap_0
+W: [FAILED] ././testcases/maps/0011vmap_0
+I: [EXECUTING] ././testcases/maps/0012map_0
+W: [FAILED] ././testcases/maps/0012map_0
+I: [EXECUTING] ././testcases/maps/0013map_0
+W: [FAILED] ././testcases/maps/0013map_0
+I: [EXECUTING] ././testcases/maps/0014destroy_0
+W: [FAILED] ././testcases/maps/0014destroy_0
+I: [EXECUTING] ././testcases/maps/0016map_leak_0
+I: [OK] ././testcases/maps/0016map_leak_0
+I: [EXECUTING] ././testcases/maps/0017_map_variable_0
+W: [FAILED] ././testcases/maps/0017_map_variable_0
+I: [EXECUTING] ././testcases/maps/0018map_leak_timeout_0
+I: [OK] ././testcases/maps/0018map_leak_timeout_0
+I: [EXECUTING] ././testcases/maps/anon_objmap_concat
+W: [FAILED] ././testcases/maps/anon_objmap_concat
+I: [EXECUTING] ././testcases/maps/anonymous_snat_map_0
+I: [OK] ././testcases/maps/anonymous_snat_map_0
+I: [EXECUTING] ././testcases/maps/different_map_types_1
+I: [OK] ././testcases/maps/different_map_types_1
+I: [EXECUTING] ././testcases/maps/map_catchall_double_deactivate
+W: [FAILED] ././testcases/maps/map_catchall_double_deactivate
+I: [EXECUTING] ././testcases/maps/map_with_flags_0
+I: [OK] ././testcases/maps/map_with_flags_0
+I: [EXECUTING] ././testcases/maps/named_snat_map_0
+I: [OK] ././testcases/maps/named_snat_map_0
+I: [EXECUTING] ././testcases/maps/nat_addr_port
+W: [FAILED] ././testcases/maps/nat_addr_port
+I: [EXECUTING] ././testcases/maps/typeof_integer_0
+W: [FAILED] ././testcases/maps/typeof_integer_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_0
+W: [FAILED] ././testcases/maps/typeof_maps_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_add_delete
+W: [FAILED] ././testcases/maps/typeof_maps_add_delete
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat
+W: [FAILED] ././testcases/maps/typeof_maps_concat
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat_update_0
+W: [FAILED] ././testcases/maps/typeof_maps_concat_update_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_update_0
+W: [FAILED] ././testcases/maps/typeof_maps_update_0
+I: [EXECUTING] ././testcases/maps/typeof_raw_0
+W: [FAILED] ././testcases/maps/typeof_raw_0
+I: [EXECUTING] ././testcases/maps/vmap_timeout
+W: [FAILED] ././testcases/maps/vmap_timeout
+I: [EXECUTING] ././testcases/netns/0001nft-f_0
+W: [FAILED] ././testcases/netns/0001nft-f_0
+I: [EXECUTING] ././testcases/netns/0002loosecommands_0
+I: [OK] ././testcases/netns/0002loosecommands_0
+I: [EXECUTING] ././testcases/netns/0003many_0
+W: [FAILED] ././testcases/netns/0003many_0
+I: [EXECUTING] ././testcases/nft-f/0001define_slash_0
+I: [OK] ././testcases/nft-f/0001define_slash_0
+I: [EXECUTING] ././testcases/nft-f/0002rollback_rule_0
+I: [OK] ././testcases/nft-f/0002rollback_rule_0
+I: [EXECUTING] ././testcases/nft-f/0003rollback_jump_0
+I: [OK] ././testcases/nft-f/0003rollback_jump_0
+I: [EXECUTING] ././testcases/nft-f/0004rollback_set_0
+I: [OK] ././testcases/nft-f/0004rollback_set_0
+I: [EXECUTING] ././testcases/nft-f/0005rollback_map_0
+I: [OK] ././testcases/nft-f/0005rollback_map_0
+I: [EXECUTING] ././testcases/nft-f/0006action_object_0
+I: [OK] ././testcases/nft-f/0006action_object_0
+I: [EXECUTING] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [EXECUTING] ././testcases/nft-f/0008split_tables_0
+I: [OK] ././testcases/nft-f/0008split_tables_0
+I: [EXECUTING] ././testcases/nft-f/0009variable_0
+I: [OK] ././testcases/nft-f/0009variable_0
+I: [EXECUTING] ././testcases/nft-f/0010variable_0
+I: [OK] ././testcases/nft-f/0010variable_0
+I: [EXECUTING] ././testcases/nft-f/0011manydefines_0
+I: [OK] ././testcases/nft-f/0011manydefines_0
+I: [EXECUTING] ././testcases/nft-f/0012different_defines_0
+I: [OK] ././testcases/nft-f/0012different_defines_0
+I: [EXECUTING] ././testcases/nft-f/0013defines_1
+I: [OK] ././testcases/nft-f/0013defines_1
+I: [EXECUTING] ././testcases/nft-f/0014defines_1
+I: [OK] ././testcases/nft-f/0014defines_1
+I: [EXECUTING] ././testcases/nft-f/0015defines_1
+I: [OK] ././testcases/nft-f/0015defines_1
+I: [EXECUTING] ././testcases/nft-f/0016redefines_1
+I: [OK] ././testcases/nft-f/0016redefines_1
+I: [EXECUTING] ././testcases/nft-f/0017ct_timeout_obj_0
+W: [FAILED] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018ct_expectation_obj_0
+W: [FAILED] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018jump_variable_0
+I: [OK] ././testcases/nft-f/0018jump_variable_0
+I: [EXECUTING] ././testcases/nft-f/0019jump_variable_1
+I: [OK] ././testcases/nft-f/0019jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0020jump_variable_1
+I: [OK] ././testcases/nft-f/0020jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0021list_ruleset_0
+I: [OK] ././testcases/nft-f/0021list_ruleset_0
+I: [EXECUTING] ././testcases/nft-f/0022variables_0
+W: [DUMP FAIL] ././testcases/nft-f/0022variables_0
+I: [EXECUTING] ././testcases/nft-f/0023check_1
+I: [OK] ././testcases/nft-f/0023check_1
+I: [EXECUTING] ././testcases/nft-f/0024priority_0
+I: [OK] ././testcases/nft-f/0024priority_0
+I: [EXECUTING] ././testcases/nft-f/0025empty_dynset_0
+W: [DUMP FAIL] ././testcases/nft-f/0025empty_dynset_0
+I: [EXECUTING] ././testcases/nft-f/0026listing_0
+I: [OK] ././testcases/nft-f/0026listing_0
+I: [EXECUTING] ././testcases/nft-f/0027split_chains_0
+I: [OK] ././testcases/nft-f/0027split_chains_0
+I: [EXECUTING] ././testcases/nft-f/0028variable_cmdline_0
+I: [OK] ././testcases/nft-f/0028variable_cmdline_0
+I: [EXECUTING] ././testcases/nft-f/0029split_file_0
+I: [OK] ././testcases/nft-f/0029split_file_0
+I: [EXECUTING] ././testcases/nft-f/0030variable_reuse_0
+I: [OK] ././testcases/nft-f/0030variable_reuse_0
+I: [EXECUTING] ././testcases/nft-f/0031vmap_string_0
+I: [OK] ././testcases/nft-f/0031vmap_string_0
+I: [EXECUTING] ././testcases/nft-f/0032pknock_0
+W: [DUMP FAIL] ././testcases/nft-f/0032pknock_0
+I: [EXECUTING] ././testcases/nft-i/0001define_0
+I: [OK] ././testcases/nft-i/0001define_0
+I: [EXECUTING] ././testcases/optimizations/dependency_kill
+W: [DUMP FAIL] ././testcases/optimizations/dependency_kill
+I: [EXECUTING] ././testcases/optimizations/merge_nat
+W: [FAILED] ././testcases/optimizations/merge_nat
+I: [EXECUTING] ././testcases/optimizations/merge_reject
+I: [OK] ././testcases/optimizations/merge_reject
+I: [EXECUTING] ././testcases/optimizations/merge_stmts
+I: [OK] ././testcases/optimizations/merge_stmts
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat
+W: [FAILED] ././testcases/optimizations/merge_stmts_concat
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_vmap
+W: [DUMP FAIL] ././testcases/optimizations/merge_stmts_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_vmap_raw
+W: [FAILED] ././testcases/optimizations/merge_vmap_raw
+I: [EXECUTING] ././testcases/optimizations/merge_vmaps
+W: [FAILED] ././testcases/optimizations/merge_vmaps
+I: [EXECUTING] ././testcases/optimizations/not_mergeable
+I: [OK] ././testcases/optimizations/not_mergeable
+I: [EXECUTING] ././testcases/optimizations/ruleset
+W: [FAILED] ././testcases/optimizations/ruleset
+I: [EXECUTING] ././testcases/optimizations/single_anon_set
+W: [DUMP FAIL] ././testcases/optimizations/single_anon_set
+I: [EXECUTING] ././testcases/optimizations/skip_merge
+I: [OK] ././testcases/optimizations/skip_merge
+I: [EXECUTING] ././testcases/optimizations/skip_non_eq
+I: [OK] ././testcases/optimizations/skip_non_eq
+I: [EXECUTING] ././testcases/optimizations/skip_unsupported
+I: [OK] ././testcases/optimizations/skip_unsupported
+I: [EXECUTING] ././testcases/optimizations/variables
+I: [OK] ././testcases/optimizations/variables
+I: [EXECUTING] ././testcases/optionals/comments_0
+I: [OK] ././testcases/optionals/comments_0
+I: [EXECUTING] ././testcases/optionals/comments_chain_0
+W: [DUMP FAIL] ././testcases/optionals/comments_chain_0
+I: [EXECUTING] ././testcases/optionals/comments_handles_0
+I: [OK] ././testcases/optionals/comments_handles_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_0
+W: [FAILED] ././testcases/optionals/comments_objects_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_dup_0
+I: [OK] ././testcases/optionals/comments_objects_dup_0
+I: [EXECUTING] ././testcases/optionals/comments_table_0
+W: [DUMP FAIL] ././testcases/optionals/comments_table_0
+I: [EXECUTING] ././testcases/optionals/delete_object_handles_0
+W: [FAILED] ././testcases/optionals/delete_object_handles_0
+I: [EXECUTING] ././testcases/optionals/handles_0
+I: [OK] ././testcases/optionals/handles_0
+I: [EXECUTING] ././testcases/optionals/handles_1
+I: [OK] ././testcases/optionals/handles_1
+I: [EXECUTING] ././testcases/optionals/log_prefix_0
+I: [OK] ././testcases/optionals/log_prefix_0
+I: [EXECUTING] ././testcases/optionals/update_object_handles_0
+W: [FAILED] ././testcases/optionals/update_object_handles_0
+I: [EXECUTING] ././testcases/owner/0001-flowtable-uaf
+W: [FAILED] ././testcases/owner/0001-flowtable-uaf
+I: [EXECUTING] ././testcases/parsing/describe
+I: [OK] ././testcases/parsing/describe
+I: [EXECUTING] ././testcases/parsing/large_rule_pipe
+I: [OK] ././testcases/parsing/large_rule_pipe
+I: [EXECUTING] ././testcases/parsing/log
+I: [OK] ././testcases/parsing/log
+I: [EXECUTING] ././testcases/parsing/octal
+I: [OK] ././testcases/parsing/octal
+I: [EXECUTING] ././testcases/rule_management/0001addinsertposition_0
+I: [OK] ././testcases/rule_management/0001addinsertposition_0
+I: [EXECUTING] ././testcases/rule_management/0002addinsertlocation_1
+I: [OK] ././testcases/rule_management/0002addinsertlocation_1
+I: [EXECUTING] ././testcases/rule_management/0003insert_0
+I: [OK] ././testcases/rule_management/0003insert_0
+I: [EXECUTING] ././testcases/rule_management/0004replace_0
+I: [OK] ././testcases/rule_management/0004replace_0
+I: [EXECUTING] ././testcases/rule_management/0005replace_1
+I: [OK] ././testcases/rule_management/0005replace_1
+I: [EXECUTING] ././testcases/rule_management/0006replace_1
+I: [OK] ././testcases/rule_management/0006replace_1
+I: [EXECUTING] ././testcases/rule_management/0007delete_0
+I: [OK] ././testcases/rule_management/0007delete_0
+I: [EXECUTING] ././testcases/rule_management/0008delete_1
+I: [OK] ././testcases/rule_management/0008delete_1
+I: [EXECUTING] ././testcases/rule_management/0009delete_1
+I: [OK] ././testcases/rule_management/0009delete_1
+I: [EXECUTING] ././testcases/rule_management/0010replace_0
+I: [OK] ././testcases/rule_management/0010replace_0
+I: [EXECUTING] ././testcases/rule_management/0011reset_0
+W: [FAILED] ././testcases/rule_management/0011reset_0
+I: [EXECUTING] ././testcases/rule_management/0012destroy_0
+W: [FAILED] ././testcases/rule_management/0012destroy_0
+I: [EXECUTING] ././testcases/sets/0001named_interval_0
+I: [OK] ././testcases/sets/0001named_interval_0
+I: [EXECUTING] ././testcases/sets/0002named_interval_automerging_0
+I: [OK] ././testcases/sets/0002named_interval_automerging_0
+I: [EXECUTING] ././testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ././testcases/sets/0003named_interval_missing_flag_0
+I: [EXECUTING] ././testcases/sets/0004named_interval_shadow_0
+I: [OK] ././testcases/sets/0004named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0005named_interval_shadow_0
+I: [OK] ././testcases/sets/0005named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0006create_set_0
+I: [OK] ././testcases/sets/0006create_set_0
+I: [EXECUTING] ././testcases/sets/0007create_element_0
+I: [OK] ././testcases/sets/0007create_element_0
+I: [EXECUTING] ././testcases/sets/0008comments_interval_0
+I: [OK] ././testcases/sets/0008comments_interval_0
+I: [EXECUTING] ././testcases/sets/0008create_verdict_map_0
+I: [OK] ././testcases/sets/0008create_verdict_map_0
+I: [EXECUTING] ././testcases/sets/0009comments_timeout_0
+I: [OK] ././testcases/sets/0009comments_timeout_0
+I: [EXECUTING] ././testcases/sets/0010comments_0
+I: [OK] ././testcases/sets/0010comments_0
+I: [EXECUTING] ././testcases/sets/0011add_many_elements_0
+I: [OK] ././testcases/sets/0011add_many_elements_0
+I: [EXECUTING] ././testcases/sets/0012add_delete_many_elements_0
+I: [OK] ././testcases/sets/0012add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0013add_delete_many_elements_0
+I: [OK] ././testcases/sets/0013add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [EXECUTING] ././testcases/sets/0015rulesetflush_0
+I: [OK] ././testcases/sets/0015rulesetflush_0
+I: [EXECUTING] ././testcases/sets/0016element_leak_0
+I: [OK] ././testcases/sets/0016element_leak_0
+I: [EXECUTING] ././testcases/sets/0017add_after_flush_0
+I: [OK] ././testcases/sets/0017add_after_flush_0
+I: [EXECUTING] ././testcases/sets/0018set_check_size_1
+I: [OK] ././testcases/sets/0018set_check_size_1
+I: [EXECUTING] ././testcases/sets/0019set_check_size_0
+I: [OK] ././testcases/sets/0019set_check_size_0
+I: [EXECUTING] ././testcases/sets/0020comments_0
+I: [OK] ././testcases/sets/0020comments_0
+I: [EXECUTING] ././testcases/sets/0021nesting_0
+I: [OK] ././testcases/sets/0021nesting_0
+I: [EXECUTING] ././testcases/sets/0022type_selective_flush_0
+W: [DUMP FAIL] ././testcases/sets/0022type_selective_flush_0
+I: [EXECUTING] ././testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ././testcases/sets/0023incomplete_add_set_command_0
+I: [EXECUTING] ././testcases/sets/0024named_objects_0
+W: [FAILED] ././testcases/sets/0024named_objects_0
+I: [EXECUTING] ././testcases/sets/0025anonymous_set_0
+I: [OK] ././testcases/sets/0025anonymous_set_0
+I: [EXECUTING] ././testcases/sets/0026named_limit_0
+I: [OK] ././testcases/sets/0026named_limit_0
+I: [EXECUTING] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [EXECUTING] ././testcases/sets/0028autoselect_0
+W: [FAILED] ././testcases/sets/0028autoselect_0
+I: [EXECUTING] ././testcases/sets/0028delete_handle_0
+W: [FAILED] ././testcases/sets/0028delete_handle_0
+I: [EXECUTING] ././testcases/sets/0029named_ifname_dtype_0
+I: [OK] ././testcases/sets/0029named_ifname_dtype_0
+I: [EXECUTING] ././testcases/sets/0030add_many_elements_interval_0
+I: [OK] ././testcases/sets/0030add_many_elements_interval_0
+I: [EXECUTING] ././testcases/sets/0031set_timeout_size_0
+W: [FAILED] ././testcases/sets/0031set_timeout_size_0
+I: [EXECUTING] ././testcases/sets/0032restore_set_simple_0
+I: [OK] ././testcases/sets/0032restore_set_simple_0
+I: [EXECUTING] ././testcases/sets/0033add_set_simple_flat_0
+I: [OK] ././testcases/sets/0033add_set_simple_flat_0
+I: [EXECUTING] ././testcases/sets/0034get_element_0
+W: [FAILED] ././testcases/sets/0034get_element_0
+I: [EXECUTING] ././testcases/sets/0035add_set_elements_flat_0
+I: [OK] ././testcases/sets/0035add_set_elements_flat_0
+I: [EXECUTING] ././testcases/sets/0036add_set_element_expiration_0
+W: [FAILED] ././testcases/sets/0036add_set_element_expiration_0
+I: [EXECUTING] ././testcases/sets/0037_set_with_inet_service_0
+I: [OK] ././testcases/sets/0037_set_with_inet_service_0
+I: [EXECUTING] ././testcases/sets/0038meter_list_0
+W: [FAILED] ././testcases/sets/0038meter_list_0
+I: [EXECUTING] ././testcases/sets/0039delete_interval_0
+I: [OK] ././testcases/sets/0039delete_interval_0
+I: [EXECUTING] ././testcases/sets/0040get_host_endian_elements_0
+W: [FAILED] ././testcases/sets/0040get_host_endian_elements_0
+I: [EXECUTING] ././testcases/sets/0041interval_0
+W: [FAILED] ././testcases/sets/0041interval_0
+I: [EXECUTING] ././testcases/sets/0042update_set_0
+W: [FAILED] ././testcases/sets/0042update_set_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_0
+W: [FAILED] ././testcases/sets/0043concatenated_ranges_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_1
+W: [FAILED] ././testcases/sets/0043concatenated_ranges_1
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_0
+W: [FAILED] ././testcases/sets/0044interval_overlap_0
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_1
+I: [OK] ././testcases/sets/0044interval_overlap_1
+I: [EXECUTING] ././testcases/sets/0045concat_ipv4_service
+W: [FAILED] ././testcases/sets/0045concat_ipv4_service
+I: [EXECUTING] ././testcases/sets/0046netmap_0
+W: [FAILED] ././testcases/sets/0046netmap_0
+I: [EXECUTING] ././testcases/sets/0047nat_0
+W: [FAILED] ././testcases/sets/0047nat_0
+I: [EXECUTING] ././testcases/sets/0048set_counters_0
+W: [DUMP FAIL] ././testcases/sets/0048set_counters_0
+I: [EXECUTING] ././testcases/sets/0049set_define_0
+I: [OK] ././testcases/sets/0049set_define_0
+I: [EXECUTING] ././testcases/sets/0050set_define_1
+I: [OK] ././testcases/sets/0050set_define_1
+I: [EXECUTING] ././testcases/sets/0051set_interval_counter_0
+W: [DUMP FAIL] ././testcases/sets/0051set_interval_counter_0
+I: [EXECUTING] ././testcases/sets/0052overlap_0
+I: [OK] ././testcases/sets/0052overlap_0
+I: [EXECUTING] ././testcases/sets/0053echo_0
+I: [OK] ././testcases/sets/0053echo_0
+I: [EXECUTING] ././testcases/sets/0054comments_set_0
+I: [OK] ././testcases/sets/0054comments_set_0
+I: [EXECUTING] ././testcases/sets/0055tcpflags_0
+I: [OK] ././testcases/sets/0055tcpflags_0
+I: [EXECUTING] ././testcases/sets/0056dynamic_limit_0
+I: [OK] ././testcases/sets/0056dynamic_limit_0
+I: [EXECUTING] ././testcases/sets/0057set_create_fails_0
+I: [OK] ././testcases/sets/0057set_create_fails_0
+I: [EXECUTING] ././testcases/sets/0058_setupdate_timeout_0
+W: [FAILED] ././testcases/sets/0058_setupdate_timeout_0
+I: [EXECUTING] ././testcases/sets/0059set_update_multistmt_0
+W: [FAILED] ././testcases/sets/0059set_update_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_0
+W: [FAILED] ././testcases/sets/0060set_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_1
+W: [FAILED] ././testcases/sets/0060set_multistmt_1
+I: [EXECUTING] ././testcases/sets/0061anonymous_automerge_0
+I: [OK] ././testcases/sets/0061anonymous_automerge_0
+I: [EXECUTING] ././testcases/sets/0062set_connlimit_0
+I: [OK] ././testcases/sets/0062set_connlimit_0
+I: [EXECUTING] ././testcases/sets/0063set_catchall_0
+W: [FAILED] ././testcases/sets/0063set_catchall_0
+I: [EXECUTING] ././testcases/sets/0064map_catchall_0
+W: [FAILED] ././testcases/sets/0064map_catchall_0
+I: [EXECUTING] ././testcases/sets/0065_icmp_postprocessing
+I: [OK] ././testcases/sets/0065_icmp_postprocessing
+I: [EXECUTING] ././testcases/sets/0067nat_concat_interval_0
+W: [FAILED] ././testcases/sets/0067nat_concat_interval_0
+I: [EXECUTING] ././testcases/sets/0068interval_stack_overflow_0
+I: [OK] ././testcases/sets/0068interval_stack_overflow_0
+I: [EXECUTING] ././testcases/sets/0069interval_merge_0
+I: [OK] ././testcases/sets/0069interval_merge_0
+I: [EXECUTING] ././testcases/sets/0070stacked_l2_headers
+W: [FAILED] ././testcases/sets/0070stacked_l2_headers
+I: [EXECUTING] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [EXECUTING] ././testcases/sets/0072destroy_0
+W: [FAILED] ././testcases/sets/0072destroy_0
+I: [EXECUTING] ././testcases/sets/automerge_0
+W: [FAILED] ././testcases/sets/automerge_0
+I: [EXECUTING] ././testcases/sets/collapse_elem_0
+I: [OK] ././testcases/sets/collapse_elem_0
+I: [EXECUTING] ././testcases/sets/concat_interval_0
+W: [FAILED] ././testcases/sets/concat_interval_0
+I: [EXECUTING] ././testcases/sets/dynset_missing
+W: [FAILED] ././testcases/sets/dynset_missing
+I: [EXECUTING] ././testcases/sets/errors_0
+I: [OK] ././testcases/sets/errors_0
+I: [EXECUTING] ././testcases/sets/exact_overlap_0
+I: [OK] ././testcases/sets/exact_overlap_0
+I: [EXECUTING] ././testcases/sets/inner_0
+W: [FAILED] ././testcases/sets/inner_0
+I: [EXECUTING] ././testcases/sets/reset_command_0
+W: [FAILED] ././testcases/sets/reset_command_0
+I: [EXECUTING] ././testcases/sets/set_eval_0
+I: [OK] ././testcases/sets/set_eval_0
+I: [EXECUTING] ././testcases/sets/sets_with_ifnames
+W: [FAILED] ././testcases/sets/sets_with_ifnames
+I: [EXECUTING] ././testcases/sets/typeof_raw_0
+W: [FAILED] ././testcases/sets/typeof_raw_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_0
+W: [FAILED] ././testcases/sets/typeof_sets_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_1
+I: [OK] ././testcases/sets/typeof_sets_1
+I: [EXECUTING] ././testcases/sets/typeof_sets_concat
+W: [FAILED] ././testcases/sets/typeof_sets_concat
+I: [EXECUTING] ././testcases/sets/type_set_symbol
+W: [FAILED] ././testcases/sets/type_set_symbol
+I: [EXECUTING] ././testcases/transactions/0001table_0
+I: [OK] ././testcases/transactions/0001table_0
+I: [EXECUTING] ././testcases/transactions/0002table_0
+I: [OK] ././testcases/transactions/0002table_0
+I: [EXECUTING] ././testcases/transactions/0003table_0
+I: [OK] ././testcases/transactions/0003table_0
+I: [EXECUTING] ././testcases/transactions/0010chain_0
+I: [OK] ././testcases/transactions/0010chain_0
+I: [EXECUTING] ././testcases/transactions/0011chain_0
+I: [OK] ././testcases/transactions/0011chain_0
+I: [EXECUTING] ././testcases/transactions/0012chain_0
+I: [OK] ././testcases/transactions/0012chain_0
+I: [EXECUTING] ././testcases/transactions/0013chain_0
+I: [OK] ././testcases/transactions/0013chain_0
+I: [EXECUTING] ././testcases/transactions/0014chain_1
+I: [OK] ././testcases/transactions/0014chain_1
+I: [EXECUTING] ././testcases/transactions/0015chain_0
+I: [OK] ././testcases/transactions/0015chain_0
+I: [EXECUTING] ././testcases/transactions/0020rule_0
+I: [OK] ././testcases/transactions/0020rule_0
+I: [EXECUTING] ././testcases/transactions/0021rule_0
+I: [OK] ././testcases/transactions/0021rule_0
+I: [EXECUTING] ././testcases/transactions/0022rule_1
+I: [OK] ././testcases/transactions/0022rule_1
+I: [EXECUTING] ././testcases/transactions/0023rule_1
+I: [OK] ././testcases/transactions/0023rule_1
+I: [EXECUTING] ././testcases/transactions/0024rule_0
+W: [DUMP FAIL] ././testcases/transactions/0024rule_0
+I: [EXECUTING] ././testcases/transactions/0025rule_0
+I: [OK] ././testcases/transactions/0025rule_0
+I: [EXECUTING] ././testcases/transactions/0030set_0
+I: [OK] ././testcases/transactions/0030set_0
+I: [EXECUTING] ././testcases/transactions/0031set_0
+I: [OK] ././testcases/transactions/0031set_0
+I: [EXECUTING] ././testcases/transactions/0032set_0
+I: [OK] ././testcases/transactions/0032set_0
+I: [EXECUTING] ././testcases/transactions/0033set_0
+I: [OK] ././testcases/transactions/0033set_0
+I: [EXECUTING] ././testcases/transactions/0034set_0
+I: [OK] ././testcases/transactions/0034set_0
+I: [EXECUTING] ././testcases/transactions/0035set_0
+I: [OK] ././testcases/transactions/0035set_0
+I: [EXECUTING] ././testcases/transactions/0036set_1
+I: [OK] ././testcases/transactions/0036set_1
+I: [EXECUTING] ././testcases/transactions/0037set_0
+I: [OK] ././testcases/transactions/0037set_0
+I: [EXECUTING] ././testcases/transactions/0038set_0
+I: [OK] ././testcases/transactions/0038set_0
+I: [EXECUTING] ././testcases/transactions/0039set_0
+I: [OK] ././testcases/transactions/0039set_0
+I: [EXECUTING] ././testcases/transactions/0040set_0
+I: [OK] ././testcases/transactions/0040set_0
+I: [EXECUTING] ././testcases/transactions/0041nat_restore_0
+I: [OK] ././testcases/transactions/0041nat_restore_0
+I: [EXECUTING] ././testcases/transactions/0042_stateful_expr_0
+I: [OK] ././testcases/transactions/0042_stateful_expr_0
+I: [EXECUTING] ././testcases/transactions/0043set_1
+I: [OK] ././testcases/transactions/0043set_1
+I: [EXECUTING] ././testcases/transactions/0044rule_0
+I: [OK] ././testcases/transactions/0044rule_0
+I: [EXECUTING] ././testcases/transactions/0045anon-unbind_0
+I: [OK] ././testcases/transactions/0045anon-unbind_0
+I: [EXECUTING] ././testcases/transactions/0046set_0
+I: [OK] ././testcases/transactions/0046set_0
+I: [EXECUTING] ././testcases/transactions/0047set_0
+I: [OK] ././testcases/transactions/0047set_0
+I: [EXECUTING] ././testcases/transactions/0048helpers_0
+I: [OK] ././testcases/transactions/0048helpers_0
+I: [EXECUTING] ././testcases/transactions/0049huge_0
+W: [FAILED] ././testcases/transactions/0049huge_0
+I: [EXECUTING] ././testcases/transactions/0050rule_1
+I: [OK] ././testcases/transactions/0050rule_1
+I: [EXECUTING] ././testcases/transactions/0051map_0
+I: [OK] ././testcases/transactions/0051map_0
+I: [EXECUTING] ././testcases/transactions/30s-stress
+W: [FAILED] ././testcases/transactions/30s-stress
+I: [EXECUTING] ././testcases/transactions/anon_chain_loop
+I: [OK] ././testcases/transactions/anon_chain_loop
+I: [EXECUTING] ././testcases/transactions/bad_expression
+I: [OK] ././testcases/transactions/bad_expression
+
+I: results: [OK] 246 [FAILED] 127 [TOTAL] 373
diff --git a/tests/shell/stable-log/log-4.19 b/tests/shell/stable-log/log-4.19
new file mode 100644
index 0000000..fd325cd
--- /dev/null
+++ b/tests/shell/stable-log/log-4.19
@@ -0,0 +1,750 @@
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_0
+W: [FAILED] ././testcases/bitwise/0040mark_binop_0
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_1
+W: [FAILED] ././testcases/bitwise/0040mark_binop_1
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_2
+W: [FAILED] ././testcases/bitwise/0040mark_binop_2
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_3
+W: [FAILED] ././testcases/bitwise/0040mark_binop_3
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_4
+W: [FAILED] ././testcases/bitwise/0040mark_binop_4
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_5
+W: [FAILED] ././testcases/bitwise/0040mark_binop_5
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_6
+W: [FAILED] ././testcases/bitwise/0040mark_binop_6
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_7
+W: [FAILED] ././testcases/bitwise/0040mark_binop_7
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_8
+W: [FAILED] ././testcases/bitwise/0040mark_binop_8
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_9
+W: [FAILED] ././testcases/bitwise/0040mark_binop_9
+I: [EXECUTING] ././testcases/bogons/assert_failures
+I: [OK] ././testcases/bogons/assert_failures
+I: [EXECUTING] ././testcases/cache/0001_cache_handling_0
+I: [OK] ././testcases/cache/0001_cache_handling_0
+I: [EXECUTING] ././testcases/cache/0002_interval_0
+I: [OK] ././testcases/cache/0002_interval_0
+I: [EXECUTING] ././testcases/cache/0003_cache_update_0
+I: [OK] ././testcases/cache/0003_cache_update_0
+I: [EXECUTING] ././testcases/cache/0004_cache_update_0
+I: [OK] ././testcases/cache/0004_cache_update_0
+I: [EXECUTING] ././testcases/cache/0005_cache_chain_flush
+I: [OK] ././testcases/cache/0005_cache_chain_flush
+I: [EXECUTING] ././testcases/cache/0006_cache_table_flush
+I: [OK] ././testcases/cache/0006_cache_table_flush
+I: [EXECUTING] ././testcases/cache/0007_echo_cache_init_0
+I: [OK] ././testcases/cache/0007_echo_cache_init_0
+I: [EXECUTING] ././testcases/cache/0008_delete_by_handle_0
+W: [FAILED] ././testcases/cache/0008_delete_by_handle_0
+I: [EXECUTING] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [EXECUTING] ././testcases/cache/0010_implicit_chain_0
+W: [FAILED] ././testcases/cache/0010_implicit_chain_0
+I: [EXECUTING] ././testcases/cache/0011_index_0
+W: [DUMP FAIL] ././testcases/cache/0011_index_0
+I: [EXECUTING] ././testcases/chains/0001jumps_0
+I: [OK] ././testcases/chains/0001jumps_0
+I: [EXECUTING] ././testcases/chains/0002jumps_1
+I: [OK] ././testcases/chains/0002jumps_1
+I: [EXECUTING] ././testcases/chains/0003jump_loop_1
+I: [OK] ././testcases/chains/0003jump_loop_1
+I: [EXECUTING] ././testcases/chains/0004busy_1
+I: [OK] ././testcases/chains/0004busy_1
+I: [EXECUTING] ././testcases/chains/0005busy_map_1
+I: [OK] ././testcases/chains/0005busy_map_1
+I: [EXECUTING] ././testcases/chains/0006masquerade_0
+I: [OK] ././testcases/chains/0006masquerade_0
+I: [EXECUTING] ././testcases/chains/0007masquerade_1
+I: [OK] ././testcases/chains/0007masquerade_1
+I: [EXECUTING] ././testcases/chains/0008masquerade_jump_1
+I: [OK] ././testcases/chains/0008masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0009masquerade_jump_1
+I: [OK] ././testcases/chains/0009masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0010endless_jump_loop_1
+I: [OK] ././testcases/chains/0010endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0011endless_jump_loop_1
+I: [OK] ././testcases/chains/0011endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0013rename_0
+I: [OK] ././testcases/chains/0013rename_0
+I: [EXECUTING] ././testcases/chains/0014rename_0
+I: [OK] ././testcases/chains/0014rename_0
+I: [EXECUTING] ././testcases/chains/0015check_jump_loop_1
+I: [OK] ././testcases/chains/0015check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0016delete_handle_0
+I: [OK] ././testcases/chains/0016delete_handle_0
+I: [EXECUTING] ././testcases/chains/0017masquerade_jump_1
+I: [OK] ././testcases/chains/0017masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0018check_jump_loop_1
+I: [OK] ././testcases/chains/0018check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0019masquerade_jump_1
+I: [OK] ././testcases/chains/0019masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0020depth_1
+I: [OK] ././testcases/chains/0020depth_1
+I: [EXECUTING] ././testcases/chains/0021prio_0
+W: [FAILED] ././testcases/chains/0021prio_0
+I: [EXECUTING] ././testcases/chains/0022prio_dummy_1
+I: [OK] ././testcases/chains/0022prio_dummy_1
+I: [EXECUTING] ././testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ././testcases/chains/0023prio_inet_srcnat_1
+I: [EXECUTING] ././testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ././testcases/chains/0024prio_inet_dstnat_1
+I: [EXECUTING] ././testcases/chains/0025prio_arp_1
+I: [OK] ././testcases/chains/0025prio_arp_1
+I: [EXECUTING] ././testcases/chains/0026prio_netdev_1
+I: [OK] ././testcases/chains/0026prio_netdev_1
+I: [EXECUTING] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [EXECUTING] ././testcases/chains/0028prio_bridge_out_1
+I: [OK] ././testcases/chains/0028prio_bridge_out_1
+I: [EXECUTING] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [EXECUTING] ././testcases/chains/0030create_0
+I: [OK] ././testcases/chains/0030create_0
+I: [EXECUTING] ././testcases/chains/0031priority_variable_0
+I: [OK] ././testcases/chains/0031priority_variable_0
+I: [EXECUTING] ././testcases/chains/0032priority_variable_0
+I: [OK] ././testcases/chains/0032priority_variable_0
+I: [EXECUTING] ././testcases/chains/0033priority_variable_1
+I: [OK] ././testcases/chains/0033priority_variable_1
+I: [EXECUTING] ././testcases/chains/0034priority_variable_1
+I: [OK] ././testcases/chains/0034priority_variable_1
+I: [EXECUTING] ././testcases/chains/0035policy_variable_0
+I: [OK] ././testcases/chains/0035policy_variable_0
+I: [EXECUTING] ././testcases/chains/0036policy_variable_0
+I: [OK] ././testcases/chains/0036policy_variable_0
+I: [EXECUTING] ././testcases/chains/0037policy_variable_1
+I: [OK] ././testcases/chains/0037policy_variable_1
+I: [EXECUTING] ././testcases/chains/0038policy_variable_1
+I: [OK] ././testcases/chains/0038policy_variable_1
+I: [EXECUTING] ././testcases/chains/0039negative_priority_0
+I: [OK] ././testcases/chains/0039negative_priority_0
+I: [EXECUTING] ././testcases/chains/0041chain_binding_0
+W: [FAILED] ././testcases/chains/0041chain_binding_0
+I: [EXECUTING] ././testcases/chains/0042chain_variable_0
+W: [FAILED] ././testcases/chains/0042chain_variable_0
+I: [EXECUTING] ././testcases/chains/0043chain_ingress_0
+W: [FAILED] ././testcases/chains/0043chain_ingress_0
+I: [EXECUTING] ././testcases/chains/0044chain_destroy_0
+W: [FAILED] ././testcases/chains/0044chain_destroy_0
+I: [EXECUTING] ././testcases/chains/netdev_chain_0
+W: [FAILED] ././testcases/chains/netdev_chain_0
+I: [EXECUTING] ././testcases/comments/comments_0
+I: [OK] ././testcases/comments/comments_0
+I: [EXECUTING] ././testcases/flowtable/0001flowtable_0
+I: [OK] ././testcases/flowtable/0001flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0002create_flowtable_0
+I: [OK] ././testcases/flowtable/0002create_flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0003add_after_flush_0
+I: [OK] ././testcases/flowtable/0003add_after_flush_0
+I: [EXECUTING] ././testcases/flowtable/0004delete_after_add_0
+I: [OK] ././testcases/flowtable/0004delete_after_add_0
+I: [EXECUTING] ././testcases/flowtable/0005delete_in_use_1
+I: [OK] ././testcases/flowtable/0005delete_in_use_1
+I: [EXECUTING] ././testcases/flowtable/0006segfault_0
+I: [OK] ././testcases/flowtable/0006segfault_0
+I: [EXECUTING] ././testcases/flowtable/0007prio_0
+I: [OK] ././testcases/flowtable/0007prio_0
+I: [EXECUTING] ././testcases/flowtable/0008prio_1
+I: [OK] ././testcases/flowtable/0008prio_1
+I: [EXECUTING] ././testcases/flowtable/0009deleteafterflush_0
+I: [OK] ././testcases/flowtable/0009deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0010delete_handle_0
+I: [OK] ././testcases/flowtable/0010delete_handle_0
+I: [EXECUTING] ././testcases/flowtable/0011deleteafterflush_0
+I: [OK] ././testcases/flowtable/0011deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0012flowtable_variable_0
+W: [DUMP FAIL] ././testcases/flowtable/0012flowtable_variable_0
+I: [EXECUTING] ././testcases/flowtable/0013addafterdelete_0
+W: [FAILED] ././testcases/flowtable/0013addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0014addafterdelete_0
+W: [FAILED] ././testcases/flowtable/0014addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0015destroy_0
+W: [FAILED] ././testcases/flowtable/0015destroy_0
+I: [EXECUTING] ././testcases/include/0001absolute_0
+I: [OK] ././testcases/include/0001absolute_0
+I: [EXECUTING] ././testcases/include/0002relative_0
+I: [OK] ././testcases/include/0002relative_0
+I: [EXECUTING] ././testcases/include/0003includepath_0
+I: [OK] ././testcases/include/0003includepath_0
+I: [EXECUTING] ././testcases/include/0004endlessloop_1
+I: [OK] ././testcases/include/0004endlessloop_1
+I: [EXECUTING] ././testcases/include/0005glob_empty_0
+I: [OK] ././testcases/include/0005glob_empty_0
+I: [EXECUTING] ././testcases/include/0006glob_single_0
+I: [OK] ././testcases/include/0006glob_single_0
+I: [EXECUTING] ././testcases/include/0007glob_double_0
+I: [OK] ././testcases/include/0007glob_double_0
+I: [EXECUTING] ././testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ././testcases/include/0008glob_nofile_wildcard_0
+I: [EXECUTING] ././testcases/include/0009glob_nofile_1
+I: [OK] ././testcases/include/0009glob_nofile_1
+I: [EXECUTING] ././testcases/include/0010glob_broken_file_1
+I: [OK] ././testcases/include/0010glob_broken_file_1
+I: [EXECUTING] ././testcases/include/0011glob_dependency_0
+I: [OK] ././testcases/include/0011glob_dependency_0
+I: [EXECUTING] ././testcases/include/0012glob_dependency_1
+I: [OK] ././testcases/include/0012glob_dependency_1
+I: [EXECUTING] ././testcases/include/0013glob_dotfile_0
+I: [OK] ././testcases/include/0013glob_dotfile_0
+I: [EXECUTING] ././testcases/include/0013input_descriptors_included_files_0
+I: [OK] ././testcases/include/0013input_descriptors_included_files_0
+I: [EXECUTING] ././testcases/include/0014glob_directory_0
+I: [OK] ././testcases/include/0014glob_directory_0
+I: [EXECUTING] ././testcases/include/0015doubleincludepath_0
+I: [OK] ././testcases/include/0015doubleincludepath_0
+I: [EXECUTING] ././testcases/include/0016maxdepth_0
+I: [OK] ././testcases/include/0016maxdepth_0
+I: [EXECUTING] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [EXECUTING] ././testcases/include/0018include_error_0
+I: [OK] ././testcases/include/0018include_error_0
+I: [EXECUTING] ././testcases/include/0019include_error_0
+I: [OK] ././testcases/include/0019include_error_0
+I: [EXECUTING] ././testcases/include/0020include_chain_0
+I: [OK] ././testcases/include/0020include_chain_0
+I: [EXECUTING] ././testcases/json/0001set_statements_0
+W: [FAILED] ././testcases/json/0001set_statements_0
+I: [EXECUTING] ././testcases/json/0002table_map_0
+W: [FAILED] ././testcases/json/0002table_map_0
+I: [EXECUTING] ././testcases/json/0003json_schema_version_0
+I: [OK] ././testcases/json/0003json_schema_version_0
+I: [EXECUTING] ././testcases/json/0004json_schema_version_1
+I: [OK] ././testcases/json/0004json_schema_version_1
+I: [EXECUTING] ././testcases/json/0005secmark_objref_0
+W: [FAILED] ././testcases/json/0005secmark_objref_0
+I: [EXECUTING] ././testcases/json/0006obj_comment_0
+W: [DUMP FAIL] ././testcases/json/0006obj_comment_0
+I: [EXECUTING] ././testcases/json/netdev
+I: [OK] ././testcases/json/netdev
+I: [EXECUTING] ././testcases/listing/0001ruleset_0
+I: [OK] ././testcases/listing/0001ruleset_0
+I: [EXECUTING] ././testcases/listing/0002ruleset_0
+I: [OK] ././testcases/listing/0002ruleset_0
+I: [EXECUTING] ././testcases/listing/0003table_0
+I: [OK] ././testcases/listing/0003table_0
+I: [EXECUTING] ././testcases/listing/0004table_0
+I: [OK] ././testcases/listing/0004table_0
+I: [EXECUTING] ././testcases/listing/0005ruleset_ip_0
+I: [OK] ././testcases/listing/0005ruleset_ip_0
+I: [EXECUTING] ././testcases/listing/0006ruleset_ip6_0
+I: [OK] ././testcases/listing/0006ruleset_ip6_0
+I: [EXECUTING] ././testcases/listing/0007ruleset_inet_0
+I: [OK] ././testcases/listing/0007ruleset_inet_0
+I: [EXECUTING] ././testcases/listing/0008ruleset_arp_0
+I: [OK] ././testcases/listing/0008ruleset_arp_0
+I: [EXECUTING] ././testcases/listing/0009ruleset_bridge_0
+I: [OK] ././testcases/listing/0009ruleset_bridge_0
+I: [EXECUTING] ././testcases/listing/0010sets_0
+I: [OK] ././testcases/listing/0010sets_0
+I: [EXECUTING] ././testcases/listing/0011sets_0
+I: [OK] ././testcases/listing/0011sets_0
+I: [EXECUTING] ././testcases/listing/0012sets_0
+I: [OK] ././testcases/listing/0012sets_0
+I: [EXECUTING] ././testcases/listing/0013objects_0
+W: [FAILED] ././testcases/listing/0013objects_0
+I: [EXECUTING] ././testcases/listing/0014objects_0
+I: [OK] ././testcases/listing/0014objects_0
+I: [EXECUTING] ././testcases/listing/0015dynamic_0
+I: [OK] ././testcases/listing/0015dynamic_0
+I: [EXECUTING] ././testcases/listing/0016anonymous_0
+I: [OK] ././testcases/listing/0016anonymous_0
+I: [EXECUTING] ././testcases/listing/0017objects_0
+I: [OK] ././testcases/listing/0017objects_0
+I: [EXECUTING] ././testcases/listing/0018data_0
+I: [OK] ././testcases/listing/0018data_0
+I: [EXECUTING] ././testcases/listing/0019set_0
+I: [OK] ././testcases/listing/0019set_0
+I: [EXECUTING] ././testcases/listing/0020flowtable_0
+I: [OK] ././testcases/listing/0020flowtable_0
+I: [EXECUTING] ././testcases/listing/0021ruleset_json_terse_0
+I: [OK] ././testcases/listing/0021ruleset_json_terse_0
+I: [EXECUTING] ././testcases/listing/0022terse_0
+I: [OK] ././testcases/listing/0022terse_0
+I: [EXECUTING] ././testcases/maps/0003map_add_many_elements_0
+I: [OK] ././testcases/maps/0003map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0004interval_map_create_once_0
+I: [OK] ././testcases/maps/0004interval_map_create_once_0
+I: [EXECUTING] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0006interval_map_overlap_0
+I: [OK] ././testcases/maps/0006interval_map_overlap_0
+I: [EXECUTING] ././testcases/maps/0007named_ifname_dtype_0
+I: [OK] ././testcases/maps/0007named_ifname_dtype_0
+I: [EXECUTING] ././testcases/maps/0008interval_map_delete_0
+I: [OK] ././testcases/maps/0008interval_map_delete_0
+I: [EXECUTING] ././testcases/maps/0009vmap_0
+W: [DUMP FAIL] ././testcases/maps/0009vmap_0
+I: [EXECUTING] ././testcases/maps/0010concat_map_0
+W: [FAILED] ././testcases/maps/0010concat_map_0
+I: [EXECUTING] ././testcases/maps/0011vmap_0
+W: [FAILED] ././testcases/maps/0011vmap_0
+I: [EXECUTING] ././testcases/maps/0012map_0
+W: [FAILED] ././testcases/maps/0012map_0
+I: [EXECUTING] ././testcases/maps/0013map_0
+W: [FAILED] ././testcases/maps/0013map_0
+I: [EXECUTING] ././testcases/maps/0014destroy_0
+W: [FAILED] ././testcases/maps/0014destroy_0
+I: [EXECUTING] ././testcases/maps/0016map_leak_0
+I: [OK] ././testcases/maps/0016map_leak_0
+I: [EXECUTING] ././testcases/maps/0017_map_variable_0
+W: [FAILED] ././testcases/maps/0017_map_variable_0
+I: [EXECUTING] ././testcases/maps/0018map_leak_timeout_0
+I: [OK] ././testcases/maps/0018map_leak_timeout_0
+I: [EXECUTING] ././testcases/maps/anon_objmap_concat
+W: [FAILED] ././testcases/maps/anon_objmap_concat
+I: [EXECUTING] ././testcases/maps/anonymous_snat_map_0
+I: [OK] ././testcases/maps/anonymous_snat_map_0
+I: [EXECUTING] ././testcases/maps/different_map_types_1
+I: [OK] ././testcases/maps/different_map_types_1
+I: [EXECUTING] ././testcases/maps/map_catchall_double_deactivate
+W: [FAILED] ././testcases/maps/map_catchall_double_deactivate
+I: [EXECUTING] ././testcases/maps/map_with_flags_0
+I: [OK] ././testcases/maps/map_with_flags_0
+I: [EXECUTING] ././testcases/maps/named_snat_map_0
+I: [OK] ././testcases/maps/named_snat_map_0
+I: [EXECUTING] ././testcases/maps/nat_addr_port
+W: [FAILED] ././testcases/maps/nat_addr_port
+I: [EXECUTING] ././testcases/maps/typeof_integer_0
+W: [FAILED] ././testcases/maps/typeof_integer_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_0
+W: [FAILED] ././testcases/maps/typeof_maps_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_add_delete
+W: [FAILED] ././testcases/maps/typeof_maps_add_delete
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat
+I: [OK] ././testcases/maps/typeof_maps_concat
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat_update_0
+I: [OK] ././testcases/maps/typeof_maps_concat_update_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_update_0
+I: [OK] ././testcases/maps/typeof_maps_update_0
+I: [EXECUTING] ././testcases/maps/typeof_raw_0
+W: [FAILED] ././testcases/maps/typeof_raw_0
+I: [EXECUTING] ././testcases/maps/vmap_timeout
+W: [FAILED] ././testcases/maps/vmap_timeout
+I: [EXECUTING] ././testcases/netns/0001nft-f_0
+I: [OK] ././testcases/netns/0001nft-f_0
+I: [EXECUTING] ././testcases/netns/0002loosecommands_0
+I: [OK] ././testcases/netns/0002loosecommands_0
+I: [EXECUTING] ././testcases/netns/0003many_0
+I: [OK] ././testcases/netns/0003many_0
+I: [EXECUTING] ././testcases/nft-f/0001define_slash_0
+I: [OK] ././testcases/nft-f/0001define_slash_0
+I: [EXECUTING] ././testcases/nft-f/0002rollback_rule_0
+I: [OK] ././testcases/nft-f/0002rollback_rule_0
+I: [EXECUTING] ././testcases/nft-f/0003rollback_jump_0
+I: [OK] ././testcases/nft-f/0003rollback_jump_0
+I: [EXECUTING] ././testcases/nft-f/0004rollback_set_0
+I: [OK] ././testcases/nft-f/0004rollback_set_0
+I: [EXECUTING] ././testcases/nft-f/0005rollback_map_0
+I: [OK] ././testcases/nft-f/0005rollback_map_0
+I: [EXECUTING] ././testcases/nft-f/0006action_object_0
+I: [OK] ././testcases/nft-f/0006action_object_0
+I: [EXECUTING] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [EXECUTING] ././testcases/nft-f/0008split_tables_0
+I: [OK] ././testcases/nft-f/0008split_tables_0
+I: [EXECUTING] ././testcases/nft-f/0009variable_0
+I: [OK] ././testcases/nft-f/0009variable_0
+I: [EXECUTING] ././testcases/nft-f/0010variable_0
+I: [OK] ././testcases/nft-f/0010variable_0
+I: [EXECUTING] ././testcases/nft-f/0011manydefines_0
+I: [OK] ././testcases/nft-f/0011manydefines_0
+I: [EXECUTING] ././testcases/nft-f/0012different_defines_0
+I: [OK] ././testcases/nft-f/0012different_defines_0
+I: [EXECUTING] ././testcases/nft-f/0013defines_1
+I: [OK] ././testcases/nft-f/0013defines_1
+I: [EXECUTING] ././testcases/nft-f/0014defines_1
+I: [OK] ././testcases/nft-f/0014defines_1
+I: [EXECUTING] ././testcases/nft-f/0015defines_1
+I: [OK] ././testcases/nft-f/0015defines_1
+I: [EXECUTING] ././testcases/nft-f/0016redefines_1
+I: [OK] ././testcases/nft-f/0016redefines_1
+I: [EXECUTING] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018ct_expectation_obj_0
+W: [FAILED] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018jump_variable_0
+I: [OK] ././testcases/nft-f/0018jump_variable_0
+I: [EXECUTING] ././testcases/nft-f/0019jump_variable_1
+I: [OK] ././testcases/nft-f/0019jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0020jump_variable_1
+I: [OK] ././testcases/nft-f/0020jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0021list_ruleset_0
+I: [OK] ././testcases/nft-f/0021list_ruleset_0
+I: [EXECUTING] ././testcases/nft-f/0022variables_0
+I: [OK] ././testcases/nft-f/0022variables_0
+I: [EXECUTING] ././testcases/nft-f/0023check_1
+W: [FAILED] ././testcases/nft-f/0023check_1
+I: [EXECUTING] ././testcases/nft-f/0024priority_0
+I: [OK] ././testcases/nft-f/0024priority_0
+I: [EXECUTING] ././testcases/nft-f/0025empty_dynset_0
+W: [DUMP FAIL] ././testcases/nft-f/0025empty_dynset_0
+I: [EXECUTING] ././testcases/nft-f/0026listing_0
+I: [OK] ././testcases/nft-f/0026listing_0
+I: [EXECUTING] ././testcases/nft-f/0027split_chains_0
+I: [OK] ././testcases/nft-f/0027split_chains_0
+I: [EXECUTING] ././testcases/nft-f/0028variable_cmdline_0
+I: [OK] ././testcases/nft-f/0028variable_cmdline_0
+I: [EXECUTING] ././testcases/nft-f/0029split_file_0
+I: [OK] ././testcases/nft-f/0029split_file_0
+I: [EXECUTING] ././testcases/nft-f/0030variable_reuse_0
+I: [OK] ././testcases/nft-f/0030variable_reuse_0
+I: [EXECUTING] ././testcases/nft-f/0031vmap_string_0
+I: [OK] ././testcases/nft-f/0031vmap_string_0
+I: [EXECUTING] ././testcases/nft-f/0032pknock_0
+I: [OK] ././testcases/nft-f/0032pknock_0
+I: [EXECUTING] ././testcases/nft-i/0001define_0
+I: [OK] ././testcases/nft-i/0001define_0
+I: [EXECUTING] ././testcases/optimizations/dependency_kill
+I: [OK] ././testcases/optimizations/dependency_kill
+I: [EXECUTING] ././testcases/optimizations/merge_nat
+W: [FAILED] ././testcases/optimizations/merge_nat
+I: [EXECUTING] ././testcases/optimizations/merge_reject
+I: [OK] ././testcases/optimizations/merge_reject
+I: [EXECUTING] ././testcases/optimizations/merge_stmts
+I: [OK] ././testcases/optimizations/merge_stmts
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat
+W: [FAILED] ././testcases/optimizations/merge_stmts_concat
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_vmap
+W: [DUMP FAIL] ././testcases/optimizations/merge_stmts_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_vmap_raw
+W: [FAILED] ././testcases/optimizations/merge_vmap_raw
+I: [EXECUTING] ././testcases/optimizations/merge_vmaps
+W: [FAILED] ././testcases/optimizations/merge_vmaps
+I: [EXECUTING] ././testcases/optimizations/not_mergeable
+I: [OK] ././testcases/optimizations/not_mergeable
+I: [EXECUTING] ././testcases/optimizations/ruleset
+W: [FAILED] ././testcases/optimizations/ruleset
+I: [EXECUTING] ././testcases/optimizations/single_anon_set
+W: [DUMP FAIL] ././testcases/optimizations/single_anon_set
+I: [EXECUTING] ././testcases/optimizations/skip_merge
+I: [OK] ././testcases/optimizations/skip_merge
+I: [EXECUTING] ././testcases/optimizations/skip_non_eq
+I: [OK] ././testcases/optimizations/skip_non_eq
+I: [EXECUTING] ././testcases/optimizations/skip_unsupported
+I: [OK] ././testcases/optimizations/skip_unsupported
+I: [EXECUTING] ././testcases/optimizations/variables
+I: [OK] ././testcases/optimizations/variables
+I: [EXECUTING] ././testcases/optionals/comments_0
+I: [OK] ././testcases/optionals/comments_0
+I: [EXECUTING] ././testcases/optionals/comments_chain_0
+W: [DUMP FAIL] ././testcases/optionals/comments_chain_0
+I: [EXECUTING] ././testcases/optionals/comments_handles_0
+I: [OK] ././testcases/optionals/comments_handles_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_0
+W: [FAILED] ././testcases/optionals/comments_objects_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_dup_0
+I: [OK] ././testcases/optionals/comments_objects_dup_0
+I: [EXECUTING] ././testcases/optionals/comments_table_0
+W: [DUMP FAIL] ././testcases/optionals/comments_table_0
+I: [EXECUTING] ././testcases/optionals/delete_object_handles_0
+I: [OK] ././testcases/optionals/delete_object_handles_0
+I: [EXECUTING] ././testcases/optionals/handles_0
+I: [OK] ././testcases/optionals/handles_0
+I: [EXECUTING] ././testcases/optionals/handles_1
+I: [OK] ././testcases/optionals/handles_1
+I: [EXECUTING] ././testcases/optionals/log_prefix_0
+I: [OK] ././testcases/optionals/log_prefix_0
+I: [EXECUTING] ././testcases/optionals/update_object_handles_0
+W: [FAILED] ././testcases/optionals/update_object_handles_0
+I: [EXECUTING] ././testcases/owner/0001-flowtable-uaf
+W: [FAILED] ././testcases/owner/0001-flowtable-uaf
+I: [EXECUTING] ././testcases/parsing/describe
+I: [OK] ././testcases/parsing/describe
+I: [EXECUTING] ././testcases/parsing/large_rule_pipe
+I: [OK] ././testcases/parsing/large_rule_pipe
+I: [EXECUTING] ././testcases/parsing/log
+I: [OK] ././testcases/parsing/log
+I: [EXECUTING] ././testcases/parsing/octal
+I: [OK] ././testcases/parsing/octal
+I: [EXECUTING] ././testcases/rule_management/0001addinsertposition_0
+I: [OK] ././testcases/rule_management/0001addinsertposition_0
+I: [EXECUTING] ././testcases/rule_management/0002addinsertlocation_1
+I: [OK] ././testcases/rule_management/0002addinsertlocation_1
+I: [EXECUTING] ././testcases/rule_management/0003insert_0
+I: [OK] ././testcases/rule_management/0003insert_0
+I: [EXECUTING] ././testcases/rule_management/0004replace_0
+I: [OK] ././testcases/rule_management/0004replace_0
+I: [EXECUTING] ././testcases/rule_management/0005replace_1
+I: [OK] ././testcases/rule_management/0005replace_1
+I: [EXECUTING] ././testcases/rule_management/0006replace_1
+I: [OK] ././testcases/rule_management/0006replace_1
+I: [EXECUTING] ././testcases/rule_management/0007delete_0
+I: [OK] ././testcases/rule_management/0007delete_0
+I: [EXECUTING] ././testcases/rule_management/0008delete_1
+I: [OK] ././testcases/rule_management/0008delete_1
+I: [EXECUTING] ././testcases/rule_management/0009delete_1
+I: [OK] ././testcases/rule_management/0009delete_1
+I: [EXECUTING] ././testcases/rule_management/0010replace_0
+I: [OK] ././testcases/rule_management/0010replace_0
+I: [EXECUTING] ././testcases/rule_management/0011reset_0
+W: [FAILED] ././testcases/rule_management/0011reset_0
+I: [EXECUTING] ././testcases/rule_management/0012destroy_0
+W: [FAILED] ././testcases/rule_management/0012destroy_0
+I: [EXECUTING] ././testcases/sets/0001named_interval_0
+I: [OK] ././testcases/sets/0001named_interval_0
+I: [EXECUTING] ././testcases/sets/0002named_interval_automerging_0
+I: [OK] ././testcases/sets/0002named_interval_automerging_0
+I: [EXECUTING] ././testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ././testcases/sets/0003named_interval_missing_flag_0
+I: [EXECUTING] ././testcases/sets/0004named_interval_shadow_0
+I: [OK] ././testcases/sets/0004named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0005named_interval_shadow_0
+I: [OK] ././testcases/sets/0005named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0006create_set_0
+I: [OK] ././testcases/sets/0006create_set_0
+I: [EXECUTING] ././testcases/sets/0007create_element_0
+I: [OK] ././testcases/sets/0007create_element_0
+I: [EXECUTING] ././testcases/sets/0008comments_interval_0
+I: [OK] ././testcases/sets/0008comments_interval_0
+I: [EXECUTING] ././testcases/sets/0008create_verdict_map_0
+I: [OK] ././testcases/sets/0008create_verdict_map_0
+I: [EXECUTING] ././testcases/sets/0009comments_timeout_0
+I: [OK] ././testcases/sets/0009comments_timeout_0
+I: [EXECUTING] ././testcases/sets/0010comments_0
+I: [OK] ././testcases/sets/0010comments_0
+I: [EXECUTING] ././testcases/sets/0011add_many_elements_0
+I: [OK] ././testcases/sets/0011add_many_elements_0
+I: [EXECUTING] ././testcases/sets/0012add_delete_many_elements_0
+I: [OK] ././testcases/sets/0012add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0013add_delete_many_elements_0
+I: [OK] ././testcases/sets/0013add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [EXECUTING] ././testcases/sets/0015rulesetflush_0
+I: [OK] ././testcases/sets/0015rulesetflush_0
+I: [EXECUTING] ././testcases/sets/0016element_leak_0
+I: [OK] ././testcases/sets/0016element_leak_0
+I: [EXECUTING] ././testcases/sets/0017add_after_flush_0
+I: [OK] ././testcases/sets/0017add_after_flush_0
+I: [EXECUTING] ././testcases/sets/0018set_check_size_1
+I: [OK] ././testcases/sets/0018set_check_size_1
+I: [EXECUTING] ././testcases/sets/0019set_check_size_0
+I: [OK] ././testcases/sets/0019set_check_size_0
+I: [EXECUTING] ././testcases/sets/0020comments_0
+I: [OK] ././testcases/sets/0020comments_0
+I: [EXECUTING] ././testcases/sets/0021nesting_0
+I: [OK] ././testcases/sets/0021nesting_0
+I: [EXECUTING] ././testcases/sets/0022type_selective_flush_0
+I: [OK] ././testcases/sets/0022type_selective_flush_0
+I: [EXECUTING] ././testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ././testcases/sets/0023incomplete_add_set_command_0
+I: [EXECUTING] ././testcases/sets/0024named_objects_0
+W: [FAILED] ././testcases/sets/0024named_objects_0
+I: [EXECUTING] ././testcases/sets/0025anonymous_set_0
+I: [OK] ././testcases/sets/0025anonymous_set_0
+I: [EXECUTING] ././testcases/sets/0026named_limit_0
+I: [OK] ././testcases/sets/0026named_limit_0
+I: [EXECUTING] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [EXECUTING] ././testcases/sets/0028autoselect_0
+I: [OK] ././testcases/sets/0028autoselect_0
+I: [EXECUTING] ././testcases/sets/0028delete_handle_0
+I: [OK] ././testcases/sets/0028delete_handle_0
+I: [EXECUTING] ././testcases/sets/0029named_ifname_dtype_0
+I: [OK] ././testcases/sets/0029named_ifname_dtype_0
+I: [EXECUTING] ././testcases/sets/0030add_many_elements_interval_0
+I: [OK] ././testcases/sets/0030add_many_elements_interval_0
+I: [EXECUTING] ././testcases/sets/0031set_timeout_size_0
+I: [OK] ././testcases/sets/0031set_timeout_size_0
+I: [EXECUTING] ././testcases/sets/0032restore_set_simple_0
+I: [OK] ././testcases/sets/0032restore_set_simple_0
+I: [EXECUTING] ././testcases/sets/0033add_set_simple_flat_0
+I: [OK] ././testcases/sets/0033add_set_simple_flat_0
+I: [EXECUTING] ././testcases/sets/0034get_element_0
+W: [FAILED] ././testcases/sets/0034get_element_0
+I: [EXECUTING] ././testcases/sets/0035add_set_elements_flat_0
+I: [OK] ././testcases/sets/0035add_set_elements_flat_0
+I: [EXECUTING] ././testcases/sets/0036add_set_element_expiration_0
+W: [FAILED] ././testcases/sets/0036add_set_element_expiration_0
+I: [EXECUTING] ././testcases/sets/0037_set_with_inet_service_0
+I: [OK] ././testcases/sets/0037_set_with_inet_service_0
+I: [EXECUTING] ././testcases/sets/0038meter_list_0
+I: [OK] ././testcases/sets/0038meter_list_0
+I: [EXECUTING] ././testcases/sets/0039delete_interval_0
+I: [OK] ././testcases/sets/0039delete_interval_0
+I: [EXECUTING] ././testcases/sets/0040get_host_endian_elements_0
+I: [OK] ././testcases/sets/0040get_host_endian_elements_0
+I: [EXECUTING] ././testcases/sets/0041interval_0
+I: [OK] ././testcases/sets/0041interval_0
+I: [EXECUTING] ././testcases/sets/0042update_set_0
+I: [OK] ././testcases/sets/0042update_set_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_0
+W: [FAILED] ././testcases/sets/0043concatenated_ranges_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_1
+W: [FAILED] ././testcases/sets/0043concatenated_ranges_1
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_0
+W: [FAILED] ././testcases/sets/0044interval_overlap_0
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_1
+I: [OK] ././testcases/sets/0044interval_overlap_1
+I: [EXECUTING] ././testcases/sets/0045concat_ipv4_service
+I: [OK] ././testcases/sets/0045concat_ipv4_service
+I: [EXECUTING] ././testcases/sets/0046netmap_0
+W: [FAILED] ././testcases/sets/0046netmap_0
+I: [EXECUTING] ././testcases/sets/0047nat_0
+W: [FAILED] ././testcases/sets/0047nat_0
+I: [EXECUTING] ././testcases/sets/0048set_counters_0
+W: [DUMP FAIL] ././testcases/sets/0048set_counters_0
+I: [EXECUTING] ././testcases/sets/0049set_define_0
+I: [OK] ././testcases/sets/0049set_define_0
+I: [EXECUTING] ././testcases/sets/0050set_define_1
+I: [OK] ././testcases/sets/0050set_define_1
+I: [EXECUTING] ././testcases/sets/0051set_interval_counter_0
+W: [DUMP FAIL] ././testcases/sets/0051set_interval_counter_0
+I: [EXECUTING] ././testcases/sets/0052overlap_0
+I: [OK] ././testcases/sets/0052overlap_0
+I: [EXECUTING] ././testcases/sets/0053echo_0
+I: [OK] ././testcases/sets/0053echo_0
+I: [EXECUTING] ././testcases/sets/0054comments_set_0
+I: [OK] ././testcases/sets/0054comments_set_0
+I: [EXECUTING] ././testcases/sets/0055tcpflags_0
+I: [OK] ././testcases/sets/0055tcpflags_0
+I: [EXECUTING] ././testcases/sets/0056dynamic_limit_0
+I: [OK] ././testcases/sets/0056dynamic_limit_0
+I: [EXECUTING] ././testcases/sets/0057set_create_fails_0
+I: [OK] ././testcases/sets/0057set_create_fails_0
+I: [EXECUTING] ././testcases/sets/0058_setupdate_timeout_0
+W: [DUMP FAIL] ././testcases/sets/0058_setupdate_timeout_0
+I: [EXECUTING] ././testcases/sets/0059set_update_multistmt_0
+W: [FAILED] ././testcases/sets/0059set_update_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_0
+W: [FAILED] ././testcases/sets/0060set_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_1
+W: [FAILED] ././testcases/sets/0060set_multistmt_1
+I: [EXECUTING] ././testcases/sets/0061anonymous_automerge_0
+I: [OK] ././testcases/sets/0061anonymous_automerge_0
+I: [EXECUTING] ././testcases/sets/0062set_connlimit_0
+I: [OK] ././testcases/sets/0062set_connlimit_0
+I: [EXECUTING] ././testcases/sets/0063set_catchall_0
+W: [FAILED] ././testcases/sets/0063set_catchall_0
+I: [EXECUTING] ././testcases/sets/0064map_catchall_0
+W: [FAILED] ././testcases/sets/0064map_catchall_0
+I: [EXECUTING] ././testcases/sets/0065_icmp_postprocessing
+I: [OK] ././testcases/sets/0065_icmp_postprocessing
+I: [EXECUTING] ././testcases/sets/0067nat_concat_interval_0
+W: [FAILED] ././testcases/sets/0067nat_concat_interval_0
+I: [EXECUTING] ././testcases/sets/0068interval_stack_overflow_0
+I: [OK] ././testcases/sets/0068interval_stack_overflow_0
+I: [EXECUTING] ././testcases/sets/0069interval_merge_0
+I: [OK] ././testcases/sets/0069interval_merge_0
+I: [EXECUTING] ././testcases/sets/0070stacked_l2_headers
+I: [OK] ././testcases/sets/0070stacked_l2_headers
+I: [EXECUTING] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [EXECUTING] ././testcases/sets/0072destroy_0
+W: [FAILED] ././testcases/sets/0072destroy_0
+I: [EXECUTING] ././testcases/sets/automerge_0
+I: [OK] ././testcases/sets/automerge_0
+I: [EXECUTING] ././testcases/sets/collapse_elem_0
+I: [OK] ././testcases/sets/collapse_elem_0
+I: [EXECUTING] ././testcases/sets/concat_interval_0
+W: [FAILED] ././testcases/sets/concat_interval_0
+I: [EXECUTING] ././testcases/sets/dynset_missing
+W: [FAILED] ././testcases/sets/dynset_missing
+I: [EXECUTING] ././testcases/sets/errors_0
+I: [OK] ././testcases/sets/errors_0
+I: [EXECUTING] ././testcases/sets/exact_overlap_0
+I: [OK] ././testcases/sets/exact_overlap_0
+I: [EXECUTING] ././testcases/sets/inner_0
+W: [FAILED] ././testcases/sets/inner_0
+I: [EXECUTING] ././testcases/sets/reset_command_0
+W: [FAILED] ././testcases/sets/reset_command_0
+I: [EXECUTING] ././testcases/sets/set_eval_0
+I: [OK] ././testcases/sets/set_eval_0
+I: [EXECUTING] ././testcases/sets/sets_with_ifnames
+W: [FAILED] ././testcases/sets/sets_with_ifnames
+I: [EXECUTING] ././testcases/sets/typeof_raw_0
+W: [FAILED] ././testcases/sets/typeof_raw_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_0
+W: [FAILED] ././testcases/sets/typeof_sets_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_1
+I: [OK] ././testcases/sets/typeof_sets_1
+I: [EXECUTING] ././testcases/sets/typeof_sets_concat
+I: [OK] ././testcases/sets/typeof_sets_concat
+I: [EXECUTING] ././testcases/sets/type_set_symbol
+I: [OK] ././testcases/sets/type_set_symbol
+I: [EXECUTING] ././testcases/transactions/0001table_0
+I: [OK] ././testcases/transactions/0001table_0
+I: [EXECUTING] ././testcases/transactions/0002table_0
+I: [OK] ././testcases/transactions/0002table_0
+I: [EXECUTING] ././testcases/transactions/0003table_0
+I: [OK] ././testcases/transactions/0003table_0
+I: [EXECUTING] ././testcases/transactions/0010chain_0
+I: [OK] ././testcases/transactions/0010chain_0
+I: [EXECUTING] ././testcases/transactions/0011chain_0
+I: [OK] ././testcases/transactions/0011chain_0
+I: [EXECUTING] ././testcases/transactions/0012chain_0
+I: [OK] ././testcases/transactions/0012chain_0
+I: [EXECUTING] ././testcases/transactions/0013chain_0
+I: [OK] ././testcases/transactions/0013chain_0
+I: [EXECUTING] ././testcases/transactions/0014chain_1
+I: [OK] ././testcases/transactions/0014chain_1
+I: [EXECUTING] ././testcases/transactions/0015chain_0
+I: [OK] ././testcases/transactions/0015chain_0
+I: [EXECUTING] ././testcases/transactions/0020rule_0
+I: [OK] ././testcases/transactions/0020rule_0
+I: [EXECUTING] ././testcases/transactions/0021rule_0
+I: [OK] ././testcases/transactions/0021rule_0
+I: [EXECUTING] ././testcases/transactions/0022rule_1
+I: [OK] ././testcases/transactions/0022rule_1
+I: [EXECUTING] ././testcases/transactions/0023rule_1
+I: [OK] ././testcases/transactions/0023rule_1
+I: [EXECUTING] ././testcases/transactions/0024rule_0
+W: [DUMP FAIL] ././testcases/transactions/0024rule_0
+I: [EXECUTING] ././testcases/transactions/0025rule_0
+I: [OK] ././testcases/transactions/0025rule_0
+I: [EXECUTING] ././testcases/transactions/0030set_0
+I: [OK] ././testcases/transactions/0030set_0
+I: [EXECUTING] ././testcases/transactions/0031set_0
+I: [OK] ././testcases/transactions/0031set_0
+I: [EXECUTING] ././testcases/transactions/0032set_0
+I: [OK] ././testcases/transactions/0032set_0
+I: [EXECUTING] ././testcases/transactions/0033set_0
+I: [OK] ././testcases/transactions/0033set_0
+I: [EXECUTING] ././testcases/transactions/0034set_0
+I: [OK] ././testcases/transactions/0034set_0
+I: [EXECUTING] ././testcases/transactions/0035set_0
+I: [OK] ././testcases/transactions/0035set_0
+I: [EXECUTING] ././testcases/transactions/0036set_1
+I: [OK] ././testcases/transactions/0036set_1
+I: [EXECUTING] ././testcases/transactions/0037set_0
+I: [OK] ././testcases/transactions/0037set_0
+I: [EXECUTING] ././testcases/transactions/0038set_0
+I: [OK] ././testcases/transactions/0038set_0
+I: [EXECUTING] ././testcases/transactions/0039set_0
+I: [OK] ././testcases/transactions/0039set_0
+I: [EXECUTING] ././testcases/transactions/0040set_0
+I: [OK] ././testcases/transactions/0040set_0
+I: [EXECUTING] ././testcases/transactions/0041nat_restore_0
+I: [OK] ././testcases/transactions/0041nat_restore_0
+I: [EXECUTING] ././testcases/transactions/0042_stateful_expr_0
+I: [OK] ././testcases/transactions/0042_stateful_expr_0
+I: [EXECUTING] ././testcases/transactions/0043set_1
+I: [OK] ././testcases/transactions/0043set_1
+I: [EXECUTING] ././testcases/transactions/0044rule_0
+I: [OK] ././testcases/transactions/0044rule_0
+I: [EXECUTING] ././testcases/transactions/0045anon-unbind_0
+I: [OK] ././testcases/transactions/0045anon-unbind_0
+I: [EXECUTING] ././testcases/transactions/0046set_0
+I: [OK] ././testcases/transactions/0046set_0
+I: [EXECUTING] ././testcases/transactions/0047set_0
+I: [OK] ././testcases/transactions/0047set_0
+I: [EXECUTING] ././testcases/transactions/0048helpers_0
+I: [OK] ././testcases/transactions/0048helpers_0
+I: [EXECUTING] ././testcases/transactions/0049huge_0
+I: [OK] ././testcases/transactions/0049huge_0
+I: [EXECUTING] ././testcases/transactions/0050rule_1
+I: [OK] ././testcases/transactions/0050rule_1
+I: [EXECUTING] ././testcases/transactions/0051map_0
+I: [OK] ././testcases/transactions/0051map_0
+I: [EXECUTING] ././testcases/transactions/30s-stress
+I: [OK] ././testcases/transactions/30s-stress
+I: [EXECUTING] ././testcases/transactions/anon_chain_loop
+I: [OK] ././testcases/transactions/anon_chain_loop
+I: [EXECUTING] ././testcases/transactions/bad_expression
+I: [OK] ././testcases/transactions/bad_expression
+
+I: results: [OK] 287 [FAILED] 86 [TOTAL] 373
diff --git a/tests/shell/stable-log/log-5.10 b/tests/shell/stable-log/log-5.10
new file mode 100644
index 0000000..51fc992
--- /dev/null
+++ b/tests/shell/stable-log/log-5.10
@@ -0,0 +1,754 @@
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_0
+I: [OK] ././testcases/bitwise/0040mark_binop_0
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_1
+I: [OK] ././testcases/bitwise/0040mark_binop_1
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_2
+I: [OK] ././testcases/bitwise/0040mark_binop_2
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_3
+I: [OK] ././testcases/bitwise/0040mark_binop_3
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_4
+I: [OK] ././testcases/bitwise/0040mark_binop_4
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_5
+I: [OK] ././testcases/bitwise/0040mark_binop_5
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_6
+I: [OK] ././testcases/bitwise/0040mark_binop_6
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_7
+I: [OK] ././testcases/bitwise/0040mark_binop_7
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_8
+I: [OK] ././testcases/bitwise/0040mark_binop_8
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_9
+I: [OK] ././testcases/bitwise/0040mark_binop_9
+I: [EXECUTING] ././testcases/bogons/assert_failures
+I: [OK] ././testcases/bogons/assert_failures
+I: [EXECUTING] ././testcases/cache/0001_cache_handling_0
+I: [OK] ././testcases/cache/0001_cache_handling_0
+I: [EXECUTING] ././testcases/cache/0002_interval_0
+I: [OK] ././testcases/cache/0002_interval_0
+I: [EXECUTING] ././testcases/cache/0003_cache_update_0
+I: [OK] ././testcases/cache/0003_cache_update_0
+I: [EXECUTING] ././testcases/cache/0004_cache_update_0
+I: [OK] ././testcases/cache/0004_cache_update_0
+I: [EXECUTING] ././testcases/cache/0005_cache_chain_flush
+I: [OK] ././testcases/cache/0005_cache_chain_flush
+I: [EXECUTING] ././testcases/cache/0006_cache_table_flush
+I: [OK] ././testcases/cache/0006_cache_table_flush
+I: [EXECUTING] ././testcases/cache/0007_echo_cache_init_0
+I: [OK] ././testcases/cache/0007_echo_cache_init_0
+I: [EXECUTING] ././testcases/cache/0008_delete_by_handle_0
+I: [OK] ././testcases/cache/0008_delete_by_handle_0
+I: [EXECUTING] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [EXECUTING] ././testcases/cache/0010_implicit_chain_0
+I: [OK] ././testcases/cache/0010_implicit_chain_0
+I: [EXECUTING] ././testcases/cache/0011_index_0
+I: [OK] ././testcases/cache/0011_index_0
+I: [EXECUTING] ././testcases/chains/0001jumps_0
+I: [OK] ././testcases/chains/0001jumps_0
+I: [EXECUTING] ././testcases/chains/0002jumps_1
+I: [OK] ././testcases/chains/0002jumps_1
+I: [EXECUTING] ././testcases/chains/0003jump_loop_1
+I: [OK] ././testcases/chains/0003jump_loop_1
+I: [EXECUTING] ././testcases/chains/0004busy_1
+I: [OK] ././testcases/chains/0004busy_1
+I: [EXECUTING] ././testcases/chains/0005busy_map_1
+I: [OK] ././testcases/chains/0005busy_map_1
+I: [EXECUTING] ././testcases/chains/0006masquerade_0
+I: [OK] ././testcases/chains/0006masquerade_0
+I: [EXECUTING] ././testcases/chains/0007masquerade_1
+I: [OK] ././testcases/chains/0007masquerade_1
+I: [EXECUTING] ././testcases/chains/0008masquerade_jump_1
+I: [OK] ././testcases/chains/0008masquerade_jump_1
+W: [FAILED] kmemleak detected 5510 memory leaks
+I: [EXECUTING] ././testcases/chains/0009masquerade_jump_1
+I: [OK] ././testcases/chains/0009masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0010endless_jump_loop_1
+I: [OK] ././testcases/chains/0010endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0011endless_jump_loop_1
+I: [OK] ././testcases/chains/0011endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0013rename_0
+I: [OK] ././testcases/chains/0013rename_0
+I: [EXECUTING] ././testcases/chains/0014rename_0
+I: [OK] ././testcases/chains/0014rename_0
+I: [EXECUTING] ././testcases/chains/0015check_jump_loop_1
+I: [OK] ././testcases/chains/0015check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0016delete_handle_0
+I: [OK] ././testcases/chains/0016delete_handle_0
+I: [EXECUTING] ././testcases/chains/0017masquerade_jump_1
+I: [OK] ././testcases/chains/0017masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0018check_jump_loop_1
+I: [OK] ././testcases/chains/0018check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0019masquerade_jump_1
+I: [OK] ././testcases/chains/0019masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0020depth_1
+I: [OK] ././testcases/chains/0020depth_1
+I: [EXECUTING] ././testcases/chains/0021prio_0
+W: [FAILED] ././testcases/chains/0021prio_0
+I: [EXECUTING] ././testcases/chains/0022prio_dummy_1
+I: [OK] ././testcases/chains/0022prio_dummy_1
+I: [EXECUTING] ././testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ././testcases/chains/0023prio_inet_srcnat_1
+I: [EXECUTING] ././testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ././testcases/chains/0024prio_inet_dstnat_1
+I: [EXECUTING] ././testcases/chains/0025prio_arp_1
+I: [OK] ././testcases/chains/0025prio_arp_1
+I: [EXECUTING] ././testcases/chains/0026prio_netdev_1
+I: [OK] ././testcases/chains/0026prio_netdev_1
+I: [EXECUTING] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [EXECUTING] ././testcases/chains/0028prio_bridge_out_1
+I: [OK] ././testcases/chains/0028prio_bridge_out_1
+I: [EXECUTING] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [EXECUTING] ././testcases/chains/0030create_0
+I: [OK] ././testcases/chains/0030create_0
+I: [EXECUTING] ././testcases/chains/0031priority_variable_0
+I: [OK] ././testcases/chains/0031priority_variable_0
+I: [EXECUTING] ././testcases/chains/0032priority_variable_0
+I: [OK] ././testcases/chains/0032priority_variable_0
+I: [EXECUTING] ././testcases/chains/0033priority_variable_1
+I: [OK] ././testcases/chains/0033priority_variable_1
+I: [EXECUTING] ././testcases/chains/0034priority_variable_1
+I: [OK] ././testcases/chains/0034priority_variable_1
+I: [EXECUTING] ././testcases/chains/0035policy_variable_0
+I: [OK] ././testcases/chains/0035policy_variable_0
+I: [EXECUTING] ././testcases/chains/0036policy_variable_0
+I: [OK] ././testcases/chains/0036policy_variable_0
+I: [EXECUTING] ././testcases/chains/0037policy_variable_1
+I: [OK] ././testcases/chains/0037policy_variable_1
+I: [EXECUTING] ././testcases/chains/0038policy_variable_1
+I: [OK] ././testcases/chains/0038policy_variable_1
+I: [EXECUTING] ././testcases/chains/0039negative_priority_0
+I: [OK] ././testcases/chains/0039negative_priority_0
+W: [FAILED] kmemleak detected 0 memory leaks
+I: [EXECUTING] ././testcases/chains/0041chain_binding_0
+I: [OK] ././testcases/chains/0041chain_binding_0
+I: [EXECUTING] ././testcases/chains/0042chain_variable_0
+W: [FAILED] ././testcases/chains/0042chain_variable_0
+I: [EXECUTING] ././testcases/chains/0043chain_ingress_0
+I: [OK] ././testcases/chains/0043chain_ingress_0
+W: [FAILED] kernel is tainted: 0 -> 512
+I: [EXECUTING] ././testcases/chains/0044chain_destroy_0
+W: [FAILED] ././testcases/chains/0044chain_destroy_0
+I: [EXECUTING] ././testcases/chains/netdev_chain_0
+W: [FAILED] ././testcases/chains/netdev_chain_0
+I: [EXECUTING] ././testcases/comments/comments_0
+I: [OK] ././testcases/comments/comments_0
+I: [EXECUTING] ././testcases/flowtable/0001flowtable_0
+I: [OK] ././testcases/flowtable/0001flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0002create_flowtable_0
+I: [OK] ././testcases/flowtable/0002create_flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0003add_after_flush_0
+I: [OK] ././testcases/flowtable/0003add_after_flush_0
+I: [EXECUTING] ././testcases/flowtable/0004delete_after_add_0
+I: [OK] ././testcases/flowtable/0004delete_after_add_0
+I: [EXECUTING] ././testcases/flowtable/0005delete_in_use_1
+I: [OK] ././testcases/flowtable/0005delete_in_use_1
+I: [EXECUTING] ././testcases/flowtable/0006segfault_0
+I: [OK] ././testcases/flowtable/0006segfault_0
+I: [EXECUTING] ././testcases/flowtable/0007prio_0
+I: [OK] ././testcases/flowtable/0007prio_0
+I: [EXECUTING] ././testcases/flowtable/0008prio_1
+I: [OK] ././testcases/flowtable/0008prio_1
+I: [EXECUTING] ././testcases/flowtable/0009deleteafterflush_0
+I: [OK] ././testcases/flowtable/0009deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0010delete_handle_0
+I: [OK] ././testcases/flowtable/0010delete_handle_0
+I: [EXECUTING] ././testcases/flowtable/0011deleteafterflush_0
+I: [OK] ././testcases/flowtable/0011deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0012flowtable_variable_0
+I: [OK] ././testcases/flowtable/0012flowtable_variable_0
+I: [EXECUTING] ././testcases/flowtable/0013addafterdelete_0
+I: [OK] ././testcases/flowtable/0013addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0014addafterdelete_0
+I: [OK] ././testcases/flowtable/0014addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0015destroy_0
+W: [FAILED] ././testcases/flowtable/0015destroy_0
+I: [EXECUTING] ././testcases/include/0001absolute_0
+I: [OK] ././testcases/include/0001absolute_0
+I: [EXECUTING] ././testcases/include/0002relative_0
+I: [OK] ././testcases/include/0002relative_0
+I: [EXECUTING] ././testcases/include/0003includepath_0
+I: [OK] ././testcases/include/0003includepath_0
+I: [EXECUTING] ././testcases/include/0004endlessloop_1
+I: [OK] ././testcases/include/0004endlessloop_1
+I: [EXECUTING] ././testcases/include/0005glob_empty_0
+I: [OK] ././testcases/include/0005glob_empty_0
+I: [EXECUTING] ././testcases/include/0006glob_single_0
+I: [OK] ././testcases/include/0006glob_single_0
+I: [EXECUTING] ././testcases/include/0007glob_double_0
+I: [OK] ././testcases/include/0007glob_double_0
+I: [EXECUTING] ././testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ././testcases/include/0008glob_nofile_wildcard_0
+I: [EXECUTING] ././testcases/include/0009glob_nofile_1
+I: [OK] ././testcases/include/0009glob_nofile_1
+I: [EXECUTING] ././testcases/include/0010glob_broken_file_1
+I: [OK] ././testcases/include/0010glob_broken_file_1
+I: [EXECUTING] ././testcases/include/0011glob_dependency_0
+I: [OK] ././testcases/include/0011glob_dependency_0
+I: [EXECUTING] ././testcases/include/0012glob_dependency_1
+I: [OK] ././testcases/include/0012glob_dependency_1
+I: [EXECUTING] ././testcases/include/0013glob_dotfile_0
+I: [OK] ././testcases/include/0013glob_dotfile_0
+I: [EXECUTING] ././testcases/include/0013input_descriptors_included_files_0
+I: [OK] ././testcases/include/0013input_descriptors_included_files_0
+I: [EXECUTING] ././testcases/include/0014glob_directory_0
+I: [OK] ././testcases/include/0014glob_directory_0
+I: [EXECUTING] ././testcases/include/0015doubleincludepath_0
+I: [OK] ././testcases/include/0015doubleincludepath_0
+I: [EXECUTING] ././testcases/include/0016maxdepth_0
+I: [OK] ././testcases/include/0016maxdepth_0
+I: [EXECUTING] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [EXECUTING] ././testcases/include/0018include_error_0
+I: [OK] ././testcases/include/0018include_error_0
+I: [EXECUTING] ././testcases/include/0019include_error_0
+I: [OK] ././testcases/include/0019include_error_0
+I: [EXECUTING] ././testcases/include/0020include_chain_0
+I: [OK] ././testcases/include/0020include_chain_0
+I: [EXECUTING] ././testcases/json/0001set_statements_0
+I: [OK] ././testcases/json/0001set_statements_0
+I: [EXECUTING] ././testcases/json/0002table_map_0
+I: [OK] ././testcases/json/0002table_map_0
+I: [EXECUTING] ././testcases/json/0003json_schema_version_0
+I: [OK] ././testcases/json/0003json_schema_version_0
+I: [EXECUTING] ././testcases/json/0004json_schema_version_1
+I: [OK] ././testcases/json/0004json_schema_version_1
+I: [EXECUTING] ././testcases/json/0005secmark_objref_0
+I: [OK] ././testcases/json/0005secmark_objref_0
+I: [EXECUTING] ././testcases/json/0006obj_comment_0
+I: [OK] ././testcases/json/0006obj_comment_0
+I: [EXECUTING] ././testcases/json/netdev
+I: [OK] ././testcases/json/netdev
+I: [EXECUTING] ././testcases/listing/0001ruleset_0
+I: [OK] ././testcases/listing/0001ruleset_0
+I: [EXECUTING] ././testcases/listing/0002ruleset_0
+I: [OK] ././testcases/listing/0002ruleset_0
+I: [EXECUTING] ././testcases/listing/0003table_0
+I: [OK] ././testcases/listing/0003table_0
+I: [EXECUTING] ././testcases/listing/0004table_0
+I: [OK] ././testcases/listing/0004table_0
+I: [EXECUTING] ././testcases/listing/0005ruleset_ip_0
+I: [OK] ././testcases/listing/0005ruleset_ip_0
+I: [EXECUTING] ././testcases/listing/0006ruleset_ip6_0
+I: [OK] ././testcases/listing/0006ruleset_ip6_0
+I: [EXECUTING] ././testcases/listing/0007ruleset_inet_0
+I: [OK] ././testcases/listing/0007ruleset_inet_0
+I: [EXECUTING] ././testcases/listing/0008ruleset_arp_0
+I: [OK] ././testcases/listing/0008ruleset_arp_0
+I: [EXECUTING] ././testcases/listing/0009ruleset_bridge_0
+I: [OK] ././testcases/listing/0009ruleset_bridge_0
+I: [EXECUTING] ././testcases/listing/0010sets_0
+I: [OK] ././testcases/listing/0010sets_0
+I: [EXECUTING] ././testcases/listing/0011sets_0
+I: [OK] ././testcases/listing/0011sets_0
+I: [EXECUTING] ././testcases/listing/0012sets_0
+I: [OK] ././testcases/listing/0012sets_0
+I: [EXECUTING] ././testcases/listing/0013objects_0
+I: [OK] ././testcases/listing/0013objects_0
+I: [EXECUTING] ././testcases/listing/0014objects_0
+I: [OK] ././testcases/listing/0014objects_0
+I: [EXECUTING] ././testcases/listing/0015dynamic_0
+I: [OK] ././testcases/listing/0015dynamic_0
+I: [EXECUTING] ././testcases/listing/0016anonymous_0
+I: [OK] ././testcases/listing/0016anonymous_0
+I: [EXECUTING] ././testcases/listing/0017objects_0
+I: [OK] ././testcases/listing/0017objects_0
+I: [EXECUTING] ././testcases/listing/0018data_0
+I: [OK] ././testcases/listing/0018data_0
+I: [EXECUTING] ././testcases/listing/0019set_0
+I: [OK] ././testcases/listing/0019set_0
+I: [EXECUTING] ././testcases/listing/0020flowtable_0
+I: [OK] ././testcases/listing/0020flowtable_0
+I: [EXECUTING] ././testcases/listing/0021ruleset_json_terse_0
+I: [OK] ././testcases/listing/0021ruleset_json_terse_0
+I: [EXECUTING] ././testcases/listing/0022terse_0
+I: [OK] ././testcases/listing/0022terse_0
+I: [EXECUTING] ././testcases/maps/0003map_add_many_elements_0
+I: [OK] ././testcases/maps/0003map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0004interval_map_create_once_0
+I: [OK] ././testcases/maps/0004interval_map_create_once_0
+I: [EXECUTING] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0006interval_map_overlap_0
+I: [OK] ././testcases/maps/0006interval_map_overlap_0
+I: [EXECUTING] ././testcases/maps/0007named_ifname_dtype_0
+I: [OK] ././testcases/maps/0007named_ifname_dtype_0
+I: [EXECUTING] ././testcases/maps/0008interval_map_delete_0
+I: [OK] ././testcases/maps/0008interval_map_delete_0
+I: [EXECUTING] ././testcases/maps/0009vmap_0
+I: [OK] ././testcases/maps/0009vmap_0
+I: [EXECUTING] ././testcases/maps/0010concat_map_0
+I: [OK] ././testcases/maps/0010concat_map_0
+I: [EXECUTING] ././testcases/maps/0011vmap_0
+W: [FAILED] ././testcases/maps/0011vmap_0
+I: [EXECUTING] ././testcases/maps/0012map_0
+I: [OK] ././testcases/maps/0012map_0
+I: [EXECUTING] ././testcases/maps/0013map_0
+I: [OK] ././testcases/maps/0013map_0
+I: [EXECUTING] ././testcases/maps/0014destroy_0
+W: [FAILED] ././testcases/maps/0014destroy_0
+I: [EXECUTING] ././testcases/maps/0016map_leak_0
+I: [OK] ././testcases/maps/0016map_leak_0
+I: [EXECUTING] ././testcases/maps/0017_map_variable_0
+W: [FAILED] ././testcases/maps/0017_map_variable_0
+I: [EXECUTING] ././testcases/maps/0018map_leak_timeout_0
+I: [OK] ././testcases/maps/0018map_leak_timeout_0
+I: [EXECUTING] ././testcases/maps/anon_objmap_concat
+I: [OK] ././testcases/maps/anon_objmap_concat
+I: [EXECUTING] ././testcases/maps/anonymous_snat_map_0
+I: [OK] ././testcases/maps/anonymous_snat_map_0
+I: [EXECUTING] ././testcases/maps/different_map_types_1
+I: [OK] ././testcases/maps/different_map_types_1
+I: [EXECUTING] ././testcases/maps/map_catchall_double_deactivate
+W: [FAILED] ././testcases/maps/map_catchall_double_deactivate
+I: [EXECUTING] ././testcases/maps/map_with_flags_0
+I: [OK] ././testcases/maps/map_with_flags_0
+I: [EXECUTING] ././testcases/maps/named_snat_map_0
+I: [OK] ././testcases/maps/named_snat_map_0
+I: [EXECUTING] ././testcases/maps/nat_addr_port
+I: [OK] ././testcases/maps/nat_addr_port
+I: [EXECUTING] ././testcases/maps/typeof_integer_0
+W: [FAILED] ././testcases/maps/typeof_integer_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_0
+I: [OK] ././testcases/maps/typeof_maps_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_add_delete
+W: [FAILED] ././testcases/maps/typeof_maps_add_delete
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat
+I: [OK] ././testcases/maps/typeof_maps_concat
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat_update_0
+I: [OK] ././testcases/maps/typeof_maps_concat_update_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_update_0
+I: [OK] ././testcases/maps/typeof_maps_update_0
+I: [EXECUTING] ././testcases/maps/typeof_raw_0
+W: [FAILED] ././testcases/maps/typeof_raw_0
+I: [EXECUTING] ././testcases/maps/vmap_timeout
+W: [FAILED] ././testcases/maps/vmap_timeout
+I: [EXECUTING] ././testcases/netns/0001nft-f_0
+I: [OK] ././testcases/netns/0001nft-f_0
+I: [EXECUTING] ././testcases/netns/0002loosecommands_0
+I: [OK] ././testcases/netns/0002loosecommands_0
+I: [EXECUTING] ././testcases/netns/0003many_0
+I: [OK] ././testcases/netns/0003many_0
+I: [EXECUTING] ././testcases/nft-f/0001define_slash_0
+I: [OK] ././testcases/nft-f/0001define_slash_0
+I: [EXECUTING] ././testcases/nft-f/0002rollback_rule_0
+I: [OK] ././testcases/nft-f/0002rollback_rule_0
+I: [EXECUTING] ././testcases/nft-f/0003rollback_jump_0
+I: [OK] ././testcases/nft-f/0003rollback_jump_0
+I: [EXECUTING] ././testcases/nft-f/0004rollback_set_0
+I: [OK] ././testcases/nft-f/0004rollback_set_0
+I: [EXECUTING] ././testcases/nft-f/0005rollback_map_0
+I: [OK] ././testcases/nft-f/0005rollback_map_0
+I: [EXECUTING] ././testcases/nft-f/0006action_object_0
+I: [OK] ././testcases/nft-f/0006action_object_0
+I: [EXECUTING] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [EXECUTING] ././testcases/nft-f/0008split_tables_0
+I: [OK] ././testcases/nft-f/0008split_tables_0
+I: [EXECUTING] ././testcases/nft-f/0009variable_0
+I: [OK] ././testcases/nft-f/0009variable_0
+I: [EXECUTING] ././testcases/nft-f/0010variable_0
+I: [OK] ././testcases/nft-f/0010variable_0
+I: [EXECUTING] ././testcases/nft-f/0011manydefines_0
+I: [OK] ././testcases/nft-f/0011manydefines_0
+I: [EXECUTING] ././testcases/nft-f/0012different_defines_0
+I: [OK] ././testcases/nft-f/0012different_defines_0
+I: [EXECUTING] ././testcases/nft-f/0013defines_1
+I: [OK] ././testcases/nft-f/0013defines_1
+I: [EXECUTING] ././testcases/nft-f/0014defines_1
+I: [OK] ././testcases/nft-f/0014defines_1
+I: [EXECUTING] ././testcases/nft-f/0015defines_1
+I: [OK] ././testcases/nft-f/0015defines_1
+I: [EXECUTING] ././testcases/nft-f/0016redefines_1
+I: [OK] ././testcases/nft-f/0016redefines_1
+I: [EXECUTING] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018jump_variable_0
+I: [OK] ././testcases/nft-f/0018jump_variable_0
+I: [EXECUTING] ././testcases/nft-f/0019jump_variable_1
+I: [OK] ././testcases/nft-f/0019jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0020jump_variable_1
+I: [OK] ././testcases/nft-f/0020jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0021list_ruleset_0
+I: [OK] ././testcases/nft-f/0021list_ruleset_0
+I: [EXECUTING] ././testcases/nft-f/0022variables_0
+I: [OK] ././testcases/nft-f/0022variables_0
+I: [EXECUTING] ././testcases/nft-f/0023check_1
+I: [OK] ././testcases/nft-f/0023check_1
+I: [EXECUTING] ././testcases/nft-f/0024priority_0
+I: [OK] ././testcases/nft-f/0024priority_0
+I: [EXECUTING] ././testcases/nft-f/0025empty_dynset_0
+W: [DUMP FAIL] ././testcases/nft-f/0025empty_dynset_0
+I: [EXECUTING] ././testcases/nft-f/0026listing_0
+I: [OK] ././testcases/nft-f/0026listing_0
+I: [EXECUTING] ././testcases/nft-f/0027split_chains_0
+I: [OK] ././testcases/nft-f/0027split_chains_0
+I: [EXECUTING] ././testcases/nft-f/0028variable_cmdline_0
+I: [OK] ././testcases/nft-f/0028variable_cmdline_0
+I: [EXECUTING] ././testcases/nft-f/0029split_file_0
+I: [OK] ././testcases/nft-f/0029split_file_0
+I: [EXECUTING] ././testcases/nft-f/0030variable_reuse_0
+I: [OK] ././testcases/nft-f/0030variable_reuse_0
+I: [EXECUTING] ././testcases/nft-f/0031vmap_string_0
+I: [OK] ././testcases/nft-f/0031vmap_string_0
+I: [EXECUTING] ././testcases/nft-f/0032pknock_0
+I: [OK] ././testcases/nft-f/0032pknock_0
+I: [EXECUTING] ././testcases/nft-i/0001define_0
+I: [OK] ././testcases/nft-i/0001define_0
+I: [EXECUTING] ././testcases/optimizations/dependency_kill
+I: [OK] ././testcases/optimizations/dependency_kill
+I: [EXECUTING] ././testcases/optimizations/merge_nat
+I: [OK] ././testcases/optimizations/merge_nat
+I: [EXECUTING] ././testcases/optimizations/merge_reject
+I: [OK] ././testcases/optimizations/merge_reject
+I: [EXECUTING] ././testcases/optimizations/merge_stmts
+I: [OK] ././testcases/optimizations/merge_stmts
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat
+I: [OK] ././testcases/optimizations/merge_stmts_concat
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_vmap_raw
+I: [OK] ././testcases/optimizations/merge_vmap_raw
+I: [EXECUTING] ././testcases/optimizations/merge_vmaps
+I: [OK] ././testcases/optimizations/merge_vmaps
+I: [EXECUTING] ././testcases/optimizations/not_mergeable
+I: [OK] ././testcases/optimizations/not_mergeable
+I: [EXECUTING] ././testcases/optimizations/ruleset
+I: [OK] ././testcases/optimizations/ruleset
+I: [EXECUTING] ././testcases/optimizations/single_anon_set
+I: [OK] ././testcases/optimizations/single_anon_set
+I: [EXECUTING] ././testcases/optimizations/skip_merge
+I: [OK] ././testcases/optimizations/skip_merge
+I: [EXECUTING] ././testcases/optimizations/skip_non_eq
+I: [OK] ././testcases/optimizations/skip_non_eq
+I: [EXECUTING] ././testcases/optimizations/skip_unsupported
+I: [OK] ././testcases/optimizations/skip_unsupported
+I: [EXECUTING] ././testcases/optimizations/variables
+I: [OK] ././testcases/optimizations/variables
+I: [EXECUTING] ././testcases/optionals/comments_0
+I: [OK] ././testcases/optionals/comments_0
+I: [EXECUTING] ././testcases/optionals/comments_chain_0
+I: [OK] ././testcases/optionals/comments_chain_0
+I: [EXECUTING] ././testcases/optionals/comments_handles_0
+I: [OK] ././testcases/optionals/comments_handles_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_0
+I: [OK] ././testcases/optionals/comments_objects_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_dup_0
+I: [OK] ././testcases/optionals/comments_objects_dup_0
+I: [EXECUTING] ././testcases/optionals/comments_table_0
+I: [OK] ././testcases/optionals/comments_table_0
+I: [EXECUTING] ././testcases/optionals/delete_object_handles_0
+I: [OK] ././testcases/optionals/delete_object_handles_0
+I: [EXECUTING] ././testcases/optionals/handles_0
+I: [OK] ././testcases/optionals/handles_0
+I: [EXECUTING] ././testcases/optionals/handles_1
+I: [OK] ././testcases/optionals/handles_1
+I: [EXECUTING] ././testcases/optionals/log_prefix_0
+I: [OK] ././testcases/optionals/log_prefix_0
+I: [EXECUTING] ././testcases/optionals/update_object_handles_0
+I: [OK] ././testcases/optionals/update_object_handles_0
+I: [EXECUTING] ././testcases/owner/0001-flowtable-uaf
+W: [FAILED] ././testcases/owner/0001-flowtable-uaf
+I: [EXECUTING] ././testcases/parsing/describe
+I: [OK] ././testcases/parsing/describe
+I: [EXECUTING] ././testcases/parsing/large_rule_pipe
+I: [OK] ././testcases/parsing/large_rule_pipe
+I: [EXECUTING] ././testcases/parsing/log
+I: [OK] ././testcases/parsing/log
+I: [EXECUTING] ././testcases/parsing/octal
+I: [OK] ././testcases/parsing/octal
+I: [EXECUTING] ././testcases/rule_management/0001addinsertposition_0
+I: [OK] ././testcases/rule_management/0001addinsertposition_0
+I: [EXECUTING] ././testcases/rule_management/0002addinsertlocation_1
+I: [OK] ././testcases/rule_management/0002addinsertlocation_1
+I: [EXECUTING] ././testcases/rule_management/0003insert_0
+I: [OK] ././testcases/rule_management/0003insert_0
+I: [EXECUTING] ././testcases/rule_management/0004replace_0
+I: [OK] ././testcases/rule_management/0004replace_0
+I: [EXECUTING] ././testcases/rule_management/0005replace_1
+I: [OK] ././testcases/rule_management/0005replace_1
+I: [EXECUTING] ././testcases/rule_management/0006replace_1
+I: [OK] ././testcases/rule_management/0006replace_1
+I: [EXECUTING] ././testcases/rule_management/0007delete_0
+I: [OK] ././testcases/rule_management/0007delete_0
+I: [EXECUTING] ././testcases/rule_management/0008delete_1
+I: [OK] ././testcases/rule_management/0008delete_1
+I: [EXECUTING] ././testcases/rule_management/0009delete_1
+I: [OK] ././testcases/rule_management/0009delete_1
+I: [EXECUTING] ././testcases/rule_management/0010replace_0
+I: [OK] ././testcases/rule_management/0010replace_0
+I: [EXECUTING] ././testcases/rule_management/0011reset_0
+W: [FAILED] ././testcases/rule_management/0011reset_0
+I: [EXECUTING] ././testcases/rule_management/0012destroy_0
+W: [FAILED] ././testcases/rule_management/0012destroy_0
+I: [EXECUTING] ././testcases/sets/0001named_interval_0
+I: [OK] ././testcases/sets/0001named_interval_0
+I: [EXECUTING] ././testcases/sets/0002named_interval_automerging_0
+I: [OK] ././testcases/sets/0002named_interval_automerging_0
+I: [EXECUTING] ././testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ././testcases/sets/0003named_interval_missing_flag_0
+I: [EXECUTING] ././testcases/sets/0004named_interval_shadow_0
+I: [OK] ././testcases/sets/0004named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0005named_interval_shadow_0
+I: [OK] ././testcases/sets/0005named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0006create_set_0
+I: [OK] ././testcases/sets/0006create_set_0
+I: [EXECUTING] ././testcases/sets/0007create_element_0
+I: [OK] ././testcases/sets/0007create_element_0
+I: [EXECUTING] ././testcases/sets/0008comments_interval_0
+I: [OK] ././testcases/sets/0008comments_interval_0
+I: [EXECUTING] ././testcases/sets/0008create_verdict_map_0
+I: [OK] ././testcases/sets/0008create_verdict_map_0
+I: [EXECUTING] ././testcases/sets/0009comments_timeout_0
+I: [OK] ././testcases/sets/0009comments_timeout_0
+I: [EXECUTING] ././testcases/sets/0010comments_0
+I: [OK] ././testcases/sets/0010comments_0
+I: [EXECUTING] ././testcases/sets/0011add_many_elements_0
+I: [OK] ././testcases/sets/0011add_many_elements_0
+I: [EXECUTING] ././testcases/sets/0012add_delete_many_elements_0
+I: [OK] ././testcases/sets/0012add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0013add_delete_many_elements_0
+I: [OK] ././testcases/sets/0013add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [EXECUTING] ././testcases/sets/0015rulesetflush_0
+I: [OK] ././testcases/sets/0015rulesetflush_0
+I: [EXECUTING] ././testcases/sets/0016element_leak_0
+I: [OK] ././testcases/sets/0016element_leak_0
+I: [EXECUTING] ././testcases/sets/0017add_after_flush_0
+I: [OK] ././testcases/sets/0017add_after_flush_0
+I: [EXECUTING] ././testcases/sets/0018set_check_size_1
+I: [OK] ././testcases/sets/0018set_check_size_1
+I: [EXECUTING] ././testcases/sets/0019set_check_size_0
+I: [OK] ././testcases/sets/0019set_check_size_0
+I: [EXECUTING] ././testcases/sets/0020comments_0
+I: [OK] ././testcases/sets/0020comments_0
+I: [EXECUTING] ././testcases/sets/0021nesting_0
+I: [OK] ././testcases/sets/0021nesting_0
+I: [EXECUTING] ././testcases/sets/0022type_selective_flush_0
+I: [OK] ././testcases/sets/0022type_selective_flush_0
+I: [EXECUTING] ././testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ././testcases/sets/0023incomplete_add_set_command_0
+I: [EXECUTING] ././testcases/sets/0024named_objects_0
+I: [OK] ././testcases/sets/0024named_objects_0
+I: [EXECUTING] ././testcases/sets/0025anonymous_set_0
+I: [OK] ././testcases/sets/0025anonymous_set_0
+I: [EXECUTING] ././testcases/sets/0026named_limit_0
+I: [OK] ././testcases/sets/0026named_limit_0
+I: [EXECUTING] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [EXECUTING] ././testcases/sets/0028autoselect_0
+I: [OK] ././testcases/sets/0028autoselect_0
+I: [EXECUTING] ././testcases/sets/0028delete_handle_0
+I: [OK] ././testcases/sets/0028delete_handle_0
+I: [EXECUTING] ././testcases/sets/0029named_ifname_dtype_0
+I: [OK] ././testcases/sets/0029named_ifname_dtype_0
+I: [EXECUTING] ././testcases/sets/0030add_many_elements_interval_0
+I: [OK] ././testcases/sets/0030add_many_elements_interval_0
+I: [EXECUTING] ././testcases/sets/0031set_timeout_size_0
+I: [OK] ././testcases/sets/0031set_timeout_size_0
+I: [EXECUTING] ././testcases/sets/0032restore_set_simple_0
+I: [OK] ././testcases/sets/0032restore_set_simple_0
+I: [EXECUTING] ././testcases/sets/0033add_set_simple_flat_0
+I: [OK] ././testcases/sets/0033add_set_simple_flat_0
+I: [EXECUTING] ././testcases/sets/0034get_element_0
+I: [OK] ././testcases/sets/0034get_element_0
+I: [EXECUTING] ././testcases/sets/0035add_set_elements_flat_0
+I: [OK] ././testcases/sets/0035add_set_elements_flat_0
+I: [EXECUTING] ././testcases/sets/0036add_set_element_expiration_0
+I: [OK] ././testcases/sets/0036add_set_element_expiration_0
+I: [EXECUTING] ././testcases/sets/0037_set_with_inet_service_0
+I: [OK] ././testcases/sets/0037_set_with_inet_service_0
+I: [EXECUTING] ././testcases/sets/0038meter_list_0
+I: [OK] ././testcases/sets/0038meter_list_0
+I: [EXECUTING] ././testcases/sets/0039delete_interval_0
+I: [OK] ././testcases/sets/0039delete_interval_0
+I: [EXECUTING] ././testcases/sets/0040get_host_endian_elements_0
+I: [OK] ././testcases/sets/0040get_host_endian_elements_0
+I: [EXECUTING] ././testcases/sets/0041interval_0
+I: [OK] ././testcases/sets/0041interval_0
+I: [EXECUTING] ././testcases/sets/0042update_set_0
+I: [OK] ././testcases/sets/0042update_set_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_0
+I: [OK] ././testcases/sets/0043concatenated_ranges_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_1
+I: [OK] ././testcases/sets/0043concatenated_ranges_1
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_0
+I: [OK] ././testcases/sets/0044interval_overlap_0
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_1
+I: [OK] ././testcases/sets/0044interval_overlap_1
+I: [EXECUTING] ././testcases/sets/0045concat_ipv4_service
+I: [OK] ././testcases/sets/0045concat_ipv4_service
+I: [EXECUTING] ././testcases/sets/0046netmap_0
+I: [OK] ././testcases/sets/0046netmap_0
+I: [EXECUTING] ././testcases/sets/0047nat_0
+I: [OK] ././testcases/sets/0047nat_0
+I: [EXECUTING] ././testcases/sets/0048set_counters_0
+I: [OK] ././testcases/sets/0048set_counters_0
+I: [EXECUTING] ././testcases/sets/0049set_define_0
+I: [OK] ././testcases/sets/0049set_define_0
+I: [EXECUTING] ././testcases/sets/0050set_define_1
+I: [OK] ././testcases/sets/0050set_define_1
+I: [EXECUTING] ././testcases/sets/0051set_interval_counter_0
+I: [OK] ././testcases/sets/0051set_interval_counter_0
+I: [EXECUTING] ././testcases/sets/0052overlap_0
+I: [OK] ././testcases/sets/0052overlap_0
+I: [EXECUTING] ././testcases/sets/0053echo_0
+I: [OK] ././testcases/sets/0053echo_0
+I: [EXECUTING] ././testcases/sets/0054comments_set_0
+I: [OK] ././testcases/sets/0054comments_set_0
+I: [EXECUTING] ././testcases/sets/0055tcpflags_0
+I: [OK] ././testcases/sets/0055tcpflags_0
+I: [EXECUTING] ././testcases/sets/0056dynamic_limit_0
+I: [OK] ././testcases/sets/0056dynamic_limit_0
+I: [EXECUTING] ././testcases/sets/0057set_create_fails_0
+I: [OK] ././testcases/sets/0057set_create_fails_0
+I: [EXECUTING] ././testcases/sets/0058_setupdate_timeout_0
+I: [OK] ././testcases/sets/0058_setupdate_timeout_0
+I: [EXECUTING] ././testcases/sets/0059set_update_multistmt_0
+W: [FAILED] ././testcases/sets/0059set_update_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_0
+W: [FAILED] ././testcases/sets/0060set_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_1
+W: [FAILED] ././testcases/sets/0060set_multistmt_1
+I: [EXECUTING] ././testcases/sets/0061anonymous_automerge_0
+I: [OK] ././testcases/sets/0061anonymous_automerge_0
+I: [EXECUTING] ././testcases/sets/0062set_connlimit_0
+I: [OK] ././testcases/sets/0062set_connlimit_0
+I: [EXECUTING] ././testcases/sets/0063set_catchall_0
+W: [FAILED] ././testcases/sets/0063set_catchall_0
+I: [EXECUTING] ././testcases/sets/0064map_catchall_0
+W: [FAILED] ././testcases/sets/0064map_catchall_0
+I: [EXECUTING] ././testcases/sets/0065_icmp_postprocessing
+I: [OK] ././testcases/sets/0065_icmp_postprocessing
+I: [EXECUTING] ././testcases/sets/0067nat_concat_interval_0
+I: [OK] ././testcases/sets/0067nat_concat_interval_0
+I: [EXECUTING] ././testcases/sets/0068interval_stack_overflow_0
+I: [OK] ././testcases/sets/0068interval_stack_overflow_0
+I: [EXECUTING] ././testcases/sets/0069interval_merge_0
+I: [OK] ././testcases/sets/0069interval_merge_0
+I: [EXECUTING] ././testcases/sets/0070stacked_l2_headers
+I: [OK] ././testcases/sets/0070stacked_l2_headers
+I: [EXECUTING] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [EXECUTING] ././testcases/sets/0072destroy_0
+W: [FAILED] ././testcases/sets/0072destroy_0
+I: [EXECUTING] ././testcases/sets/automerge_0
+I: [OK] ././testcases/sets/automerge_0
+I: [EXECUTING] ././testcases/sets/collapse_elem_0
+I: [OK] ././testcases/sets/collapse_elem_0
+I: [EXECUTING] ././testcases/sets/concat_interval_0
+I: [OK] ././testcases/sets/concat_interval_0
+I: [EXECUTING] ././testcases/sets/dynset_missing
+I: [OK] ././testcases/sets/dynset_missing
+I: [EXECUTING] ././testcases/sets/errors_0
+I: [OK] ././testcases/sets/errors_0
+I: [EXECUTING] ././testcases/sets/exact_overlap_0
+I: [OK] ././testcases/sets/exact_overlap_0
+I: [EXECUTING] ././testcases/sets/inner_0
+W: [FAILED] ././testcases/sets/inner_0
+I: [EXECUTING] ././testcases/sets/reset_command_0
+W: [FAILED] ././testcases/sets/reset_command_0
+I: [EXECUTING] ././testcases/sets/set_eval_0
+I: [OK] ././testcases/sets/set_eval_0
+I: [EXECUTING] ././testcases/sets/sets_with_ifnames
+I: [OK] ././testcases/sets/sets_with_ifnames
+I: [EXECUTING] ././testcases/sets/typeof_raw_0
+W: [FAILED] ././testcases/sets/typeof_raw_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_0
+W: [FAILED] ././testcases/sets/typeof_sets_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_1
+I: [OK] ././testcases/sets/typeof_sets_1
+I: [EXECUTING] ././testcases/sets/typeof_sets_concat
+I: [OK] ././testcases/sets/typeof_sets_concat
+I: [EXECUTING] ././testcases/sets/type_set_symbol
+I: [OK] ././testcases/sets/type_set_symbol
+I: [EXECUTING] ././testcases/transactions/0001table_0
+I: [OK] ././testcases/transactions/0001table_0
+I: [EXECUTING] ././testcases/transactions/0002table_0
+I: [OK] ././testcases/transactions/0002table_0
+I: [EXECUTING] ././testcases/transactions/0003table_0
+I: [OK] ././testcases/transactions/0003table_0
+I: [EXECUTING] ././testcases/transactions/0010chain_0
+I: [OK] ././testcases/transactions/0010chain_0
+I: [EXECUTING] ././testcases/transactions/0011chain_0
+I: [OK] ././testcases/transactions/0011chain_0
+I: [EXECUTING] ././testcases/transactions/0012chain_0
+I: [OK] ././testcases/transactions/0012chain_0
+I: [EXECUTING] ././testcases/transactions/0013chain_0
+I: [OK] ././testcases/transactions/0013chain_0
+I: [EXECUTING] ././testcases/transactions/0014chain_1
+I: [OK] ././testcases/transactions/0014chain_1
+I: [EXECUTING] ././testcases/transactions/0015chain_0
+I: [OK] ././testcases/transactions/0015chain_0
+I: [EXECUTING] ././testcases/transactions/0020rule_0
+I: [OK] ././testcases/transactions/0020rule_0
+I: [EXECUTING] ././testcases/transactions/0021rule_0
+I: [OK] ././testcases/transactions/0021rule_0
+I: [EXECUTING] ././testcases/transactions/0022rule_1
+I: [OK] ././testcases/transactions/0022rule_1
+I: [EXECUTING] ././testcases/transactions/0023rule_1
+I: [OK] ././testcases/transactions/0023rule_1
+I: [EXECUTING] ././testcases/transactions/0024rule_0
+I: [OK] ././testcases/transactions/0024rule_0
+I: [EXECUTING] ././testcases/transactions/0025rule_0
+I: [OK] ././testcases/transactions/0025rule_0
+I: [EXECUTING] ././testcases/transactions/0030set_0
+I: [OK] ././testcases/transactions/0030set_0
+I: [EXECUTING] ././testcases/transactions/0031set_0
+I: [OK] ././testcases/transactions/0031set_0
+I: [EXECUTING] ././testcases/transactions/0032set_0
+I: [OK] ././testcases/transactions/0032set_0
+I: [EXECUTING] ././testcases/transactions/0033set_0
+I: [OK] ././testcases/transactions/0033set_0
+I: [EXECUTING] ././testcases/transactions/0034set_0
+I: [OK] ././testcases/transactions/0034set_0
+I: [EXECUTING] ././testcases/transactions/0035set_0
+I: [OK] ././testcases/transactions/0035set_0
+I: [EXECUTING] ././testcases/transactions/0036set_1
+I: [OK] ././testcases/transactions/0036set_1
+I: [EXECUTING] ././testcases/transactions/0037set_0
+I: [OK] ././testcases/transactions/0037set_0
+I: [EXECUTING] ././testcases/transactions/0038set_0
+I: [OK] ././testcases/transactions/0038set_0
+I: [EXECUTING] ././testcases/transactions/0039set_0
+I: [OK] ././testcases/transactions/0039set_0
+I: [EXECUTING] ././testcases/transactions/0040set_0
+I: [OK] ././testcases/transactions/0040set_0
+I: [EXECUTING] ././testcases/transactions/0041nat_restore_0
+I: [OK] ././testcases/transactions/0041nat_restore_0
+W: [FAILED] kmemleak detected 1 memory leaks
+I: [EXECUTING] ././testcases/transactions/0042_stateful_expr_0
+I: [OK] ././testcases/transactions/0042_stateful_expr_0
+I: [EXECUTING] ././testcases/transactions/0043set_1
+I: [OK] ././testcases/transactions/0043set_1
+I: [EXECUTING] ././testcases/transactions/0044rule_0
+I: [OK] ././testcases/transactions/0044rule_0
+I: [EXECUTING] ././testcases/transactions/0045anon-unbind_0
+I: [OK] ././testcases/transactions/0045anon-unbind_0
+I: [EXECUTING] ././testcases/transactions/0046set_0
+I: [OK] ././testcases/transactions/0046set_0
+I: [EXECUTING] ././testcases/transactions/0047set_0
+I: [OK] ././testcases/transactions/0047set_0
+I: [EXECUTING] ././testcases/transactions/0048helpers_0
+I: [OK] ././testcases/transactions/0048helpers_0
+I: [EXECUTING] ././testcases/transactions/0049huge_0
+I: [OK] ././testcases/transactions/0049huge_0
+I: [EXECUTING] ././testcases/transactions/0050rule_1
+I: [OK] ././testcases/transactions/0050rule_1
+I: [EXECUTING] ././testcases/transactions/0051map_0
+I: [OK] ././testcases/transactions/0051map_0
+I: [EXECUTING] ././testcases/transactions/30s-stress
+I: [OK] ././testcases/transactions/30s-stress
+I: [EXECUTING] ././testcases/transactions/anon_chain_loop
+I: [OK] ././testcases/transactions/anon_chain_loop
+I: [EXECUTING] ././testcases/transactions/bad_expression
+I: [OK] ././testcases/transactions/bad_expression
+
+I: results: [OK] 346 [FAILED] 27 [TOTAL] 373
diff --git a/tests/shell/stable-log/log-5.15 b/tests/shell/stable-log/log-5.15
new file mode 100644
index 0000000..9ec3491
--- /dev/null
+++ b/tests/shell/stable-log/log-5.15
@@ -0,0 +1,751 @@
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_0
+I: [OK] ././testcases/bitwise/0040mark_binop_0
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_1
+I: [OK] ././testcases/bitwise/0040mark_binop_1
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_2
+I: [OK] ././testcases/bitwise/0040mark_binop_2
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_3
+I: [OK] ././testcases/bitwise/0040mark_binop_3
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_4
+I: [OK] ././testcases/bitwise/0040mark_binop_4
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_5
+I: [OK] ././testcases/bitwise/0040mark_binop_5
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_6
+I: [OK] ././testcases/bitwise/0040mark_binop_6
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_7
+I: [OK] ././testcases/bitwise/0040mark_binop_7
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_8
+I: [OK] ././testcases/bitwise/0040mark_binop_8
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_9
+I: [OK] ././testcases/bitwise/0040mark_binop_9
+I: [EXECUTING] ././testcases/bogons/assert_failures
+I: [OK] ././testcases/bogons/assert_failures
+I: [EXECUTING] ././testcases/cache/0001_cache_handling_0
+I: [OK] ././testcases/cache/0001_cache_handling_0
+I: [EXECUTING] ././testcases/cache/0002_interval_0
+I: [OK] ././testcases/cache/0002_interval_0
+I: [EXECUTING] ././testcases/cache/0003_cache_update_0
+I: [OK] ././testcases/cache/0003_cache_update_0
+I: [EXECUTING] ././testcases/cache/0004_cache_update_0
+I: [OK] ././testcases/cache/0004_cache_update_0
+I: [EXECUTING] ././testcases/cache/0005_cache_chain_flush
+I: [OK] ././testcases/cache/0005_cache_chain_flush
+I: [EXECUTING] ././testcases/cache/0006_cache_table_flush
+I: [OK] ././testcases/cache/0006_cache_table_flush
+I: [EXECUTING] ././testcases/cache/0007_echo_cache_init_0
+I: [OK] ././testcases/cache/0007_echo_cache_init_0
+I: [EXECUTING] ././testcases/cache/0008_delete_by_handle_0
+I: [OK] ././testcases/cache/0008_delete_by_handle_0
+I: [EXECUTING] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [EXECUTING] ././testcases/cache/0010_implicit_chain_0
+I: [OK] ././testcases/cache/0010_implicit_chain_0
+I: [EXECUTING] ././testcases/cache/0011_index_0
+I: [OK] ././testcases/cache/0011_index_0
+I: [EXECUTING] ././testcases/chains/0001jumps_0
+I: [OK] ././testcases/chains/0001jumps_0
+I: [EXECUTING] ././testcases/chains/0002jumps_1
+I: [OK] ././testcases/chains/0002jumps_1
+I: [EXECUTING] ././testcases/chains/0003jump_loop_1
+I: [OK] ././testcases/chains/0003jump_loop_1
+I: [EXECUTING] ././testcases/chains/0004busy_1
+I: [OK] ././testcases/chains/0004busy_1
+I: [EXECUTING] ././testcases/chains/0005busy_map_1
+I: [OK] ././testcases/chains/0005busy_map_1
+I: [EXECUTING] ././testcases/chains/0006masquerade_0
+I: [OK] ././testcases/chains/0006masquerade_0
+I: [EXECUTING] ././testcases/chains/0007masquerade_1
+I: [OK] ././testcases/chains/0007masquerade_1
+I: [EXECUTING] ././testcases/chains/0008masquerade_jump_1
+I: [OK] ././testcases/chains/0008masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0009masquerade_jump_1
+I: [OK] ././testcases/chains/0009masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0010endless_jump_loop_1
+I: [OK] ././testcases/chains/0010endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0011endless_jump_loop_1
+I: [OK] ././testcases/chains/0011endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0013rename_0
+I: [OK] ././testcases/chains/0013rename_0
+I: [EXECUTING] ././testcases/chains/0014rename_0
+I: [OK] ././testcases/chains/0014rename_0
+I: [EXECUTING] ././testcases/chains/0015check_jump_loop_1
+I: [OK] ././testcases/chains/0015check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0016delete_handle_0
+I: [OK] ././testcases/chains/0016delete_handle_0
+I: [EXECUTING] ././testcases/chains/0017masquerade_jump_1
+I: [OK] ././testcases/chains/0017masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0018check_jump_loop_1
+I: [OK] ././testcases/chains/0018check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0019masquerade_jump_1
+I: [OK] ././testcases/chains/0019masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0020depth_1
+I: [OK] ././testcases/chains/0020depth_1
+I: [EXECUTING] ././testcases/chains/0021prio_0
+W: [FAILED] ././testcases/chains/0021prio_0
+I: [EXECUTING] ././testcases/chains/0022prio_dummy_1
+I: [OK] ././testcases/chains/0022prio_dummy_1
+I: [EXECUTING] ././testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ././testcases/chains/0023prio_inet_srcnat_1
+I: [EXECUTING] ././testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ././testcases/chains/0024prio_inet_dstnat_1
+I: [EXECUTING] ././testcases/chains/0025prio_arp_1
+I: [OK] ././testcases/chains/0025prio_arp_1
+I: [EXECUTING] ././testcases/chains/0026prio_netdev_1
+I: [OK] ././testcases/chains/0026prio_netdev_1
+I: [EXECUTING] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [EXECUTING] ././testcases/chains/0028prio_bridge_out_1
+I: [OK] ././testcases/chains/0028prio_bridge_out_1
+I: [EXECUTING] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [EXECUTING] ././testcases/chains/0030create_0
+I: [OK] ././testcases/chains/0030create_0
+I: [EXECUTING] ././testcases/chains/0031priority_variable_0
+I: [OK] ././testcases/chains/0031priority_variable_0
+I: [EXECUTING] ././testcases/chains/0032priority_variable_0
+I: [OK] ././testcases/chains/0032priority_variable_0
+I: [EXECUTING] ././testcases/chains/0033priority_variable_1
+I: [OK] ././testcases/chains/0033priority_variable_1
+I: [EXECUTING] ././testcases/chains/0034priority_variable_1
+I: [OK] ././testcases/chains/0034priority_variable_1
+I: [EXECUTING] ././testcases/chains/0035policy_variable_0
+I: [OK] ././testcases/chains/0035policy_variable_0
+I: [EXECUTING] ././testcases/chains/0036policy_variable_0
+I: [OK] ././testcases/chains/0036policy_variable_0
+I: [EXECUTING] ././testcases/chains/0037policy_variable_1
+I: [OK] ././testcases/chains/0037policy_variable_1
+I: [EXECUTING] ././testcases/chains/0038policy_variable_1
+I: [OK] ././testcases/chains/0038policy_variable_1
+I: [EXECUTING] ././testcases/chains/0039negative_priority_0
+I: [OK] ././testcases/chains/0039negative_priority_0
+I: [EXECUTING] ././testcases/chains/0041chain_binding_0
+I: [OK] ././testcases/chains/0041chain_binding_0
+I: [EXECUTING] ././testcases/chains/0042chain_variable_0
+W: [FAILED] ././testcases/chains/0042chain_variable_0
+I: [EXECUTING] ././testcases/chains/0043chain_ingress_0
+I: [OK] ././testcases/chains/0043chain_ingress_0
+I: [EXECUTING] ././testcases/chains/0044chain_destroy_0
+W: [FAILED] ././testcases/chains/0044chain_destroy_0
+I: [EXECUTING] ././testcases/chains/netdev_chain_0
+W: [FAILED] ././testcases/chains/netdev_chain_0
+I: [EXECUTING] ././testcases/comments/comments_0
+I: [OK] ././testcases/comments/comments_0
+I: [EXECUTING] ././testcases/flowtable/0001flowtable_0
+I: [OK] ././testcases/flowtable/0001flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0002create_flowtable_0
+I: [OK] ././testcases/flowtable/0002create_flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0003add_after_flush_0
+I: [OK] ././testcases/flowtable/0003add_after_flush_0
+I: [EXECUTING] ././testcases/flowtable/0004delete_after_add_0
+I: [OK] ././testcases/flowtable/0004delete_after_add_0
+I: [EXECUTING] ././testcases/flowtable/0005delete_in_use_1
+I: [OK] ././testcases/flowtable/0005delete_in_use_1
+I: [EXECUTING] ././testcases/flowtable/0006segfault_0
+I: [OK] ././testcases/flowtable/0006segfault_0
+I: [EXECUTING] ././testcases/flowtable/0007prio_0
+I: [OK] ././testcases/flowtable/0007prio_0
+I: [EXECUTING] ././testcases/flowtable/0008prio_1
+I: [OK] ././testcases/flowtable/0008prio_1
+I: [EXECUTING] ././testcases/flowtable/0009deleteafterflush_0
+I: [OK] ././testcases/flowtable/0009deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0010delete_handle_0
+I: [OK] ././testcases/flowtable/0010delete_handle_0
+I: [EXECUTING] ././testcases/flowtable/0011deleteafterflush_0
+I: [OK] ././testcases/flowtable/0011deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0012flowtable_variable_0
+I: [OK] ././testcases/flowtable/0012flowtable_variable_0
+I: [EXECUTING] ././testcases/flowtable/0013addafterdelete_0
+I: [OK] ././testcases/flowtable/0013addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0014addafterdelete_0
+I: [OK] ././testcases/flowtable/0014addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0015destroy_0
+W: [FAILED] ././testcases/flowtable/0015destroy_0
+I: [EXECUTING] ././testcases/include/0001absolute_0
+I: [OK] ././testcases/include/0001absolute_0
+I: [EXECUTING] ././testcases/include/0002relative_0
+I: [OK] ././testcases/include/0002relative_0
+I: [EXECUTING] ././testcases/include/0003includepath_0
+I: [OK] ././testcases/include/0003includepath_0
+I: [EXECUTING] ././testcases/include/0004endlessloop_1
+I: [OK] ././testcases/include/0004endlessloop_1
+I: [EXECUTING] ././testcases/include/0005glob_empty_0
+I: [OK] ././testcases/include/0005glob_empty_0
+I: [EXECUTING] ././testcases/include/0006glob_single_0
+I: [OK] ././testcases/include/0006glob_single_0
+I: [EXECUTING] ././testcases/include/0007glob_double_0
+I: [OK] ././testcases/include/0007glob_double_0
+I: [EXECUTING] ././testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ././testcases/include/0008glob_nofile_wildcard_0
+I: [EXECUTING] ././testcases/include/0009glob_nofile_1
+I: [OK] ././testcases/include/0009glob_nofile_1
+I: [EXECUTING] ././testcases/include/0010glob_broken_file_1
+I: [OK] ././testcases/include/0010glob_broken_file_1
+I: [EXECUTING] ././testcases/include/0011glob_dependency_0
+I: [OK] ././testcases/include/0011glob_dependency_0
+I: [EXECUTING] ././testcases/include/0012glob_dependency_1
+I: [OK] ././testcases/include/0012glob_dependency_1
+I: [EXECUTING] ././testcases/include/0013glob_dotfile_0
+I: [OK] ././testcases/include/0013glob_dotfile_0
+I: [EXECUTING] ././testcases/include/0013input_descriptors_included_files_0
+I: [OK] ././testcases/include/0013input_descriptors_included_files_0
+I: [EXECUTING] ././testcases/include/0014glob_directory_0
+I: [OK] ././testcases/include/0014glob_directory_0
+I: [EXECUTING] ././testcases/include/0015doubleincludepath_0
+I: [OK] ././testcases/include/0015doubleincludepath_0
+I: [EXECUTING] ././testcases/include/0016maxdepth_0
+I: [OK] ././testcases/include/0016maxdepth_0
+I: [EXECUTING] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [EXECUTING] ././testcases/include/0018include_error_0
+I: [OK] ././testcases/include/0018include_error_0
+I: [EXECUTING] ././testcases/include/0019include_error_0
+I: [OK] ././testcases/include/0019include_error_0
+I: [EXECUTING] ././testcases/include/0020include_chain_0
+I: [OK] ././testcases/include/0020include_chain_0
+I: [EXECUTING] ././testcases/json/0001set_statements_0
+I: [OK] ././testcases/json/0001set_statements_0
+I: [EXECUTING] ././testcases/json/0002table_map_0
+I: [OK] ././testcases/json/0002table_map_0
+I: [EXECUTING] ././testcases/json/0003json_schema_version_0
+I: [OK] ././testcases/json/0003json_schema_version_0
+I: [EXECUTING] ././testcases/json/0004json_schema_version_1
+I: [OK] ././testcases/json/0004json_schema_version_1
+I: [EXECUTING] ././testcases/json/0005secmark_objref_0
+I: [OK] ././testcases/json/0005secmark_objref_0
+I: [EXECUTING] ././testcases/json/0006obj_comment_0
+I: [OK] ././testcases/json/0006obj_comment_0
+I: [EXECUTING] ././testcases/json/netdev
+I: [OK] ././testcases/json/netdev
+I: [EXECUTING] ././testcases/listing/0001ruleset_0
+I: [OK] ././testcases/listing/0001ruleset_0
+I: [EXECUTING] ././testcases/listing/0002ruleset_0
+I: [OK] ././testcases/listing/0002ruleset_0
+I: [EXECUTING] ././testcases/listing/0003table_0
+I: [OK] ././testcases/listing/0003table_0
+I: [EXECUTING] ././testcases/listing/0004table_0
+I: [OK] ././testcases/listing/0004table_0
+I: [EXECUTING] ././testcases/listing/0005ruleset_ip_0
+I: [OK] ././testcases/listing/0005ruleset_ip_0
+I: [EXECUTING] ././testcases/listing/0006ruleset_ip6_0
+I: [OK] ././testcases/listing/0006ruleset_ip6_0
+I: [EXECUTING] ././testcases/listing/0007ruleset_inet_0
+I: [OK] ././testcases/listing/0007ruleset_inet_0
+I: [EXECUTING] ././testcases/listing/0008ruleset_arp_0
+I: [OK] ././testcases/listing/0008ruleset_arp_0
+I: [EXECUTING] ././testcases/listing/0009ruleset_bridge_0
+I: [OK] ././testcases/listing/0009ruleset_bridge_0
+I: [EXECUTING] ././testcases/listing/0010sets_0
+I: [OK] ././testcases/listing/0010sets_0
+I: [EXECUTING] ././testcases/listing/0011sets_0
+I: [OK] ././testcases/listing/0011sets_0
+I: [EXECUTING] ././testcases/listing/0012sets_0
+I: [OK] ././testcases/listing/0012sets_0
+I: [EXECUTING] ././testcases/listing/0013objects_0
+I: [OK] ././testcases/listing/0013objects_0
+I: [EXECUTING] ././testcases/listing/0014objects_0
+I: [OK] ././testcases/listing/0014objects_0
+I: [EXECUTING] ././testcases/listing/0015dynamic_0
+I: [OK] ././testcases/listing/0015dynamic_0
+I: [EXECUTING] ././testcases/listing/0016anonymous_0
+I: [OK] ././testcases/listing/0016anonymous_0
+I: [EXECUTING] ././testcases/listing/0017objects_0
+I: [OK] ././testcases/listing/0017objects_0
+I: [EXECUTING] ././testcases/listing/0018data_0
+I: [OK] ././testcases/listing/0018data_0
+I: [EXECUTING] ././testcases/listing/0019set_0
+I: [OK] ././testcases/listing/0019set_0
+I: [EXECUTING] ././testcases/listing/0020flowtable_0
+I: [OK] ././testcases/listing/0020flowtable_0
+I: [EXECUTING] ././testcases/listing/0021ruleset_json_terse_0
+I: [OK] ././testcases/listing/0021ruleset_json_terse_0
+I: [EXECUTING] ././testcases/listing/0022terse_0
+I: [OK] ././testcases/listing/0022terse_0
+I: [EXECUTING] ././testcases/maps/0003map_add_many_elements_0
+I: [OK] ././testcases/maps/0003map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0004interval_map_create_once_0
+I: [OK] ././testcases/maps/0004interval_map_create_once_0
+I: [EXECUTING] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0006interval_map_overlap_0
+I: [OK] ././testcases/maps/0006interval_map_overlap_0
+I: [EXECUTING] ././testcases/maps/0007named_ifname_dtype_0
+I: [OK] ././testcases/maps/0007named_ifname_dtype_0
+I: [EXECUTING] ././testcases/maps/0008interval_map_delete_0
+I: [OK] ././testcases/maps/0008interval_map_delete_0
+I: [EXECUTING] ././testcases/maps/0009vmap_0
+I: [OK] ././testcases/maps/0009vmap_0
+I: [EXECUTING] ././testcases/maps/0010concat_map_0
+I: [OK] ././testcases/maps/0010concat_map_0
+I: [EXECUTING] ././testcases/maps/0011vmap_0
+I: [OK] ././testcases/maps/0011vmap_0
+I: [EXECUTING] ././testcases/maps/0012map_0
+I: [OK] ././testcases/maps/0012map_0
+I: [EXECUTING] ././testcases/maps/0013map_0
+I: [OK] ././testcases/maps/0013map_0
+I: [EXECUTING] ././testcases/maps/0014destroy_0
+W: [FAILED] ././testcases/maps/0014destroy_0
+I: [EXECUTING] ././testcases/maps/0016map_leak_0
+I: [OK] ././testcases/maps/0016map_leak_0
+I: [EXECUTING] ././testcases/maps/0017_map_variable_0
+I: [OK] ././testcases/maps/0017_map_variable_0
+I: [EXECUTING] ././testcases/maps/0018map_leak_timeout_0
+I: [OK] ././testcases/maps/0018map_leak_timeout_0
+I: [EXECUTING] ././testcases/maps/anon_objmap_concat
+I: [OK] ././testcases/maps/anon_objmap_concat
+I: [EXECUTING] ././testcases/maps/anonymous_snat_map_0
+I: [OK] ././testcases/maps/anonymous_snat_map_0
+I: [EXECUTING] ././testcases/maps/different_map_types_1
+I: [OK] ././testcases/maps/different_map_types_1
+I: [EXECUTING] ././testcases/maps/map_catchall_double_deactivate
+I: [OK] ././testcases/maps/map_catchall_double_deactivate
+I: [EXECUTING] ././testcases/maps/map_with_flags_0
+I: [OK] ././testcases/maps/map_with_flags_0
+I: [EXECUTING] ././testcases/maps/named_snat_map_0
+I: [OK] ././testcases/maps/named_snat_map_0
+I: [EXECUTING] ././testcases/maps/nat_addr_port
+I: [OK] ././testcases/maps/nat_addr_port
+I: [EXECUTING] ././testcases/maps/typeof_integer_0
+I: [OK] ././testcases/maps/typeof_integer_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_0
+I: [OK] ././testcases/maps/typeof_maps_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_add_delete
+W: [FAILED] ././testcases/maps/typeof_maps_add_delete
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat
+I: [OK] ././testcases/maps/typeof_maps_concat
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat_update_0
+I: [OK] ././testcases/maps/typeof_maps_concat_update_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_update_0
+I: [OK] ././testcases/maps/typeof_maps_update_0
+I: [EXECUTING] ././testcases/maps/typeof_raw_0
+I: [OK] ././testcases/maps/typeof_raw_0
+I: [EXECUTING] ././testcases/maps/vmap_timeout
+I: [OK] ././testcases/maps/vmap_timeout
+I: [EXECUTING] ././testcases/netns/0001nft-f_0
+I: [OK] ././testcases/netns/0001nft-f_0
+I: [EXECUTING] ././testcases/netns/0002loosecommands_0
+I: [OK] ././testcases/netns/0002loosecommands_0
+I: [EXECUTING] ././testcases/netns/0003many_0
+I: [OK] ././testcases/netns/0003many_0
+I: [EXECUTING] ././testcases/nft-f/0001define_slash_0
+I: [OK] ././testcases/nft-f/0001define_slash_0
+I: [EXECUTING] ././testcases/nft-f/0002rollback_rule_0
+I: [OK] ././testcases/nft-f/0002rollback_rule_0
+I: [EXECUTING] ././testcases/nft-f/0003rollback_jump_0
+I: [OK] ././testcases/nft-f/0003rollback_jump_0
+I: [EXECUTING] ././testcases/nft-f/0004rollback_set_0
+I: [OK] ././testcases/nft-f/0004rollback_set_0
+I: [EXECUTING] ././testcases/nft-f/0005rollback_map_0
+I: [OK] ././testcases/nft-f/0005rollback_map_0
+I: [EXECUTING] ././testcases/nft-f/0006action_object_0
+I: [OK] ././testcases/nft-f/0006action_object_0
+I: [EXECUTING] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [EXECUTING] ././testcases/nft-f/0008split_tables_0
+I: [OK] ././testcases/nft-f/0008split_tables_0
+I: [EXECUTING] ././testcases/nft-f/0009variable_0
+I: [OK] ././testcases/nft-f/0009variable_0
+I: [EXECUTING] ././testcases/nft-f/0010variable_0
+I: [OK] ././testcases/nft-f/0010variable_0
+I: [EXECUTING] ././testcases/nft-f/0011manydefines_0
+I: [OK] ././testcases/nft-f/0011manydefines_0
+I: [EXECUTING] ././testcases/nft-f/0012different_defines_0
+I: [OK] ././testcases/nft-f/0012different_defines_0
+I: [EXECUTING] ././testcases/nft-f/0013defines_1
+I: [OK] ././testcases/nft-f/0013defines_1
+I: [EXECUTING] ././testcases/nft-f/0014defines_1
+I: [OK] ././testcases/nft-f/0014defines_1
+I: [EXECUTING] ././testcases/nft-f/0015defines_1
+I: [OK] ././testcases/nft-f/0015defines_1
+I: [EXECUTING] ././testcases/nft-f/0016redefines_1
+I: [OK] ././testcases/nft-f/0016redefines_1
+I: [EXECUTING] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018jump_variable_0
+I: [OK] ././testcases/nft-f/0018jump_variable_0
+I: [EXECUTING] ././testcases/nft-f/0019jump_variable_1
+I: [OK] ././testcases/nft-f/0019jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0020jump_variable_1
+I: [OK] ././testcases/nft-f/0020jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0021list_ruleset_0
+I: [OK] ././testcases/nft-f/0021list_ruleset_0
+I: [EXECUTING] ././testcases/nft-f/0022variables_0
+I: [OK] ././testcases/nft-f/0022variables_0
+I: [EXECUTING] ././testcases/nft-f/0023check_1
+I: [OK] ././testcases/nft-f/0023check_1
+I: [EXECUTING] ././testcases/nft-f/0024priority_0
+I: [OK] ././testcases/nft-f/0024priority_0
+I: [EXECUTING] ././testcases/nft-f/0025empty_dynset_0
+I: [OK] ././testcases/nft-f/0025empty_dynset_0
+I: [EXECUTING] ././testcases/nft-f/0026listing_0
+I: [OK] ././testcases/nft-f/0026listing_0
+I: [EXECUTING] ././testcases/nft-f/0027split_chains_0
+I: [OK] ././testcases/nft-f/0027split_chains_0
+I: [EXECUTING] ././testcases/nft-f/0028variable_cmdline_0
+I: [OK] ././testcases/nft-f/0028variable_cmdline_0
+I: [EXECUTING] ././testcases/nft-f/0029split_file_0
+I: [OK] ././testcases/nft-f/0029split_file_0
+I: [EXECUTING] ././testcases/nft-f/0030variable_reuse_0
+I: [OK] ././testcases/nft-f/0030variable_reuse_0
+I: [EXECUTING] ././testcases/nft-f/0031vmap_string_0
+I: [OK] ././testcases/nft-f/0031vmap_string_0
+I: [EXECUTING] ././testcases/nft-f/0032pknock_0
+I: [OK] ././testcases/nft-f/0032pknock_0
+I: [EXECUTING] ././testcases/nft-i/0001define_0
+I: [OK] ././testcases/nft-i/0001define_0
+I: [EXECUTING] ././testcases/optimizations/dependency_kill
+I: [OK] ././testcases/optimizations/dependency_kill
+I: [EXECUTING] ././testcases/optimizations/merge_nat
+I: [OK] ././testcases/optimizations/merge_nat
+I: [EXECUTING] ././testcases/optimizations/merge_reject
+I: [OK] ././testcases/optimizations/merge_reject
+I: [EXECUTING] ././testcases/optimizations/merge_stmts
+I: [OK] ././testcases/optimizations/merge_stmts
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat
+I: [OK] ././testcases/optimizations/merge_stmts_concat
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_vmap_raw
+I: [OK] ././testcases/optimizations/merge_vmap_raw
+I: [EXECUTING] ././testcases/optimizations/merge_vmaps
+I: [OK] ././testcases/optimizations/merge_vmaps
+I: [EXECUTING] ././testcases/optimizations/not_mergeable
+I: [OK] ././testcases/optimizations/not_mergeable
+I: [EXECUTING] ././testcases/optimizations/ruleset
+I: [OK] ././testcases/optimizations/ruleset
+I: [EXECUTING] ././testcases/optimizations/single_anon_set
+I: [OK] ././testcases/optimizations/single_anon_set
+I: [EXECUTING] ././testcases/optimizations/skip_merge
+I: [OK] ././testcases/optimizations/skip_merge
+I: [EXECUTING] ././testcases/optimizations/skip_non_eq
+I: [OK] ././testcases/optimizations/skip_non_eq
+I: [EXECUTING] ././testcases/optimizations/skip_unsupported
+I: [OK] ././testcases/optimizations/skip_unsupported
+I: [EXECUTING] ././testcases/optimizations/variables
+I: [OK] ././testcases/optimizations/variables
+I: [EXECUTING] ././testcases/optionals/comments_0
+I: [OK] ././testcases/optionals/comments_0
+I: [EXECUTING] ././testcases/optionals/comments_chain_0
+I: [OK] ././testcases/optionals/comments_chain_0
+I: [EXECUTING] ././testcases/optionals/comments_handles_0
+I: [OK] ././testcases/optionals/comments_handles_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_0
+I: [OK] ././testcases/optionals/comments_objects_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_dup_0
+I: [OK] ././testcases/optionals/comments_objects_dup_0
+I: [EXECUTING] ././testcases/optionals/comments_table_0
+I: [OK] ././testcases/optionals/comments_table_0
+I: [EXECUTING] ././testcases/optionals/delete_object_handles_0
+I: [OK] ././testcases/optionals/delete_object_handles_0
+I: [EXECUTING] ././testcases/optionals/handles_0
+I: [OK] ././testcases/optionals/handles_0
+I: [EXECUTING] ././testcases/optionals/handles_1
+I: [OK] ././testcases/optionals/handles_1
+I: [EXECUTING] ././testcases/optionals/log_prefix_0
+I: [OK] ././testcases/optionals/log_prefix_0
+I: [EXECUTING] ././testcases/optionals/update_object_handles_0
+I: [OK] ././testcases/optionals/update_object_handles_0
+I: [EXECUTING] ././testcases/owner/0001-flowtable-uaf
+I: [OK] ././testcases/owner/0001-flowtable-uaf
+I: [EXECUTING] ././testcases/parsing/describe
+I: [OK] ././testcases/parsing/describe
+I: [EXECUTING] ././testcases/parsing/large_rule_pipe
+I: [OK] ././testcases/parsing/large_rule_pipe
+I: [EXECUTING] ././testcases/parsing/log
+I: [OK] ././testcases/parsing/log
+I: [EXECUTING] ././testcases/parsing/octal
+I: [OK] ././testcases/parsing/octal
+I: [EXECUTING] ././testcases/rule_management/0001addinsertposition_0
+I: [OK] ././testcases/rule_management/0001addinsertposition_0
+I: [EXECUTING] ././testcases/rule_management/0002addinsertlocation_1
+I: [OK] ././testcases/rule_management/0002addinsertlocation_1
+I: [EXECUTING] ././testcases/rule_management/0003insert_0
+I: [OK] ././testcases/rule_management/0003insert_0
+I: [EXECUTING] ././testcases/rule_management/0004replace_0
+I: [OK] ././testcases/rule_management/0004replace_0
+I: [EXECUTING] ././testcases/rule_management/0005replace_1
+I: [OK] ././testcases/rule_management/0005replace_1
+I: [EXECUTING] ././testcases/rule_management/0006replace_1
+I: [OK] ././testcases/rule_management/0006replace_1
+I: [EXECUTING] ././testcases/rule_management/0007delete_0
+I: [OK] ././testcases/rule_management/0007delete_0
+I: [EXECUTING] ././testcases/rule_management/0008delete_1
+I: [OK] ././testcases/rule_management/0008delete_1
+I: [EXECUTING] ././testcases/rule_management/0009delete_1
+I: [OK] ././testcases/rule_management/0009delete_1
+I: [EXECUTING] ././testcases/rule_management/0010replace_0
+I: [OK] ././testcases/rule_management/0010replace_0
+I: [EXECUTING] ././testcases/rule_management/0011reset_0
+W: [FAILED] ././testcases/rule_management/0011reset_0
+I: [EXECUTING] ././testcases/rule_management/0012destroy_0
+W: [FAILED] ././testcases/rule_management/0012destroy_0
+I: [EXECUTING] ././testcases/sets/0001named_interval_0
+I: [OK] ././testcases/sets/0001named_interval_0
+I: [EXECUTING] ././testcases/sets/0002named_interval_automerging_0
+I: [OK] ././testcases/sets/0002named_interval_automerging_0
+I: [EXECUTING] ././testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ././testcases/sets/0003named_interval_missing_flag_0
+I: [EXECUTING] ././testcases/sets/0004named_interval_shadow_0
+I: [OK] ././testcases/sets/0004named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0005named_interval_shadow_0
+I: [OK] ././testcases/sets/0005named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0006create_set_0
+I: [OK] ././testcases/sets/0006create_set_0
+I: [EXECUTING] ././testcases/sets/0007create_element_0
+I: [OK] ././testcases/sets/0007create_element_0
+I: [EXECUTING] ././testcases/sets/0008comments_interval_0
+I: [OK] ././testcases/sets/0008comments_interval_0
+I: [EXECUTING] ././testcases/sets/0008create_verdict_map_0
+I: [OK] ././testcases/sets/0008create_verdict_map_0
+I: [EXECUTING] ././testcases/sets/0009comments_timeout_0
+I: [OK] ././testcases/sets/0009comments_timeout_0
+I: [EXECUTING] ././testcases/sets/0010comments_0
+I: [OK] ././testcases/sets/0010comments_0
+I: [EXECUTING] ././testcases/sets/0011add_many_elements_0
+I: [OK] ././testcases/sets/0011add_many_elements_0
+I: [EXECUTING] ././testcases/sets/0012add_delete_many_elements_0
+I: [OK] ././testcases/sets/0012add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0013add_delete_many_elements_0
+I: [OK] ././testcases/sets/0013add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [EXECUTING] ././testcases/sets/0015rulesetflush_0
+I: [OK] ././testcases/sets/0015rulesetflush_0
+I: [EXECUTING] ././testcases/sets/0016element_leak_0
+I: [OK] ././testcases/sets/0016element_leak_0
+I: [EXECUTING] ././testcases/sets/0017add_after_flush_0
+I: [OK] ././testcases/sets/0017add_after_flush_0
+I: [EXECUTING] ././testcases/sets/0018set_check_size_1
+I: [OK] ././testcases/sets/0018set_check_size_1
+I: [EXECUTING] ././testcases/sets/0019set_check_size_0
+I: [OK] ././testcases/sets/0019set_check_size_0
+I: [EXECUTING] ././testcases/sets/0020comments_0
+I: [OK] ././testcases/sets/0020comments_0
+I: [EXECUTING] ././testcases/sets/0021nesting_0
+I: [OK] ././testcases/sets/0021nesting_0
+I: [EXECUTING] ././testcases/sets/0022type_selective_flush_0
+I: [OK] ././testcases/sets/0022type_selective_flush_0
+I: [EXECUTING] ././testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ././testcases/sets/0023incomplete_add_set_command_0
+I: [EXECUTING] ././testcases/sets/0024named_objects_0
+I: [OK] ././testcases/sets/0024named_objects_0
+I: [EXECUTING] ././testcases/sets/0025anonymous_set_0
+I: [OK] ././testcases/sets/0025anonymous_set_0
+I: [EXECUTING] ././testcases/sets/0026named_limit_0
+I: [OK] ././testcases/sets/0026named_limit_0
+I: [EXECUTING] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [EXECUTING] ././testcases/sets/0028autoselect_0
+I: [OK] ././testcases/sets/0028autoselect_0
+I: [EXECUTING] ././testcases/sets/0028delete_handle_0
+I: [OK] ././testcases/sets/0028delete_handle_0
+I: [EXECUTING] ././testcases/sets/0029named_ifname_dtype_0
+I: [OK] ././testcases/sets/0029named_ifname_dtype_0
+I: [EXECUTING] ././testcases/sets/0030add_many_elements_interval_0
+I: [OK] ././testcases/sets/0030add_many_elements_interval_0
+I: [EXECUTING] ././testcases/sets/0031set_timeout_size_0
+I: [OK] ././testcases/sets/0031set_timeout_size_0
+I: [EXECUTING] ././testcases/sets/0032restore_set_simple_0
+I: [OK] ././testcases/sets/0032restore_set_simple_0
+I: [EXECUTING] ././testcases/sets/0033add_set_simple_flat_0
+I: [OK] ././testcases/sets/0033add_set_simple_flat_0
+I: [EXECUTING] ././testcases/sets/0034get_element_0
+I: [OK] ././testcases/sets/0034get_element_0
+I: [EXECUTING] ././testcases/sets/0035add_set_elements_flat_0
+I: [OK] ././testcases/sets/0035add_set_elements_flat_0
+I: [EXECUTING] ././testcases/sets/0036add_set_element_expiration_0
+I: [OK] ././testcases/sets/0036add_set_element_expiration_0
+I: [EXECUTING] ././testcases/sets/0037_set_with_inet_service_0
+I: [OK] ././testcases/sets/0037_set_with_inet_service_0
+I: [EXECUTING] ././testcases/sets/0038meter_list_0
+I: [OK] ././testcases/sets/0038meter_list_0
+I: [EXECUTING] ././testcases/sets/0039delete_interval_0
+I: [OK] ././testcases/sets/0039delete_interval_0
+I: [EXECUTING] ././testcases/sets/0040get_host_endian_elements_0
+I: [OK] ././testcases/sets/0040get_host_endian_elements_0
+I: [EXECUTING] ././testcases/sets/0041interval_0
+I: [OK] ././testcases/sets/0041interval_0
+I: [EXECUTING] ././testcases/sets/0042update_set_0
+I: [OK] ././testcases/sets/0042update_set_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_0
+I: [OK] ././testcases/sets/0043concatenated_ranges_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_1
+I: [OK] ././testcases/sets/0043concatenated_ranges_1
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_0
+I: [OK] ././testcases/sets/0044interval_overlap_0
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_1
+I: [OK] ././testcases/sets/0044interval_overlap_1
+I: [EXECUTING] ././testcases/sets/0045concat_ipv4_service
+I: [OK] ././testcases/sets/0045concat_ipv4_service
+I: [EXECUTING] ././testcases/sets/0046netmap_0
+I: [OK] ././testcases/sets/0046netmap_0
+I: [EXECUTING] ././testcases/sets/0047nat_0
+I: [OK] ././testcases/sets/0047nat_0
+I: [EXECUTING] ././testcases/sets/0048set_counters_0
+I: [OK] ././testcases/sets/0048set_counters_0
+I: [EXECUTING] ././testcases/sets/0049set_define_0
+I: [OK] ././testcases/sets/0049set_define_0
+I: [EXECUTING] ././testcases/sets/0050set_define_1
+I: [OK] ././testcases/sets/0050set_define_1
+I: [EXECUTING] ././testcases/sets/0051set_interval_counter_0
+I: [OK] ././testcases/sets/0051set_interval_counter_0
+I: [EXECUTING] ././testcases/sets/0052overlap_0
+I: [OK] ././testcases/sets/0052overlap_0
+I: [EXECUTING] ././testcases/sets/0053echo_0
+I: [OK] ././testcases/sets/0053echo_0
+I: [EXECUTING] ././testcases/sets/0054comments_set_0
+I: [OK] ././testcases/sets/0054comments_set_0
+I: [EXECUTING] ././testcases/sets/0055tcpflags_0
+I: [OK] ././testcases/sets/0055tcpflags_0
+I: [EXECUTING] ././testcases/sets/0056dynamic_limit_0
+I: [OK] ././testcases/sets/0056dynamic_limit_0
+I: [EXECUTING] ././testcases/sets/0057set_create_fails_0
+I: [OK] ././testcases/sets/0057set_create_fails_0
+I: [EXECUTING] ././testcases/sets/0058_setupdate_timeout_0
+I: [OK] ././testcases/sets/0058_setupdate_timeout_0
+I: [EXECUTING] ././testcases/sets/0059set_update_multistmt_0
+I: [OK] ././testcases/sets/0059set_update_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_0
+I: [OK] ././testcases/sets/0060set_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_1
+I: [OK] ././testcases/sets/0060set_multistmt_1
+I: [EXECUTING] ././testcases/sets/0061anonymous_automerge_0
+I: [OK] ././testcases/sets/0061anonymous_automerge_0
+I: [EXECUTING] ././testcases/sets/0062set_connlimit_0
+I: [OK] ././testcases/sets/0062set_connlimit_0
+I: [EXECUTING] ././testcases/sets/0063set_catchall_0
+I: [OK] ././testcases/sets/0063set_catchall_0
+I: [EXECUTING] ././testcases/sets/0064map_catchall_0
+I: [OK] ././testcases/sets/0064map_catchall_0
+I: [EXECUTING] ././testcases/sets/0065_icmp_postprocessing
+I: [OK] ././testcases/sets/0065_icmp_postprocessing
+I: [EXECUTING] ././testcases/sets/0067nat_concat_interval_0
+I: [OK] ././testcases/sets/0067nat_concat_interval_0
+I: [EXECUTING] ././testcases/sets/0068interval_stack_overflow_0
+I: [OK] ././testcases/sets/0068interval_stack_overflow_0
+I: [EXECUTING] ././testcases/sets/0069interval_merge_0
+I: [OK] ././testcases/sets/0069interval_merge_0
+I: [EXECUTING] ././testcases/sets/0070stacked_l2_headers
+I: [OK] ././testcases/sets/0070stacked_l2_headers
+I: [EXECUTING] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [EXECUTING] ././testcases/sets/0072destroy_0
+W: [FAILED] ././testcases/sets/0072destroy_0
+I: [EXECUTING] ././testcases/sets/automerge_0
+I: [OK] ././testcases/sets/automerge_0
+I: [EXECUTING] ././testcases/sets/collapse_elem_0
+I: [OK] ././testcases/sets/collapse_elem_0
+I: [EXECUTING] ././testcases/sets/concat_interval_0
+I: [OK] ././testcases/sets/concat_interval_0
+I: [EXECUTING] ././testcases/sets/dynset_missing
+I: [OK] ././testcases/sets/dynset_missing
+I: [EXECUTING] ././testcases/sets/errors_0
+I: [OK] ././testcases/sets/errors_0
+I: [EXECUTING] ././testcases/sets/exact_overlap_0
+I: [OK] ././testcases/sets/exact_overlap_0
+I: [EXECUTING] ././testcases/sets/inner_0
+W: [FAILED] ././testcases/sets/inner_0
+I: [EXECUTING] ././testcases/sets/reset_command_0
+W: [FAILED] ././testcases/sets/reset_command_0
+I: [EXECUTING] ././testcases/sets/set_eval_0
+I: [OK] ././testcases/sets/set_eval_0
+I: [EXECUTING] ././testcases/sets/sets_with_ifnames
+I: [OK] ././testcases/sets/sets_with_ifnames
+I: [EXECUTING] ././testcases/sets/typeof_raw_0
+I: [OK] ././testcases/sets/typeof_raw_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_0
+I: [OK] ././testcases/sets/typeof_sets_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_1
+I: [OK] ././testcases/sets/typeof_sets_1
+I: [EXECUTING] ././testcases/sets/typeof_sets_concat
+I: [OK] ././testcases/sets/typeof_sets_concat
+I: [EXECUTING] ././testcases/sets/type_set_symbol
+I: [OK] ././testcases/sets/type_set_symbol
+I: [EXECUTING] ././testcases/transactions/0001table_0
+I: [OK] ././testcases/transactions/0001table_0
+I: [EXECUTING] ././testcases/transactions/0002table_0
+I: [OK] ././testcases/transactions/0002table_0
+I: [EXECUTING] ././testcases/transactions/0003table_0
+I: [OK] ././testcases/transactions/0003table_0
+I: [EXECUTING] ././testcases/transactions/0010chain_0
+I: [OK] ././testcases/transactions/0010chain_0
+I: [EXECUTING] ././testcases/transactions/0011chain_0
+I: [OK] ././testcases/transactions/0011chain_0
+I: [EXECUTING] ././testcases/transactions/0012chain_0
+I: [OK] ././testcases/transactions/0012chain_0
+I: [EXECUTING] ././testcases/transactions/0013chain_0
+I: [OK] ././testcases/transactions/0013chain_0
+I: [EXECUTING] ././testcases/transactions/0014chain_1
+I: [OK] ././testcases/transactions/0014chain_1
+I: [EXECUTING] ././testcases/transactions/0015chain_0
+I: [OK] ././testcases/transactions/0015chain_0
+I: [EXECUTING] ././testcases/transactions/0020rule_0
+I: [OK] ././testcases/transactions/0020rule_0
+I: [EXECUTING] ././testcases/transactions/0021rule_0
+I: [OK] ././testcases/transactions/0021rule_0
+I: [EXECUTING] ././testcases/transactions/0022rule_1
+I: [OK] ././testcases/transactions/0022rule_1
+I: [EXECUTING] ././testcases/transactions/0023rule_1
+I: [OK] ././testcases/transactions/0023rule_1
+I: [EXECUTING] ././testcases/transactions/0024rule_0
+I: [OK] ././testcases/transactions/0024rule_0
+I: [EXECUTING] ././testcases/transactions/0025rule_0
+I: [OK] ././testcases/transactions/0025rule_0
+I: [EXECUTING] ././testcases/transactions/0030set_0
+I: [OK] ././testcases/transactions/0030set_0
+I: [EXECUTING] ././testcases/transactions/0031set_0
+I: [OK] ././testcases/transactions/0031set_0
+I: [EXECUTING] ././testcases/transactions/0032set_0
+I: [OK] ././testcases/transactions/0032set_0
+I: [EXECUTING] ././testcases/transactions/0033set_0
+I: [OK] ././testcases/transactions/0033set_0
+I: [EXECUTING] ././testcases/transactions/0034set_0
+I: [OK] ././testcases/transactions/0034set_0
+I: [EXECUTING] ././testcases/transactions/0035set_0
+I: [OK] ././testcases/transactions/0035set_0
+I: [EXECUTING] ././testcases/transactions/0036set_1
+I: [OK] ././testcases/transactions/0036set_1
+I: [EXECUTING] ././testcases/transactions/0037set_0
+I: [OK] ././testcases/transactions/0037set_0
+I: [EXECUTING] ././testcases/transactions/0038set_0
+I: [OK] ././testcases/transactions/0038set_0
+I: [EXECUTING] ././testcases/transactions/0039set_0
+I: [OK] ././testcases/transactions/0039set_0
+I: [EXECUTING] ././testcases/transactions/0040set_0
+I: [OK] ././testcases/transactions/0040set_0
+I: [EXECUTING] ././testcases/transactions/0041nat_restore_0
+I: [OK] ././testcases/transactions/0041nat_restore_0
+I: [EXECUTING] ././testcases/transactions/0042_stateful_expr_0
+I: [OK] ././testcases/transactions/0042_stateful_expr_0
+I: [EXECUTING] ././testcases/transactions/0043set_1
+I: [OK] ././testcases/transactions/0043set_1
+I: [EXECUTING] ././testcases/transactions/0044rule_0
+I: [OK] ././testcases/transactions/0044rule_0
+I: [EXECUTING] ././testcases/transactions/0045anon-unbind_0
+I: [OK] ././testcases/transactions/0045anon-unbind_0
+I: [EXECUTING] ././testcases/transactions/0046set_0
+I: [OK] ././testcases/transactions/0046set_0
+I: [EXECUTING] ././testcases/transactions/0047set_0
+I: [OK] ././testcases/transactions/0047set_0
+I: [EXECUTING] ././testcases/transactions/0048helpers_0
+I: [OK] ././testcases/transactions/0048helpers_0
+I: [EXECUTING] ././testcases/transactions/0049huge_0
+I: [OK] ././testcases/transactions/0049huge_0
+I: [EXECUTING] ././testcases/transactions/0050rule_1
+I: [OK] ././testcases/transactions/0050rule_1
+I: [EXECUTING] ././testcases/transactions/0051map_0
+I: [OK] ././testcases/transactions/0051map_0
+I: [EXECUTING] ././testcases/transactions/30s-stress
+I: [OK] ././testcases/transactions/30s-stress
+I: [EXECUTING] ././testcases/transactions/anon_chain_loop
+I: [OK] ././testcases/transactions/anon_chain_loop
+I: [EXECUTING] ././testcases/transactions/bad_expression
+I: [OK] ././testcases/transactions/bad_expression
+
+W: [FAILED] kmemleak detected 2966 memory leaks
+I: results: [OK] 361 [FAILED] 12 [TOTAL] 373
diff --git a/tests/shell/stable-log/log-5.4 b/tests/shell/stable-log/log-5.4
new file mode 100644
index 0000000..588866b
--- /dev/null
+++ b/tests/shell/stable-log/log-5.4
@@ -0,0 +1,751 @@
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_0
+W: [FAILED] ././testcases/bitwise/0040mark_binop_0
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_1
+W: [FAILED] ././testcases/bitwise/0040mark_binop_1
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_2
+W: [FAILED] ././testcases/bitwise/0040mark_binop_2
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_3
+W: [FAILED] ././testcases/bitwise/0040mark_binop_3
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_4
+W: [FAILED] ././testcases/bitwise/0040mark_binop_4
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_5
+W: [FAILED] ././testcases/bitwise/0040mark_binop_5
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_6
+W: [FAILED] ././testcases/bitwise/0040mark_binop_6
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_7
+W: [FAILED] ././testcases/bitwise/0040mark_binop_7
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_8
+W: [FAILED] ././testcases/bitwise/0040mark_binop_8
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_9
+W: [FAILED] ././testcases/bitwise/0040mark_binop_9
+I: [EXECUTING] ././testcases/bogons/assert_failures
+I: [OK] ././testcases/bogons/assert_failures
+I: [EXECUTING] ././testcases/cache/0001_cache_handling_0
+I: [OK] ././testcases/cache/0001_cache_handling_0
+I: [EXECUTING] ././testcases/cache/0002_interval_0
+I: [OK] ././testcases/cache/0002_interval_0
+I: [EXECUTING] ././testcases/cache/0003_cache_update_0
+I: [OK] ././testcases/cache/0003_cache_update_0
+I: [EXECUTING] ././testcases/cache/0004_cache_update_0
+I: [OK] ././testcases/cache/0004_cache_update_0
+I: [EXECUTING] ././testcases/cache/0005_cache_chain_flush
+I: [OK] ././testcases/cache/0005_cache_chain_flush
+I: [EXECUTING] ././testcases/cache/0006_cache_table_flush
+I: [OK] ././testcases/cache/0006_cache_table_flush
+I: [EXECUTING] ././testcases/cache/0007_echo_cache_init_0
+I: [OK] ././testcases/cache/0007_echo_cache_init_0
+I: [EXECUTING] ././testcases/cache/0008_delete_by_handle_0
+W: [FAILED] ././testcases/cache/0008_delete_by_handle_0
+I: [EXECUTING] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [EXECUTING] ././testcases/cache/0010_implicit_chain_0
+W: [FAILED] ././testcases/cache/0010_implicit_chain_0
+I: [EXECUTING] ././testcases/cache/0011_index_0
+I: [OK] ././testcases/cache/0011_index_0
+I: [EXECUTING] ././testcases/chains/0001jumps_0
+I: [OK] ././testcases/chains/0001jumps_0
+I: [EXECUTING] ././testcases/chains/0002jumps_1
+I: [OK] ././testcases/chains/0002jumps_1
+I: [EXECUTING] ././testcases/chains/0003jump_loop_1
+I: [OK] ././testcases/chains/0003jump_loop_1
+I: [EXECUTING] ././testcases/chains/0004busy_1
+I: [OK] ././testcases/chains/0004busy_1
+I: [EXECUTING] ././testcases/chains/0005busy_map_1
+I: [OK] ././testcases/chains/0005busy_map_1
+I: [EXECUTING] ././testcases/chains/0006masquerade_0
+I: [OK] ././testcases/chains/0006masquerade_0
+I: [EXECUTING] ././testcases/chains/0007masquerade_1
+I: [OK] ././testcases/chains/0007masquerade_1
+I: [EXECUTING] ././testcases/chains/0008masquerade_jump_1
+I: [OK] ././testcases/chains/0008masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0009masquerade_jump_1
+I: [OK] ././testcases/chains/0009masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0010endless_jump_loop_1
+I: [OK] ././testcases/chains/0010endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0011endless_jump_loop_1
+I: [OK] ././testcases/chains/0011endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0013rename_0
+I: [OK] ././testcases/chains/0013rename_0
+I: [EXECUTING] ././testcases/chains/0014rename_0
+I: [OK] ././testcases/chains/0014rename_0
+I: [EXECUTING] ././testcases/chains/0015check_jump_loop_1
+I: [OK] ././testcases/chains/0015check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0016delete_handle_0
+I: [OK] ././testcases/chains/0016delete_handle_0
+I: [EXECUTING] ././testcases/chains/0017masquerade_jump_1
+I: [OK] ././testcases/chains/0017masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0018check_jump_loop_1
+I: [OK] ././testcases/chains/0018check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0019masquerade_jump_1
+I: [OK] ././testcases/chains/0019masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0020depth_1
+I: [OK] ././testcases/chains/0020depth_1
+I: [EXECUTING] ././testcases/chains/0021prio_0
+W: [FAILED] ././testcases/chains/0021prio_0
+I: [EXECUTING] ././testcases/chains/0022prio_dummy_1
+I: [OK] ././testcases/chains/0022prio_dummy_1
+I: [EXECUTING] ././testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ././testcases/chains/0023prio_inet_srcnat_1
+I: [EXECUTING] ././testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ././testcases/chains/0024prio_inet_dstnat_1
+I: [EXECUTING] ././testcases/chains/0025prio_arp_1
+I: [OK] ././testcases/chains/0025prio_arp_1
+I: [EXECUTING] ././testcases/chains/0026prio_netdev_1
+I: [OK] ././testcases/chains/0026prio_netdev_1
+I: [EXECUTING] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [EXECUTING] ././testcases/chains/0028prio_bridge_out_1
+I: [OK] ././testcases/chains/0028prio_bridge_out_1
+I: [EXECUTING] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [EXECUTING] ././testcases/chains/0030create_0
+I: [OK] ././testcases/chains/0030create_0
+I: [EXECUTING] ././testcases/chains/0031priority_variable_0
+I: [OK] ././testcases/chains/0031priority_variable_0
+I: [EXECUTING] ././testcases/chains/0032priority_variable_0
+I: [OK] ././testcases/chains/0032priority_variable_0
+I: [EXECUTING] ././testcases/chains/0033priority_variable_1
+I: [OK] ././testcases/chains/0033priority_variable_1
+I: [EXECUTING] ././testcases/chains/0034priority_variable_1
+I: [OK] ././testcases/chains/0034priority_variable_1
+I: [EXECUTING] ././testcases/chains/0035policy_variable_0
+I: [OK] ././testcases/chains/0035policy_variable_0
+I: [EXECUTING] ././testcases/chains/0036policy_variable_0
+I: [OK] ././testcases/chains/0036policy_variable_0
+I: [EXECUTING] ././testcases/chains/0037policy_variable_1
+I: [OK] ././testcases/chains/0037policy_variable_1
+I: [EXECUTING] ././testcases/chains/0038policy_variable_1
+I: [OK] ././testcases/chains/0038policy_variable_1
+I: [EXECUTING] ././testcases/chains/0039negative_priority_0
+I: [OK] ././testcases/chains/0039negative_priority_0
+I: [EXECUTING] ././testcases/chains/0041chain_binding_0
+W: [FAILED] ././testcases/chains/0041chain_binding_0
+I: [EXECUTING] ././testcases/chains/0042chain_variable_0
+W: [FAILED] ././testcases/chains/0042chain_variable_0
+I: [EXECUTING] ././testcases/chains/0043chain_ingress_0
+W: [FAILED] ././testcases/chains/0043chain_ingress_0
+W: [FAILED] kernel is tainted: 0 -> 512
+I: [EXECUTING] ././testcases/chains/0044chain_destroy_0
+W: [FAILED] ././testcases/chains/0044chain_destroy_0
+I: [EXECUTING] ././testcases/chains/netdev_chain_0
+W: [FAILED] ././testcases/chains/netdev_chain_0
+I: [EXECUTING] ././testcases/comments/comments_0
+I: [OK] ././testcases/comments/comments_0
+I: [EXECUTING] ././testcases/flowtable/0001flowtable_0
+I: [OK] ././testcases/flowtable/0001flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0002create_flowtable_0
+I: [OK] ././testcases/flowtable/0002create_flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0003add_after_flush_0
+I: [OK] ././testcases/flowtable/0003add_after_flush_0
+I: [EXECUTING] ././testcases/flowtable/0004delete_after_add_0
+I: [OK] ././testcases/flowtable/0004delete_after_add_0
+I: [EXECUTING] ././testcases/flowtable/0005delete_in_use_1
+I: [OK] ././testcases/flowtable/0005delete_in_use_1
+I: [EXECUTING] ././testcases/flowtable/0006segfault_0
+I: [OK] ././testcases/flowtable/0006segfault_0
+I: [EXECUTING] ././testcases/flowtable/0007prio_0
+I: [OK] ././testcases/flowtable/0007prio_0
+I: [EXECUTING] ././testcases/flowtable/0008prio_1
+I: [OK] ././testcases/flowtable/0008prio_1
+I: [EXECUTING] ././testcases/flowtable/0009deleteafterflush_0
+I: [OK] ././testcases/flowtable/0009deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0010delete_handle_0
+I: [OK] ././testcases/flowtable/0010delete_handle_0
+I: [EXECUTING] ././testcases/flowtable/0011deleteafterflush_0
+I: [OK] ././testcases/flowtable/0011deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0012flowtable_variable_0
+W: [DUMP FAIL] ././testcases/flowtable/0012flowtable_variable_0
+I: [EXECUTING] ././testcases/flowtable/0013addafterdelete_0
+W: [FAILED] ././testcases/flowtable/0013addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0014addafterdelete_0
+W: [FAILED] ././testcases/flowtable/0014addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0015destroy_0
+W: [FAILED] ././testcases/flowtable/0015destroy_0
+I: [EXECUTING] ././testcases/include/0001absolute_0
+I: [OK] ././testcases/include/0001absolute_0
+I: [EXECUTING] ././testcases/include/0002relative_0
+I: [OK] ././testcases/include/0002relative_0
+I: [EXECUTING] ././testcases/include/0003includepath_0
+I: [OK] ././testcases/include/0003includepath_0
+I: [EXECUTING] ././testcases/include/0004endlessloop_1
+I: [OK] ././testcases/include/0004endlessloop_1
+I: [EXECUTING] ././testcases/include/0005glob_empty_0
+I: [OK] ././testcases/include/0005glob_empty_0
+I: [EXECUTING] ././testcases/include/0006glob_single_0
+I: [OK] ././testcases/include/0006glob_single_0
+I: [EXECUTING] ././testcases/include/0007glob_double_0
+I: [OK] ././testcases/include/0007glob_double_0
+I: [EXECUTING] ././testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ././testcases/include/0008glob_nofile_wildcard_0
+I: [EXECUTING] ././testcases/include/0009glob_nofile_1
+I: [OK] ././testcases/include/0009glob_nofile_1
+I: [EXECUTING] ././testcases/include/0010glob_broken_file_1
+I: [OK] ././testcases/include/0010glob_broken_file_1
+I: [EXECUTING] ././testcases/include/0011glob_dependency_0
+I: [OK] ././testcases/include/0011glob_dependency_0
+I: [EXECUTING] ././testcases/include/0012glob_dependency_1
+I: [OK] ././testcases/include/0012glob_dependency_1
+I: [EXECUTING] ././testcases/include/0013glob_dotfile_0
+I: [OK] ././testcases/include/0013glob_dotfile_0
+I: [EXECUTING] ././testcases/include/0013input_descriptors_included_files_0
+I: [OK] ././testcases/include/0013input_descriptors_included_files_0
+I: [EXECUTING] ././testcases/include/0014glob_directory_0
+I: [OK] ././testcases/include/0014glob_directory_0
+I: [EXECUTING] ././testcases/include/0015doubleincludepath_0
+I: [OK] ././testcases/include/0015doubleincludepath_0
+I: [EXECUTING] ././testcases/include/0016maxdepth_0
+I: [OK] ././testcases/include/0016maxdepth_0
+I: [EXECUTING] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [EXECUTING] ././testcases/include/0018include_error_0
+I: [OK] ././testcases/include/0018include_error_0
+I: [EXECUTING] ././testcases/include/0019include_error_0
+I: [OK] ././testcases/include/0019include_error_0
+I: [EXECUTING] ././testcases/include/0020include_chain_0
+I: [OK] ././testcases/include/0020include_chain_0
+I: [EXECUTING] ././testcases/json/0001set_statements_0
+I: [OK] ././testcases/json/0001set_statements_0
+I: [EXECUTING] ././testcases/json/0002table_map_0
+W: [DUMP FAIL] ././testcases/json/0002table_map_0
+I: [EXECUTING] ././testcases/json/0003json_schema_version_0
+I: [OK] ././testcases/json/0003json_schema_version_0
+I: [EXECUTING] ././testcases/json/0004json_schema_version_1
+I: [OK] ././testcases/json/0004json_schema_version_1
+I: [EXECUTING] ././testcases/json/0005secmark_objref_0
+I: [OK] ././testcases/json/0005secmark_objref_0
+I: [EXECUTING] ././testcases/json/0006obj_comment_0
+W: [DUMP FAIL] ././testcases/json/0006obj_comment_0
+I: [EXECUTING] ././testcases/json/netdev
+I: [OK] ././testcases/json/netdev
+I: [EXECUTING] ././testcases/listing/0001ruleset_0
+I: [OK] ././testcases/listing/0001ruleset_0
+I: [EXECUTING] ././testcases/listing/0002ruleset_0
+I: [OK] ././testcases/listing/0002ruleset_0
+I: [EXECUTING] ././testcases/listing/0003table_0
+I: [OK] ././testcases/listing/0003table_0
+I: [EXECUTING] ././testcases/listing/0004table_0
+I: [OK] ././testcases/listing/0004table_0
+I: [EXECUTING] ././testcases/listing/0005ruleset_ip_0
+I: [OK] ././testcases/listing/0005ruleset_ip_0
+I: [EXECUTING] ././testcases/listing/0006ruleset_ip6_0
+I: [OK] ././testcases/listing/0006ruleset_ip6_0
+I: [EXECUTING] ././testcases/listing/0007ruleset_inet_0
+I: [OK] ././testcases/listing/0007ruleset_inet_0
+I: [EXECUTING] ././testcases/listing/0008ruleset_arp_0
+I: [OK] ././testcases/listing/0008ruleset_arp_0
+I: [EXECUTING] ././testcases/listing/0009ruleset_bridge_0
+I: [OK] ././testcases/listing/0009ruleset_bridge_0
+I: [EXECUTING] ././testcases/listing/0010sets_0
+I: [OK] ././testcases/listing/0010sets_0
+I: [EXECUTING] ././testcases/listing/0011sets_0
+I: [OK] ././testcases/listing/0011sets_0
+I: [EXECUTING] ././testcases/listing/0012sets_0
+I: [OK] ././testcases/listing/0012sets_0
+I: [EXECUTING] ././testcases/listing/0013objects_0
+I: [OK] ././testcases/listing/0013objects_0
+I: [EXECUTING] ././testcases/listing/0014objects_0
+I: [OK] ././testcases/listing/0014objects_0
+I: [EXECUTING] ././testcases/listing/0015dynamic_0
+I: [OK] ././testcases/listing/0015dynamic_0
+I: [EXECUTING] ././testcases/listing/0016anonymous_0
+I: [OK] ././testcases/listing/0016anonymous_0
+I: [EXECUTING] ././testcases/listing/0017objects_0
+I: [OK] ././testcases/listing/0017objects_0
+I: [EXECUTING] ././testcases/listing/0018data_0
+I: [OK] ././testcases/listing/0018data_0
+I: [EXECUTING] ././testcases/listing/0019set_0
+I: [OK] ././testcases/listing/0019set_0
+I: [EXECUTING] ././testcases/listing/0020flowtable_0
+I: [OK] ././testcases/listing/0020flowtable_0
+I: [EXECUTING] ././testcases/listing/0021ruleset_json_terse_0
+I: [OK] ././testcases/listing/0021ruleset_json_terse_0
+I: [EXECUTING] ././testcases/listing/0022terse_0
+I: [OK] ././testcases/listing/0022terse_0
+I: [EXECUTING] ././testcases/maps/0003map_add_many_elements_0
+I: [OK] ././testcases/maps/0003map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0004interval_map_create_once_0
+I: [OK] ././testcases/maps/0004interval_map_create_once_0
+I: [EXECUTING] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0006interval_map_overlap_0
+I: [OK] ././testcases/maps/0006interval_map_overlap_0
+I: [EXECUTING] ././testcases/maps/0007named_ifname_dtype_0
+I: [OK] ././testcases/maps/0007named_ifname_dtype_0
+I: [EXECUTING] ././testcases/maps/0008interval_map_delete_0
+I: [OK] ././testcases/maps/0008interval_map_delete_0
+I: [EXECUTING] ././testcases/maps/0009vmap_0
+W: [DUMP FAIL] ././testcases/maps/0009vmap_0
+I: [EXECUTING] ././testcases/maps/0010concat_map_0
+I: [OK] ././testcases/maps/0010concat_map_0
+I: [EXECUTING] ././testcases/maps/0011vmap_0
+W: [FAILED] ././testcases/maps/0011vmap_0
+I: [EXECUTING] ././testcases/maps/0012map_0
+W: [FAILED] ././testcases/maps/0012map_0
+I: [EXECUTING] ././testcases/maps/0013map_0
+W: [FAILED] ././testcases/maps/0013map_0
+I: [EXECUTING] ././testcases/maps/0014destroy_0
+W: [FAILED] ././testcases/maps/0014destroy_0
+I: [EXECUTING] ././testcases/maps/0016map_leak_0
+I: [OK] ././testcases/maps/0016map_leak_0
+I: [EXECUTING] ././testcases/maps/0017_map_variable_0
+W: [FAILED] ././testcases/maps/0017_map_variable_0
+I: [EXECUTING] ././testcases/maps/0018map_leak_timeout_0
+I: [OK] ././testcases/maps/0018map_leak_timeout_0
+I: [EXECUTING] ././testcases/maps/anon_objmap_concat
+W: [FAILED] ././testcases/maps/anon_objmap_concat
+I: [EXECUTING] ././testcases/maps/anonymous_snat_map_0
+I: [OK] ././testcases/maps/anonymous_snat_map_0
+I: [EXECUTING] ././testcases/maps/different_map_types_1
+I: [OK] ././testcases/maps/different_map_types_1
+I: [EXECUTING] ././testcases/maps/map_catchall_double_deactivate
+W: [FAILED] ././testcases/maps/map_catchall_double_deactivate
+I: [EXECUTING] ././testcases/maps/map_with_flags_0
+I: [OK] ././testcases/maps/map_with_flags_0
+I: [EXECUTING] ././testcases/maps/named_snat_map_0
+I: [OK] ././testcases/maps/named_snat_map_0
+I: [EXECUTING] ././testcases/maps/nat_addr_port
+I: [OK] ././testcases/maps/nat_addr_port
+I: [EXECUTING] ././testcases/maps/typeof_integer_0
+W: [FAILED] ././testcases/maps/typeof_integer_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_0
+I: [OK] ././testcases/maps/typeof_maps_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_add_delete
+W: [FAILED] ././testcases/maps/typeof_maps_add_delete
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat
+I: [OK] ././testcases/maps/typeof_maps_concat
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat_update_0
+I: [OK] ././testcases/maps/typeof_maps_concat_update_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_update_0
+I: [OK] ././testcases/maps/typeof_maps_update_0
+I: [EXECUTING] ././testcases/maps/typeof_raw_0
+W: [FAILED] ././testcases/maps/typeof_raw_0
+I: [EXECUTING] ././testcases/maps/vmap_timeout
+I: [OK] ././testcases/maps/vmap_timeout
+I: [EXECUTING] ././testcases/netns/0001nft-f_0
+I: [OK] ././testcases/netns/0001nft-f_0
+I: [EXECUTING] ././testcases/netns/0002loosecommands_0
+I: [OK] ././testcases/netns/0002loosecommands_0
+I: [EXECUTING] ././testcases/netns/0003many_0
+I: [OK] ././testcases/netns/0003many_0
+I: [EXECUTING] ././testcases/nft-f/0001define_slash_0
+I: [OK] ././testcases/nft-f/0001define_slash_0
+I: [EXECUTING] ././testcases/nft-f/0002rollback_rule_0
+I: [OK] ././testcases/nft-f/0002rollback_rule_0
+I: [EXECUTING] ././testcases/nft-f/0003rollback_jump_0
+I: [OK] ././testcases/nft-f/0003rollback_jump_0
+I: [EXECUTING] ././testcases/nft-f/0004rollback_set_0
+I: [OK] ././testcases/nft-f/0004rollback_set_0
+I: [EXECUTING] ././testcases/nft-f/0005rollback_map_0
+I: [OK] ././testcases/nft-f/0005rollback_map_0
+I: [EXECUTING] ././testcases/nft-f/0006action_object_0
+I: [OK] ././testcases/nft-f/0006action_object_0
+I: [EXECUTING] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [EXECUTING] ././testcases/nft-f/0008split_tables_0
+I: [OK] ././testcases/nft-f/0008split_tables_0
+I: [EXECUTING] ././testcases/nft-f/0009variable_0
+I: [OK] ././testcases/nft-f/0009variable_0
+I: [EXECUTING] ././testcases/nft-f/0010variable_0
+I: [OK] ././testcases/nft-f/0010variable_0
+I: [EXECUTING] ././testcases/nft-f/0011manydefines_0
+I: [OK] ././testcases/nft-f/0011manydefines_0
+I: [EXECUTING] ././testcases/nft-f/0012different_defines_0
+I: [OK] ././testcases/nft-f/0012different_defines_0
+I: [EXECUTING] ././testcases/nft-f/0013defines_1
+I: [OK] ././testcases/nft-f/0013defines_1
+I: [EXECUTING] ././testcases/nft-f/0014defines_1
+I: [OK] ././testcases/nft-f/0014defines_1
+I: [EXECUTING] ././testcases/nft-f/0015defines_1
+I: [OK] ././testcases/nft-f/0015defines_1
+I: [EXECUTING] ././testcases/nft-f/0016redefines_1
+I: [OK] ././testcases/nft-f/0016redefines_1
+I: [EXECUTING] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018jump_variable_0
+I: [OK] ././testcases/nft-f/0018jump_variable_0
+I: [EXECUTING] ././testcases/nft-f/0019jump_variable_1
+I: [OK] ././testcases/nft-f/0019jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0020jump_variable_1
+I: [OK] ././testcases/nft-f/0020jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0021list_ruleset_0
+I: [OK] ././testcases/nft-f/0021list_ruleset_0
+I: [EXECUTING] ././testcases/nft-f/0022variables_0
+I: [OK] ././testcases/nft-f/0022variables_0
+I: [EXECUTING] ././testcases/nft-f/0023check_1
+I: [OK] ././testcases/nft-f/0023check_1
+I: [EXECUTING] ././testcases/nft-f/0024priority_0
+I: [OK] ././testcases/nft-f/0024priority_0
+I: [EXECUTING] ././testcases/nft-f/0025empty_dynset_0
+W: [DUMP FAIL] ././testcases/nft-f/0025empty_dynset_0
+I: [EXECUTING] ././testcases/nft-f/0026listing_0
+I: [OK] ././testcases/nft-f/0026listing_0
+I: [EXECUTING] ././testcases/nft-f/0027split_chains_0
+I: [OK] ././testcases/nft-f/0027split_chains_0
+I: [EXECUTING] ././testcases/nft-f/0028variable_cmdline_0
+I: [OK] ././testcases/nft-f/0028variable_cmdline_0
+I: [EXECUTING] ././testcases/nft-f/0029split_file_0
+I: [OK] ././testcases/nft-f/0029split_file_0
+I: [EXECUTING] ././testcases/nft-f/0030variable_reuse_0
+I: [OK] ././testcases/nft-f/0030variable_reuse_0
+I: [EXECUTING] ././testcases/nft-f/0031vmap_string_0
+I: [OK] ././testcases/nft-f/0031vmap_string_0
+I: [EXECUTING] ././testcases/nft-f/0032pknock_0
+I: [OK] ././testcases/nft-f/0032pknock_0
+I: [EXECUTING] ././testcases/nft-i/0001define_0
+I: [OK] ././testcases/nft-i/0001define_0
+I: [EXECUTING] ././testcases/optimizations/dependency_kill
+I: [OK] ././testcases/optimizations/dependency_kill
+I: [EXECUTING] ././testcases/optimizations/merge_nat
+W: [FAILED] ././testcases/optimizations/merge_nat
+I: [EXECUTING] ././testcases/optimizations/merge_reject
+I: [OK] ././testcases/optimizations/merge_reject
+I: [EXECUTING] ././testcases/optimizations/merge_stmts
+I: [OK] ././testcases/optimizations/merge_stmts
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat
+W: [FAILED] ././testcases/optimizations/merge_stmts_concat
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_vmap
+W: [DUMP FAIL] ././testcases/optimizations/merge_stmts_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_vmap_raw
+W: [FAILED] ././testcases/optimizations/merge_vmap_raw
+I: [EXECUTING] ././testcases/optimizations/merge_vmaps
+I: [OK] ././testcases/optimizations/merge_vmaps
+I: [EXECUTING] ././testcases/optimizations/not_mergeable
+I: [OK] ././testcases/optimizations/not_mergeable
+I: [EXECUTING] ././testcases/optimizations/ruleset
+W: [FAILED] ././testcases/optimizations/ruleset
+I: [EXECUTING] ././testcases/optimizations/single_anon_set
+W: [FAILED] ././testcases/optimizations/single_anon_set
+I: [EXECUTING] ././testcases/optimizations/skip_merge
+I: [OK] ././testcases/optimizations/skip_merge
+I: [EXECUTING] ././testcases/optimizations/skip_non_eq
+I: [OK] ././testcases/optimizations/skip_non_eq
+I: [EXECUTING] ././testcases/optimizations/skip_unsupported
+I: [OK] ././testcases/optimizations/skip_unsupported
+I: [EXECUTING] ././testcases/optimizations/variables
+I: [OK] ././testcases/optimizations/variables
+I: [EXECUTING] ././testcases/optionals/comments_0
+I: [OK] ././testcases/optionals/comments_0
+I: [EXECUTING] ././testcases/optionals/comments_chain_0
+W: [DUMP FAIL] ././testcases/optionals/comments_chain_0
+I: [EXECUTING] ././testcases/optionals/comments_handles_0
+I: [OK] ././testcases/optionals/comments_handles_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_0
+W: [DUMP FAIL] ././testcases/optionals/comments_objects_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_dup_0
+I: [OK] ././testcases/optionals/comments_objects_dup_0
+I: [EXECUTING] ././testcases/optionals/comments_table_0
+W: [DUMP FAIL] ././testcases/optionals/comments_table_0
+I: [EXECUTING] ././testcases/optionals/delete_object_handles_0
+I: [OK] ././testcases/optionals/delete_object_handles_0
+I: [EXECUTING] ././testcases/optionals/handles_0
+I: [OK] ././testcases/optionals/handles_0
+I: [EXECUTING] ././testcases/optionals/handles_1
+I: [OK] ././testcases/optionals/handles_1
+I: [EXECUTING] ././testcases/optionals/log_prefix_0
+I: [OK] ././testcases/optionals/log_prefix_0
+I: [EXECUTING] ././testcases/optionals/update_object_handles_0
+I: [OK] ././testcases/optionals/update_object_handles_0
+I: [EXECUTING] ././testcases/owner/0001-flowtable-uaf
+W: [FAILED] ././testcases/owner/0001-flowtable-uaf
+I: [EXECUTING] ././testcases/parsing/describe
+I: [OK] ././testcases/parsing/describe
+I: [EXECUTING] ././testcases/parsing/large_rule_pipe
+I: [OK] ././testcases/parsing/large_rule_pipe
+I: [EXECUTING] ././testcases/parsing/log
+I: [OK] ././testcases/parsing/log
+I: [EXECUTING] ././testcases/parsing/octal
+I: [OK] ././testcases/parsing/octal
+I: [EXECUTING] ././testcases/rule_management/0001addinsertposition_0
+I: [OK] ././testcases/rule_management/0001addinsertposition_0
+I: [EXECUTING] ././testcases/rule_management/0002addinsertlocation_1
+I: [OK] ././testcases/rule_management/0002addinsertlocation_1
+I: [EXECUTING] ././testcases/rule_management/0003insert_0
+I: [OK] ././testcases/rule_management/0003insert_0
+I: [EXECUTING] ././testcases/rule_management/0004replace_0
+I: [OK] ././testcases/rule_management/0004replace_0
+I: [EXECUTING] ././testcases/rule_management/0005replace_1
+I: [OK] ././testcases/rule_management/0005replace_1
+I: [EXECUTING] ././testcases/rule_management/0006replace_1
+I: [OK] ././testcases/rule_management/0006replace_1
+I: [EXECUTING] ././testcases/rule_management/0007delete_0
+I: [OK] ././testcases/rule_management/0007delete_0
+I: [EXECUTING] ././testcases/rule_management/0008delete_1
+I: [OK] ././testcases/rule_management/0008delete_1
+I: [EXECUTING] ././testcases/rule_management/0009delete_1
+I: [OK] ././testcases/rule_management/0009delete_1
+I: [EXECUTING] ././testcases/rule_management/0010replace_0
+I: [OK] ././testcases/rule_management/0010replace_0
+I: [EXECUTING] ././testcases/rule_management/0011reset_0
+W: [FAILED] ././testcases/rule_management/0011reset_0
+I: [EXECUTING] ././testcases/rule_management/0012destroy_0
+W: [FAILED] ././testcases/rule_management/0012destroy_0
+I: [EXECUTING] ././testcases/sets/0001named_interval_0
+I: [OK] ././testcases/sets/0001named_interval_0
+I: [EXECUTING] ././testcases/sets/0002named_interval_automerging_0
+I: [OK] ././testcases/sets/0002named_interval_automerging_0
+I: [EXECUTING] ././testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ././testcases/sets/0003named_interval_missing_flag_0
+I: [EXECUTING] ././testcases/sets/0004named_interval_shadow_0
+I: [OK] ././testcases/sets/0004named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0005named_interval_shadow_0
+I: [OK] ././testcases/sets/0005named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0006create_set_0
+I: [OK] ././testcases/sets/0006create_set_0
+I: [EXECUTING] ././testcases/sets/0007create_element_0
+I: [OK] ././testcases/sets/0007create_element_0
+I: [EXECUTING] ././testcases/sets/0008comments_interval_0
+I: [OK] ././testcases/sets/0008comments_interval_0
+I: [EXECUTING] ././testcases/sets/0008create_verdict_map_0
+I: [OK] ././testcases/sets/0008create_verdict_map_0
+I: [EXECUTING] ././testcases/sets/0009comments_timeout_0
+I: [OK] ././testcases/sets/0009comments_timeout_0
+I: [EXECUTING] ././testcases/sets/0010comments_0
+I: [OK] ././testcases/sets/0010comments_0
+I: [EXECUTING] ././testcases/sets/0011add_many_elements_0
+I: [OK] ././testcases/sets/0011add_many_elements_0
+I: [EXECUTING] ././testcases/sets/0012add_delete_many_elements_0
+I: [OK] ././testcases/sets/0012add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0013add_delete_many_elements_0
+I: [OK] ././testcases/sets/0013add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [EXECUTING] ././testcases/sets/0015rulesetflush_0
+I: [OK] ././testcases/sets/0015rulesetflush_0
+I: [EXECUTING] ././testcases/sets/0016element_leak_0
+I: [OK] ././testcases/sets/0016element_leak_0
+I: [EXECUTING] ././testcases/sets/0017add_after_flush_0
+I: [OK] ././testcases/sets/0017add_after_flush_0
+I: [EXECUTING] ././testcases/sets/0018set_check_size_1
+I: [OK] ././testcases/sets/0018set_check_size_1
+I: [EXECUTING] ././testcases/sets/0019set_check_size_0
+I: [OK] ././testcases/sets/0019set_check_size_0
+I: [EXECUTING] ././testcases/sets/0020comments_0
+I: [OK] ././testcases/sets/0020comments_0
+I: [EXECUTING] ././testcases/sets/0021nesting_0
+I: [OK] ././testcases/sets/0021nesting_0
+I: [EXECUTING] ././testcases/sets/0022type_selective_flush_0
+I: [OK] ././testcases/sets/0022type_selective_flush_0
+I: [EXECUTING] ././testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ././testcases/sets/0023incomplete_add_set_command_0
+I: [EXECUTING] ././testcases/sets/0024named_objects_0
+I: [OK] ././testcases/sets/0024named_objects_0
+I: [EXECUTING] ././testcases/sets/0025anonymous_set_0
+I: [OK] ././testcases/sets/0025anonymous_set_0
+I: [EXECUTING] ././testcases/sets/0026named_limit_0
+I: [OK] ././testcases/sets/0026named_limit_0
+I: [EXECUTING] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [EXECUTING] ././testcases/sets/0028autoselect_0
+I: [OK] ././testcases/sets/0028autoselect_0
+I: [EXECUTING] ././testcases/sets/0028delete_handle_0
+I: [OK] ././testcases/sets/0028delete_handle_0
+I: [EXECUTING] ././testcases/sets/0029named_ifname_dtype_0
+I: [OK] ././testcases/sets/0029named_ifname_dtype_0
+I: [EXECUTING] ././testcases/sets/0030add_many_elements_interval_0
+I: [OK] ././testcases/sets/0030add_many_elements_interval_0
+I: [EXECUTING] ././testcases/sets/0031set_timeout_size_0
+I: [OK] ././testcases/sets/0031set_timeout_size_0
+I: [EXECUTING] ././testcases/sets/0032restore_set_simple_0
+I: [OK] ././testcases/sets/0032restore_set_simple_0
+I: [EXECUTING] ././testcases/sets/0033add_set_simple_flat_0
+I: [OK] ././testcases/sets/0033add_set_simple_flat_0
+I: [EXECUTING] ././testcases/sets/0034get_element_0
+W: [FAILED] ././testcases/sets/0034get_element_0
+I: [EXECUTING] ././testcases/sets/0035add_set_elements_flat_0
+I: [OK] ././testcases/sets/0035add_set_elements_flat_0
+I: [EXECUTING] ././testcases/sets/0036add_set_element_expiration_0
+W: [FAILED] ././testcases/sets/0036add_set_element_expiration_0
+I: [EXECUTING] ././testcases/sets/0037_set_with_inet_service_0
+I: [OK] ././testcases/sets/0037_set_with_inet_service_0
+I: [EXECUTING] ././testcases/sets/0038meter_list_0
+I: [OK] ././testcases/sets/0038meter_list_0
+I: [EXECUTING] ././testcases/sets/0039delete_interval_0
+I: [OK] ././testcases/sets/0039delete_interval_0
+I: [EXECUTING] ././testcases/sets/0040get_host_endian_elements_0
+I: [OK] ././testcases/sets/0040get_host_endian_elements_0
+I: [EXECUTING] ././testcases/sets/0041interval_0
+I: [OK] ././testcases/sets/0041interval_0
+I: [EXECUTING] ././testcases/sets/0042update_set_0
+I: [OK] ././testcases/sets/0042update_set_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_0
+W: [FAILED] ././testcases/sets/0043concatenated_ranges_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_1
+W: [FAILED] ././testcases/sets/0043concatenated_ranges_1
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_0
+W: [FAILED] ././testcases/sets/0044interval_overlap_0
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_1
+I: [OK] ././testcases/sets/0044interval_overlap_1
+I: [EXECUTING] ././testcases/sets/0045concat_ipv4_service
+I: [OK] ././testcases/sets/0045concat_ipv4_service
+I: [EXECUTING] ././testcases/sets/0046netmap_0
+W: [FAILED] ././testcases/sets/0046netmap_0
+I: [EXECUTING] ././testcases/sets/0047nat_0
+W: [FAILED] ././testcases/sets/0047nat_0
+I: [EXECUTING] ././testcases/sets/0048set_counters_0
+W: [DUMP FAIL] ././testcases/sets/0048set_counters_0
+I: [EXECUTING] ././testcases/sets/0049set_define_0
+I: [OK] ././testcases/sets/0049set_define_0
+I: [EXECUTING] ././testcases/sets/0050set_define_1
+I: [OK] ././testcases/sets/0050set_define_1
+I: [EXECUTING] ././testcases/sets/0051set_interval_counter_0
+W: [DUMP FAIL] ././testcases/sets/0051set_interval_counter_0
+I: [EXECUTING] ././testcases/sets/0052overlap_0
+I: [OK] ././testcases/sets/0052overlap_0
+I: [EXECUTING] ././testcases/sets/0053echo_0
+I: [OK] ././testcases/sets/0053echo_0
+I: [EXECUTING] ././testcases/sets/0054comments_set_0
+I: [OK] ././testcases/sets/0054comments_set_0
+I: [EXECUTING] ././testcases/sets/0055tcpflags_0
+I: [OK] ././testcases/sets/0055tcpflags_0
+I: [EXECUTING] ././testcases/sets/0056dynamic_limit_0
+I: [OK] ././testcases/sets/0056dynamic_limit_0
+I: [EXECUTING] ././testcases/sets/0057set_create_fails_0
+I: [OK] ././testcases/sets/0057set_create_fails_0
+I: [EXECUTING] ././testcases/sets/0058_setupdate_timeout_0
+I: [OK] ././testcases/sets/0058_setupdate_timeout_0
+I: [EXECUTING] ././testcases/sets/0059set_update_multistmt_0
+W: [FAILED] ././testcases/sets/0059set_update_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_0
+W: [FAILED] ././testcases/sets/0060set_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_1
+W: [FAILED] ././testcases/sets/0060set_multistmt_1
+I: [EXECUTING] ././testcases/sets/0061anonymous_automerge_0
+I: [OK] ././testcases/sets/0061anonymous_automerge_0
+I: [EXECUTING] ././testcases/sets/0062set_connlimit_0
+I: [OK] ././testcases/sets/0062set_connlimit_0
+I: [EXECUTING] ././testcases/sets/0063set_catchall_0
+W: [FAILED] ././testcases/sets/0063set_catchall_0
+I: [EXECUTING] ././testcases/sets/0064map_catchall_0
+W: [FAILED] ././testcases/sets/0064map_catchall_0
+I: [EXECUTING] ././testcases/sets/0065_icmp_postprocessing
+I: [OK] ././testcases/sets/0065_icmp_postprocessing
+I: [EXECUTING] ././testcases/sets/0067nat_concat_interval_0
+W: [FAILED] ././testcases/sets/0067nat_concat_interval_0
+I: [EXECUTING] ././testcases/sets/0068interval_stack_overflow_0
+I: [OK] ././testcases/sets/0068interval_stack_overflow_0
+I: [EXECUTING] ././testcases/sets/0069interval_merge_0
+I: [OK] ././testcases/sets/0069interval_merge_0
+I: [EXECUTING] ././testcases/sets/0070stacked_l2_headers
+I: [OK] ././testcases/sets/0070stacked_l2_headers
+I: [EXECUTING] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [EXECUTING] ././testcases/sets/0072destroy_0
+W: [FAILED] ././testcases/sets/0072destroy_0
+I: [EXECUTING] ././testcases/sets/automerge_0
+I: [OK] ././testcases/sets/automerge_0
+I: [EXECUTING] ././testcases/sets/collapse_elem_0
+I: [OK] ././testcases/sets/collapse_elem_0
+I: [EXECUTING] ././testcases/sets/concat_interval_0
+W: [FAILED] ././testcases/sets/concat_interval_0
+I: [EXECUTING] ././testcases/sets/dynset_missing
+I: [OK] ././testcases/sets/dynset_missing
+I: [EXECUTING] ././testcases/sets/errors_0
+I: [OK] ././testcases/sets/errors_0
+I: [EXECUTING] ././testcases/sets/exact_overlap_0
+I: [OK] ././testcases/sets/exact_overlap_0
+I: [EXECUTING] ././testcases/sets/inner_0
+W: [FAILED] ././testcases/sets/inner_0
+I: [EXECUTING] ././testcases/sets/reset_command_0
+W: [FAILED] ././testcases/sets/reset_command_0
+I: [EXECUTING] ././testcases/sets/set_eval_0
+I: [OK] ././testcases/sets/set_eval_0
+I: [EXECUTING] ././testcases/sets/sets_with_ifnames
+W: [FAILED] ././testcases/sets/sets_with_ifnames
+I: [EXECUTING] ././testcases/sets/typeof_raw_0
+W: [FAILED] ././testcases/sets/typeof_raw_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_0
+W: [FAILED] ././testcases/sets/typeof_sets_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_1
+I: [OK] ././testcases/sets/typeof_sets_1
+I: [EXECUTING] ././testcases/sets/typeof_sets_concat
+I: [OK] ././testcases/sets/typeof_sets_concat
+I: [EXECUTING] ././testcases/sets/type_set_symbol
+I: [OK] ././testcases/sets/type_set_symbol
+I: [EXECUTING] ././testcases/transactions/0001table_0
+I: [OK] ././testcases/transactions/0001table_0
+I: [EXECUTING] ././testcases/transactions/0002table_0
+I: [OK] ././testcases/transactions/0002table_0
+I: [EXECUTING] ././testcases/transactions/0003table_0
+I: [OK] ././testcases/transactions/0003table_0
+I: [EXECUTING] ././testcases/transactions/0010chain_0
+I: [OK] ././testcases/transactions/0010chain_0
+I: [EXECUTING] ././testcases/transactions/0011chain_0
+I: [OK] ././testcases/transactions/0011chain_0
+I: [EXECUTING] ././testcases/transactions/0012chain_0
+I: [OK] ././testcases/transactions/0012chain_0
+I: [EXECUTING] ././testcases/transactions/0013chain_0
+I: [OK] ././testcases/transactions/0013chain_0
+I: [EXECUTING] ././testcases/transactions/0014chain_1
+I: [OK] ././testcases/transactions/0014chain_1
+I: [EXECUTING] ././testcases/transactions/0015chain_0
+I: [OK] ././testcases/transactions/0015chain_0
+I: [EXECUTING] ././testcases/transactions/0020rule_0
+I: [OK] ././testcases/transactions/0020rule_0
+I: [EXECUTING] ././testcases/transactions/0021rule_0
+I: [OK] ././testcases/transactions/0021rule_0
+I: [EXECUTING] ././testcases/transactions/0022rule_1
+I: [OK] ././testcases/transactions/0022rule_1
+I: [EXECUTING] ././testcases/transactions/0023rule_1
+I: [OK] ././testcases/transactions/0023rule_1
+I: [EXECUTING] ././testcases/transactions/0024rule_0
+I: [OK] ././testcases/transactions/0024rule_0
+I: [EXECUTING] ././testcases/transactions/0025rule_0
+I: [OK] ././testcases/transactions/0025rule_0
+I: [EXECUTING] ././testcases/transactions/0030set_0
+I: [OK] ././testcases/transactions/0030set_0
+I: [EXECUTING] ././testcases/transactions/0031set_0
+I: [OK] ././testcases/transactions/0031set_0
+I: [EXECUTING] ././testcases/transactions/0032set_0
+I: [OK] ././testcases/transactions/0032set_0
+I: [EXECUTING] ././testcases/transactions/0033set_0
+I: [OK] ././testcases/transactions/0033set_0
+I: [EXECUTING] ././testcases/transactions/0034set_0
+I: [OK] ././testcases/transactions/0034set_0
+I: [EXECUTING] ././testcases/transactions/0035set_0
+I: [OK] ././testcases/transactions/0035set_0
+I: [EXECUTING] ././testcases/transactions/0036set_1
+I: [OK] ././testcases/transactions/0036set_1
+I: [EXECUTING] ././testcases/transactions/0037set_0
+I: [OK] ././testcases/transactions/0037set_0
+I: [EXECUTING] ././testcases/transactions/0038set_0
+I: [OK] ././testcases/transactions/0038set_0
+I: [EXECUTING] ././testcases/transactions/0039set_0
+I: [OK] ././testcases/transactions/0039set_0
+I: [EXECUTING] ././testcases/transactions/0040set_0
+I: [OK] ././testcases/transactions/0040set_0
+I: [EXECUTING] ././testcases/transactions/0041nat_restore_0
+I: [OK] ././testcases/transactions/0041nat_restore_0
+I: [EXECUTING] ././testcases/transactions/0042_stateful_expr_0
+I: [OK] ././testcases/transactions/0042_stateful_expr_0
+I: [EXECUTING] ././testcases/transactions/0043set_1
+I: [OK] ././testcases/transactions/0043set_1
+I: [EXECUTING] ././testcases/transactions/0044rule_0
+I: [OK] ././testcases/transactions/0044rule_0
+I: [EXECUTING] ././testcases/transactions/0045anon-unbind_0
+I: [OK] ././testcases/transactions/0045anon-unbind_0
+I: [EXECUTING] ././testcases/transactions/0046set_0
+I: [OK] ././testcases/transactions/0046set_0
+I: [EXECUTING] ././testcases/transactions/0047set_0
+I: [OK] ././testcases/transactions/0047set_0
+I: [EXECUTING] ././testcases/transactions/0048helpers_0
+I: [OK] ././testcases/transactions/0048helpers_0
+I: [EXECUTING] ././testcases/transactions/0049huge_0
+I: [OK] ././testcases/transactions/0049huge_0
+I: [EXECUTING] ././testcases/transactions/0050rule_1
+I: [OK] ././testcases/transactions/0050rule_1
+I: [EXECUTING] ././testcases/transactions/0051map_0
+I: [OK] ././testcases/transactions/0051map_0
+I: [EXECUTING] ././testcases/transactions/30s-stress
+W: [FAILED] ././testcases/transactions/30s-stress
+I: [EXECUTING] ././testcases/transactions/anon_chain_loop
+I: [OK] ././testcases/transactions/anon_chain_loop
+I: [EXECUTING] ././testcases/transactions/bad_expression
+I: [OK] ././testcases/transactions/bad_expression
+
+I: results: [OK] 302 [FAILED] 71 [TOTAL] 373
diff --git a/tests/shell/stable-log/log-6.1 b/tests/shell/stable-log/log-6.1
new file mode 100644
index 0000000..feb84d9
--- /dev/null
+++ b/tests/shell/stable-log/log-6.1
@@ -0,0 +1,751 @@
+I: using nft command: ./../../src/nft
+
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_0
+I: [OK] ././testcases/bitwise/0040mark_binop_0
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_1
+I: [OK] ././testcases/bitwise/0040mark_binop_1
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_2
+I: [OK] ././testcases/bitwise/0040mark_binop_2
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_3
+I: [OK] ././testcases/bitwise/0040mark_binop_3
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_4
+I: [OK] ././testcases/bitwise/0040mark_binop_4
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_5
+I: [OK] ././testcases/bitwise/0040mark_binop_5
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_6
+I: [OK] ././testcases/bitwise/0040mark_binop_6
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_7
+I: [OK] ././testcases/bitwise/0040mark_binop_7
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_8
+I: [OK] ././testcases/bitwise/0040mark_binop_8
+I: [EXECUTING] ././testcases/bitwise/0040mark_binop_9
+I: [OK] ././testcases/bitwise/0040mark_binop_9
+I: [EXECUTING] ././testcases/bogons/assert_failures
+I: [OK] ././testcases/bogons/assert_failures
+I: [EXECUTING] ././testcases/cache/0001_cache_handling_0
+I: [OK] ././testcases/cache/0001_cache_handling_0
+I: [EXECUTING] ././testcases/cache/0002_interval_0
+I: [OK] ././testcases/cache/0002_interval_0
+I: [EXECUTING] ././testcases/cache/0003_cache_update_0
+I: [OK] ././testcases/cache/0003_cache_update_0
+I: [EXECUTING] ././testcases/cache/0004_cache_update_0
+I: [OK] ././testcases/cache/0004_cache_update_0
+I: [EXECUTING] ././testcases/cache/0005_cache_chain_flush
+I: [OK] ././testcases/cache/0005_cache_chain_flush
+I: [EXECUTING] ././testcases/cache/0006_cache_table_flush
+I: [OK] ././testcases/cache/0006_cache_table_flush
+I: [EXECUTING] ././testcases/cache/0007_echo_cache_init_0
+I: [OK] ././testcases/cache/0007_echo_cache_init_0
+I: [EXECUTING] ././testcases/cache/0008_delete_by_handle_0
+I: [OK] ././testcases/cache/0008_delete_by_handle_0
+I: [EXECUTING] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [OK] ././testcases/cache/0009_delete_by_handle_incorrect_0
+I: [EXECUTING] ././testcases/cache/0010_implicit_chain_0
+I: [OK] ././testcases/cache/0010_implicit_chain_0
+I: [EXECUTING] ././testcases/cache/0011_index_0
+I: [OK] ././testcases/cache/0011_index_0
+I: [EXECUTING] ././testcases/chains/0001jumps_0
+I: [OK] ././testcases/chains/0001jumps_0
+I: [EXECUTING] ././testcases/chains/0002jumps_1
+I: [OK] ././testcases/chains/0002jumps_1
+I: [EXECUTING] ././testcases/chains/0003jump_loop_1
+I: [OK] ././testcases/chains/0003jump_loop_1
+I: [EXECUTING] ././testcases/chains/0004busy_1
+I: [OK] ././testcases/chains/0004busy_1
+I: [EXECUTING] ././testcases/chains/0005busy_map_1
+I: [OK] ././testcases/chains/0005busy_map_1
+I: [EXECUTING] ././testcases/chains/0006masquerade_0
+I: [OK] ././testcases/chains/0006masquerade_0
+I: [EXECUTING] ././testcases/chains/0007masquerade_1
+I: [OK] ././testcases/chains/0007masquerade_1
+I: [EXECUTING] ././testcases/chains/0008masquerade_jump_1
+I: [OK] ././testcases/chains/0008masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0009masquerade_jump_1
+I: [OK] ././testcases/chains/0009masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0010endless_jump_loop_1
+I: [OK] ././testcases/chains/0010endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0011endless_jump_loop_1
+I: [OK] ././testcases/chains/0011endless_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0013rename_0
+I: [OK] ././testcases/chains/0013rename_0
+I: [EXECUTING] ././testcases/chains/0014rename_0
+I: [OK] ././testcases/chains/0014rename_0
+I: [EXECUTING] ././testcases/chains/0015check_jump_loop_1
+I: [OK] ././testcases/chains/0015check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0016delete_handle_0
+I: [OK] ././testcases/chains/0016delete_handle_0
+I: [EXECUTING] ././testcases/chains/0017masquerade_jump_1
+I: [OK] ././testcases/chains/0017masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0018check_jump_loop_1
+I: [OK] ././testcases/chains/0018check_jump_loop_1
+I: [EXECUTING] ././testcases/chains/0019masquerade_jump_1
+I: [OK] ././testcases/chains/0019masquerade_jump_1
+I: [EXECUTING] ././testcases/chains/0020depth_1
+I: [OK] ././testcases/chains/0020depth_1
+I: [EXECUTING] ././testcases/chains/0021prio_0
+I: [OK] ././testcases/chains/0021prio_0
+I: [EXECUTING] ././testcases/chains/0022prio_dummy_1
+I: [OK] ././testcases/chains/0022prio_dummy_1
+I: [EXECUTING] ././testcases/chains/0023prio_inet_srcnat_1
+I: [OK] ././testcases/chains/0023prio_inet_srcnat_1
+I: [EXECUTING] ././testcases/chains/0024prio_inet_dstnat_1
+I: [OK] ././testcases/chains/0024prio_inet_dstnat_1
+I: [EXECUTING] ././testcases/chains/0025prio_arp_1
+I: [OK] ././testcases/chains/0025prio_arp_1
+I: [EXECUTING] ././testcases/chains/0026prio_netdev_1
+I: [OK] ././testcases/chains/0026prio_netdev_1
+I: [EXECUTING] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [OK] ././testcases/chains/0027prio_bridge_dstnat_1
+I: [EXECUTING] ././testcases/chains/0028prio_bridge_out_1
+I: [OK] ././testcases/chains/0028prio_bridge_out_1
+I: [EXECUTING] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [OK] ././testcases/chains/0029prio_bridge_srcnat_1
+I: [EXECUTING] ././testcases/chains/0030create_0
+I: [OK] ././testcases/chains/0030create_0
+I: [EXECUTING] ././testcases/chains/0031priority_variable_0
+I: [OK] ././testcases/chains/0031priority_variable_0
+I: [EXECUTING] ././testcases/chains/0032priority_variable_0
+I: [OK] ././testcases/chains/0032priority_variable_0
+I: [EXECUTING] ././testcases/chains/0033priority_variable_1
+I: [OK] ././testcases/chains/0033priority_variable_1
+I: [EXECUTING] ././testcases/chains/0034priority_variable_1
+I: [OK] ././testcases/chains/0034priority_variable_1
+I: [EXECUTING] ././testcases/chains/0035policy_variable_0
+I: [OK] ././testcases/chains/0035policy_variable_0
+I: [EXECUTING] ././testcases/chains/0036policy_variable_0
+I: [OK] ././testcases/chains/0036policy_variable_0
+I: [EXECUTING] ././testcases/chains/0037policy_variable_1
+I: [OK] ././testcases/chains/0037policy_variable_1
+I: [EXECUTING] ././testcases/chains/0038policy_variable_1
+I: [OK] ././testcases/chains/0038policy_variable_1
+I: [EXECUTING] ././testcases/chains/0039negative_priority_0
+I: [OK] ././testcases/chains/0039negative_priority_0
+I: [EXECUTING] ././testcases/chains/0041chain_binding_0
+I: [OK] ././testcases/chains/0041chain_binding_0
+I: [EXECUTING] ././testcases/chains/0042chain_variable_0
+I: [OK] ././testcases/chains/0042chain_variable_0
+I: [EXECUTING] ././testcases/chains/0043chain_ingress_0
+I: [OK] ././testcases/chains/0043chain_ingress_0
+I: [EXECUTING] ././testcases/chains/0044chain_destroy_0
+W: [FAILED] ././testcases/chains/0044chain_destroy_0
+I: [EXECUTING] ././testcases/chains/netdev_chain_0
+W: [FAILED] ././testcases/chains/netdev_chain_0
+I: [EXECUTING] ././testcases/comments/comments_0
+I: [OK] ././testcases/comments/comments_0
+I: [EXECUTING] ././testcases/flowtable/0001flowtable_0
+I: [OK] ././testcases/flowtable/0001flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0002create_flowtable_0
+I: [OK] ././testcases/flowtable/0002create_flowtable_0
+I: [EXECUTING] ././testcases/flowtable/0003add_after_flush_0
+I: [OK] ././testcases/flowtable/0003add_after_flush_0
+I: [EXECUTING] ././testcases/flowtable/0004delete_after_add_0
+I: [OK] ././testcases/flowtable/0004delete_after_add_0
+I: [EXECUTING] ././testcases/flowtable/0005delete_in_use_1
+I: [OK] ././testcases/flowtable/0005delete_in_use_1
+I: [EXECUTING] ././testcases/flowtable/0006segfault_0
+I: [OK] ././testcases/flowtable/0006segfault_0
+I: [EXECUTING] ././testcases/flowtable/0007prio_0
+I: [OK] ././testcases/flowtable/0007prio_0
+I: [EXECUTING] ././testcases/flowtable/0008prio_1
+I: [OK] ././testcases/flowtable/0008prio_1
+I: [EXECUTING] ././testcases/flowtable/0009deleteafterflush_0
+I: [OK] ././testcases/flowtable/0009deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0010delete_handle_0
+I: [OK] ././testcases/flowtable/0010delete_handle_0
+I: [EXECUTING] ././testcases/flowtable/0011deleteafterflush_0
+I: [OK] ././testcases/flowtable/0011deleteafterflush_0
+I: [EXECUTING] ././testcases/flowtable/0012flowtable_variable_0
+I: [OK] ././testcases/flowtable/0012flowtable_variable_0
+I: [EXECUTING] ././testcases/flowtable/0013addafterdelete_0
+I: [OK] ././testcases/flowtable/0013addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0014addafterdelete_0
+I: [OK] ././testcases/flowtable/0014addafterdelete_0
+I: [EXECUTING] ././testcases/flowtable/0015destroy_0
+W: [FAILED] ././testcases/flowtable/0015destroy_0
+I: [EXECUTING] ././testcases/include/0001absolute_0
+I: [OK] ././testcases/include/0001absolute_0
+I: [EXECUTING] ././testcases/include/0002relative_0
+I: [OK] ././testcases/include/0002relative_0
+I: [EXECUTING] ././testcases/include/0003includepath_0
+I: [OK] ././testcases/include/0003includepath_0
+I: [EXECUTING] ././testcases/include/0004endlessloop_1
+I: [OK] ././testcases/include/0004endlessloop_1
+I: [EXECUTING] ././testcases/include/0005glob_empty_0
+I: [OK] ././testcases/include/0005glob_empty_0
+I: [EXECUTING] ././testcases/include/0006glob_single_0
+I: [OK] ././testcases/include/0006glob_single_0
+I: [EXECUTING] ././testcases/include/0007glob_double_0
+I: [OK] ././testcases/include/0007glob_double_0
+I: [EXECUTING] ././testcases/include/0008glob_nofile_wildcard_0
+I: [OK] ././testcases/include/0008glob_nofile_wildcard_0
+I: [EXECUTING] ././testcases/include/0009glob_nofile_1
+I: [OK] ././testcases/include/0009glob_nofile_1
+I: [EXECUTING] ././testcases/include/0010glob_broken_file_1
+I: [OK] ././testcases/include/0010glob_broken_file_1
+I: [EXECUTING] ././testcases/include/0011glob_dependency_0
+I: [OK] ././testcases/include/0011glob_dependency_0
+I: [EXECUTING] ././testcases/include/0012glob_dependency_1
+I: [OK] ././testcases/include/0012glob_dependency_1
+I: [EXECUTING] ././testcases/include/0013glob_dotfile_0
+I: [OK] ././testcases/include/0013glob_dotfile_0
+I: [EXECUTING] ././testcases/include/0013input_descriptors_included_files_0
+I: [OK] ././testcases/include/0013input_descriptors_included_files_0
+I: [EXECUTING] ././testcases/include/0014glob_directory_0
+I: [OK] ././testcases/include/0014glob_directory_0
+I: [EXECUTING] ././testcases/include/0015doubleincludepath_0
+I: [OK] ././testcases/include/0015doubleincludepath_0
+I: [EXECUTING] ././testcases/include/0016maxdepth_0
+I: [OK] ././testcases/include/0016maxdepth_0
+I: [EXECUTING] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [OK] ././testcases/include/0017glob_more_than_maxdepth_1
+I: [EXECUTING] ././testcases/include/0018include_error_0
+I: [OK] ././testcases/include/0018include_error_0
+I: [EXECUTING] ././testcases/include/0019include_error_0
+I: [OK] ././testcases/include/0019include_error_0
+I: [EXECUTING] ././testcases/include/0020include_chain_0
+I: [OK] ././testcases/include/0020include_chain_0
+I: [EXECUTING] ././testcases/json/0001set_statements_0
+I: [OK] ././testcases/json/0001set_statements_0
+I: [EXECUTING] ././testcases/json/0002table_map_0
+I: [OK] ././testcases/json/0002table_map_0
+I: [EXECUTING] ././testcases/json/0003json_schema_version_0
+I: [OK] ././testcases/json/0003json_schema_version_0
+I: [EXECUTING] ././testcases/json/0004json_schema_version_1
+I: [OK] ././testcases/json/0004json_schema_version_1
+I: [EXECUTING] ././testcases/json/0005secmark_objref_0
+I: [OK] ././testcases/json/0005secmark_objref_0
+I: [EXECUTING] ././testcases/json/0006obj_comment_0
+I: [OK] ././testcases/json/0006obj_comment_0
+I: [EXECUTING] ././testcases/json/netdev
+I: [OK] ././testcases/json/netdev
+I: [EXECUTING] ././testcases/listing/0001ruleset_0
+I: [OK] ././testcases/listing/0001ruleset_0
+I: [EXECUTING] ././testcases/listing/0002ruleset_0
+I: [OK] ././testcases/listing/0002ruleset_0
+I: [EXECUTING] ././testcases/listing/0003table_0
+I: [OK] ././testcases/listing/0003table_0
+I: [EXECUTING] ././testcases/listing/0004table_0
+I: [OK] ././testcases/listing/0004table_0
+I: [EXECUTING] ././testcases/listing/0005ruleset_ip_0
+I: [OK] ././testcases/listing/0005ruleset_ip_0
+I: [EXECUTING] ././testcases/listing/0006ruleset_ip6_0
+I: [OK] ././testcases/listing/0006ruleset_ip6_0
+I: [EXECUTING] ././testcases/listing/0007ruleset_inet_0
+I: [OK] ././testcases/listing/0007ruleset_inet_0
+I: [EXECUTING] ././testcases/listing/0008ruleset_arp_0
+I: [OK] ././testcases/listing/0008ruleset_arp_0
+I: [EXECUTING] ././testcases/listing/0009ruleset_bridge_0
+I: [OK] ././testcases/listing/0009ruleset_bridge_0
+I: [EXECUTING] ././testcases/listing/0010sets_0
+I: [OK] ././testcases/listing/0010sets_0
+I: [EXECUTING] ././testcases/listing/0011sets_0
+I: [OK] ././testcases/listing/0011sets_0
+I: [EXECUTING] ././testcases/listing/0012sets_0
+I: [OK] ././testcases/listing/0012sets_0
+I: [EXECUTING] ././testcases/listing/0013objects_0
+I: [OK] ././testcases/listing/0013objects_0
+I: [EXECUTING] ././testcases/listing/0014objects_0
+I: [OK] ././testcases/listing/0014objects_0
+I: [EXECUTING] ././testcases/listing/0015dynamic_0
+I: [OK] ././testcases/listing/0015dynamic_0
+I: [EXECUTING] ././testcases/listing/0016anonymous_0
+I: [OK] ././testcases/listing/0016anonymous_0
+I: [EXECUTING] ././testcases/listing/0017objects_0
+I: [OK] ././testcases/listing/0017objects_0
+I: [EXECUTING] ././testcases/listing/0018data_0
+I: [OK] ././testcases/listing/0018data_0
+I: [EXECUTING] ././testcases/listing/0019set_0
+I: [OK] ././testcases/listing/0019set_0
+I: [EXECUTING] ././testcases/listing/0020flowtable_0
+I: [OK] ././testcases/listing/0020flowtable_0
+I: [EXECUTING] ././testcases/listing/0021ruleset_json_terse_0
+I: [OK] ././testcases/listing/0021ruleset_json_terse_0
+I: [EXECUTING] ././testcases/listing/0022terse_0
+I: [OK] ././testcases/listing/0022terse_0
+I: [EXECUTING] ././testcases/maps/0003map_add_many_elements_0
+I: [OK] ././testcases/maps/0003map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0004interval_map_create_once_0
+I: [OK] ././testcases/maps/0004interval_map_create_once_0
+I: [EXECUTING] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [OK] ././testcases/maps/0005interval_map_add_many_elements_0
+I: [EXECUTING] ././testcases/maps/0006interval_map_overlap_0
+I: [OK] ././testcases/maps/0006interval_map_overlap_0
+I: [EXECUTING] ././testcases/maps/0007named_ifname_dtype_0
+I: [OK] ././testcases/maps/0007named_ifname_dtype_0
+I: [EXECUTING] ././testcases/maps/0008interval_map_delete_0
+I: [OK] ././testcases/maps/0008interval_map_delete_0
+I: [EXECUTING] ././testcases/maps/0009vmap_0
+I: [OK] ././testcases/maps/0009vmap_0
+I: [EXECUTING] ././testcases/maps/0010concat_map_0
+I: [OK] ././testcases/maps/0010concat_map_0
+I: [EXECUTING] ././testcases/maps/0011vmap_0
+I: [OK] ././testcases/maps/0011vmap_0
+I: [EXECUTING] ././testcases/maps/0012map_0
+I: [OK] ././testcases/maps/0012map_0
+I: [EXECUTING] ././testcases/maps/0013map_0
+I: [OK] ././testcases/maps/0013map_0
+I: [EXECUTING] ././testcases/maps/0014destroy_0
+W: [FAILED] ././testcases/maps/0014destroy_0
+I: [EXECUTING] ././testcases/maps/0016map_leak_0
+I: [OK] ././testcases/maps/0016map_leak_0
+I: [EXECUTING] ././testcases/maps/0017_map_variable_0
+I: [OK] ././testcases/maps/0017_map_variable_0
+I: [EXECUTING] ././testcases/maps/0018map_leak_timeout_0
+I: [OK] ././testcases/maps/0018map_leak_timeout_0
+I: [EXECUTING] ././testcases/maps/anon_objmap_concat
+I: [OK] ././testcases/maps/anon_objmap_concat
+I: [EXECUTING] ././testcases/maps/anonymous_snat_map_0
+I: [OK] ././testcases/maps/anonymous_snat_map_0
+I: [EXECUTING] ././testcases/maps/different_map_types_1
+I: [OK] ././testcases/maps/different_map_types_1
+I: [EXECUTING] ././testcases/maps/map_catchall_double_deactivate
+I: [OK] ././testcases/maps/map_catchall_double_deactivate
+I: [EXECUTING] ././testcases/maps/map_with_flags_0
+I: [OK] ././testcases/maps/map_with_flags_0
+I: [EXECUTING] ././testcases/maps/named_snat_map_0
+I: [OK] ././testcases/maps/named_snat_map_0
+I: [EXECUTING] ././testcases/maps/nat_addr_port
+I: [OK] ././testcases/maps/nat_addr_port
+I: [EXECUTING] ././testcases/maps/typeof_integer_0
+I: [OK] ././testcases/maps/typeof_integer_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_0
+I: [OK] ././testcases/maps/typeof_maps_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_add_delete
+W: [FAILED] ././testcases/maps/typeof_maps_add_delete
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat
+I: [OK] ././testcases/maps/typeof_maps_concat
+I: [EXECUTING] ././testcases/maps/typeof_maps_concat_update_0
+I: [OK] ././testcases/maps/typeof_maps_concat_update_0
+I: [EXECUTING] ././testcases/maps/typeof_maps_update_0
+I: [OK] ././testcases/maps/typeof_maps_update_0
+I: [EXECUTING] ././testcases/maps/typeof_raw_0
+I: [OK] ././testcases/maps/typeof_raw_0
+I: [EXECUTING] ././testcases/maps/vmap_timeout
+I: [OK] ././testcases/maps/vmap_timeout
+I: [EXECUTING] ././testcases/netns/0001nft-f_0
+I: [OK] ././testcases/netns/0001nft-f_0
+I: [EXECUTING] ././testcases/netns/0002loosecommands_0
+I: [OK] ././testcases/netns/0002loosecommands_0
+I: [EXECUTING] ././testcases/netns/0003many_0
+I: [OK] ././testcases/netns/0003many_0
+I: [EXECUTING] ././testcases/nft-f/0001define_slash_0
+I: [OK] ././testcases/nft-f/0001define_slash_0
+I: [EXECUTING] ././testcases/nft-f/0002rollback_rule_0
+I: [OK] ././testcases/nft-f/0002rollback_rule_0
+I: [EXECUTING] ././testcases/nft-f/0003rollback_jump_0
+I: [OK] ././testcases/nft-f/0003rollback_jump_0
+I: [EXECUTING] ././testcases/nft-f/0004rollback_set_0
+I: [OK] ././testcases/nft-f/0004rollback_set_0
+I: [EXECUTING] ././testcases/nft-f/0005rollback_map_0
+I: [OK] ././testcases/nft-f/0005rollback_map_0
+I: [EXECUTING] ././testcases/nft-f/0006action_object_0
+I: [OK] ././testcases/nft-f/0006action_object_0
+I: [EXECUTING] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [OK] ././testcases/nft-f/0007action_object_set_segfault_1
+I: [EXECUTING] ././testcases/nft-f/0008split_tables_0
+I: [OK] ././testcases/nft-f/0008split_tables_0
+I: [EXECUTING] ././testcases/nft-f/0009variable_0
+I: [OK] ././testcases/nft-f/0009variable_0
+I: [EXECUTING] ././testcases/nft-f/0010variable_0
+I: [OK] ././testcases/nft-f/0010variable_0
+I: [EXECUTING] ././testcases/nft-f/0011manydefines_0
+I: [OK] ././testcases/nft-f/0011manydefines_0
+I: [EXECUTING] ././testcases/nft-f/0012different_defines_0
+I: [OK] ././testcases/nft-f/0012different_defines_0
+I: [EXECUTING] ././testcases/nft-f/0013defines_1
+I: [OK] ././testcases/nft-f/0013defines_1
+I: [EXECUTING] ././testcases/nft-f/0014defines_1
+I: [OK] ././testcases/nft-f/0014defines_1
+I: [EXECUTING] ././testcases/nft-f/0015defines_1
+I: [OK] ././testcases/nft-f/0015defines_1
+I: [EXECUTING] ././testcases/nft-f/0016redefines_1
+I: [OK] ././testcases/nft-f/0016redefines_1
+I: [EXECUTING] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [OK] ././testcases/nft-f/0017ct_timeout_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [OK] ././testcases/nft-f/0018ct_expectation_obj_0
+I: [EXECUTING] ././testcases/nft-f/0018jump_variable_0
+I: [OK] ././testcases/nft-f/0018jump_variable_0
+I: [EXECUTING] ././testcases/nft-f/0019jump_variable_1
+I: [OK] ././testcases/nft-f/0019jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0020jump_variable_1
+I: [OK] ././testcases/nft-f/0020jump_variable_1
+I: [EXECUTING] ././testcases/nft-f/0021list_ruleset_0
+I: [OK] ././testcases/nft-f/0021list_ruleset_0
+I: [EXECUTING] ././testcases/nft-f/0022variables_0
+I: [OK] ././testcases/nft-f/0022variables_0
+I: [EXECUTING] ././testcases/nft-f/0023check_1
+I: [OK] ././testcases/nft-f/0023check_1
+I: [EXECUTING] ././testcases/nft-f/0024priority_0
+I: [OK] ././testcases/nft-f/0024priority_0
+I: [EXECUTING] ././testcases/nft-f/0025empty_dynset_0
+I: [OK] ././testcases/nft-f/0025empty_dynset_0
+I: [EXECUTING] ././testcases/nft-f/0026listing_0
+I: [OK] ././testcases/nft-f/0026listing_0
+I: [EXECUTING] ././testcases/nft-f/0027split_chains_0
+I: [OK] ././testcases/nft-f/0027split_chains_0
+I: [EXECUTING] ././testcases/nft-f/0028variable_cmdline_0
+I: [OK] ././testcases/nft-f/0028variable_cmdline_0
+I: [EXECUTING] ././testcases/nft-f/0029split_file_0
+I: [OK] ././testcases/nft-f/0029split_file_0
+I: [EXECUTING] ././testcases/nft-f/0030variable_reuse_0
+I: [OK] ././testcases/nft-f/0030variable_reuse_0
+I: [EXECUTING] ././testcases/nft-f/0031vmap_string_0
+I: [OK] ././testcases/nft-f/0031vmap_string_0
+I: [EXECUTING] ././testcases/nft-f/0032pknock_0
+I: [OK] ././testcases/nft-f/0032pknock_0
+I: [EXECUTING] ././testcases/nft-i/0001define_0
+I: [OK] ././testcases/nft-i/0001define_0
+I: [EXECUTING] ././testcases/optimizations/dependency_kill
+I: [OK] ././testcases/optimizations/dependency_kill
+I: [EXECUTING] ././testcases/optimizations/merge_nat
+I: [OK] ././testcases/optimizations/merge_nat
+I: [EXECUTING] ././testcases/optimizations/merge_reject
+I: [OK] ././testcases/optimizations/merge_reject
+I: [EXECUTING] ././testcases/optimizations/merge_stmts
+I: [OK] ././testcases/optimizations/merge_stmts
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat
+I: [OK] ././testcases/optimizations/merge_stmts_concat
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_concat_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_stmts_vmap
+I: [OK] ././testcases/optimizations/merge_stmts_vmap
+I: [EXECUTING] ././testcases/optimizations/merge_vmap_raw
+I: [OK] ././testcases/optimizations/merge_vmap_raw
+I: [EXECUTING] ././testcases/optimizations/merge_vmaps
+I: [OK] ././testcases/optimizations/merge_vmaps
+I: [EXECUTING] ././testcases/optimizations/not_mergeable
+I: [OK] ././testcases/optimizations/not_mergeable
+I: [EXECUTING] ././testcases/optimizations/ruleset
+I: [OK] ././testcases/optimizations/ruleset
+I: [EXECUTING] ././testcases/optimizations/single_anon_set
+I: [OK] ././testcases/optimizations/single_anon_set
+I: [EXECUTING] ././testcases/optimizations/skip_merge
+I: [OK] ././testcases/optimizations/skip_merge
+I: [EXECUTING] ././testcases/optimizations/skip_non_eq
+I: [OK] ././testcases/optimizations/skip_non_eq
+I: [EXECUTING] ././testcases/optimizations/skip_unsupported
+I: [OK] ././testcases/optimizations/skip_unsupported
+I: [EXECUTING] ././testcases/optimizations/variables
+I: [OK] ././testcases/optimizations/variables
+I: [EXECUTING] ././testcases/optionals/comments_0
+I: [OK] ././testcases/optionals/comments_0
+I: [EXECUTING] ././testcases/optionals/comments_chain_0
+I: [OK] ././testcases/optionals/comments_chain_0
+I: [EXECUTING] ././testcases/optionals/comments_handles_0
+I: [OK] ././testcases/optionals/comments_handles_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_0
+I: [OK] ././testcases/optionals/comments_objects_0
+I: [EXECUTING] ././testcases/optionals/comments_objects_dup_0
+I: [OK] ././testcases/optionals/comments_objects_dup_0
+I: [EXECUTING] ././testcases/optionals/comments_table_0
+I: [OK] ././testcases/optionals/comments_table_0
+I: [EXECUTING] ././testcases/optionals/delete_object_handles_0
+I: [OK] ././testcases/optionals/delete_object_handles_0
+I: [EXECUTING] ././testcases/optionals/handles_0
+I: [OK] ././testcases/optionals/handles_0
+I: [EXECUTING] ././testcases/optionals/handles_1
+I: [OK] ././testcases/optionals/handles_1
+I: [EXECUTING] ././testcases/optionals/log_prefix_0
+I: [OK] ././testcases/optionals/log_prefix_0
+I: [EXECUTING] ././testcases/optionals/update_object_handles_0
+I: [OK] ././testcases/optionals/update_object_handles_0
+I: [EXECUTING] ././testcases/owner/0001-flowtable-uaf
+I: [OK] ././testcases/owner/0001-flowtable-uaf
+I: [EXECUTING] ././testcases/parsing/describe
+I: [OK] ././testcases/parsing/describe
+I: [EXECUTING] ././testcases/parsing/large_rule_pipe
+I: [OK] ././testcases/parsing/large_rule_pipe
+I: [EXECUTING] ././testcases/parsing/log
+I: [OK] ././testcases/parsing/log
+I: [EXECUTING] ././testcases/parsing/octal
+I: [OK] ././testcases/parsing/octal
+I: [EXECUTING] ././testcases/rule_management/0001addinsertposition_0
+I: [OK] ././testcases/rule_management/0001addinsertposition_0
+I: [EXECUTING] ././testcases/rule_management/0002addinsertlocation_1
+I: [OK] ././testcases/rule_management/0002addinsertlocation_1
+I: [EXECUTING] ././testcases/rule_management/0003insert_0
+I: [OK] ././testcases/rule_management/0003insert_0
+I: [EXECUTING] ././testcases/rule_management/0004replace_0
+I: [OK] ././testcases/rule_management/0004replace_0
+I: [EXECUTING] ././testcases/rule_management/0005replace_1
+I: [OK] ././testcases/rule_management/0005replace_1
+I: [EXECUTING] ././testcases/rule_management/0006replace_1
+I: [OK] ././testcases/rule_management/0006replace_1
+I: [EXECUTING] ././testcases/rule_management/0007delete_0
+I: [OK] ././testcases/rule_management/0007delete_0
+I: [EXECUTING] ././testcases/rule_management/0008delete_1
+I: [OK] ././testcases/rule_management/0008delete_1
+I: [EXECUTING] ././testcases/rule_management/0009delete_1
+I: [OK] ././testcases/rule_management/0009delete_1
+I: [EXECUTING] ././testcases/rule_management/0010replace_0
+I: [OK] ././testcases/rule_management/0010replace_0
+I: [EXECUTING] ././testcases/rule_management/0011reset_0
+W: [FAILED] ././testcases/rule_management/0011reset_0
+I: [EXECUTING] ././testcases/rule_management/0012destroy_0
+W: [FAILED] ././testcases/rule_management/0012destroy_0
+I: [EXECUTING] ././testcases/sets/0001named_interval_0
+I: [OK] ././testcases/sets/0001named_interval_0
+I: [EXECUTING] ././testcases/sets/0002named_interval_automerging_0
+I: [OK] ././testcases/sets/0002named_interval_automerging_0
+I: [EXECUTING] ././testcases/sets/0003named_interval_missing_flag_0
+I: [OK] ././testcases/sets/0003named_interval_missing_flag_0
+I: [EXECUTING] ././testcases/sets/0004named_interval_shadow_0
+I: [OK] ././testcases/sets/0004named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0005named_interval_shadow_0
+I: [OK] ././testcases/sets/0005named_interval_shadow_0
+I: [EXECUTING] ././testcases/sets/0006create_set_0
+I: [OK] ././testcases/sets/0006create_set_0
+I: [EXECUTING] ././testcases/sets/0007create_element_0
+I: [OK] ././testcases/sets/0007create_element_0
+I: [EXECUTING] ././testcases/sets/0008comments_interval_0
+I: [OK] ././testcases/sets/0008comments_interval_0
+I: [EXECUTING] ././testcases/sets/0008create_verdict_map_0
+I: [OK] ././testcases/sets/0008create_verdict_map_0
+I: [EXECUTING] ././testcases/sets/0009comments_timeout_0
+I: [OK] ././testcases/sets/0009comments_timeout_0
+I: [EXECUTING] ././testcases/sets/0010comments_0
+I: [OK] ././testcases/sets/0010comments_0
+I: [EXECUTING] ././testcases/sets/0011add_many_elements_0
+I: [OK] ././testcases/sets/0011add_many_elements_0
+I: [EXECUTING] ././testcases/sets/0012add_delete_many_elements_0
+I: [OK] ././testcases/sets/0012add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0013add_delete_many_elements_0
+I: [OK] ././testcases/sets/0013add_delete_many_elements_0
+I: [EXECUTING] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [OK] ././testcases/sets/0014malformed_set_is_not_defined_0
+I: [EXECUTING] ././testcases/sets/0015rulesetflush_0
+I: [OK] ././testcases/sets/0015rulesetflush_0
+I: [EXECUTING] ././testcases/sets/0016element_leak_0
+I: [OK] ././testcases/sets/0016element_leak_0
+I: [EXECUTING] ././testcases/sets/0017add_after_flush_0
+I: [OK] ././testcases/sets/0017add_after_flush_0
+I: [EXECUTING] ././testcases/sets/0018set_check_size_1
+I: [OK] ././testcases/sets/0018set_check_size_1
+I: [EXECUTING] ././testcases/sets/0019set_check_size_0
+I: [OK] ././testcases/sets/0019set_check_size_0
+I: [EXECUTING] ././testcases/sets/0020comments_0
+I: [OK] ././testcases/sets/0020comments_0
+I: [EXECUTING] ././testcases/sets/0021nesting_0
+I: [OK] ././testcases/sets/0021nesting_0
+I: [EXECUTING] ././testcases/sets/0022type_selective_flush_0
+I: [OK] ././testcases/sets/0022type_selective_flush_0
+I: [EXECUTING] ././testcases/sets/0023incomplete_add_set_command_0
+I: [OK] ././testcases/sets/0023incomplete_add_set_command_0
+I: [EXECUTING] ././testcases/sets/0024named_objects_0
+I: [OK] ././testcases/sets/0024named_objects_0
+I: [EXECUTING] ././testcases/sets/0025anonymous_set_0
+I: [OK] ././testcases/sets/0025anonymous_set_0
+I: [EXECUTING] ././testcases/sets/0026named_limit_0
+I: [OK] ././testcases/sets/0026named_limit_0
+I: [EXECUTING] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [OK] ././testcases/sets/0027ipv6_maps_ipv4_0
+I: [EXECUTING] ././testcases/sets/0028autoselect_0
+I: [OK] ././testcases/sets/0028autoselect_0
+I: [EXECUTING] ././testcases/sets/0028delete_handle_0
+I: [OK] ././testcases/sets/0028delete_handle_0
+I: [EXECUTING] ././testcases/sets/0029named_ifname_dtype_0
+I: [OK] ././testcases/sets/0029named_ifname_dtype_0
+I: [EXECUTING] ././testcases/sets/0030add_many_elements_interval_0
+I: [OK] ././testcases/sets/0030add_many_elements_interval_0
+I: [EXECUTING] ././testcases/sets/0031set_timeout_size_0
+I: [OK] ././testcases/sets/0031set_timeout_size_0
+I: [EXECUTING] ././testcases/sets/0032restore_set_simple_0
+I: [OK] ././testcases/sets/0032restore_set_simple_0
+I: [EXECUTING] ././testcases/sets/0033add_set_simple_flat_0
+I: [OK] ././testcases/sets/0033add_set_simple_flat_0
+I: [EXECUTING] ././testcases/sets/0034get_element_0
+I: [OK] ././testcases/sets/0034get_element_0
+I: [EXECUTING] ././testcases/sets/0035add_set_elements_flat_0
+I: [OK] ././testcases/sets/0035add_set_elements_flat_0
+I: [EXECUTING] ././testcases/sets/0036add_set_element_expiration_0
+I: [OK] ././testcases/sets/0036add_set_element_expiration_0
+I: [EXECUTING] ././testcases/sets/0037_set_with_inet_service_0
+I: [OK] ././testcases/sets/0037_set_with_inet_service_0
+I: [EXECUTING] ././testcases/sets/0038meter_list_0
+I: [OK] ././testcases/sets/0038meter_list_0
+I: [EXECUTING] ././testcases/sets/0039delete_interval_0
+I: [OK] ././testcases/sets/0039delete_interval_0
+I: [EXECUTING] ././testcases/sets/0040get_host_endian_elements_0
+I: [OK] ././testcases/sets/0040get_host_endian_elements_0
+I: [EXECUTING] ././testcases/sets/0041interval_0
+I: [OK] ././testcases/sets/0041interval_0
+I: [EXECUTING] ././testcases/sets/0042update_set_0
+I: [OK] ././testcases/sets/0042update_set_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_0
+I: [OK] ././testcases/sets/0043concatenated_ranges_0
+I: [EXECUTING] ././testcases/sets/0043concatenated_ranges_1
+I: [OK] ././testcases/sets/0043concatenated_ranges_1
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_0
+I: [OK] ././testcases/sets/0044interval_overlap_0
+I: [EXECUTING] ././testcases/sets/0044interval_overlap_1
+I: [OK] ././testcases/sets/0044interval_overlap_1
+I: [EXECUTING] ././testcases/sets/0045concat_ipv4_service
+I: [OK] ././testcases/sets/0045concat_ipv4_service
+I: [EXECUTING] ././testcases/sets/0046netmap_0
+I: [OK] ././testcases/sets/0046netmap_0
+I: [EXECUTING] ././testcases/sets/0047nat_0
+I: [OK] ././testcases/sets/0047nat_0
+I: [EXECUTING] ././testcases/sets/0048set_counters_0
+I: [OK] ././testcases/sets/0048set_counters_0
+I: [EXECUTING] ././testcases/sets/0049set_define_0
+I: [OK] ././testcases/sets/0049set_define_0
+I: [EXECUTING] ././testcases/sets/0050set_define_1
+I: [OK] ././testcases/sets/0050set_define_1
+I: [EXECUTING] ././testcases/sets/0051set_interval_counter_0
+I: [OK] ././testcases/sets/0051set_interval_counter_0
+I: [EXECUTING] ././testcases/sets/0052overlap_0
+I: [OK] ././testcases/sets/0052overlap_0
+I: [EXECUTING] ././testcases/sets/0053echo_0
+I: [OK] ././testcases/sets/0053echo_0
+I: [EXECUTING] ././testcases/sets/0054comments_set_0
+I: [OK] ././testcases/sets/0054comments_set_0
+I: [EXECUTING] ././testcases/sets/0055tcpflags_0
+I: [OK] ././testcases/sets/0055tcpflags_0
+I: [EXECUTING] ././testcases/sets/0056dynamic_limit_0
+I: [OK] ././testcases/sets/0056dynamic_limit_0
+I: [EXECUTING] ././testcases/sets/0057set_create_fails_0
+I: [OK] ././testcases/sets/0057set_create_fails_0
+I: [EXECUTING] ././testcases/sets/0058_setupdate_timeout_0
+I: [OK] ././testcases/sets/0058_setupdate_timeout_0
+I: [EXECUTING] ././testcases/sets/0059set_update_multistmt_0
+I: [OK] ././testcases/sets/0059set_update_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_0
+I: [OK] ././testcases/sets/0060set_multistmt_0
+I: [EXECUTING] ././testcases/sets/0060set_multistmt_1
+I: [OK] ././testcases/sets/0060set_multistmt_1
+I: [EXECUTING] ././testcases/sets/0061anonymous_automerge_0
+I: [OK] ././testcases/sets/0061anonymous_automerge_0
+I: [EXECUTING] ././testcases/sets/0062set_connlimit_0
+I: [OK] ././testcases/sets/0062set_connlimit_0
+I: [EXECUTING] ././testcases/sets/0063set_catchall_0
+I: [OK] ././testcases/sets/0063set_catchall_0
+I: [EXECUTING] ././testcases/sets/0064map_catchall_0
+I: [OK] ././testcases/sets/0064map_catchall_0
+I: [EXECUTING] ././testcases/sets/0065_icmp_postprocessing
+I: [OK] ././testcases/sets/0065_icmp_postprocessing
+I: [EXECUTING] ././testcases/sets/0067nat_concat_interval_0
+I: [OK] ././testcases/sets/0067nat_concat_interval_0
+I: [EXECUTING] ././testcases/sets/0068interval_stack_overflow_0
+I: [OK] ././testcases/sets/0068interval_stack_overflow_0
+I: [EXECUTING] ././testcases/sets/0069interval_merge_0
+I: [OK] ././testcases/sets/0069interval_merge_0
+I: [EXECUTING] ././testcases/sets/0070stacked_l2_headers
+I: [OK] ././testcases/sets/0070stacked_l2_headers
+I: [EXECUTING] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [OK] ././testcases/sets/0071unclosed_prefix_interval_0
+I: [EXECUTING] ././testcases/sets/0072destroy_0
+W: [FAILED] ././testcases/sets/0072destroy_0
+I: [EXECUTING] ././testcases/sets/automerge_0
+I: [OK] ././testcases/sets/automerge_0
+I: [EXECUTING] ././testcases/sets/collapse_elem_0
+I: [OK] ././testcases/sets/collapse_elem_0
+I: [EXECUTING] ././testcases/sets/concat_interval_0
+I: [OK] ././testcases/sets/concat_interval_0
+I: [EXECUTING] ././testcases/sets/dynset_missing
+I: [OK] ././testcases/sets/dynset_missing
+I: [EXECUTING] ././testcases/sets/errors_0
+I: [OK] ././testcases/sets/errors_0
+I: [EXECUTING] ././testcases/sets/exact_overlap_0
+I: [OK] ././testcases/sets/exact_overlap_0
+I: [EXECUTING] ././testcases/sets/inner_0
+W: [FAILED] ././testcases/sets/inner_0
+I: [EXECUTING] ././testcases/sets/reset_command_0
+W: [FAILED] ././testcases/sets/reset_command_0
+I: [EXECUTING] ././testcases/sets/set_eval_0
+I: [OK] ././testcases/sets/set_eval_0
+I: [EXECUTING] ././testcases/sets/sets_with_ifnames
+I: [OK] ././testcases/sets/sets_with_ifnames
+I: [EXECUTING] ././testcases/sets/typeof_raw_0
+I: [OK] ././testcases/sets/typeof_raw_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_0
+I: [OK] ././testcases/sets/typeof_sets_0
+I: [EXECUTING] ././testcases/sets/typeof_sets_1
+I: [OK] ././testcases/sets/typeof_sets_1
+I: [EXECUTING] ././testcases/sets/typeof_sets_concat
+I: [OK] ././testcases/sets/typeof_sets_concat
+I: [EXECUTING] ././testcases/sets/type_set_symbol
+I: [OK] ././testcases/sets/type_set_symbol
+I: [EXECUTING] ././testcases/transactions/0001table_0
+I: [OK] ././testcases/transactions/0001table_0
+I: [EXECUTING] ././testcases/transactions/0002table_0
+I: [OK] ././testcases/transactions/0002table_0
+I: [EXECUTING] ././testcases/transactions/0003table_0
+I: [OK] ././testcases/transactions/0003table_0
+I: [EXECUTING] ././testcases/transactions/0010chain_0
+I: [OK] ././testcases/transactions/0010chain_0
+I: [EXECUTING] ././testcases/transactions/0011chain_0
+I: [OK] ././testcases/transactions/0011chain_0
+I: [EXECUTING] ././testcases/transactions/0012chain_0
+I: [OK] ././testcases/transactions/0012chain_0
+I: [EXECUTING] ././testcases/transactions/0013chain_0
+I: [OK] ././testcases/transactions/0013chain_0
+I: [EXECUTING] ././testcases/transactions/0014chain_1
+I: [OK] ././testcases/transactions/0014chain_1
+I: [EXECUTING] ././testcases/transactions/0015chain_0
+I: [OK] ././testcases/transactions/0015chain_0
+I: [EXECUTING] ././testcases/transactions/0020rule_0
+I: [OK] ././testcases/transactions/0020rule_0
+I: [EXECUTING] ././testcases/transactions/0021rule_0
+I: [OK] ././testcases/transactions/0021rule_0
+I: [EXECUTING] ././testcases/transactions/0022rule_1
+I: [OK] ././testcases/transactions/0022rule_1
+I: [EXECUTING] ././testcases/transactions/0023rule_1
+I: [OK] ././testcases/transactions/0023rule_1
+I: [EXECUTING] ././testcases/transactions/0024rule_0
+I: [OK] ././testcases/transactions/0024rule_0
+I: [EXECUTING] ././testcases/transactions/0025rule_0
+I: [OK] ././testcases/transactions/0025rule_0
+I: [EXECUTING] ././testcases/transactions/0030set_0
+I: [OK] ././testcases/transactions/0030set_0
+I: [EXECUTING] ././testcases/transactions/0031set_0
+I: [OK] ././testcases/transactions/0031set_0
+I: [EXECUTING] ././testcases/transactions/0032set_0
+I: [OK] ././testcases/transactions/0032set_0
+I: [EXECUTING] ././testcases/transactions/0033set_0
+I: [OK] ././testcases/transactions/0033set_0
+I: [EXECUTING] ././testcases/transactions/0034set_0
+I: [OK] ././testcases/transactions/0034set_0
+I: [EXECUTING] ././testcases/transactions/0035set_0
+I: [OK] ././testcases/transactions/0035set_0
+I: [EXECUTING] ././testcases/transactions/0036set_1
+I: [OK] ././testcases/transactions/0036set_1
+I: [EXECUTING] ././testcases/transactions/0037set_0
+I: [OK] ././testcases/transactions/0037set_0
+I: [EXECUTING] ././testcases/transactions/0038set_0
+I: [OK] ././testcases/transactions/0038set_0
+I: [EXECUTING] ././testcases/transactions/0039set_0
+I: [OK] ././testcases/transactions/0039set_0
+I: [EXECUTING] ././testcases/transactions/0040set_0
+I: [OK] ././testcases/transactions/0040set_0
+I: [EXECUTING] ././testcases/transactions/0041nat_restore_0
+I: [OK] ././testcases/transactions/0041nat_restore_0
+I: [EXECUTING] ././testcases/transactions/0042_stateful_expr_0
+I: [OK] ././testcases/transactions/0042_stateful_expr_0
+I: [EXECUTING] ././testcases/transactions/0043set_1
+I: [OK] ././testcases/transactions/0043set_1
+I: [EXECUTING] ././testcases/transactions/0044rule_0
+I: [OK] ././testcases/transactions/0044rule_0
+I: [EXECUTING] ././testcases/transactions/0045anon-unbind_0
+I: [OK] ././testcases/transactions/0045anon-unbind_0
+I: [EXECUTING] ././testcases/transactions/0046set_0
+I: [OK] ././testcases/transactions/0046set_0
+I: [EXECUTING] ././testcases/transactions/0047set_0
+I: [OK] ././testcases/transactions/0047set_0
+I: [EXECUTING] ././testcases/transactions/0048helpers_0
+I: [OK] ././testcases/transactions/0048helpers_0
+I: [EXECUTING] ././testcases/transactions/0049huge_0
+I: [OK] ././testcases/transactions/0049huge_0
+I: [EXECUTING] ././testcases/transactions/0050rule_1
+I: [OK] ././testcases/transactions/0050rule_1
+I: [EXECUTING] ././testcases/transactions/0051map_0
+I: [OK] ././testcases/transactions/0051map_0
+I: [EXECUTING] ././testcases/transactions/30s-stress
+I: [OK] ././testcases/transactions/30s-stress
+I: [EXECUTING] ././testcases/transactions/anon_chain_loop
+I: [OK] ././testcases/transactions/anon_chain_loop
+I: [EXECUTING] ././testcases/transactions/bad_expression
+I: [OK] ././testcases/transactions/bad_expression
+
+W: [FAILED] kmemleak detected 1333 memory leaks
+I: results: [OK] 363 [FAILED] 10 [TOTAL] 373
diff --git a/tests/shell/test-list.txt b/tests/shell/test-list.txt
new file mode 100644
index 0000000..a044896
--- /dev/null
+++ b/tests/shell/test-list.txt
@@ -0,0 +1,367 @@
+testcases/chains/0013rename_0
+testcases/chains/0029prio_bridge_srcnat_1
+testcases/chains/0017masquerade_jump_1
+testcases/chains/0004busy_1
+testcases/chains/0003jump_loop_1
+testcases/chains/0021prio_0
+testcases/chains/0014rename_0
+testcases/chains/0006masquerade_0
+testcases/chains/0007masquerade_1
+testcases/chains/0005busy_map_1
+testcases/chains/0001jumps_0
+testcases/chains/0031priority_variable_0
+testcases/chains/0024prio_inet_dstnat_1
+testcases/chains/0038policy_variable_1
+testcases/chains/0030create_0
+testcases/chains/0036policy_variable_0
+testcases/chains/0035policy_variable_0
+testcases/chains/0033priority_variable_1
+testcases/chains/0043chain_ingress_0
+testcases/chains/0034priority_variable_1
+testcases/chains/0026prio_netdev_1
+testcases/chains/0044chain_destroy_0
+testcases/chains/0037policy_variable_1
+testcases/chains/0019masquerade_jump_1
+testcases/chains/0010endless_jump_loop_1
+testcases/chains/0009masquerade_jump_1
+testcases/chains/0023prio_inet_srcnat_1
+testcases/chains/0042chain_variable_0
+testcases/chains/0016delete_handle_0
+testcases/chains/0025prio_arp_1
+testcases/chains/0002jumps_1
+testcases/chains/0022prio_dummy_1
+testcases/chains/0018check_jump_loop_1
+testcases/chains/netdev_chain_0
+testcases/chains/0041chain_binding_0
+testcases/chains/0008masquerade_jump_1
+testcases/chains/0045chain_destroy_0
+testcases/chains/0015check_jump_loop_1
+testcases/chains/0020depth_1
+testcases/chains/0011endless_jump_loop_1
+testcases/chains/0032priority_variable_0
+testcases/chains/0028prio_bridge_out_1
+testcases/chains/0027prio_bridge_dstnat_1
+testcases/chains/0039negative_priority_0
+testcases/bitwise/0040mark_binop_8
+testcases/bitwise/0040mark_binop_5
+testcases/bitwise/0040mark_binop_4
+testcases/bitwise/0040mark_binop_3
+testcases/bitwise/0040mark_binop_2
+testcases/bitwise/0040mark_binop_6
+testcases/bitwise/0040mark_binop_7
+testcases/bitwise/0040mark_binop_1
+testcases/bitwise/0040mark_binop_0
+testcases/bitwise/0040mark_binop_9
+testcases/maps/0011vmap_0
+testcases/maps/named_snat_map_0
+testcases/maps/typeof_maps_concat_update_0
+testcases/maps/typeof_maps_concat
+testcases/maps/different_map_types_1
+testcases/maps/0005interval_map_add_many_elements_0
+testcases/maps/0007named_ifname_dtype_0
+testcases/maps/typeof_maps_update_0
+testcases/maps/map_with_flags_0
+testcases/maps/0014destroy_0
+testcases/maps/typeof_maps_0
+testcases/maps/0004interval_map_create_once_0
+testcases/maps/0006interval_map_overlap_0
+testcases/maps/0009vmap_0
+testcases/maps/anon_objmap_concat
+testcases/maps/0013map_0
+testcases/maps/0008interval_map_delete_0
+testcases/maps/0010concat_map_0
+testcases/maps/0003map_add_many_elements_0
+testcases/maps/typeof_raw_0
+testcases/maps/anonymous_snat_map_0
+testcases/maps/nat_addr_port
+testcases/maps/0015destroy_0
+testcases/maps/0012map_0
+testcases/maps/typeof_integer_0
+testcases/listing/0013objects_0
+testcases/listing/0017objects_0
+testcases/listing/0010sets_0
+testcases/listing/0009ruleset_bridge_0
+testcases/listing/0006ruleset_ip6_0
+testcases/listing/0020flowtable_0
+testcases/listing/0012sets_0
+testcases/listing/0008ruleset_arp_0
+testcases/listing/0011sets_0
+testcases/listing/0002ruleset_0
+testcases/listing/0015dynamic_0
+testcases/listing/0004table_0
+testcases/listing/0001ruleset_0
+testcases/listing/0003table_0
+testcases/listing/0019set_0
+testcases/listing/0021ruleset_json_terse_0
+testcases/listing/0022terse_0
+testcases/listing/0005ruleset_ip_0
+testcases/listing/0016anonymous_0
+testcases/listing/0007ruleset_inet_0
+testcases/listing/0014objects_0
+testcases/listing/0018data_0
+testcases/nft-i/0001define_0
+testcases/optionals/handles_0
+testcases/optionals/comments_objects_0
+testcases/optionals/comments_chain_0
+testcases/optionals/delete_object_handles_0
+testcases/optionals/update_object_handles_0
+testcases/optionals/comments_table_0
+testcases/optionals/comments_objects_dup_0
+testcases/optionals/comments_handles_0
+testcases/optionals/comments_0
+testcases/optionals/handles_1
+testcases/optionals/log_prefix_0
+testcases/optimizations
+testcases/optimizations/skip_non_eq
+testcases/optimizations/merge_nat
+testcases/optimizations/merge_stmts_concat_vmap
+testcases/optimizations/single_anon_set
+testcases/optimizations/dependency_kill
+testcases/optimizations/merge_reject
+testcases/optimizations/not_mergeable
+testcases/optimizations/merge_stmts_vmap
+testcases/optimizations/merge_vmaps
+testcases/optimizations/skip_merge
+testcases/optimizations/merge_vmap_raw
+testcases/optimizations/merge_stmts
+testcases/optimizations/merge_stmts_concat
+testcases/optimizations/skip_unsupported
+testcases/optimizations/ruleset
+testcases/optimizations/variables
+testcases/json/netdev
+testcases/json/0005secmark_objref_0
+testcases/json/0002table_map_0
+testcases/json/0003json_schema_version_0
+testcases/json/0001set_statements_0
+testcases/json/0004json_schema_version_1
+testcases/json/0006obj_comment_0
+testcases/rule_management/0010replace_0
+testcases/rule_management/0003insert_0
+testcases/rule_management/0005replace_1
+testcases/rule_management/0004replace_0
+testcases/rule_management/0008delete_1
+testcases/rule_management/0011reset_0
+testcases/rule_management/0012destroy_0
+testcases/rule_management/0007delete_0
+testcases/rule_management/0002addinsertlocation_1
+testcases/rule_management/0013destroy_0
+testcases/rule_management/0006replace_1
+testcases/rule_management/0009delete_1
+testcases/rule_management/0001addinsertposition_0
+testcases/cache/0010_implicit_chain_0
+testcases/cache/0002_interval_0
+testcases/cache/0004_cache_update_0
+testcases/cache/0011_index_0
+testcases/cache/0005_cache_chain_flush
+testcases/cache/0009_delete_by_handle_incorrect_0
+testcases/cache/0007_echo_cache_init_0
+testcases/cache/0006_cache_table_flush
+testcases/cache/0001_cache_handling_0
+testcases/cache/0008_delete_by_handle_0
+testcases/cache/0003_cache_update_0
+testcases/flowtable/0016destroy_0
+testcases/flowtable/0001flowtable_0
+testcases/flowtable/0014addafterdelete_0
+testcases/flowtable/0012flowtable_variable_0
+testcases/flowtable/0008prio_1
+testcases/flowtable/0013addafterdelete_0
+testcases/flowtable/0006segfault_0
+testcases/flowtable/0007prio_0
+testcases/flowtable/0004delete_after_add_0
+testcases/flowtable/0011deleteafterflush_0
+testcases/flowtable/0010delete_handle_0
+testcases/flowtable/0002create_flowtable_0
+testcases/flowtable/0009deleteafterflush_0
+testcases/flowtable/0015destroy_0
+testcases/flowtable/0003add_after_flush_0
+testcases/flowtable/0005delete_in_use_1
+testcases/nft-f/0008split_tables_0
+testcases/nft-f/0005rollback_map_0
+testcases/nft-f/0028variable_cmdline_0
+testcases/nft-f/0017ct_timeout_obj_0
+testcases/nft-f/0010variable_0
+testcases/nft-f/0027split_chains_0
+testcases/nft-f/0023check_1
+testcases/nft-f/0012different_defines_0
+testcases/nft-f/0018jump_variable_0
+testcases/nft-f/0022variables_0
+testcases/nft-f/0018ct_expectation_obj_0
+testcases/nft-f/0016redefines_1
+testcases/nft-f/0029split_file_0
+testcases/nft-f/0004rollback_set_0
+testcases/nft-f/0031vmap_string_0
+testcases/nft-f/0001define_slash_0
+testcases/nft-f/0024priority_0
+testcases/nft-f/0003rollback_jump_0
+testcases/nft-f/0030variable_reuse_0
+testcases/nft-f/0013defines_1
+testcases/nft-f/0014defines_1
+testcases/nft-f/0020jump_variable_1
+testcases/nft-f/0006action_object_0
+testcases/nft-f/0002rollback_rule_0
+testcases/nft-f/0019jump_variable_1
+testcases/nft-f/0011manydefines_0
+testcases/nft-f/0025empty_dynset_0
+testcases/nft-f/0015defines_1
+testcases/nft-f/0009variable_0
+testcases/nft-f/0021list_ruleset_0
+testcases/nft-f/0007action_object_set_segfault_1
+testcases/nft-f/0026listing_0
+testcases/comments/comments_0
+testcases/transactions/0002table_0
+testcases/transactions/0039set_0
+testcases/transactions/0035set_0
+testcases/transactions/0037set_0
+testcases/transactions/0043set_1
+testcases/transactions/0041nat_restore_0
+testcases/transactions/0021rule_0
+testcases/transactions/0046set_0
+testcases/transactions/0023rule_1
+testcases/transactions/0045anon-unbind_0
+testcases/transactions/0014chain_1
+testcases/transactions/0022rule_1
+testcases/transactions/0038set_0
+testcases/transactions/0048helpers_0
+testcases/transactions/0040set_0
+testcases/transactions/0001table_0
+testcases/transactions/0032set_0
+testcases/transactions/0049huge_0
+testcases/transactions/0024rule_0
+testcases/transactions/0044rule_0
+testcases/transactions/0011chain_0
+testcases/transactions/0050rule_1
+testcases/transactions/0031set_0
+testcases/transactions/0036set_1
+testcases/transactions/0010chain_0
+testcases/transactions/0030set_0
+testcases/transactions/0013chain_0
+testcases/transactions/0025rule_0
+testcases/transactions/0012chain_0
+testcases/transactions/0042_stateful_expr_0
+testcases/transactions/0051map_0
+testcases/transactions/0003table_0
+testcases/transactions/0015chain_0
+testcases/transactions/0033set_0
+testcases/transactions/anon_chain_loop
+testcases/transactions/0047set_0
+testcases/transactions/0034set_0
+testcases/transactions/0020rule_0
+testcases/parsing/describe
+testcases/parsing/log
+testcases/parsing/octal
+testcases/include/0005glob_empty_0
+testcases/include/0020include_chain_0
+testcases/include/0019include_error_0
+testcases/include/0010glob_broken_file_1
+testcases/include/0018include_error_0
+testcases/include/0012glob_dependency_1
+testcases/include/0011glob_dependency_0
+testcases/include/0013input_descriptors_included_files_0
+testcases/include/0002relative_0
+testcases/include/0017glob_more_than_maxdepth_1
+testcases/include/0014glob_directory_0
+testcases/include/0016maxdepth_0
+testcases/include/0008glob_nofile_wildcard_0
+testcases/include/0013glob_dotfile_0
+testcases/include/0006glob_single_0
+testcases/include/0003includepath_0
+testcases/include/0004endlessloop_1
+testcases/include/0001absolute_0
+testcases/include/0015doubleincludepath_0
+testcases/include/0007glob_double_0
+testcases/include/0009glob_nofile_1
+testcases/owner/0001-flowtable-uaf
+testcases/sets/0028autoselect_0
+testcases/sets/0037_set_with_inet_service_0
+testcases/sets/0043concatenated_ranges_0
+testcases/sets/0073destroy_0
+testcases/sets/0064map_catchall_0
+testcases/sets/0058_setupdate_timeout_0
+testcases/sets/0068interval_stack_overflow_0
+testcases/sets/0003named_interval_missing_flag_0
+testcases/sets/0027ipv6_maps_ipv4_0
+testcases/sets/0049set_define_0
+testcases/sets/0021nesting_0
+testcases/sets/0019set_check_size_0
+testcases/sets/0008comments_interval_0
+testcases/sets/0029named_ifname_dtype_0
+testcases/sets/0024named_objects_0
+testcases/sets/0013add_delete_many_elements_0
+testcases/sets/type_set_symbol
+testcases/sets/0056dynamic_limit_0
+testcases/sets/errors_0
+testcases/sets/0028delete_handle_0
+testcases/sets/0006create_set_0
+testcases/sets/0031set_timeout_size_0
+testcases/sets/0014malformed_set_is_not_defined_0
+testcases/sets/0048set_counters_0
+testcases/sets/collapse_elem_0
+testcases/sets/0070stacked_l2_headers
+testcases/sets/0046netmap_0
+testcases/sets/0044interval_overlap_1
+testcases/sets/0057set_create_fails_0
+testcases/sets/0012add_delete_many_elements_0
+testcases/sets/0018set_check_size_1
+testcases/sets/0035add_set_elements_flat_0
+testcases/sets/0020comments_0
+testcases/sets/0052overlap_0
+testcases/sets/exact_overlap_0
+testcases/sets/0047nat_0
+testcases/sets/0069interval_merge_0
+testcases/sets/0051set_interval_counter_0
+testcases/sets/0022type_selective_flush_0
+testcases/sets/0039delete_interval_0
+testcases/sets/0016element_leak_0
+testcases/sets/0023incomplete_add_set_command_0
+testcases/sets/0033add_set_simple_flat_0
+testcases/sets/typeof_sets_1
+testcases/sets/0060set_multistmt_0
+testcases/sets/typeof_sets_concat
+testcases/sets/0026named_limit_0
+testcases/sets/0072destroy_0
+testcases/sets/0038meter_list_0
+testcases/sets/typeof_sets_0
+testcases/sets/0010comments_0
+testcases/sets/inner_0
+testcases/sets/set_eval_0
+testcases/sets/0045concat_ipv4_service
+testcases/sets/0041interval_0
+testcases/sets/0007create_element_0
+testcases/sets/0040get_host_endian_elements_0
+testcases/sets/0061anonymous_automerge_0
+testcases/sets/0055tcpflags_0
+testcases/sets/0071unclosed_prefix_interval_0
+testcases/sets/sets_with_ifnames
+testcases/sets/0017add_after_flush_0
+testcases/sets/0034get_element_0
+testcases/sets/0060set_multistmt_1
+testcases/sets/0043concatenated_ranges_1
+testcases/sets/0065_icmp_postprocessing
+testcases/sets/0063set_catchall_0
+testcases/sets/0030add_many_elements_interval_0
+testcases/sets/0008create_verdict_map_0
+testcases/sets/concat_interval_0
+testcases/sets/0025anonymous_set_0
+testcases/sets/0011add_many_elements_0
+testcases/sets/0059set_update_multistmt_0
+testcases/sets/0054comments_set_0
+testcases/sets/0009comments_timeout_0
+testcases/sets/0067nat_concat_interval_0
+testcases/sets/typeof_raw_0
+testcases/sets/0004named_interval_shadow_0
+testcases/sets/0036add_set_element_expiration_0
+testcases/sets/0044interval_overlap_0
+testcases/sets/automerge_0
+testcases/sets/dynset_missing
+testcases/sets/0032restore_set_simple_0
+testcases/sets/0002named_interval_automerging_0
+testcases/sets/0001named_interval_0
+testcases/sets/0042update_set_0
+testcases/sets/0053echo_0
+testcases/sets/0005named_interval_shadow_0
+testcases/sets/0062set_connlimit_0
+testcases/sets/0050set_define_1
+testcases/sets/0015rulesetflush_0
+testcases/netns/0001nft-f_0
+testcases/netns/0002loosecommands_0
+testcases/netns/0003many_0
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_0 b/tests/shell/testcases/bitwise/0040mark_binop_0
new file mode 100755
index 0000000..4ecc9d3
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_0
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook output priority filter; }
+ add rule t c oif lo ct mark set (meta mark | 0x10) << 8
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_1 b/tests/shell/testcases/bitwise/0040mark_binop_1
new file mode 100755
index 0000000..bd9e028
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook input priority filter; }
+ add rule t c iif lo ct mark & 0xff 0x10 meta mark set ct mark >> 8
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_2 b/tests/shell/testcases/bitwise/0040mark_binop_2
new file mode 100755
index 0000000..5e66a27
--- /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 0000000..21dda67
--- /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 0000000..e5c8a42
--- /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 0000000..184fbed
--- /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 0000000..129dd5c
--- /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 0000000..791a794
--- /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 0000000..5e7bd28
--- /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 0000000..a7b60fb
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft
new file mode 100644
index 0000000..fc0a600
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook output priority filter; policy accept;
+ oif "lo" ct mark set (meta mark | 0x00000010) << 8
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft
new file mode 100644
index 0000000..dbaacef
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook input priority filter; policy accept;
+ iif "lo" ct mark & 0x000000ff == 0x00000010 meta mark set ct mark >> 8
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.nft
new file mode 100644
index 0000000..2b9be36
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_3.nft
new file mode 100644
index 0000000..8206fec
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_4.nft
new file mode 100644
index 0000000..91d9f56
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_5.nft
new file mode 100644
index 0000000..f2b51eb
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_6.nft
new file mode 100644
index 0000000..cf7be90
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_7.nft
new file mode 100644
index 0000000..a9663e6
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_8.nft
new file mode 100644
index 0000000..04b866a
--- /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.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_9.nft
new file mode 100644
index 0000000..d4745ea
--- /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 0000000..7909942
--- /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.nft b/tests/shell/testcases/bogons/dumps/assert_failures.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/bogons/dumps/assert_failures.nft
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 0000000..1eb7977
--- /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/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 0000000..18c7edd
--- /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/scope_underflow_assert b/tests/shell/testcases/bogons/nft-f/scope_underflow_assert
new file mode 100644
index 0000000..aee1dcb
--- /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/zero_length_devicename_assert b/tests/shell/testcases/bogons/nft-f/zero_length_devicename_assert
new file mode 100644
index 0000000..84f3307
--- /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 0000000..2c3e6c3
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/zero_length_devicename_flowtable_assert
@@ -0,0 +1,5 @@
+table t {
+ flowtable f {
+ devices = { """"lo }
+ }
+}
diff --git a/tests/shell/testcases/cache/0001_cache_handling_0 b/tests/shell/testcases/cache/0001_cache_handling_0
new file mode 100755
index 0000000..0a68440
--- /dev/null
+++ b/tests/shell/testcases/cache/0001_cache_handling_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+RULESET='
+table inet test {
+ set test {
+ type ipv4_addr
+ elements = { 1.1.1.1, 3.3.3.3}
+ }
+
+ chain test {
+ ip saddr @test counter accept
+ ip daddr { 2.2.2.2, 4.4.4.4} counter accept
+ }
+}'
+
+set -e
+
+$NFT -f - <<< "$RULESET"
+TMP=$(mktemp)
+echo "$RULESET" >> "$TMP"
+$NFT "flush ruleset;include \"$TMP\""
+rm -f "$TMP"
+rule_handle=$($NFT -a list ruleset | awk '/saddr/{print $NF}')
+$NFT delete rule inet test test handle $rule_handle
+$NFT delete set inet test test
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/cache/0002_interval_0 b/tests/shell/testcases/cache/0002_interval_0
new file mode 100755
index 0000000..506a6c8
--- /dev/null
+++ b/tests/shell/testcases/cache/0002_interval_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# This testcase checks that we can load a ruleset twice in a row.
+# bug --> Error: interval overlaps with an existing one
+
+set -e
+
+RULESET="flush ruleset
+table inet t {
+ set s { type ipv4_addr; flags interval; }
+}
+
+add element inet t s {
+ 192.168.0.1/24,
+}"
+
+$NFT -f - <<< "$RULESET"
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/cache/0003_cache_update_0 b/tests/shell/testcases/cache/0003_cache_update_0
new file mode 100755
index 0000000..05edc9c
--- /dev/null
+++ b/tests/shell/testcases/cache/0003_cache_update_0
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+set -e
+
+# Expose how naive cache update logic (i.e., drop cache and repopulate from
+# kernel ruleset) may mess things up. The following input does:
+#
+# list ruleset -> populate the cache, cache->genid is non-zero
+# add table ip t -> make kernel's genid increment (cache->genid remains
+# unchanged)
+# add table ip t2; -> first command of batch, new table t2 is added to the cache
+# add chain ip t2 c -> second command of batch, triggers cache_update() which
+# removes table t2 from it
+
+$NFT -i >/dev/null <<EOF
+list ruleset
+add table ip t
+add table ip t2; add chain ip t2 c
+EOF
+
+# The following test exposes a problem with simple locking of cache when local
+# entries are added:
+#
+# add table ip t3 -> cache would be locked without previous update
+# add chain ip t c -> table t is not found due to no cache update happening
+
+$NFT -i >/dev/null <<EOF
+add table ip t3; add chain ip t c
+EOF
+
+# The following test exposes a problem with incremental cache update when
+# reading commands from a file that add a rule using the "index" keyword.
+#
+# add rule ip t4 c meta l4proto icmp accept -> rule to reference in next step
+# add rule ip t4 c index 0 drop -> index 0 is not found due to rule cache not
+# being updated
+# add rule ip t4 c index 2 drop -> index 2 is not found due to igmp rule being
+# in same transaction and therefore not having
+# an allocated handle
+$NFT -i >/dev/null <<EOF
+add table ip t4; add chain ip t4 c
+add rule ip t4 c meta l4proto icmp accept
+EOF
+$NFT -f - >/dev/null <<EOF
+add rule ip t4 c index 0 drop
+EOF
+$NFT -f - >/dev/null <<EOF
+add rule ip t4 c meta l4proto igmp accept
+add rule ip t4 c index 2 drop
+EOF
diff --git a/tests/shell/testcases/cache/0004_cache_update_0 b/tests/shell/testcases/cache/0004_cache_update_0
new file mode 100755
index 0000000..697d9de
--- /dev/null
+++ b/tests/shell/testcases/cache/0004_cache_update_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+# Trigger a crash or rule restore error with nft 0.9.1
+$NFT -f - >/dev/null <<EOF
+flush ruleset
+table inet testfilter {
+}
+table inet testfilter {
+ chain test {
+ counter
+ }
+}
+EOF
diff --git a/tests/shell/testcases/cache/0005_cache_chain_flush b/tests/shell/testcases/cache/0005_cache_chain_flush
new file mode 100755
index 0000000..7dfe5c1
--- /dev/null
+++ b/tests/shell/testcases/cache/0005_cache_chain_flush
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table ip x
+add chain x y
+add chain x z
+add map ip x mapping { type ipv4_addr : inet_service; flags dynamic,timeout; }
+add rule x y counter
+add rule x z counter"
+
+$NFT -f - <<< "$RULESET" 2>&1
+
+RULESET="flush chain x y; add rule x y update @mapping { ip saddr : tcp sport }; flush chain x z"
+
+$NFT "$RULESET" 2>&1
diff --git a/tests/shell/testcases/cache/0006_cache_table_flush b/tests/shell/testcases/cache/0006_cache_table_flush
new file mode 100755
index 0000000..fa4da97
--- /dev/null
+++ b/tests/shell/testcases/cache/0006_cache_table_flush
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table ip x
+add chain x y
+add chain x z
+add map ip x mapping { type ipv4_addr : inet_service; flags dynamic,timeout; }
+add rule x y counter
+add rule x z counter"
+
+$NFT -f - <<< "$RULESET" 2>&1
+
+RULESET="flush table x; add rule x y update @mapping { ip saddr : tcp sport }; flush chain x z"
+
+$NFT "$RULESET" 2>&1
diff --git a/tests/shell/testcases/cache/0007_echo_cache_init_0 b/tests/shell/testcases/cache/0007_echo_cache_init_0
new file mode 100755
index 0000000..280a0d0
--- /dev/null
+++ b/tests/shell/testcases/cache/0007_echo_cache_init_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+$NFT -i >/dev/null <<EOF
+add table inet t
+add chain inet t c
+add rule inet t c accept comment "first"
+add rule inet t c accept comment "third"
+EOF
+
+# make sure the rule cache gets initialized when using echo option
+#
+$NFT --echo add rule inet t c index 0 accept comment '"second"' >/dev/null
diff --git a/tests/shell/testcases/cache/0008_delete_by_handle_0 b/tests/shell/testcases/cache/0008_delete_by_handle_0
new file mode 100755
index 0000000..0db4c69
--- /dev/null
+++ b/tests/shell/testcases/cache/0008_delete_by_handle_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+HANDLE=`$NFT -a list ruleset | grep "table.*handle" | cut -d' ' -f7`
+$NFT delete table handle $HANDLE
+
+$NFT add table t
+
+$NFT add chain t c
+HANDLE=`$NFT -a list ruleset | grep "chain.*handle" | cut -d' ' -f6`
+$NFT delete chain t handle $HANDLE
+
+$NFT add set t s { type ipv4_addr\; }
+HANDLE=`$NFT -a list ruleset | grep "set.*handle" | cut -d' ' -f6`
+$NFT delete set t handle $HANDLE
+
+$NFT add flowtable t f { hook ingress priority 0\; devices = { lo } \; }
+HANDLE=`$NFT -a list ruleset | grep "flowtable.*handle" | cut -d' ' -f6`
+$NFT delete flowtable t handle $HANDLE
+
+$NFT add counter t x
+HANDLE=`$NFT -a list ruleset | grep "counter.*handle" | cut -d' ' -f6`
+$NFT delete counter t handle $HANDLE
diff --git a/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0 b/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0
new file mode 100755
index 0000000..f0bb02a
--- /dev/null
+++ b/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+$NFT delete table handle 4000 && exit 1
+$NFT delete chain t handle 4000 && exit 1
+$NFT delete set t handle 4000 && exit 1
+$NFT delete flowtable t handle 4000 && exit 1
+$NFT delete counter t handle 4000 && exit 1
+exit 0
diff --git a/tests/shell/testcases/cache/0010_implicit_chain_0 b/tests/shell/testcases/cache/0010_implicit_chain_0
new file mode 100755
index 0000000..834dc6e
--- /dev/null
+++ b/tests/shell/testcases/cache/0010_implicit_chain_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_chain_binding)
+
+set -e
+
+EXPECTED="table ip f {
+ chain c {
+ jump {
+ accept
+ }
+ }
+}"
+
+$NFT 'table ip f { chain c { jump { accept; }; }; }'
+GET="$($NFT list chain ip f c)"
+
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/cache/0011_index_0 b/tests/shell/testcases/cache/0011_index_0
new file mode 100755
index 0000000..c9eb868
--- /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.nft b/tests/shell/testcases/cache/dumps/0001_cache_handling_0.nft
new file mode 100644
index 0000000..2099865
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0001_cache_handling_0.nft
@@ -0,0 +1,12 @@
+table inet test {
+ set test {
+ type ipv4_addr
+ elements = { 1.1.1.1, 3.3.3.3 }
+ }
+
+ chain test {
+ ip daddr { 2.2.2.2, 4.4.4.4 } counter packets 0 bytes 0 accept
+ ip saddr @test counter packets 0 bytes 0 accept
+ ip daddr { 2.2.2.2, 4.4.4.4 } counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/cache/dumps/0002_interval_0.nft b/tests/shell/testcases/cache/dumps/0002_interval_0.nft
new file mode 100644
index 0000000..6a08132
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0002_interval_0.nft
@@ -0,0 +1,7 @@
+table inet t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.0.0/24 }
+ }
+}
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 0000000..43898d3
--- /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.nft b/tests/shell/testcases/cache/dumps/0004_cache_update_0.nft
new file mode 100644
index 0000000..4f5761b
--- /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.nft b/tests/shell/testcases/cache/dumps/0005_cache_chain_flush.nft
new file mode 100644
index 0000000..8ab55a2
--- /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.nft b/tests/shell/testcases/cache/dumps/0006_cache_table_flush.nft
new file mode 100644
index 0000000..8ab55a2
--- /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.nft b/tests/shell/testcases/cache/dumps/0007_echo_cache_init_0.nft
new file mode 100644
index 0000000..c774ee7
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0007_echo_cache_init_0.nft
@@ -0,0 +1,7 @@
+table inet t {
+ chain c {
+ accept comment "first"
+ accept comment "second"
+ accept comment "third"
+ }
+}
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 0000000..985768b
--- /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.nft b/tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.nft
new file mode 100644
index 0000000..e69de29
--- /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 0000000..aba92c0
--- /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.nft b/tests/shell/testcases/cache/dumps/0011_index_0.nft
new file mode 100644
index 0000000..7e855eb
--- /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/0001jumps_0 b/tests/shell/testcases/chains/0001jumps_0
new file mode 100755
index 0000000..b39df38
--- /dev/null
+++ b/tests/shell/testcases/chains/0001jumps_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+MAX_JUMPS=16
+
+$NFT add table t
+
+for i in $(seq 1 $MAX_JUMPS)
+do
+ $NFT add chain t c${i}
+done
+
+for i in $(seq 1 $((MAX_JUMPS - 1)))
+do
+ $NFT add rule t c${i} jump c$((i + 1))
+done
diff --git a/tests/shell/testcases/chains/0002jumps_1 b/tests/shell/testcases/chains/0002jumps_1
new file mode 100755
index 0000000..aa70037
--- /dev/null
+++ b/tests/shell/testcases/chains/0002jumps_1
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -e
+
+MAX_JUMPS=16
+
+$NFT add table t
+
+$NFT add chain t c1 { type filter hook input priority 0\; }
+
+for i in $(seq 2 $MAX_JUMPS)
+do
+ $NFT add chain t c${i}
+done
+
+for i in $(seq 1 $((MAX_JUMPS - 1)))
+do
+ $NFT add rule t c${i} jump c$((i + 1))
+done
+
+# this last jump should fail: too many links
+$NFT add chain t c$((MAX_JUMPS + 1))
+
+$NFT add rule t c${MAX_JUMPS} jump c$((MAX_JUMPS + 1)) 2>/dev/null || exit 0
+echo "E: max jumps ignored?" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0003jump_loop_1 b/tests/shell/testcases/chains/0003jump_loop_1
new file mode 100755
index 0000000..80e243f
--- /dev/null
+++ b/tests/shell/testcases/chains/0003jump_loop_1
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+MAX_JUMPS=16
+
+$NFT add table t
+
+for i in $(seq 1 $MAX_JUMPS)
+do
+ $NFT add chain t c${i}
+done
+
+for i in $(seq 1 $((MAX_JUMPS - 1)))
+do
+ $NFT add rule t c${i} jump c$((i + 1))
+done
+
+# this last jump should fail: loop
+$NFT add rule t c${MAX_JUMPS} jump c1 2>/dev/null || exit 0
+echo "E: loop of jumps ignored?" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0004busy_1 b/tests/shell/testcases/chains/0004busy_1
new file mode 100755
index 0000000..e68d1ba
--- /dev/null
+++ b/tests/shell/testcases/chains/0004busy_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c1
+$NFT add chain t c2
+$NFT add rule t c1 jump c2
+
+# kernel should return EBUSY
+$NFT delete chain t c2 2>/dev/null || exit 0
+echo "E: deleted a busy chain?" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0005busy_map_1 b/tests/shell/testcases/chains/0005busy_map_1
new file mode 100755
index 0000000..c800f19
--- /dev/null
+++ b/tests/shell/testcases/chains/0005busy_map_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c1
+$NFT add chain t c2
+$NFT add rule t c1 tcp dport vmap { 1 : jump c2 }
+
+# kernel should return EBUSY
+$NFT delete chain t c2 2>/dev/null || exit 0
+echo "E: deleted a busy chain?" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0006masquerade_0 b/tests/shell/testcases/chains/0006masquerade_0
new file mode 100755
index 0000000..7934998
--- /dev/null
+++ b/tests/shell/testcases/chains/0006masquerade_0
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c1 {type nat hook postrouting priority 0 \; }
+$NFT add rule t c1 masquerade
diff --git a/tests/shell/testcases/chains/0007masquerade_1 b/tests/shell/testcases/chains/0007masquerade_1
new file mode 100755
index 0000000..4434c89
--- /dev/null
+++ b/tests/shell/testcases/chains/0007masquerade_1
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c1 {type filter hook output priority 0 \; }
+
+# wrong hook output, only postrouting is valid
+$NFT add rule t c1 masquerade 2>/dev/null || exit 0
+echo "E: accepted masquerade in output hook" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0008masquerade_jump_1 b/tests/shell/testcases/chains/0008masquerade_jump_1
new file mode 100755
index 0000000..aee1475
--- /dev/null
+++ b/tests/shell/testcases/chains/0008masquerade_jump_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t output {type nat hook output priority 0 \; }
+$NFT add chain t c1
+$NFT add rule t c1 masquerade
+
+# kernel should return EOPNOTSUPP
+$NFT add rule t output jump c1 2>/dev/null || exit 0
+echo "E: accepted masquerade in output hook" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0009masquerade_jump_1 b/tests/shell/testcases/chains/0009masquerade_jump_1
new file mode 100755
index 0000000..2b931ee
--- /dev/null
+++ b/tests/shell/testcases/chains/0009masquerade_jump_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t output {type nat hook output priority 0 \; }
+$NFT add chain t c1
+$NFT add rule t c1 masquerade
+
+# kernel should return EOPNOTSUPP
+$NFT add rule t output tcp dport vmap {1 :jump c1 } 2>/dev/null || exit 0
+echo "E: accepted masquerade in output hook in a vmap" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0010endless_jump_loop_1 b/tests/shell/testcases/chains/0010endless_jump_loop_1
new file mode 100755
index 0000000..5d3ef23
--- /dev/null
+++ b/tests/shell/testcases/chains/0010endless_jump_loop_1
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c
+
+# kernel should return ELOOP
+$NFT add rule t c tcp dport vmap {1 : jump c} 2>/dev/null || exit 0
+echo "E: accepted endless jump loop in a vmap" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0011endless_jump_loop_1 b/tests/shell/testcases/chains/0011endless_jump_loop_1
new file mode 100755
index 0000000..d75932d
--- /dev/null
+++ b/tests/shell/testcases/chains/0011endless_jump_loop_1
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c1
+$NFT add chain t c2
+$NFT add map t m {type inet_service : verdict \;}
+$NFT add element t m {2 : jump c2}
+$NFT add rule t c1 tcp dport vmap @m
+
+# kernel should return ELOOP
+$NFT add element t m {1 : jump c1} 2>/dev/null || exit 0
+echo "E: accepted endless jump loop in a vmap" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0013rename_0 b/tests/shell/testcases/chains/0013rename_0
new file mode 100755
index 0000000..b9fe11a
--- /dev/null
+++ b/tests/shell/testcases/chains/0013rename_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c1
+# kernel should not return EEXIST
+$NFT rename chain t c1 c2
diff --git a/tests/shell/testcases/chains/0014rename_0 b/tests/shell/testcases/chains/0014rename_0
new file mode 100755
index 0000000..bd84e95
--- /dev/null
+++ b/tests/shell/testcases/chains/0014rename_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+$NFT add table t || exit 1
+$NFT add chain t c1 || exit 1
+$NFT add chain t c2 || exit 1
+# kernel should return EEXIST
+$NFT rename chain t c1 c2
+
+if [ $? -eq 0 ] ; then
+ echo "E: Renamed with existing chain" >&2
+ exit 1
+fi
+
+# same, should return EEXIST
+$NFT 'rename chain t c1 c3;rename chain t c2 c3'
+if [ $? -eq 0 ] ; then
+ echo "E: Renamed two chains to same name" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/chains/0015check_jump_loop_1 b/tests/shell/testcases/chains/0015check_jump_loop_1
new file mode 100755
index 0000000..a59bb3b
--- /dev/null
+++ b/tests/shell/testcases/chains/0015check_jump_loop_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t c1
+$NFT add chain t c2
+$NFT add t c1 jump c2
+# kernel should return ENOENT
+
+$NFT add t c2 ip daddr vmap { 1 : jump c3 } || exit 0
+echo "E: Jumped to non existing chain" >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0016delete_handle_0 b/tests/shell/testcases/chains/0016delete_handle_0
new file mode 100755
index 0000000..8fd1ad8
--- /dev/null
+++ b/tests/shell/testcases/chains/0016delete_handle_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+$NFT add table test-ip
+$NFT add chain test-ip x
+$NFT add chain test-ip y
+$NFT add chain test-ip z
+$NFT add table ip6 test-ip6
+$NFT add chain ip6 test-ip6 x
+$NFT add chain ip6 test-ip6 y
+$NFT add chain ip6 test-ip6 z
+
+chain_y_handle=$($NFT -a list ruleset | awk -v n=1 '/chain y/ && !--n {print $NF; exit}');
+chain_z_handle=$($NFT -a list ruleset | awk -v n=2 '/chain z/ && !--n {print $NF; exit}');
+
+$NFT delete chain test-ip handle $chain_y_handle
+$NFT delete chain ip6 test-ip6 handle $chain_z_handle
diff --git a/tests/shell/testcases/chains/0017masquerade_jump_1 b/tests/shell/testcases/chains/0017masquerade_jump_1
new file mode 100755
index 0000000..209e6d4
--- /dev/null
+++ b/tests/shell/testcases/chains/0017masquerade_jump_1
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t input {type filter hook input priority 4 \; }
+$NFT add chain t c1
+$NFT add rule t input jump c1
+
+# kernel should return EOPNOTSUPP
+$NFT add rule t c1 masquerade 2>/dev/null >&2 || exit 0
+
+echo "E: Accepted masquerade rule in non-nat type base chain" 1>&2
+exit 1
diff --git a/tests/shell/testcases/chains/0018check_jump_loop_1 b/tests/shell/testcases/chains/0018check_jump_loop_1
new file mode 100755
index 0000000..b87520f
--- /dev/null
+++ b/tests/shell/testcases/chains/0018check_jump_loop_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table ip filter
+$NFT add chain ip filter ap1
+$NFT add chain ip filter ap2
+$NFT add rule ip filter ap1 jump ap2
+
+# kernel should return EOPNOTSUPP
+$NFT add rule ip filter ap1 jump ap1 2>/dev/null >&2 || exit 0
+echo "E: Accepted jump-to-self"
+exit 1
diff --git a/tests/shell/testcases/chains/0019masquerade_jump_1 b/tests/shell/testcases/chains/0019masquerade_jump_1
new file mode 100755
index 0000000..0ff1ac3
--- /dev/null
+++ b/tests/shell/testcases/chains/0019masquerade_jump_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+$NFT add chain t input {type filter hook input priority 4 \; }
+$NFT add chain t c1
+$NFT add rule t input ip saddr vmap { 1.1.1.1 : jump c1 }
+
+# kernel should return EOPNOTSUPP
+$NFT add rule t c1 masquerade 2>/dev/null >&2 || exit 0
+echo "E: accepted masquerade in chain from non-nat type basechain" 1>&2
+exit 1
diff --git a/tests/shell/testcases/chains/0020depth_1 b/tests/shell/testcases/chains/0020depth_1
new file mode 100755
index 0000000..23e1f82
--- /dev/null
+++ b/tests/shell/testcases/chains/0020depth_1
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+$NFT add table ip filter
+$NFT add chain ip filter input { type filter hook input priority 0\; }
+
+for ((i=0;i<20;i++)); do
+ $NFT add chain ip filter a$i
+done
+
+$NFT add rule ip filter input jump a1
+
+for ((i=0;i<10;i++)); do
+ $NFT add rule ip filter a$i jump a$((i+1))
+done
+
+for ((i=11;i<19;i++)); do
+ $NFT add rule ip filter a$i jump a$((i+1))
+done
+
+$NFT add rule ip filter a10 jump a11 || exit 0
+echo "E: Expected 20th jump to fail due to jump stack exhaustion" 1>&2
+exit 1
diff --git a/tests/shell/testcases/chains/0021prio_0 b/tests/shell/testcases/chains/0021prio_0
new file mode 100755
index 0000000..ceda155
--- /dev/null
+++ b/tests/shell/testcases/chains/0021prio_0
@@ -0,0 +1,90 @@
+#!/bin/bash
+
+set -e
+
+format_offset () {
+ local i=$1
+ if ((i == 0))
+ then
+ echo ""
+ elif ((i > 0))
+ then
+ echo "+$i"
+ else
+ echo "$i"
+ fi
+}
+
+chainname () {
+ local hook=$1
+ local prioname=$2
+ local priooffset=$3
+
+ echo "${hook}${prioname}${priooffset}" | tr "\-+" "mp"
+}
+
+gen_chains () {
+ local family=$1
+ local hook=$2
+ local prioname=$3
+ local device=${4:+device $4}
+
+ for i in -11 -10 0 10 11
+ do
+ local offset=`format_offset $i`
+ local cmd="add chain $family x"
+ cmd+=" `chainname $hook $prioname $offset` {"
+ cmd+=" type filter hook $hook $device"
+ cmd+=" priority $prioname $offset; }"
+ echo "$cmd"
+ done
+}
+
+tmpfile=$(mktemp)
+trap "rm $tmpfile" EXIT
+
+(
+
+for family in ip ip6 inet
+do
+ echo "add table $family x"
+ for hook in prerouting input forward output postrouting
+ do
+ for prioname in raw mangle filter security
+ do
+ gen_chains $family $hook $prioname
+ done
+ done
+ gen_chains $family prerouting dstnat
+ gen_chains $family postrouting srcnat
+done
+
+family=arp
+echo "add table $family x"
+for hook in input output
+do
+ gen_chains $family $hook filter
+done
+
+family=netdev
+echo "add table $family x"
+gen_chains $family ingress filter lo
+[ "$NFT_TEST_HAVE_netdev_egress" != n ] && gen_chains $family egress filter lo
+
+family=bridge
+echo "add table $family x"
+for hook in prerouting input forward output postrouting
+do
+ gen_chains $family $hook filter
+done
+gen_chains $family prerouting dstnat
+gen_chains $family output out
+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/0022prio_dummy_1 b/tests/shell/testcases/chains/0022prio_dummy_1
new file mode 100755
index 0000000..66c4407
--- /dev/null
+++ b/tests/shell/testcases/chains/0022prio_dummy_1
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table ip x
+
+$NFT add chain ip x y "{ type filter hook input priority dummy+1; }" &> /dev/null || exit 0
+echo "E: dummy should not be a valid priority." >&2
+exit 1
diff --git a/tests/shell/testcases/chains/0023prio_inet_srcnat_1 b/tests/shell/testcases/chains/0023prio_inet_srcnat_1
new file mode 100755
index 0000000..e4a668e
--- /dev/null
+++ b/tests/shell/testcases/chains/0023prio_inet_srcnat_1
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+for family in ip ip6 inet
+do
+ 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
+ if (($? == 0))
+ then
+ echo "E: srcnat should not be a valid priority name in $family $hook chains." >&2
+ exit 1
+ fi
+ done
+done
+exit 0
diff --git a/tests/shell/testcases/chains/0024prio_inet_dstnat_1 b/tests/shell/testcases/chains/0024prio_inet_dstnat_1
new file mode 100755
index 0000000..f1b802a
--- /dev/null
+++ b/tests/shell/testcases/chains/0024prio_inet_dstnat_1
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+for family in ip ip6 inet
+do
+ 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
+ if (($? == 0))
+ then
+ echo "E: dstnat should not be a valid priority name in $family $hook chains." >&2
+ exit 1
+ fi
+ done
+done
+exit 0
diff --git a/tests/shell/testcases/chains/0025prio_arp_1 b/tests/shell/testcases/chains/0025prio_arp_1
new file mode 100755
index 0000000..1a17262
--- /dev/null
+++ b/tests/shell/testcases/chains/0025prio_arp_1
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+family=arp
+ for hook in input output
+ do
+ for prioname in raw mangle dstnat security srcnat
+ do
+ $NFT add table $family x
+ $NFT add chain $family x y "{ type filter hook $hook priority $prioname; }" &> /dev/null
+ if (($? == 0))
+ then
+ echo "E: $prioname should not be a valid priority name for arp family chains." >&2
+ exit 1
+ fi
+ done
+ done
+exit 0
diff --git a/tests/shell/testcases/chains/0026prio_netdev_1 b/tests/shell/testcases/chains/0026prio_netdev_1
new file mode 100755
index 0000000..b6fa3db
--- /dev/null
+++ b/tests/shell/testcases/chains/0026prio_netdev_1
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+family=netdev
+ for hook in ingress egress
+ do
+ for prioname in raw mangle dstnat security srcnat
+ do
+ $NFT add table $family x || exit 1
+ $NFT add chain $family x y "{ type filter hook $hook device lo priority $prioname; }" &> /dev/null
+ if (($? == 0))
+ then
+ echo "E: $prioname should not be a valid priority name for netdev family chains." >&2
+ exit 1
+ fi
+ done
+ done
+exit 0
diff --git a/tests/shell/testcases/chains/0027prio_bridge_dstnat_1 b/tests/shell/testcases/chains/0027prio_bridge_dstnat_1
new file mode 100755
index 0000000..52c73e6
--- /dev/null
+++ b/tests/shell/testcases/chains/0027prio_bridge_dstnat_1
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+family=bridge
+ for hook in input forward output postrouting
+ do
+ prioname=dstnat
+ $NFT add table $family x
+ $NFT add chain $family x y "{ type filter hook $hook priority $prioname; }" &> /dev/null
+ if (($? == 0))
+ then
+ echo "E: $prioname should not be a valid priority name for bridge $hook chains." >&2
+ exit 1
+ fi
+ done
+exit 0
diff --git a/tests/shell/testcases/chains/0028prio_bridge_out_1 b/tests/shell/testcases/chains/0028prio_bridge_out_1
new file mode 100755
index 0000000..63aa296
--- /dev/null
+++ b/tests/shell/testcases/chains/0028prio_bridge_out_1
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+family=bridge
+ for hook in prerouting input forward postrouting
+ do
+ prioname=out
+ $NFT add table $family x
+ $NFT add chain $family x y "{ type filter hook $hook priority $prioname; }" &> /dev/null
+ if (($? == 0))
+ then
+ echo "E: $prioname should not be a valid priority name for bridge $hook chains." >&2
+ exit 1
+ fi
+ done
+exit 0
diff --git a/tests/shell/testcases/chains/0029prio_bridge_srcnat_1 b/tests/shell/testcases/chains/0029prio_bridge_srcnat_1
new file mode 100755
index 0000000..3891711
--- /dev/null
+++ b/tests/shell/testcases/chains/0029prio_bridge_srcnat_1
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+family=bridge
+ for hook in prerouting input forward output
+ do
+ prioname=srcnat
+ $NFT add table $family x
+ $NFT add chain $family x y "{ type filter hook $hook priority $prioname; }" &> /dev/null
+ if (($? == 0))
+ then
+ echo "E: $prioname should not be a valid priority name for bridge $hook chains." >&2
+ exit 1
+ fi
+ done
+exit 0
diff --git a/tests/shell/testcases/chains/0030create_0 b/tests/shell/testcases/chains/0030create_0
new file mode 100755
index 0000000..0b457f9
--- /dev/null
+++ b/tests/shell/testcases/chains/0030create_0
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table ip x
+$NFT create chain ip x y
diff --git a/tests/shell/testcases/chains/0031priority_variable_0 b/tests/shell/testcases/chains/0031priority_variable_0
new file mode 100755
index 0000000..2b143db
--- /dev/null
+++ b/tests/shell/testcases/chains/0031priority_variable_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Tests use of variables in priority specification
+
+set -e
+
+RULESET="
+define pri = filter
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority \$pri
+ policy accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/chains/0032priority_variable_0 b/tests/shell/testcases/chains/0032priority_variable_0
new file mode 100755
index 0000000..8f2e57b
--- /dev/null
+++ b/tests/shell/testcases/chains/0032priority_variable_0
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Tests use of variables in priority specification
+
+set -e
+
+RULESET="
+define pri = 10
+define post = -10
+define for = \"filter - 100\"
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority \$pri
+ policy accept
+ }
+ chain forward {
+ type filter hook prerouting priority \$for
+ policy accept
+ }
+ chain postrouting {
+ type filter hook postrouting priority \$post
+ policy accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/chains/0033priority_variable_1 b/tests/shell/testcases/chains/0033priority_variable_1
new file mode 100755
index 0000000..eddaf5b
--- /dev/null
+++ b/tests/shell/testcases/chains/0033priority_variable_1
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Tests use of variables in priority specification
+
+set -e
+
+RULESET="
+define pri = *
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority \$pri
+ policy accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/chains/0034priority_variable_1 b/tests/shell/testcases/chains/0034priority_variable_1
new file mode 100755
index 0000000..592cb56
--- /dev/null
+++ b/tests/shell/testcases/chains/0034priority_variable_1
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Tests use of variables in priority specification
+
+set -e
+
+RULESET="
+define pri = { 127.0.0.1 }
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority \$pri
+ policy accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/chains/0035policy_variable_0 b/tests/shell/testcases/chains/0035policy_variable_0
new file mode 100755
index 0000000..b88e968
--- /dev/null
+++ b/tests/shell/testcases/chains/0035policy_variable_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Tests use of variables in chain policy
+
+set -e
+
+RULESET="
+define default_policy = \"accept\"
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter
+ policy \$default_policy
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/chains/0036policy_variable_0 b/tests/shell/testcases/chains/0036policy_variable_0
new file mode 100755
index 0000000..d4d98ed
--- /dev/null
+++ b/tests/shell/testcases/chains/0036policy_variable_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Tests use of variables in chain policy
+
+set -e
+
+RULESET="
+define default_policy = \"drop\"
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter
+ policy \$default_policy
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/chains/0037policy_variable_1 b/tests/shell/testcases/chains/0037policy_variable_1
new file mode 100755
index 0000000..ae35516
--- /dev/null
+++ b/tests/shell/testcases/chains/0037policy_variable_1
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Tests use of variables in chain policy
+
+set -e
+
+RULESET="
+define default_policy = { 127.0.0.1 }
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter
+ policy \$default_policy
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/chains/0038policy_variable_1 b/tests/shell/testcases/chains/0038policy_variable_1
new file mode 100755
index 0000000..027eb01
--- /dev/null
+++ b/tests/shell/testcases/chains/0038policy_variable_1
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Tests use of variables in priority specification
+
+set -e
+
+RULESET="
+define default_policy = *
+
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter
+ policy \$default_policy
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/chains/0039negative_priority_0 b/tests/shell/testcases/chains/0039negative_priority_0
new file mode 100755
index 0000000..ba17b8c
--- /dev/null
+++ b/tests/shell/testcases/chains/0039negative_priority_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Test parsing of negative priority values
+
+set -e
+
+$NFT add table t
+$NFT add chain t c { type filter hook input priority -30\; }
diff --git a/tests/shell/testcases/chains/0041chain_binding_0 b/tests/shell/testcases/chains/0041chain_binding_0
new file mode 100755
index 0000000..141a4b6
--- /dev/null
+++ b/tests/shell/testcases/chains/0041chain_binding_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# no table x, caused segfault in earlier nft releases
+$NFT insert rule inet x y handle 107 'goto { log prefix "MOO! "; }'
+if [ $? -ne 1 ]; then
+ exit 1
+fi
+
+if [ $NFT_TEST_HAVE_chain_binding = "n" ] ; then
+ echo "Test partially skipped due to NFT_TEST_HAVE_chain_binding=n"
+ exit 77
+fi
+
+set -e
+
+EXPECTED="table inet x {
+ chain y {
+ type filter hook input priority 0;
+ meta l4proto { tcp, udp } th dport 53 jump {
+ ip saddr { 127.0.0.0/8, 172.23.0.0/16, 192.168.13.0/24 } counter accept
+ ip6 saddr ::1/128 counter accept
+ }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+$NFT add rule inet x y meta l4proto icmpv6 jump { counter accept\; }
+$NFT add rule inet x y meta l4proto sctp jump { drop\; }
+$NFT delete rule inet x y handle 13
diff --git a/tests/shell/testcases/chains/0042chain_variable_0 b/tests/shell/testcases/chains/0042chain_variable_0
new file mode 100755
index 0000000..1ea44e8
--- /dev/null
+++ b/tests/shell/testcases/chains/0042chain_variable_0
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+set -e
+
+ip link add name dummy0 type dummy
+
+EXPECTED="define if_main = \"lo\"
+
+table netdev filter1 {
+ chain Main_Ingress1 {
+ type filter hook ingress device \$if_main priority -500; policy accept;
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+EXPECTED="define if_main = \"lo\"
+
+table netdev filter2 {
+ chain Main_Ingress2 {
+ type filter hook ingress devices = { \$if_main, dummy0 } priority -500; policy accept;
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+if [ "$NFT_TEST_HAVE_netdev_egress" = n ] ; then
+ echo "Skip parts of the test due to NFT_TEST_HAVE_netdev_egress=n"
+ exit 77
+fi
+
+EXPECTED="define if_main = { lo, dummy0 }
+define lan_interfaces = { lo }
+
+table netdev filter3 {
+ chain Main_Ingress3 {
+ type filter hook ingress devices = \$if_main priority -500; policy accept;
+ }
+ chain Main_Egress3 {
+ type filter hook egress devices = \$lan_interfaces priority -500; policy accept;
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+
diff --git a/tests/shell/testcases/chains/0043chain_ingress_0 b/tests/shell/testcases/chains/0043chain_ingress_0
new file mode 100755
index 0000000..a6973b9
--- /dev/null
+++ b/tests/shell/testcases/chains/0043chain_ingress_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inet_ingress)
+
+set -e
+RULESET="table inet filter {
+ chain ingress {
+ type filter hook ingress device \"lo\" priority filter; policy accept;
+ }
+ chain input {
+ type filter hook input priority filter; policy accept;
+ }
+ chain forward {
+ type filter hook forward priority filter; policy accept;
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 0
+exit 1
diff --git a/tests/shell/testcases/chains/0044chain_destroy_0 b/tests/shell/testcases/chains/0044chain_destroy_0
new file mode 100755
index 0000000..5c5a10a
--- /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.nft b/tests/shell/testcases/chains/dumps/0001jumps_0.nft
new file mode 100644
index 0000000..7054cde
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0001jumps_0.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/0002jumps_1.nft b/tests/shell/testcases/chains/dumps/0002jumps_1.nft
new file mode 100644
index 0000000..ed37ad0
--- /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.nft b/tests/shell/testcases/chains/dumps/0003jump_loop_1.nft
new file mode 100644
index 0000000..7054cde
--- /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.nft b/tests/shell/testcases/chains/dumps/0004busy_1.nft
new file mode 100644
index 0000000..429dd49
--- /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.nft b/tests/shell/testcases/chains/dumps/0005busy_map_1.nft
new file mode 100644
index 0000000..acf2318
--- /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.nft b/tests/shell/testcases/chains/dumps/0006masquerade_0.nft
new file mode 100644
index 0000000..90253a4
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0006masquerade_0.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c1 {
+ type nat hook postrouting priority filter; policy accept;
+ masquerade
+ }
+}
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 0000000..b25355f
--- /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.nft b/tests/shell/testcases/chains/dumps/0008masquerade_jump_1.nft
new file mode 100644
index 0000000..4991071
--- /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.nft b/tests/shell/testcases/chains/dumps/0009masquerade_jump_1.nft
new file mode 100644
index 0000000..4991071
--- /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.nft b/tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.nft
new file mode 100644
index 0000000..1e0d1d6
--- /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.nft b/tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.nft
new file mode 100644
index 0000000..ca0a737
--- /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.nft b/tests/shell/testcases/chains/dumps/0013rename_0.nft
new file mode 100644
index 0000000..e4e0171
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0013rename_0.nft
@@ -0,0 +1,4 @@
+table ip t {
+ chain c2 {
+ }
+}
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 0000000..574c486
--- /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.nft b/tests/shell/testcases/chains/dumps/0015check_jump_loop_1.nft
new file mode 100644
index 0000000..429dd49
--- /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.nft b/tests/shell/testcases/chains/dumps/0016delete_handle_0.nft
new file mode 100644
index 0000000..c0adb1f
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0016delete_handle_0.nft
@@ -0,0 +1,14 @@
+table ip test-ip {
+ chain x {
+ }
+
+ chain z {
+ }
+}
+table ip6 test-ip6 {
+ chain x {
+ }
+
+ chain y {
+ }
+}
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 0000000..636e844
--- /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.nft b/tests/shell/testcases/chains/dumps/0018check_jump_loop_1.nft
new file mode 100644
index 0000000..437900b
--- /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.nft b/tests/shell/testcases/chains/dumps/0019masquerade_jump_1.nft
new file mode 100644
index 0000000..81cf9cc
--- /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.nft b/tests/shell/testcases/chains/dumps/0020depth_1.nft
new file mode 100644
index 0000000..422c395
--- /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.nft b/tests/shell/testcases/chains/dumps/0021prio_0.nft
new file mode 100644
index 0000000..4297d24
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0021prio_0.nft
@@ -0,0 +1,1566 @@
+table ip x {
+ chain preroutingrawm11 {
+ type filter hook prerouting priority -311; policy accept;
+ }
+
+ chain preroutingrawm10 {
+ type filter hook prerouting priority raw - 10; policy accept;
+ }
+
+ chain preroutingraw {
+ type filter hook prerouting priority raw; policy accept;
+ }
+
+ chain preroutingrawp10 {
+ type filter hook prerouting priority raw + 10; policy accept;
+ }
+
+ chain preroutingrawp11 {
+ type filter hook prerouting priority -289; policy accept;
+ }
+
+ chain preroutingmanglem11 {
+ type filter hook prerouting priority -161; policy accept;
+ }
+
+ chain preroutingmanglem10 {
+ type filter hook prerouting priority mangle - 10; policy accept;
+ }
+
+ chain preroutingmangle {
+ type filter hook prerouting priority mangle; policy accept;
+ }
+
+ chain preroutingmanglep10 {
+ type filter hook prerouting priority mangle + 10; policy accept;
+ }
+
+ chain preroutingmanglep11 {
+ type filter hook prerouting priority -139; policy accept;
+ }
+
+ chain preroutingfilterm11 {
+ type filter hook prerouting priority -11; policy accept;
+ }
+
+ chain preroutingfilterm10 {
+ type filter hook prerouting priority filter - 10; policy accept;
+ }
+
+ chain preroutingfilter {
+ type filter hook prerouting priority filter; policy accept;
+ }
+
+ chain preroutingfilterp10 {
+ type filter hook prerouting priority filter + 10; policy accept;
+ }
+
+ chain preroutingfilterp11 {
+ type filter hook prerouting priority 11; policy accept;
+ }
+
+ chain preroutingsecuritym11 {
+ type filter hook prerouting priority 39; policy accept;
+ }
+
+ chain preroutingsecuritym10 {
+ type filter hook prerouting priority security - 10; policy accept;
+ }
+
+ chain preroutingsecurity {
+ type filter hook prerouting priority security; policy accept;
+ }
+
+ chain preroutingsecurityp10 {
+ type filter hook prerouting priority security + 10; policy accept;
+ }
+
+ chain preroutingsecurityp11 {
+ type filter hook prerouting priority 61; policy accept;
+ }
+
+ chain inputrawm11 {
+ type filter hook input priority -311; policy accept;
+ }
+
+ chain inputrawm10 {
+ type filter hook input priority raw - 10; policy accept;
+ }
+
+ chain inputraw {
+ type filter hook input priority raw; policy accept;
+ }
+
+ chain inputrawp10 {
+ type filter hook input priority raw + 10; policy accept;
+ }
+
+ chain inputrawp11 {
+ type filter hook input priority -289; policy accept;
+ }
+
+ chain inputmanglem11 {
+ type filter hook input priority -161; policy accept;
+ }
+
+ chain inputmanglem10 {
+ type filter hook input priority mangle - 10; policy accept;
+ }
+
+ chain inputmangle {
+ type filter hook input priority mangle; policy accept;
+ }
+
+ chain inputmanglep10 {
+ type filter hook input priority mangle + 10; policy accept;
+ }
+
+ chain inputmanglep11 {
+ type filter hook input priority -139; policy accept;
+ }
+
+ chain inputfilterm11 {
+ type filter hook input priority -11; policy accept;
+ }
+
+ chain inputfilterm10 {
+ type filter hook input priority filter - 10; policy accept;
+ }
+
+ chain inputfilter {
+ type filter hook input priority filter; policy accept;
+ }
+
+ chain inputfilterp10 {
+ type filter hook input priority filter + 10; policy accept;
+ }
+
+ chain inputfilterp11 {
+ type filter hook input priority 11; policy accept;
+ }
+
+ chain inputsecuritym11 {
+ type filter hook input priority 39; policy accept;
+ }
+
+ chain inputsecuritym10 {
+ type filter hook input priority security - 10; policy accept;
+ }
+
+ chain inputsecurity {
+ type filter hook input priority security; policy accept;
+ }
+
+ chain inputsecurityp10 {
+ type filter hook input priority security + 10; policy accept;
+ }
+
+ chain inputsecurityp11 {
+ type filter hook input priority 61; policy accept;
+ }
+
+ chain forwardrawm11 {
+ type filter hook forward priority -311; policy accept;
+ }
+
+ chain forwardrawm10 {
+ type filter hook forward priority raw - 10; policy accept;
+ }
+
+ chain forwardraw {
+ type filter hook forward priority raw; policy accept;
+ }
+
+ chain forwardrawp10 {
+ type filter hook forward priority raw + 10; policy accept;
+ }
+
+ chain forwardrawp11 {
+ type filter hook forward priority -289; policy accept;
+ }
+
+ chain forwardmanglem11 {
+ type filter hook forward priority -161; policy accept;
+ }
+
+ chain forwardmanglem10 {
+ type filter hook forward priority mangle - 10; policy accept;
+ }
+
+ chain forwardmangle {
+ type filter hook forward priority mangle; policy accept;
+ }
+
+ chain forwardmanglep10 {
+ type filter hook forward priority mangle + 10; policy accept;
+ }
+
+ chain forwardmanglep11 {
+ type filter hook forward priority -139; policy accept;
+ }
+
+ chain forwardfilterm11 {
+ type filter hook forward priority -11; policy accept;
+ }
+
+ chain forwardfilterm10 {
+ type filter hook forward priority filter - 10; policy accept;
+ }
+
+ chain forwardfilter {
+ type filter hook forward priority filter; policy accept;
+ }
+
+ chain forwardfilterp10 {
+ type filter hook forward priority filter + 10; policy accept;
+ }
+
+ chain forwardfilterp11 {
+ type filter hook forward priority 11; policy accept;
+ }
+
+ chain forwardsecuritym11 {
+ type filter hook forward priority 39; policy accept;
+ }
+
+ chain forwardsecuritym10 {
+ type filter hook forward priority security - 10; policy accept;
+ }
+
+ chain forwardsecurity {
+ type filter hook forward priority security; policy accept;
+ }
+
+ chain forwardsecurityp10 {
+ type filter hook forward priority security + 10; policy accept;
+ }
+
+ chain forwardsecurityp11 {
+ type filter hook forward priority 61; policy accept;
+ }
+
+ chain outputrawm11 {
+ type filter hook output priority -311; policy accept;
+ }
+
+ chain outputrawm10 {
+ type filter hook output priority raw - 10; policy accept;
+ }
+
+ chain outputraw {
+ type filter hook output priority raw; policy accept;
+ }
+
+ chain outputrawp10 {
+ type filter hook output priority raw + 10; policy accept;
+ }
+
+ chain outputrawp11 {
+ type filter hook output priority -289; policy accept;
+ }
+
+ chain outputmanglem11 {
+ type filter hook output priority -161; policy accept;
+ }
+
+ chain outputmanglem10 {
+ type filter hook output priority mangle - 10; policy accept;
+ }
+
+ chain outputmangle {
+ type filter hook output priority mangle; policy accept;
+ }
+
+ chain outputmanglep10 {
+ type filter hook output priority mangle + 10; policy accept;
+ }
+
+ chain outputmanglep11 {
+ type filter hook output priority -139; policy accept;
+ }
+
+ chain outputfilterm11 {
+ type filter hook output priority -11; policy accept;
+ }
+
+ chain outputfilterm10 {
+ type filter hook output priority filter - 10; policy accept;
+ }
+
+ chain outputfilter {
+ type filter hook output priority filter; policy accept;
+ }
+
+ chain outputfilterp10 {
+ type filter hook output priority filter + 10; policy accept;
+ }
+
+ chain outputfilterp11 {
+ type filter hook output priority 11; policy accept;
+ }
+
+ chain outputsecuritym11 {
+ type filter hook output priority 39; policy accept;
+ }
+
+ chain outputsecuritym10 {
+ type filter hook output priority security - 10; policy accept;
+ }
+
+ chain outputsecurity {
+ type filter hook output priority security; policy accept;
+ }
+
+ chain outputsecurityp10 {
+ type filter hook output priority security + 10; policy accept;
+ }
+
+ chain outputsecurityp11 {
+ type filter hook output priority 61; policy accept;
+ }
+
+ chain postroutingrawm11 {
+ type filter hook postrouting priority -311; policy accept;
+ }
+
+ chain postroutingrawm10 {
+ type filter hook postrouting priority raw - 10; policy accept;
+ }
+
+ chain postroutingraw {
+ type filter hook postrouting priority raw; policy accept;
+ }
+
+ chain postroutingrawp10 {
+ type filter hook postrouting priority raw + 10; policy accept;
+ }
+
+ chain postroutingrawp11 {
+ type filter hook postrouting priority -289; policy accept;
+ }
+
+ chain postroutingmanglem11 {
+ type filter hook postrouting priority -161; policy accept;
+ }
+
+ chain postroutingmanglem10 {
+ type filter hook postrouting priority mangle - 10; policy accept;
+ }
+
+ chain postroutingmangle {
+ type filter hook postrouting priority mangle; policy accept;
+ }
+
+ chain postroutingmanglep10 {
+ type filter hook postrouting priority mangle + 10; policy accept;
+ }
+
+ chain postroutingmanglep11 {
+ type filter hook postrouting priority -139; policy accept;
+ }
+
+ chain postroutingfilterm11 {
+ type filter hook postrouting priority -11; policy accept;
+ }
+
+ chain postroutingfilterm10 {
+ type filter hook postrouting priority filter - 10; policy accept;
+ }
+
+ chain postroutingfilter {
+ type filter hook postrouting priority filter; policy accept;
+ }
+
+ chain postroutingfilterp10 {
+ type filter hook postrouting priority filter + 10; policy accept;
+ }
+
+ chain postroutingfilterp11 {
+ type filter hook postrouting priority 11; policy accept;
+ }
+
+ chain postroutingsecuritym11 {
+ type filter hook postrouting priority 39; policy accept;
+ }
+
+ chain postroutingsecuritym10 {
+ type filter hook postrouting priority security - 10; policy accept;
+ }
+
+ chain postroutingsecurity {
+ type filter hook postrouting priority security; policy accept;
+ }
+
+ chain postroutingsecurityp10 {
+ type filter hook postrouting priority security + 10; policy accept;
+ }
+
+ chain postroutingsecurityp11 {
+ type filter hook postrouting priority 61; policy accept;
+ }
+
+ chain preroutingdstnatm11 {
+ type filter hook prerouting priority -111; policy accept;
+ }
+
+ chain preroutingdstnatm10 {
+ type filter hook prerouting priority dstnat - 10; policy accept;
+ }
+
+ chain preroutingdstnat {
+ type filter hook prerouting priority dstnat; policy accept;
+ }
+
+ chain preroutingdstnatp10 {
+ type filter hook prerouting priority dstnat + 10; policy accept;
+ }
+
+ chain preroutingdstnatp11 {
+ type filter hook prerouting priority -89; policy accept;
+ }
+
+ chain postroutingsrcnatm11 {
+ type filter hook postrouting priority 89; policy accept;
+ }
+
+ chain postroutingsrcnatm10 {
+ type filter hook postrouting priority srcnat - 10; policy accept;
+ }
+
+ chain postroutingsrcnat {
+ type filter hook postrouting priority srcnat; policy accept;
+ }
+
+ chain postroutingsrcnatp10 {
+ type filter hook postrouting priority srcnat + 10; policy accept;
+ }
+
+ chain postroutingsrcnatp11 {
+ type filter hook postrouting priority 111; policy accept;
+ }
+}
+table ip6 x {
+ chain preroutingrawm11 {
+ type filter hook prerouting priority -311; policy accept;
+ }
+
+ chain preroutingrawm10 {
+ type filter hook prerouting priority raw - 10; policy accept;
+ }
+
+ chain preroutingraw {
+ type filter hook prerouting priority raw; policy accept;
+ }
+
+ chain preroutingrawp10 {
+ type filter hook prerouting priority raw + 10; policy accept;
+ }
+
+ chain preroutingrawp11 {
+ type filter hook prerouting priority -289; policy accept;
+ }
+
+ chain preroutingmanglem11 {
+ type filter hook prerouting priority -161; policy accept;
+ }
+
+ chain preroutingmanglem10 {
+ type filter hook prerouting priority mangle - 10; policy accept;
+ }
+
+ chain preroutingmangle {
+ type filter hook prerouting priority mangle; policy accept;
+ }
+
+ chain preroutingmanglep10 {
+ type filter hook prerouting priority mangle + 10; policy accept;
+ }
+
+ chain preroutingmanglep11 {
+ type filter hook prerouting priority -139; policy accept;
+ }
+
+ chain preroutingfilterm11 {
+ type filter hook prerouting priority -11; policy accept;
+ }
+
+ chain preroutingfilterm10 {
+ type filter hook prerouting priority filter - 10; policy accept;
+ }
+
+ chain preroutingfilter {
+ type filter hook prerouting priority filter; policy accept;
+ }
+
+ chain preroutingfilterp10 {
+ type filter hook prerouting priority filter + 10; policy accept;
+ }
+
+ chain preroutingfilterp11 {
+ type filter hook prerouting priority 11; policy accept;
+ }
+
+ chain preroutingsecuritym11 {
+ type filter hook prerouting priority 39; policy accept;
+ }
+
+ chain preroutingsecuritym10 {
+ type filter hook prerouting priority security - 10; policy accept;
+ }
+
+ chain preroutingsecurity {
+ type filter hook prerouting priority security; policy accept;
+ }
+
+ chain preroutingsecurityp10 {
+ type filter hook prerouting priority security + 10; policy accept;
+ }
+
+ chain preroutingsecurityp11 {
+ type filter hook prerouting priority 61; policy accept;
+ }
+
+ chain inputrawm11 {
+ type filter hook input priority -311; policy accept;
+ }
+
+ chain inputrawm10 {
+ type filter hook input priority raw - 10; policy accept;
+ }
+
+ chain inputraw {
+ type filter hook input priority raw; policy accept;
+ }
+
+ chain inputrawp10 {
+ type filter hook input priority raw + 10; policy accept;
+ }
+
+ chain inputrawp11 {
+ type filter hook input priority -289; policy accept;
+ }
+
+ chain inputmanglem11 {
+ type filter hook input priority -161; policy accept;
+ }
+
+ chain inputmanglem10 {
+ type filter hook input priority mangle - 10; policy accept;
+ }
+
+ chain inputmangle {
+ type filter hook input priority mangle; policy accept;
+ }
+
+ chain inputmanglep10 {
+ type filter hook input priority mangle + 10; policy accept;
+ }
+
+ chain inputmanglep11 {
+ type filter hook input priority -139; policy accept;
+ }
+
+ chain inputfilterm11 {
+ type filter hook input priority -11; policy accept;
+ }
+
+ chain inputfilterm10 {
+ type filter hook input priority filter - 10; policy accept;
+ }
+
+ chain inputfilter {
+ type filter hook input priority filter; policy accept;
+ }
+
+ chain inputfilterp10 {
+ type filter hook input priority filter + 10; policy accept;
+ }
+
+ chain inputfilterp11 {
+ type filter hook input priority 11; policy accept;
+ }
+
+ chain inputsecuritym11 {
+ type filter hook input priority 39; policy accept;
+ }
+
+ chain inputsecuritym10 {
+ type filter hook input priority security - 10; policy accept;
+ }
+
+ chain inputsecurity {
+ type filter hook input priority security; policy accept;
+ }
+
+ chain inputsecurityp10 {
+ type filter hook input priority security + 10; policy accept;
+ }
+
+ chain inputsecurityp11 {
+ type filter hook input priority 61; policy accept;
+ }
+
+ chain forwardrawm11 {
+ type filter hook forward priority -311; policy accept;
+ }
+
+ chain forwardrawm10 {
+ type filter hook forward priority raw - 10; policy accept;
+ }
+
+ chain forwardraw {
+ type filter hook forward priority raw; policy accept;
+ }
+
+ chain forwardrawp10 {
+ type filter hook forward priority raw + 10; policy accept;
+ }
+
+ chain forwardrawp11 {
+ type filter hook forward priority -289; policy accept;
+ }
+
+ chain forwardmanglem11 {
+ type filter hook forward priority -161; policy accept;
+ }
+
+ chain forwardmanglem10 {
+ type filter hook forward priority mangle - 10; policy accept;
+ }
+
+ chain forwardmangle {
+ type filter hook forward priority mangle; policy accept;
+ }
+
+ chain forwardmanglep10 {
+ type filter hook forward priority mangle + 10; policy accept;
+ }
+
+ chain forwardmanglep11 {
+ type filter hook forward priority -139; policy accept;
+ }
+
+ chain forwardfilterm11 {
+ type filter hook forward priority -11; policy accept;
+ }
+
+ chain forwardfilterm10 {
+ type filter hook forward priority filter - 10; policy accept;
+ }
+
+ chain forwardfilter {
+ type filter hook forward priority filter; policy accept;
+ }
+
+ chain forwardfilterp10 {
+ type filter hook forward priority filter + 10; policy accept;
+ }
+
+ chain forwardfilterp11 {
+ type filter hook forward priority 11; policy accept;
+ }
+
+ chain forwardsecuritym11 {
+ type filter hook forward priority 39; policy accept;
+ }
+
+ chain forwardsecuritym10 {
+ type filter hook forward priority security - 10; policy accept;
+ }
+
+ chain forwardsecurity {
+ type filter hook forward priority security; policy accept;
+ }
+
+ chain forwardsecurityp10 {
+ type filter hook forward priority security + 10; policy accept;
+ }
+
+ chain forwardsecurityp11 {
+ type filter hook forward priority 61; policy accept;
+ }
+
+ chain outputrawm11 {
+ type filter hook output priority -311; policy accept;
+ }
+
+ chain outputrawm10 {
+ type filter hook output priority raw - 10; policy accept;
+ }
+
+ chain outputraw {
+ type filter hook output priority raw; policy accept;
+ }
+
+ chain outputrawp10 {
+ type filter hook output priority raw + 10; policy accept;
+ }
+
+ chain outputrawp11 {
+ type filter hook output priority -289; policy accept;
+ }
+
+ chain outputmanglem11 {
+ type filter hook output priority -161; policy accept;
+ }
+
+ chain outputmanglem10 {
+ type filter hook output priority mangle - 10; policy accept;
+ }
+
+ chain outputmangle {
+ type filter hook output priority mangle; policy accept;
+ }
+
+ chain outputmanglep10 {
+ type filter hook output priority mangle + 10; policy accept;
+ }
+
+ chain outputmanglep11 {
+ type filter hook output priority -139; policy accept;
+ }
+
+ chain outputfilterm11 {
+ type filter hook output priority -11; policy accept;
+ }
+
+ chain outputfilterm10 {
+ type filter hook output priority filter - 10; policy accept;
+ }
+
+ chain outputfilter {
+ type filter hook output priority filter; policy accept;
+ }
+
+ chain outputfilterp10 {
+ type filter hook output priority filter + 10; policy accept;
+ }
+
+ chain outputfilterp11 {
+ type filter hook output priority 11; policy accept;
+ }
+
+ chain outputsecuritym11 {
+ type filter hook output priority 39; policy accept;
+ }
+
+ chain outputsecuritym10 {
+ type filter hook output priority security - 10; policy accept;
+ }
+
+ chain outputsecurity {
+ type filter hook output priority security; policy accept;
+ }
+
+ chain outputsecurityp10 {
+ type filter hook output priority security + 10; policy accept;
+ }
+
+ chain outputsecurityp11 {
+ type filter hook output priority 61; policy accept;
+ }
+
+ chain postroutingrawm11 {
+ type filter hook postrouting priority -311; policy accept;
+ }
+
+ chain postroutingrawm10 {
+ type filter hook postrouting priority raw - 10; policy accept;
+ }
+
+ chain postroutingraw {
+ type filter hook postrouting priority raw; policy accept;
+ }
+
+ chain postroutingrawp10 {
+ type filter hook postrouting priority raw + 10; policy accept;
+ }
+
+ chain postroutingrawp11 {
+ type filter hook postrouting priority -289; policy accept;
+ }
+
+ chain postroutingmanglem11 {
+ type filter hook postrouting priority -161; policy accept;
+ }
+
+ chain postroutingmanglem10 {
+ type filter hook postrouting priority mangle - 10; policy accept;
+ }
+
+ chain postroutingmangle {
+ type filter hook postrouting priority mangle; policy accept;
+ }
+
+ chain postroutingmanglep10 {
+ type filter hook postrouting priority mangle + 10; policy accept;
+ }
+
+ chain postroutingmanglep11 {
+ type filter hook postrouting priority -139; policy accept;
+ }
+
+ chain postroutingfilterm11 {
+ type filter hook postrouting priority -11; policy accept;
+ }
+
+ chain postroutingfilterm10 {
+ type filter hook postrouting priority filter - 10; policy accept;
+ }
+
+ chain postroutingfilter {
+ type filter hook postrouting priority filter; policy accept;
+ }
+
+ chain postroutingfilterp10 {
+ type filter hook postrouting priority filter + 10; policy accept;
+ }
+
+ chain postroutingfilterp11 {
+ type filter hook postrouting priority 11; policy accept;
+ }
+
+ chain postroutingsecuritym11 {
+ type filter hook postrouting priority 39; policy accept;
+ }
+
+ chain postroutingsecuritym10 {
+ type filter hook postrouting priority security - 10; policy accept;
+ }
+
+ chain postroutingsecurity {
+ type filter hook postrouting priority security; policy accept;
+ }
+
+ chain postroutingsecurityp10 {
+ type filter hook postrouting priority security + 10; policy accept;
+ }
+
+ chain postroutingsecurityp11 {
+ type filter hook postrouting priority 61; policy accept;
+ }
+
+ chain preroutingdstnatm11 {
+ type filter hook prerouting priority -111; policy accept;
+ }
+
+ chain preroutingdstnatm10 {
+ type filter hook prerouting priority dstnat - 10; policy accept;
+ }
+
+ chain preroutingdstnat {
+ type filter hook prerouting priority dstnat; policy accept;
+ }
+
+ chain preroutingdstnatp10 {
+ type filter hook prerouting priority dstnat + 10; policy accept;
+ }
+
+ chain preroutingdstnatp11 {
+ type filter hook prerouting priority -89; policy accept;
+ }
+
+ chain postroutingsrcnatm11 {
+ type filter hook postrouting priority 89; policy accept;
+ }
+
+ chain postroutingsrcnatm10 {
+ type filter hook postrouting priority srcnat - 10; policy accept;
+ }
+
+ chain postroutingsrcnat {
+ type filter hook postrouting priority srcnat; policy accept;
+ }
+
+ chain postroutingsrcnatp10 {
+ type filter hook postrouting priority srcnat + 10; policy accept;
+ }
+
+ chain postroutingsrcnatp11 {
+ type filter hook postrouting priority 111; policy accept;
+ }
+}
+table inet x {
+ chain preroutingrawm11 {
+ type filter hook prerouting priority -311; policy accept;
+ }
+
+ chain preroutingrawm10 {
+ type filter hook prerouting priority raw - 10; policy accept;
+ }
+
+ chain preroutingraw {
+ type filter hook prerouting priority raw; policy accept;
+ }
+
+ chain preroutingrawp10 {
+ type filter hook prerouting priority raw + 10; policy accept;
+ }
+
+ chain preroutingrawp11 {
+ type filter hook prerouting priority -289; policy accept;
+ }
+
+ chain preroutingmanglem11 {
+ type filter hook prerouting priority -161; policy accept;
+ }
+
+ chain preroutingmanglem10 {
+ type filter hook prerouting priority mangle - 10; policy accept;
+ }
+
+ chain preroutingmangle {
+ type filter hook prerouting priority mangle; policy accept;
+ }
+
+ chain preroutingmanglep10 {
+ type filter hook prerouting priority mangle + 10; policy accept;
+ }
+
+ chain preroutingmanglep11 {
+ type filter hook prerouting priority -139; policy accept;
+ }
+
+ chain preroutingfilterm11 {
+ type filter hook prerouting priority -11; policy accept;
+ }
+
+ chain preroutingfilterm10 {
+ type filter hook prerouting priority filter - 10; policy accept;
+ }
+
+ chain preroutingfilter {
+ type filter hook prerouting priority filter; policy accept;
+ }
+
+ chain preroutingfilterp10 {
+ type filter hook prerouting priority filter + 10; policy accept;
+ }
+
+ chain preroutingfilterp11 {
+ type filter hook prerouting priority 11; policy accept;
+ }
+
+ chain preroutingsecuritym11 {
+ type filter hook prerouting priority 39; policy accept;
+ }
+
+ chain preroutingsecuritym10 {
+ type filter hook prerouting priority security - 10; policy accept;
+ }
+
+ chain preroutingsecurity {
+ type filter hook prerouting priority security; policy accept;
+ }
+
+ chain preroutingsecurityp10 {
+ type filter hook prerouting priority security + 10; policy accept;
+ }
+
+ chain preroutingsecurityp11 {
+ type filter hook prerouting priority 61; policy accept;
+ }
+
+ chain inputrawm11 {
+ type filter hook input priority -311; policy accept;
+ }
+
+ chain inputrawm10 {
+ type filter hook input priority raw - 10; policy accept;
+ }
+
+ chain inputraw {
+ type filter hook input priority raw; policy accept;
+ }
+
+ chain inputrawp10 {
+ type filter hook input priority raw + 10; policy accept;
+ }
+
+ chain inputrawp11 {
+ type filter hook input priority -289; policy accept;
+ }
+
+ chain inputmanglem11 {
+ type filter hook input priority -161; policy accept;
+ }
+
+ chain inputmanglem10 {
+ type filter hook input priority mangle - 10; policy accept;
+ }
+
+ chain inputmangle {
+ type filter hook input priority mangle; policy accept;
+ }
+
+ chain inputmanglep10 {
+ type filter hook input priority mangle + 10; policy accept;
+ }
+
+ chain inputmanglep11 {
+ type filter hook input priority -139; policy accept;
+ }
+
+ chain inputfilterm11 {
+ type filter hook input priority -11; policy accept;
+ }
+
+ chain inputfilterm10 {
+ type filter hook input priority filter - 10; policy accept;
+ }
+
+ chain inputfilter {
+ type filter hook input priority filter; policy accept;
+ }
+
+ chain inputfilterp10 {
+ type filter hook input priority filter + 10; policy accept;
+ }
+
+ chain inputfilterp11 {
+ type filter hook input priority 11; policy accept;
+ }
+
+ chain inputsecuritym11 {
+ type filter hook input priority 39; policy accept;
+ }
+
+ chain inputsecuritym10 {
+ type filter hook input priority security - 10; policy accept;
+ }
+
+ chain inputsecurity {
+ type filter hook input priority security; policy accept;
+ }
+
+ chain inputsecurityp10 {
+ type filter hook input priority security + 10; policy accept;
+ }
+
+ chain inputsecurityp11 {
+ type filter hook input priority 61; policy accept;
+ }
+
+ chain forwardrawm11 {
+ type filter hook forward priority -311; policy accept;
+ }
+
+ chain forwardrawm10 {
+ type filter hook forward priority raw - 10; policy accept;
+ }
+
+ chain forwardraw {
+ type filter hook forward priority raw; policy accept;
+ }
+
+ chain forwardrawp10 {
+ type filter hook forward priority raw + 10; policy accept;
+ }
+
+ chain forwardrawp11 {
+ type filter hook forward priority -289; policy accept;
+ }
+
+ chain forwardmanglem11 {
+ type filter hook forward priority -161; policy accept;
+ }
+
+ chain forwardmanglem10 {
+ type filter hook forward priority mangle - 10; policy accept;
+ }
+
+ chain forwardmangle {
+ type filter hook forward priority mangle; policy accept;
+ }
+
+ chain forwardmanglep10 {
+ type filter hook forward priority mangle + 10; policy accept;
+ }
+
+ chain forwardmanglep11 {
+ type filter hook forward priority -139; policy accept;
+ }
+
+ chain forwardfilterm11 {
+ type filter hook forward priority -11; policy accept;
+ }
+
+ chain forwardfilterm10 {
+ type filter hook forward priority filter - 10; policy accept;
+ }
+
+ chain forwardfilter {
+ type filter hook forward priority filter; policy accept;
+ }
+
+ chain forwardfilterp10 {
+ type filter hook forward priority filter + 10; policy accept;
+ }
+
+ chain forwardfilterp11 {
+ type filter hook forward priority 11; policy accept;
+ }
+
+ chain forwardsecuritym11 {
+ type filter hook forward priority 39; policy accept;
+ }
+
+ chain forwardsecuritym10 {
+ type filter hook forward priority security - 10; policy accept;
+ }
+
+ chain forwardsecurity {
+ type filter hook forward priority security; policy accept;
+ }
+
+ chain forwardsecurityp10 {
+ type filter hook forward priority security + 10; policy accept;
+ }
+
+ chain forwardsecurityp11 {
+ type filter hook forward priority 61; policy accept;
+ }
+
+ chain outputrawm11 {
+ type filter hook output priority -311; policy accept;
+ }
+
+ chain outputrawm10 {
+ type filter hook output priority raw - 10; policy accept;
+ }
+
+ chain outputraw {
+ type filter hook output priority raw; policy accept;
+ }
+
+ chain outputrawp10 {
+ type filter hook output priority raw + 10; policy accept;
+ }
+
+ chain outputrawp11 {
+ type filter hook output priority -289; policy accept;
+ }
+
+ chain outputmanglem11 {
+ type filter hook output priority -161; policy accept;
+ }
+
+ chain outputmanglem10 {
+ type filter hook output priority mangle - 10; policy accept;
+ }
+
+ chain outputmangle {
+ type filter hook output priority mangle; policy accept;
+ }
+
+ chain outputmanglep10 {
+ type filter hook output priority mangle + 10; policy accept;
+ }
+
+ chain outputmanglep11 {
+ type filter hook output priority -139; policy accept;
+ }
+
+ chain outputfilterm11 {
+ type filter hook output priority -11; policy accept;
+ }
+
+ chain outputfilterm10 {
+ type filter hook output priority filter - 10; policy accept;
+ }
+
+ chain outputfilter {
+ type filter hook output priority filter; policy accept;
+ }
+
+ chain outputfilterp10 {
+ type filter hook output priority filter + 10; policy accept;
+ }
+
+ chain outputfilterp11 {
+ type filter hook output priority 11; policy accept;
+ }
+
+ chain outputsecuritym11 {
+ type filter hook output priority 39; policy accept;
+ }
+
+ chain outputsecuritym10 {
+ type filter hook output priority security - 10; policy accept;
+ }
+
+ chain outputsecurity {
+ type filter hook output priority security; policy accept;
+ }
+
+ chain outputsecurityp10 {
+ type filter hook output priority security + 10; policy accept;
+ }
+
+ chain outputsecurityp11 {
+ type filter hook output priority 61; policy accept;
+ }
+
+ chain postroutingrawm11 {
+ type filter hook postrouting priority -311; policy accept;
+ }
+
+ chain postroutingrawm10 {
+ type filter hook postrouting priority raw - 10; policy accept;
+ }
+
+ chain postroutingraw {
+ type filter hook postrouting priority raw; policy accept;
+ }
+
+ chain postroutingrawp10 {
+ type filter hook postrouting priority raw + 10; policy accept;
+ }
+
+ chain postroutingrawp11 {
+ type filter hook postrouting priority -289; policy accept;
+ }
+
+ chain postroutingmanglem11 {
+ type filter hook postrouting priority -161; policy accept;
+ }
+
+ chain postroutingmanglem10 {
+ type filter hook postrouting priority mangle - 10; policy accept;
+ }
+
+ chain postroutingmangle {
+ type filter hook postrouting priority mangle; policy accept;
+ }
+
+ chain postroutingmanglep10 {
+ type filter hook postrouting priority mangle + 10; policy accept;
+ }
+
+ chain postroutingmanglep11 {
+ type filter hook postrouting priority -139; policy accept;
+ }
+
+ chain postroutingfilterm11 {
+ type filter hook postrouting priority -11; policy accept;
+ }
+
+ chain postroutingfilterm10 {
+ type filter hook postrouting priority filter - 10; policy accept;
+ }
+
+ chain postroutingfilter {
+ type filter hook postrouting priority filter; policy accept;
+ }
+
+ chain postroutingfilterp10 {
+ type filter hook postrouting priority filter + 10; policy accept;
+ }
+
+ chain postroutingfilterp11 {
+ type filter hook postrouting priority 11; policy accept;
+ }
+
+ chain postroutingsecuritym11 {
+ type filter hook postrouting priority 39; policy accept;
+ }
+
+ chain postroutingsecuritym10 {
+ type filter hook postrouting priority security - 10; policy accept;
+ }
+
+ chain postroutingsecurity {
+ type filter hook postrouting priority security; policy accept;
+ }
+
+ chain postroutingsecurityp10 {
+ type filter hook postrouting priority security + 10; policy accept;
+ }
+
+ chain postroutingsecurityp11 {
+ type filter hook postrouting priority 61; policy accept;
+ }
+
+ chain preroutingdstnatm11 {
+ type filter hook prerouting priority -111; policy accept;
+ }
+
+ chain preroutingdstnatm10 {
+ type filter hook prerouting priority dstnat - 10; policy accept;
+ }
+
+ chain preroutingdstnat {
+ type filter hook prerouting priority dstnat; policy accept;
+ }
+
+ chain preroutingdstnatp10 {
+ type filter hook prerouting priority dstnat + 10; policy accept;
+ }
+
+ chain preroutingdstnatp11 {
+ type filter hook prerouting priority -89; policy accept;
+ }
+
+ chain postroutingsrcnatm11 {
+ type filter hook postrouting priority 89; policy accept;
+ }
+
+ chain postroutingsrcnatm10 {
+ type filter hook postrouting priority srcnat - 10; policy accept;
+ }
+
+ chain postroutingsrcnat {
+ type filter hook postrouting priority srcnat; policy accept;
+ }
+
+ chain postroutingsrcnatp10 {
+ type filter hook postrouting priority srcnat + 10; policy accept;
+ }
+
+ chain postroutingsrcnatp11 {
+ type filter hook postrouting priority 111; policy accept;
+ }
+}
+table arp x {
+ chain inputfilterm11 {
+ type filter hook input priority -11; policy accept;
+ }
+
+ chain inputfilterm10 {
+ type filter hook input priority filter - 10; policy accept;
+ }
+
+ chain inputfilter {
+ type filter hook input priority filter; policy accept;
+ }
+
+ chain inputfilterp10 {
+ type filter hook input priority filter + 10; policy accept;
+ }
+
+ chain inputfilterp11 {
+ type filter hook input priority 11; policy accept;
+ }
+
+ chain outputfilterm11 {
+ type filter hook output priority -11; policy accept;
+ }
+
+ chain outputfilterm10 {
+ type filter hook output priority filter - 10; policy accept;
+ }
+
+ chain outputfilter {
+ type filter hook output priority filter; policy accept;
+ }
+
+ chain outputfilterp10 {
+ type filter hook output priority filter + 10; policy accept;
+ }
+
+ chain outputfilterp11 {
+ type filter hook output priority 11; policy accept;
+ }
+}
+table netdev x {
+ chain ingressfilterm11 {
+ type filter hook ingress device "lo" priority -11; policy accept;
+ }
+
+ chain ingressfilterm10 {
+ type filter hook ingress device "lo" priority filter - 10; policy accept;
+ }
+
+ chain ingressfilter {
+ type filter hook ingress device "lo" priority filter; policy accept;
+ }
+
+ chain ingressfilterp10 {
+ type filter hook ingress device "lo" priority filter + 10; policy accept;
+ }
+
+ chain ingressfilterp11 {
+ type filter hook ingress device "lo" priority 11; policy accept;
+ }
+
+ chain egressfilterm11 {
+ type filter hook egress device "lo" priority -11; policy accept;
+ }
+
+ chain egressfilterm10 {
+ type filter hook egress device "lo" priority filter - 10; policy accept;
+ }
+
+ chain egressfilter {
+ type filter hook egress device "lo" priority filter; policy accept;
+ }
+
+ chain egressfilterp10 {
+ type filter hook egress device "lo" priority filter + 10; policy accept;
+ }
+
+ chain egressfilterp11 {
+ type filter hook egress device "lo" priority 11; policy accept;
+ }
+}
+table bridge x {
+ chain preroutingfilterm11 {
+ type filter hook prerouting priority -211; policy accept;
+ }
+
+ chain preroutingfilterm10 {
+ type filter hook prerouting priority filter - 10; policy accept;
+ }
+
+ chain preroutingfilter {
+ type filter hook prerouting priority filter; policy accept;
+ }
+
+ chain preroutingfilterp10 {
+ type filter hook prerouting priority filter + 10; policy accept;
+ }
+
+ chain preroutingfilterp11 {
+ type filter hook prerouting priority -189; policy accept;
+ }
+
+ chain inputfilterm11 {
+ type filter hook input priority -211; policy accept;
+ }
+
+ chain inputfilterm10 {
+ type filter hook input priority filter - 10; policy accept;
+ }
+
+ chain inputfilter {
+ type filter hook input priority filter; policy accept;
+ }
+
+ chain inputfilterp10 {
+ type filter hook input priority filter + 10; policy accept;
+ }
+
+ chain inputfilterp11 {
+ type filter hook input priority -189; policy accept;
+ }
+
+ chain forwardfilterm11 {
+ type filter hook forward priority -211; policy accept;
+ }
+
+ chain forwardfilterm10 {
+ type filter hook forward priority filter - 10; policy accept;
+ }
+
+ chain forwardfilter {
+ type filter hook forward priority filter; policy accept;
+ }
+
+ chain forwardfilterp10 {
+ type filter hook forward priority filter + 10; policy accept;
+ }
+
+ chain forwardfilterp11 {
+ type filter hook forward priority -189; policy accept;
+ }
+
+ chain outputfilterm11 {
+ type filter hook output priority -211; policy accept;
+ }
+
+ chain outputfilterm10 {
+ type filter hook output priority filter - 10; policy accept;
+ }
+
+ chain outputfilter {
+ type filter hook output priority filter; policy accept;
+ }
+
+ chain outputfilterp10 {
+ type filter hook output priority filter + 10; policy accept;
+ }
+
+ chain outputfilterp11 {
+ type filter hook output priority -189; policy accept;
+ }
+
+ chain postroutingfilterm11 {
+ type filter hook postrouting priority -211; policy accept;
+ }
+
+ chain postroutingfilterm10 {
+ type filter hook postrouting priority filter - 10; policy accept;
+ }
+
+ chain postroutingfilter {
+ type filter hook postrouting priority filter; policy accept;
+ }
+
+ chain postroutingfilterp10 {
+ type filter hook postrouting priority filter + 10; policy accept;
+ }
+
+ chain postroutingfilterp11 {
+ type filter hook postrouting priority -189; policy accept;
+ }
+
+ chain preroutingdstnatm11 {
+ type filter hook prerouting priority -311; policy accept;
+ }
+
+ chain preroutingdstnatm10 {
+ type filter hook prerouting priority dstnat - 10; policy accept;
+ }
+
+ chain preroutingdstnat {
+ type filter hook prerouting priority dstnat; policy accept;
+ }
+
+ chain preroutingdstnatp10 {
+ type filter hook prerouting priority dstnat + 10; policy accept;
+ }
+
+ chain preroutingdstnatp11 {
+ type filter hook prerouting priority -289; policy accept;
+ }
+
+ chain outputoutm11 {
+ type filter hook output priority 89; policy accept;
+ }
+
+ chain outputoutm10 {
+ type filter hook output priority out - 10; policy accept;
+ }
+
+ chain outputout {
+ type filter hook output priority out; policy accept;
+ }
+
+ chain outputoutp10 {
+ type filter hook output priority out + 10; policy accept;
+ }
+
+ chain outputoutp11 {
+ type filter hook output priority 111; policy accept;
+ }
+
+ chain postroutingsrcnatm11 {
+ type filter hook postrouting priority 289; policy accept;
+ }
+
+ chain postroutingsrcnatm10 {
+ type filter hook postrouting priority srcnat - 10; policy accept;
+ }
+
+ chain postroutingsrcnat {
+ type filter hook postrouting priority srcnat; policy accept;
+ }
+
+ chain postroutingsrcnatp10 {
+ type filter hook postrouting priority srcnat + 10; policy accept;
+ }
+
+ chain postroutingsrcnatp11 {
+ type filter hook postrouting priority 311; policy accept;
+ }
+}
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 0000000..5d4d2ca
--- /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.nft b/tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.nft
new file mode 100644
index 0000000..46912ea
--- /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.nft b/tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.nft
new file mode 100644
index 0000000..46912ea
--- /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.nft b/tests/shell/testcases/chains/dumps/0025prio_arp_1.nft
new file mode 100644
index 0000000..7483cda
--- /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.nft b/tests/shell/testcases/chains/dumps/0026prio_netdev_1.nft
new file mode 100644
index 0000000..aa571e0
--- /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.nft b/tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.nft
new file mode 100644
index 0000000..d17be81
--- /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.nft b/tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.nft
new file mode 100644
index 0000000..d17be81
--- /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.nft b/tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.nft
new file mode 100644
index 0000000..d17be81
--- /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.nft b/tests/shell/testcases/chains/dumps/0030create_0.nft
new file mode 100644
index 0000000..8e818d2
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0030create_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+ chain y {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0031priority_variable_0.nft b/tests/shell/testcases/chains/dumps/0031priority_variable_0.nft
new file mode 100644
index 0000000..f409309
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0031priority_variable_0.nft
@@ -0,0 +1,5 @@
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0032priority_variable_0.nft b/tests/shell/testcases/chains/dumps/0032priority_variable_0.nft
new file mode 100644
index 0000000..1a1b079
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0032priority_variable_0.nft
@@ -0,0 +1,13 @@
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter + 10; policy accept;
+ }
+
+ chain forward {
+ type filter hook prerouting priority dstnat; policy accept;
+ }
+
+ chain postrouting {
+ type filter hook postrouting priority filter - 10; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0033priority_variable_1.nft b/tests/shell/testcases/chains/dumps/0033priority_variable_1.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0033priority_variable_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0034priority_variable_1.nft
diff --git a/tests/shell/testcases/chains/dumps/0035policy_variable_0.nft b/tests/shell/testcases/chains/dumps/0035policy_variable_0.nft
new file mode 100644
index 0000000..f409309
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0035policy_variable_0.nft
@@ -0,0 +1,5 @@
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0036policy_variable_0.nft b/tests/shell/testcases/chains/dumps/0036policy_variable_0.nft
new file mode 100644
index 0000000..d729e1e
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0036policy_variable_0.nft
@@ -0,0 +1,5 @@
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter; policy drop;
+ }
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0037policy_variable_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0038policy_variable_1.nft
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 0000000..20f8272
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0039negative_priority_0.nft
@@ -0,0 +1,5 @@
+table ip t {
+ chain c {
+ type filter hook input priority -30; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0041chain_binding_0.nft b/tests/shell/testcases/chains/dumps/0041chain_binding_0.nft
new file mode 100644
index 0000000..520203d
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0041chain_binding_0.nft
@@ -0,0 +1,12 @@
+table inet x {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ meta l4proto { tcp, udp } th dport 53 jump {
+ ip saddr { 127.0.0.0/8, 172.23.0.0/16, 192.168.13.0/24 } counter packets 0 bytes 0 accept
+ ip6 saddr ::1 counter packets 0 bytes 0 accept
+ }
+ meta l4proto ipv6-icmp jump {
+ counter packets 0 bytes 0 accept
+ }
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft b/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft
new file mode 100644
index 0000000..5ec230d
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft
@@ -0,0 +1,19 @@
+table netdev filter1 {
+ chain Main_Ingress1 {
+ type filter hook ingress device "lo" priority -500; policy accept;
+ }
+}
+table netdev filter2 {
+ chain Main_Ingress2 {
+ type filter hook ingress devices = { dummy0, lo } priority -500; policy accept;
+ }
+}
+table netdev filter3 {
+ chain Main_Ingress3 {
+ type filter hook ingress devices = { dummy0, 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.nft b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft
new file mode 100644
index 0000000..8483b26
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft
@@ -0,0 +1,13 @@
+table inet filter {
+ chain ingress {
+ type filter hook ingress device "lo" priority filter; policy accept;
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ }
+
+ chain forward {
+ type filter hook forward priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0044chain_destroy_0.nft b/tests/shell/testcases/chains/dumps/0044chain_destroy_0.nft
new file mode 100644
index 0000000..985768b
--- /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.nft b/tests/shell/testcases/chains/dumps/netdev_chain_0.nft
new file mode 100644
index 0000000..aa571e0
--- /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.nft b/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.nft
diff --git a/tests/shell/testcases/chains/netdev_chain_0 b/tests/shell/testcases/chains/netdev_chain_0
new file mode 100755
index 0000000..a323e6e
--- /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 0000000..21f3ad2
--- /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/comments/comments_0 b/tests/shell/testcases/comments/comments_0
new file mode 100755
index 0000000..a50387d
--- /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.nft b/tests/shell/testcases/comments/dumps/comments_0.nft
new file mode 100644
index 0000000..82ae510
--- /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/0001flowtable_0 b/tests/shell/testcases/flowtable/0001flowtable_0
new file mode 100755
index 0000000..2e18099
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0001flowtable_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+EXPECTED='table inet t {
+ flowtable f {
+ hook ingress priority 10
+ devices = { lo }
+ }
+
+ chain c {
+ flow add @f
+ }
+}'
+
+set -e
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/flowtable/0002create_flowtable_0 b/tests/shell/testcases/flowtable/0002create_flowtable_0
new file mode 100755
index 0000000..4c85c3f
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0002create_flowtable_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+$NFT add table t
+$NFT add flowtable t f { hook ingress priority 10 \; devices = { lo }\; }
+if $NFT create flowtable t f { hook ingress priority 10 \; devices = { lo }\; } 2>/dev/null ; then
+ echo "E: flowtable creation not failing on existing set" >&2
+ exit 1
+fi
+$NFT add flowtable t f { hook ingress priority 10 \; devices = { lo }\; }
+
+exit 0
diff --git a/tests/shell/testcases/flowtable/0003add_after_flush_0 b/tests/shell/testcases/flowtable/0003add_after_flush_0
new file mode 100755
index 0000000..481c7ed
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0003add_after_flush_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+$NFT add table x
+$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
+$NFT flush ruleset
+$NFT add table x
+$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
diff --git a/tests/shell/testcases/flowtable/0004delete_after_add_0 b/tests/shell/testcases/flowtable/0004delete_after_add_0
new file mode 100755
index 0000000..8d9a842
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0004delete_after_add_0
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+$NFT add table x
+$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
+$NFT delete flowtable x y
diff --git a/tests/shell/testcases/flowtable/0005delete_in_use_1 b/tests/shell/testcases/flowtable/0005delete_in_use_1
new file mode 100755
index 0000000..ef52620
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0005delete_in_use_1
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+$NFT add table x
+$NFT add chain x x
+$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
+$NFT add rule x x flow add @y
+
+$NFT delete flowtable x y || exit 0
+echo "E: delete flowtable in use"
+exit 1
diff --git a/tests/shell/testcases/flowtable/0006segfault_0 b/tests/shell/testcases/flowtable/0006segfault_0
new file mode 100755
index 0000000..fb7c52f
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0006segfault_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# Make sure nft does not segfault when given invalid syntax in 'add flowtable' commands.
+
+$NFT add table ip t
+
+$NFT add flowtable ip t f { hook ingress priority 10\; devices = { lo } }
+[[ $? -eq 1 ]] || exit 1
+
+$NFT add flowtable ip t f { hook ingress\; priority 10\; }
+[[ $? -eq 1 ]] || exit 1
diff --git a/tests/shell/testcases/flowtable/0007prio_0 b/tests/shell/testcases/flowtable/0007prio_0
new file mode 100755
index 0000000..49bbcac
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0007prio_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+
+format_offset () {
+ i=$1
+ if ((i == 0))
+ then
+ echo ""
+ elif ((i > 0))
+ then
+ echo "+$i"
+ else
+ echo "$i"
+ fi
+}
+
+$NFT add table t
+for offset in -11 -10 0 10 11
+do
+ $NFT add flowtable t f "{ hook ingress priority filter `format_offset $offset`; devices = { lo }; }"
+ $NFT delete flowtable t f
+done
+
diff --git a/tests/shell/testcases/flowtable/0008prio_1 b/tests/shell/testcases/flowtable/0008prio_1
new file mode 100755
index 0000000..48953d7
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0008prio_1
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+$NFT add table t
+for prioname in raw mangle dstnar security srcnat out dummy
+do
+ $NFT add flowtable t f { hook ingress priority $prioname \; devices = { lo }\; }
+ if (($? == 0))
+ then
+ echo "E: $prioname should not be a valid priority name for flowtables" >&2
+ exit 1
+ fi
+done
+
+exit 0
diff --git a/tests/shell/testcases/flowtable/0009deleteafterflush_0 b/tests/shell/testcases/flowtable/0009deleteafterflush_0
new file mode 100755
index 0000000..2cda563
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0009deleteafterflush_0
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+$NFT add table x
+$NFT add chain x y
+$NFT add flowtable x f { hook ingress priority 0\; devices = { lo }\;}
+$NFT add rule x y flow add @f
+$NFT flush chain x y
+$NFT delete flowtable x f
diff --git a/tests/shell/testcases/flowtable/0010delete_handle_0 b/tests/shell/testcases/flowtable/0010delete_handle_0
new file mode 100755
index 0000000..8dd8d9f
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0010delete_handle_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# delete flowtable by handle
+
+set -e
+
+$NFT add table inet t
+$NFT add flowtable inet t f { hook ingress priority filter\; devices = { lo }\; }
+
+FH=$($NFT -a list ruleset | awk '/flowtable f/ { print $NF }')
+
+$NFT delete flowtable inet t handle $FH
+
+EXPECTED="table inet t {
+}"
+
+GET="$($NFT list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/flowtable/0011deleteafterflush_0 b/tests/shell/testcases/flowtable/0011deleteafterflush_0
new file mode 100755
index 0000000..4f519a7
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0011deleteafterflush_0
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -e
+$NFT add table x
+$NFT add chain x y
+$NFT add flowtable x f { hook ingress priority 0\; devices = { lo }\;}
+$NFT add rule x y ip protocol tcp flow add @f
+$NFT add rule x y ip protocol udp flow add @f
+$NFT flush chain x y
+$NFT delete flowtable x f
diff --git a/tests/shell/testcases/flowtable/0012flowtable_variable_0 b/tests/shell/testcases/flowtable/0012flowtable_variable_0
new file mode 100755
index 0000000..080059d
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0012flowtable_variable_0
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+set -e
+
+iface_cleanup() {
+ ip link del dummy1 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+iface_cleanup
+
+ip link add name dummy1 type dummy
+
+EXPECTED="define if_main = { lo, dummy1 }
+
+table filter1 {
+ flowtable Main_ft1 {
+ hook ingress priority filter
+ counter
+ devices = \$if_main
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+EXPECTED="define if_main = \"lo\"
+
+table filter2 {
+ flowtable Main_ft2 {
+ hook ingress priority filter
+ counter
+ devices = { \$if_main, dummy1 }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/flowtable/0013addafterdelete_0 b/tests/shell/testcases/flowtable/0013addafterdelete_0
new file mode 100755
index 0000000..b23ab97
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0013addafterdelete_0
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+set -e
+
+RULESET='table inet filter {
+
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ counter
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
+
+RULESET='delete flowtable inet filter f
+
+table inet filter {
+
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ counter
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/flowtable/0014addafterdelete_0 b/tests/shell/testcases/flowtable/0014addafterdelete_0
new file mode 100755
index 0000000..6a24c4b
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0014addafterdelete_0
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -e
+
+RULESET='table inet filter {
+
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ }
+
+ chain y {
+ type filter hook forward priority 0;
+ flow add @f counter
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
+
+RULESET='delete rule inet filter y handle 3
+delete flowtable inet filter f
+
+table inet filter {
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ counter
+ }
+
+ chain y {
+ type filter hook forward priority 0;
+ flow add @f counter
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/flowtable/0015destroy_0 b/tests/shell/testcases/flowtable/0015destroy_0
new file mode 100755
index 0000000..d2a87da
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0015destroy_0
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_destroy)
+
+$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 destroy flowtable t f
diff --git a/tests/shell/testcases/flowtable/dumps/0001flowtable_0.nft b/tests/shell/testcases/flowtable/dumps/0001flowtable_0.nft
new file mode 100644
index 0000000..629bfe8
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0001flowtable_0.nft
@@ -0,0 +1,10 @@
+table inet t {
+ flowtable f {
+ hook ingress priority filter + 10
+ devices = { lo }
+ }
+
+ chain c {
+ flow add @f
+ }
+}
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 0000000..aecfb2a
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.nft
new file mode 100644
index 0000000..dd904f4
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.nft
new file mode 100644
index 0000000..c1d79e7
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0006segfault_0.nft
new file mode 100644
index 0000000..985768b
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0007prio_0.nft
new file mode 100644
index 0000000..985768b
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0008prio_1.nft
new file mode 100644
index 0000000..985768b
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.nft
new file mode 100644
index 0000000..8e818d2
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0010delete_handle_0.nft
new file mode 100644
index 0000000..17838bd
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.nft
new file mode 100644
index 0000000..8e818d2
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft
new file mode 100644
index 0000000..df1c51a
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft
@@ -0,0 +1,14 @@
+table ip filter1 {
+ flowtable Main_ft1 {
+ hook ingress priority filter
+ devices = { lo }
+ counter
+ }
+}
+table ip filter2 {
+ flowtable Main_ft2 {
+ hook ingress priority filter
+ devices = { lo }
+ counter
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft b/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft
new file mode 100644
index 0000000..83fdd5d
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft
@@ -0,0 +1,7 @@
+table inet filter {
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ counter
+ }
+}
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 0000000..145aa08
--- /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.nft b/tests/shell/testcases/flowtable/dumps/0015destroy_0.nft
new file mode 100644
index 0000000..985768b
--- /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/0001absolute_0 b/tests/shell/testcases/include/0001absolute_0
new file mode 100755
index 0000000..4ad874f
--- /dev/null
+++ b/tests/shell/testcases/include/0001absolute_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -e
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2=$(mktemp)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile1 $tmpfile2" EXIT # cleanup if aborted
+
+RULESET1="add table x"
+RULESET2="include \"$tmpfile1\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+
+$NFT -f $tmpfile2
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0002relative_0 b/tests/shell/testcases/include/0002relative_0
new file mode 100755
index 0000000..a91cd8f
--- /dev/null
+++ b/tests/shell/testcases/include/0002relative_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -e
+
+tmpfile1=$(mktemp -p .)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2=$(mktemp -p .)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile1 $tmpfile2" EXIT # cleanup if aborted
+
+RULESET1="add table x"
+RULESET2="include \"$tmpfile1\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+
+$NFT -f $tmpfile2
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0003includepath_0 b/tests/shell/testcases/include/0003includepath_0
new file mode 100755
index 0000000..20037a8
--- /dev/null
+++ b/tests/shell/testcases/include/0003includepath_0
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+set -e
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile3="$(basename "$tmpfile1")"
+
+tmpfile2=$(mktemp)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile1 $tmpfile2" EXIT # cleanup if aborted
+
+RULESET1="add table x"
+RULESET2="include \"$tmpfile3\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+
+$NFT -I "$(dirname "$tmpfile1")" -f $tmpfile2
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0004endlessloop_1 b/tests/shell/testcases/include/0004endlessloop_1
new file mode 100755
index 0000000..3e6789d
--- /dev/null
+++ b/tests/shell/testcases/include/0004endlessloop_1
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+RULESET="include \"$tmpfile\""
+
+echo "$RULESET" > $tmpfile
+
+$NFT -f $tmpfile 2>/dev/null || exit 0
+echo "E: endless include loop" >&2
+exit 1
diff --git a/tests/shell/testcases/include/0005glob_empty_0 b/tests/shell/testcases/include/0005glob_empty_0
new file mode 100755
index 0000000..0743d0d
--- /dev/null
+++ b/tests/shell/testcases/include/0005glob_empty_0
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Including files in an empty directory must not fail.
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 && rmdir $tmpdir" EXIT
+
+RULESET1="include \"$tmpdir/*\""
+
+echo "$RULESET1" > $tmpfile1
+
+$NFT -f $tmpfile1
+
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0006glob_single_0 b/tests/shell/testcases/include/0006glob_single_0
new file mode 100755
index 0000000..754db6f
--- /dev/null
+++ b/tests/shell/testcases/include/0006glob_single_0
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1=$(mktemp -p $tmpdir)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2=$(mktemp)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 $tmpfile2 && rmdir $tmpdir" EXIT
+
+RULESET1="add table x"
+RULESET2="include \"$tmpdir/*\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+
+$NFT -f $tmpfile2
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0007glob_double_0 b/tests/shell/testcases/include/0007glob_double_0
new file mode 100755
index 0000000..00c3efc
--- /dev/null
+++ b/tests/shell/testcases/include/0007glob_double_0
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpdir $tmpfile" EXIT
+
+RULESET1="add table x"
+RULESET2="add table y"
+RULESET3="include \"$tmpdir/*\""
+
+echo "$RULESET1" > $tmpdir/table_x
+echo "$RULESET2" > $tmpdir/table_y
+echo "$RULESET3" > $tmpfile
+
+$NFT -f $tmpfile
+
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0008glob_nofile_wildcard_0 b/tests/shell/testcases/include/0008glob_nofile_wildcard_0
new file mode 100755
index 0000000..f9c0aa1
--- /dev/null
+++ b/tests/shell/testcases/include/0008glob_nofile_wildcard_0
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+# When using wildcards, not having any match is not an error.
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+# remove the directory
+rmdir $tmpdir
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1" EXIT
+
+RULESET1="include \"$tmpdir/non_existent_file*.nft\""
+
+echo "$RULESET1" > $tmpfile1
+
+$NFT -f $tmpfile1
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0009glob_nofile_1 b/tests/shell/testcases/include/0009glob_nofile_1
new file mode 100755
index 0000000..d769155
--- /dev/null
+++ b/tests/shell/testcases/include/0009glob_nofile_1
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# When not using wildcards, not having any match is an error.
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+# remove the directory
+rmdir $tmpdir
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1" EXIT
+
+RULESET1="include \"$tmpdir/non_existent_file.nft\""
+
+echo "$RULESET1" > $tmpfile1
+
+$NFT -f $tmpfile1 || exit 0
+echo "E: Failed to catch a missing include directory/file" >&2
+exit 1
diff --git a/tests/shell/testcases/include/0010glob_broken_file_1 b/tests/shell/testcases/include/0010glob_broken_file_1
new file mode 100755
index 0000000..a00babf
--- /dev/null
+++ b/tests/shell/testcases/include/0010glob_broken_file_1
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# Loading broken files must fail.
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1=$(mktemp -p $tmpdir)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2=$(mktemp -p $tmpdir)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 $tmpfile2 $tmpfile3 && rmdir $tmpdir" EXIT
+
+RULESET1="add table x"
+
+# do an error in a file
+RULESET2="intentionally broken file"
+RULESET3="include \"$tmpdir/*\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+echo "$RULESET3" > $tmpfile3
+
+$NFT -f $tmpfile3 || exit 0
+echo "E: didn't catch a broken file in directory" >&2
+exit 1
diff --git a/tests/shell/testcases/include/0011glob_dependency_0 b/tests/shell/testcases/include/0011glob_dependency_0
new file mode 100755
index 0000000..8786850
--- /dev/null
+++ b/tests/shell/testcases/include/0011glob_dependency_0
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# Files are included in alphabetical order.
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1="$tmpdir/01_file.nft"
+touch $tmpfile1
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2="$tmpdir/02_file.nft"
+touch $tmpfile2
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 $tmpfile2 $tmpfile3 && rmdir $tmpdir" EXIT
+
+# add interdependent rulesets
+RULESET1="add table x"
+RULESET2="add chain x y"
+RULESET3="include \"$tmpdir/*\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+echo "$RULESET3" > $tmpfile3
+
+$NFT -f $tmpfile3
+
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0012glob_dependency_1 b/tests/shell/testcases/include/0012glob_dependency_1
new file mode 100755
index 0000000..e4e12e2
--- /dev/null
+++ b/tests/shell/testcases/include/0012glob_dependency_1
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# Files are included in alphabetical order.
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1="$tmpdir/01_file.nft"
+touch $tmpfile1
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2="$tmpdir/02_file.nft"
+touch $tmpfile2
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 $tmpfile2 $tmpfile3 && rmdir $tmpdir" EXIT
+
+# add interdependent rulesets
+RULESET1="add table x"
+RULESET2="add chain x y"
+RULESET3="include \"$tmpdir/*\""
+
+# Note different order when compared with 0011dir_dependency_0. The idea
+# here is to introduce wrong order to get the loading fail.
+echo "$RULESET1" > $tmpfile2
+echo "$RULESET2" > $tmpfile1
+echo "$RULESET3" > $tmpfile3
+
+$NFT -f $tmpfile3 || exit 0
+echo "E: did not catch wrong file order in include directory" >&2
+exit 1
diff --git a/tests/shell/testcases/include/0013glob_dotfile_0 b/tests/shell/testcases/include/0013glob_dotfile_0
new file mode 100755
index 0000000..36cfe1c
--- /dev/null
+++ b/tests/shell/testcases/include/0013glob_dotfile_0
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# Must not load a dot file in globbed directory.
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1=$(mktemp -p $tmpdir)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2=$(mktemp -p $tmpdir ".XXXXXXXX")
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 $tmpfile2 $tmpfile3 && rmdir $tmpdir" EXIT
+
+RULESET1="add table x"
+
+# an error in a dot file
+RULESET2="intentionally broken file"
+RULESET3="include \"$tmpdir/*\""
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+echo "$RULESET3" > $tmpfile3
+
+$NFT -f $tmpfile3
+
+if [ $? -ne 0 ] ; then
+ echo "E: tried to load a .dot file" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0013input_descriptors_included_files_0 b/tests/shell/testcases/include/0013input_descriptors_included_files_0
new file mode 100755
index 0000000..03de50b
--- /dev/null
+++ b/tests/shell/testcases/include/0013input_descriptors_included_files_0
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# This test the changes made in commit id "b14572f72aac".
+# When the commit was not applied, nft pointed to wrong files name.
+# As the commit only fixes the error messages and hence does not change the
+# return value so, we need to compare the "file name" in the error message
+# instead of return value of nft.
+
+
+tmpfile1=$(mktemp -p .)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2=$(mktemp -p .)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile3=$(mktemp -p .)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile4=$(mktemp -p .)
+if [ ! -w $tmpfile4 ]; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile1 $tmpfile2 $tmpfile3 $tmpfile4" EXIT # cleanup if aborted
+
+RULESET1="include \"$tmpfile2\""
+RULESET2="include \"$tmpfile3\""
+RULESET3="add rule x y anything everything" # wrong nft syntax
+
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" >> $tmpfile1
+echo "$RULESET3" > $tmpfile2
+
+$NFT -f $tmpfile1 2> $tmpfile4
+
+var=$(awk -F: '$4==" Error"{print $1;exit;}' $tmpfile4)
+
+if [ $var == "$tmpfile3" ]; then
+ echo "E: Test failed" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0014glob_directory_0 b/tests/shell/testcases/include/0014glob_directory_0
new file mode 100755
index 0000000..9a2443a
--- /dev/null
+++ b/tests/shell/testcases/include/0014glob_directory_0
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Must not be confused in matched subdirectories.
+
+set -e
+
+tmpdir1=$(mktemp -d)
+if [ ! -d $tmpdir1 ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1=$(mktemp -p $tmpdir1)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpdir2=$(mktemp -p $tmpdir1 -d)
+if [ ! -w $tmpdir2 ] ; then
+ echo "Failed to create the second tmp directory" >&2
+ exit 0
+fi
+
+tmpdir3=$(mktemp -p $tmpdir2 -d)
+if [ ! -w $tmpdir3 ] ; then
+ echo "Failed to create the third tmp directory" >&2
+ exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpfile1 && rmdir $tmpdir3 && rmdir $tmpdir2 && rmdir $tmpdir1" EXIT
+
+RULESET1="include \"$tmpdir2/*\""
+
+echo "$RULESET1" > $tmpfile1
+
+$NFT -f $tmpfile1
+
+if [ $? -ne 0 ] ; then
+ echo "E: tried to include a matched directory" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0015doubleincludepath_0 b/tests/shell/testcases/include/0015doubleincludepath_0
new file mode 100755
index 0000000..db70346
--- /dev/null
+++ b/tests/shell/testcases/include/0015doubleincludepath_0
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+set -e
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpdir1=$(mktemp -d)
+if [ ! -d $tmpdir1 ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpdir2=$(mktemp -d)
+if [ ! -d $tmpdir2 ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfile1=$(mktemp -p $tmpdir1)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpfile2=$(mktemp -p $tmpdir2)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpdfile $tmpfile1 $tmpfile2 && rmdir $tmpdir1 && rmdir $tmpdir2" EXIT # cleanup if aborted
+
+RULESET1="add table x"
+RULESET2="add chain x y"
+RULESET3=" \
+include \"$(basename $tmpfile1)\"
+include \"$(basename $tmpfile2)\"
+"
+
+echo "$RULESET1" > $tmpfile1
+echo "$RULESET2" > $tmpfile2
+echo "$RULESET3" > $tmpfile
+
+$NFT -I $tmpdir1 -I $tmpdir2 -f $tmpfile
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0016maxdepth_0 b/tests/shell/testcases/include/0016maxdepth_0
new file mode 100755
index 0000000..89eb13c
--- /dev/null
+++ b/tests/shell/testcases/include/0016maxdepth_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+tmpfile=$(mktemp)
+
+echo 'include "/tmp/rules.nft"' > $tmpfile
+$NFT -f $tmpfile || exit 0
diff --git a/tests/shell/testcases/include/0017glob_more_than_maxdepth_1 b/tests/shell/testcases/include/0017glob_more_than_maxdepth_1
new file mode 100755
index 0000000..6499bcc
--- /dev/null
+++ b/tests/shell/testcases/include/0017glob_more_than_maxdepth_1
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+set -e
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpdir1=$(mktemp -d)
+if [ ! -d $tmpdir1 ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfiles=""
+for i in `seq -w 1 32`; do
+ tmpfile2=$(mktemp -p $tmpdir1)
+ if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+ fi
+ tmpfiles="$tmpfiles $tmpfile2"
+done
+
+trap "rm -rf $tmpfile $tmpfiles && rmdir $tmpdir1" EXIT # cleanup if aborted
+
+RULESET=" \
+include \"$tmpdir1/*\"
+"
+
+echo "$RULESET" > $tmpfile
+
+$NFT -f $tmpfile
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0018include_error_0 b/tests/shell/testcases/include/0018include_error_0
new file mode 100755
index 0000000..ae2dba3
--- /dev/null
+++ b/tests/shell/testcases/include/0018include_error_0
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+touch $tmpfile1
+
+RULESET="include \"$tmpfile1\"
+)
+"
+
+tmpfile2=$(mktemp)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+echo "/dev/stdin:2:1-1: Error: syntax error, unexpected ')'
+)
+^" > $tmpfile3
+
+$NFT -I/tmp/ -f - <<< "$RULESET" 2> $tmpfile2
+$DIFF -u $tmpfile2 $tmpfile3
+
+rm $tmpfile1 $tmpfile2 $tmpfile3
diff --git a/tests/shell/testcases/include/0019include_error_0 b/tests/shell/testcases/include/0019include_error_0
new file mode 100755
index 0000000..4b84a57
--- /dev/null
+++ b/tests/shell/testcases/include/0019include_error_0
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+tmpfile2=$(mktemp)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+echo "(" >> $tmpfile2
+
+tmpdir=$(mktemp -d)
+
+echo "include \"$tmpfile2\"
+include \"$tmpdir/*.nft\"
+x" > $tmpfile1
+
+echo "=" > $tmpdir/1.nft
+echo ")" > $tmpdir/2.nft
+echo "-" > $tmpdir/3.nft
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+echo "In file included from $tmpfile1:1:1-30:
+$tmpfile2:1:1-1: Error: syntax error, unexpected '('
+(
+^
+In file included from $tmpfile1:2:1-36:
+$tmpdir/1.nft:1:1-1: Error: syntax error, unexpected '='
+=
+^
+In file included from $tmpfile1:2:1-36:
+$tmpdir/2.nft:1:1-1: Error: syntax error, unexpected ')'
+)
+^
+In file included from $tmpfile1:2:1-36:
+$tmpdir/3.nft:1:1-1: Error: syntax error, unexpected -
+-
+^
+$tmpfile1:3:2-2: Error: syntax error, unexpected newline, expecting string
+x
+ ^" > $tmpfile3
+
+tmpfile4=$(mktemp)
+if [ ! -w $tmpfile4 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+$NFT -I/tmp/ -f $tmpfile1 2> $tmpfile4
+$DIFF -u $tmpfile3 $tmpfile4
+
+rm $tmpfile1 $tmpfile2 $tmpfile3 $tmpfile4
+rm -r $tmpdir
diff --git a/tests/shell/testcases/include/0020include_chain_0 b/tests/shell/testcases/include/0020include_chain_0
new file mode 100755
index 0000000..8f78e8c
--- /dev/null
+++ b/tests/shell/testcases/include/0020include_chain_0
@@ -0,0 +1,23 @@
+#!/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
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/include/dumps/0001absolute_0.nft b/tests/shell/testcases/include/dumps/0001absolute_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0001absolute_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/include/dumps/0002relative_0.nft b/tests/shell/testcases/include/dumps/0002relative_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0002relative_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/include/dumps/0003includepath_0.nft b/tests/shell/testcases/include/dumps/0003includepath_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0003includepath_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0004endlessloop_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0005glob_empty_0.nft
diff --git a/tests/shell/testcases/include/dumps/0006glob_single_0.nft b/tests/shell/testcases/include/dumps/0006glob_single_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0006glob_single_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/include/dumps/0007glob_double_0.nft b/tests/shell/testcases/include/dumps/0007glob_double_0.nft
new file mode 100644
index 0000000..e4e5f9b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0007glob_double_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+}
+table ip y {
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0009glob_nofile_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0010glob_broken_file_1.nft
diff --git a/tests/shell/testcases/include/dumps/0011glob_dependency_0.nft b/tests/shell/testcases/include/dumps/0011glob_dependency_0.nft
new file mode 100644
index 0000000..8e818d2
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0011glob_dependency_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+ chain y {
+ }
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0012glob_dependency_1.nft
diff --git a/tests/shell/testcases/include/dumps/0013glob_dotfile_0.nft b/tests/shell/testcases/include/dumps/0013glob_dotfile_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0013glob_dotfile_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/include/dumps/0014glob_directory_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0014glob_directory_0.nft
diff --git a/tests/shell/testcases/include/dumps/0015doubleincludepath_0.nft b/tests/shell/testcases/include/dumps/0015doubleincludepath_0.nft
new file mode 100644
index 0000000..8e818d2
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0015doubleincludepath_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+ chain y {
+ }
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0016maxdepth_0.nft
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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/include/dumps/0018include_error_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0018include_error_0.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0019include_error_0.nft
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 0000000..3ad6db1
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0020include_chain_0.nft
@@ -0,0 +1,6 @@
+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
+ }
+}
diff --git a/tests/shell/testcases/json/0001set_statements_0 b/tests/shell/testcases/json/0001set_statements_0
new file mode 100755
index 0000000..fc4941f
--- /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 0000000..b375e99
--- /dev/null
+++ b/tests/shell/testcases/json/0002table_map_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": "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 0000000..43f387a
--- /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 0000000..0f8d586
--- /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 0000000..992d1b0
--- /dev/null
+++ b/tests/shell/testcases/json/0005secmark_objref_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": "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 0000000..4c2a0e8
--- /dev/null
+++ b/tests/shell/testcases/json/0006obj_comment_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": "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.nft b/tests/shell/testcases/json/dumps/0001set_statements_0.nft
new file mode 100644
index 0000000..d80a432
--- /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.nft b/tests/shell/testcases/json/dumps/0002table_map_0.nft
new file mode 100644
index 0000000..357e92c
--- /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.nft b/tests/shell/testcases/json/dumps/0003json_schema_version_0.nft
new file mode 100644
index 0000000..e69de29
--- /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.nft b/tests/shell/testcases/json/dumps/0004json_schema_version_1.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0004json_schema_version_1.nft
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 0000000..4c218e9
--- /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.nft b/tests/shell/testcases/json/dumps/0006obj_comment_0.nft
new file mode 100644
index 0000000..e52b21b
--- /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.nft b/tests/shell/testcases/json/dumps/netdev.nft
new file mode 100644
index 0000000..3c568ed
--- /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 0000000..8c16cf4
--- /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/0001ruleset_0 b/tests/shell/testcases/listing/0001ruleset_0
new file mode 100755
index 0000000..19cb3b0
--- /dev/null
+++ b/tests/shell/testcases/listing/0001ruleset_0
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# list ruleset shows a table
+
+set -e
+
+$NFT add table test
diff --git a/tests/shell/testcases/listing/0002ruleset_0 b/tests/shell/testcases/listing/0002ruleset_0
new file mode 100755
index 0000000..b4a535c
--- /dev/null
+++ b/tests/shell/testcases/listing/0002ruleset_0
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# list ruleset show nothing if empty ruleset
+
+EXPECTED=""
+
+set -e
diff --git a/tests/shell/testcases/listing/0003table_0 b/tests/shell/testcases/listing/0003table_0
new file mode 100755
index 0000000..5060be0
--- /dev/null
+++ b/tests/shell/testcases/listing/0003table_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# list table show what is expected
+
+EXPECTED="table ip test {
+}"
+
+set -e
+
+$NFT add table test
+
+GET="$($NFT list table test)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+# also this way
+GET="$($NFT list table ip test)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0004table_0 b/tests/shell/testcases/listing/0004table_0
new file mode 100755
index 0000000..1d69119
--- /dev/null
+++ b/tests/shell/testcases/listing/0004table_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# list table only show table asked for
+
+EXPECTED="table ip test {
+}"
+
+set -e
+
+$NFT add table test
+$NFT add table test2
+
+GET="$($NFT list table test)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
diff --git a/tests/shell/testcases/listing/0005ruleset_ip_0 b/tests/shell/testcases/listing/0005ruleset_ip_0
new file mode 100755
index 0000000..39c0328
--- /dev/null
+++ b/tests/shell/testcases/listing/0005ruleset_ip_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# listing ruleset per family
+
+EXPECTED="table ip test {
+}"
+
+set -e
+
+$NFT add table ip test
+$NFT add table ip6 test
+$NFT add table inet test
+$NFT add table arp test
+$NFT add table bridge test
+
+GET="$($NFT list ruleset ip)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0006ruleset_ip6_0 b/tests/shell/testcases/listing/0006ruleset_ip6_0
new file mode 100755
index 0000000..1b67f50
--- /dev/null
+++ b/tests/shell/testcases/listing/0006ruleset_ip6_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# listing ruleset per family
+
+EXPECTED="table ip6 test {
+}"
+
+set -e
+
+$NFT add table ip test
+$NFT add table ip6 test
+$NFT add table inet test
+$NFT add table arp test
+$NFT add table bridge test
+
+GET="$($NFT list ruleset ip6)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0007ruleset_inet_0 b/tests/shell/testcases/listing/0007ruleset_inet_0
new file mode 100755
index 0000000..257c7a9
--- /dev/null
+++ b/tests/shell/testcases/listing/0007ruleset_inet_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# listing ruleset per family
+
+EXPECTED="table inet test {
+}"
+
+set -e
+
+$NFT add table ip test
+$NFT add table ip6 test
+$NFT add table inet test
+$NFT add table arp test
+$NFT add table bridge test
+
+GET="$($NFT list ruleset inet)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0008ruleset_arp_0 b/tests/shell/testcases/listing/0008ruleset_arp_0
new file mode 100755
index 0000000..be42c47
--- /dev/null
+++ b/tests/shell/testcases/listing/0008ruleset_arp_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# listing ruleset per family
+
+EXPECTED="table arp test {
+}"
+
+set -e
+
+$NFT add table ip test
+$NFT add table ip6 test
+$NFT add table inet test
+$NFT add table arp test
+$NFT add table bridge test
+
+GET="$($NFT list ruleset arp)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0009ruleset_bridge_0 b/tests/shell/testcases/listing/0009ruleset_bridge_0
new file mode 100755
index 0000000..c6a99f5
--- /dev/null
+++ b/tests/shell/testcases/listing/0009ruleset_bridge_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# listing ruleset per family
+
+EXPECTED="table bridge test {
+}"
+
+set -e
+
+$NFT add table ip test
+$NFT add table ip6 test
+$NFT add table inet test
+$NFT add table arp test
+$NFT add table bridge test
+
+GET="$($NFT list ruleset bridge)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0010sets_0 b/tests/shell/testcases/listing/0010sets_0
new file mode 100755
index 0000000..0f5f2bd
--- /dev/null
+++ b/tests/shell/testcases/listing/0010sets_0
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+# listing all sets
+
+EXPECTED="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
+ }
+}"
+
+set -e
+
+$NFT add table ip nat
+$NFT add set ip nat ssh { type ipv4_addr \; }
+$NFT add table ip6 test
+$NFT add set ip6 test testset { type ipv6_addr \; }
+$NFT add table arp test_arp
+$NFT add set arp test_arp test_set_arp00 { type inet_service \; }
+$NFT add set arp test_arp test_set_arp01 { type inet_service \; flags constant \; }
+$NFT add table bridge test_bridge
+$NFT add set bridge test_bridge test_set_bridge { type inet_service \; }
+$NFT add table inet filter
+$NFT add set inet filter set0 { type inet_service \; }
+$NFT add set inet filter set1 { type inet_service \; flags constant \; }
+$NFT add set inet filter set2 { type icmpv6_type \; }
+
+GET="$($NFT list sets)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0011sets_0 b/tests/shell/testcases/listing/0011sets_0
new file mode 100755
index 0000000..b6f12b5
--- /dev/null
+++ b/tests/shell/testcases/listing/0011sets_0
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# listing all sets, no anonymous sets allowed
+
+EXPECTED="table ip nat {
+}
+table ip6 test {
+}
+table arp test_arp {
+}
+table bridge test_bridge {
+}
+table inet filter {
+}"
+
+set -e
+
+$NFT add table ip nat
+$NFT add chain ip nat test
+$NFT add rule ip nat test tcp dport {123, 321}
+
+$NFT add table ip6 test
+$NFT add chain ip6 test test
+$NFT add rule ip6 test test udp sport {123, 321}
+
+$NFT add table arp test_arp
+$NFT add chain arp test_arp test
+$NFT add rule arp test_arp test meta mark {123, 321}
+
+$NFT add table bridge test_bridge
+$NFT add chain bridge test_bridge test
+$NFT add rule bridge test_bridge test ip daddr {1.1.1.1, 2.2.2.2}
+
+$NFT add table inet filter
+$NFT add chain inet filter test
+$NFT add rule inet filter test tcp dport {80, 443}
+
+GET="$($NFT list sets)"
+
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0012sets_0 b/tests/shell/testcases/listing/0012sets_0
new file mode 100755
index 0000000..6e4c959
--- /dev/null
+++ b/tests/shell/testcases/listing/0012sets_0
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# listing all sets, filtering by family
+
+EXPECTED="table inet filter {
+ set set0 {
+ type inet_service
+ }
+ set set1 {
+ type inet_service
+ flags constant
+ }
+ set set2 {
+ type icmpv6_type
+ }
+}"
+
+set -e
+
+$NFT add table ip nat
+$NFT add set ip nat ssh { type ipv4_addr \; }
+$NFT add table ip6 test
+$NFT add set ip6 test testset { type ipv6_addr \; }
+$NFT add table arp test_arp
+$NFT add set arp test_arp test_set_arp00 { type inet_service \; }
+$NFT add set arp test_arp test_set_arp01 { type inet_service \; flags constant \; }
+$NFT add table bridge test_bridge
+$NFT add set bridge test_bridge test_set_bridge { type inet_service \; }
+$NFT add table inet filter
+$NFT add set inet filter set0 { type inet_service \; }
+$NFT add set inet filter set1 { type inet_service \; flags constant \; }
+$NFT add set inet filter set2 { type icmpv6_type \; }
+
+GET="$($NFT list sets inet)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0013objects_0 b/tests/shell/testcases/listing/0013objects_0
new file mode 100755
index 0000000..c78ada9
--- /dev/null
+++ b/tests/shell/testcases/listing/0013objects_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+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 \; }
+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
+
+if [ "$NFT_TEST_HAVE_cttimeout" = n ] ; then
+ echo "Ran partial test due to NFT_TEST_HAVE_cttimeout=n (skipped)"
+ exit 77
+fi
+if [ "$NFT_TEST_HAVE_ctexpect" = n ] ; then
+ echo "Ran partial test due to NFT_TEST_HAVE_ctexpect=n (skipped)"
+ exit 77
+fi
diff --git a/tests/shell/testcases/listing/0014objects_0 b/tests/shell/testcases/listing/0014objects_0
new file mode 100755
index 0000000..31d94f8
--- /dev/null
+++ b/tests/shell/testcases/listing/0014objects_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# list only the object asked for with table
+
+EXPECTED="table ip test {
+ quota https-quota {
+ 25 mbytes
+ }
+}"
+
+set -e
+
+$NFT add table test
+$NFT add quota test https-quota 25 mbytes
+$NFT add ct helper test cthelp { type \"sip\" protocol tcp \; }
+$NFT add table test-ip
+
+GET="$($NFT list quotas)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+GET="$($NFT list quota test https-quota)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
diff --git a/tests/shell/testcases/listing/0015dynamic_0 b/tests/shell/testcases/listing/0015dynamic_0
new file mode 100755
index 0000000..65fbe62
--- /dev/null
+++ b/tests/shell/testcases/listing/0015dynamic_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# list only the object asked for with table
+
+EXPECTED="table ip filter {
+ set test_set {
+ type ipv4_addr . inet_service . ipv4_addr . inet_service . inet_proto
+ size 100000
+ flags dynamic,timeout
+ }
+}"
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
+
+GET="$($NFT list set ip filter test_set)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+$NFT flush set ip filter test_set
diff --git a/tests/shell/testcases/listing/0016anonymous_0 b/tests/shell/testcases/listing/0016anonymous_0
new file mode 100755
index 0000000..83acbcc
--- /dev/null
+++ b/tests/shell/testcases/listing/0016anonymous_0
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+$NFT add table x
+$NFT add chain x y
+$NFT add rule x y ip saddr { 1.1.1.1 }
+$NFT add rule x y meta mark set ip saddr map { 1.1.1.1 : 2 }
+
+$NFT list set x __set0 &>/dev/null
+ret=$?
+if [ $ret -eq 0 ]
+then
+ exit 1
+fi
+
+$NFT flush set x __set0 &>/dev/null
+ret=$?
+if [ $ret -eq 0 ]
+then
+ exit 1
+fi
+
+$NFT list map x __map0 &>/dev/null
+if [ $ret -eq 0 ]
+then
+ exit 1
+fi
+
+$NFT flush map x __map0 &>/dev/null
+ret=$?
+if [ $ret -eq 0 ]
+then
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0017objects_0 b/tests/shell/testcases/listing/0017objects_0
new file mode 100755
index 0000000..c4e72db
--- /dev/null
+++ b/tests/shell/testcases/listing/0017objects_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+EXPECTED="table inet filter {
+ map countermap {
+ type ipv4_addr : counter
+ }
+}"
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
+$NFT flush map inet filter countermap
+
+GET="$($NFT list map inet filter countermap)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0018data_0 b/tests/shell/testcases/listing/0018data_0
new file mode 100755
index 0000000..4af253d
--- /dev/null
+++ b/tests/shell/testcases/listing/0018data_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+EXPECTED="table inet filter {
+ map ipmap {
+ type ipv4_addr : ipv4_addr
+ }
+}"
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
+$NFT flush map inet filter ipmap
+
+GET="$($NFT list map inet filter ipmap)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0019set_0 b/tests/shell/testcases/listing/0019set_0
new file mode 100755
index 0000000..6e8cb4d
--- /dev/null
+++ b/tests/shell/testcases/listing/0019set_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+EXPECTED="table inet filter {
+ set ipset {
+ type ipv4_addr
+ }
+}"
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
+$NFT flush set inet filter ipset
+
+GET="$($NFT list set inet filter ipset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/0020flowtable_0 b/tests/shell/testcases/listing/0020flowtable_0
new file mode 100755
index 0000000..6eb82cf
--- /dev/null
+++ b/tests/shell/testcases/listing/0020flowtable_0
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+# list only the flowtable asked for with table
+
+set -e
+
+FLOWTABLES="flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+}
+flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+}"
+
+RULESET="table inet filter {
+ $FLOWTABLES
+}
+table ip filter {
+ $FLOWTABLES
+}"
+
+EXPECTED="table inet filter {
+ flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+ }
+}"
+EXPECTED2="table ip filter {
+ flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+ }
+}"
+EXPECTED3="table ip filter {
+ flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+ }
+ flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+ }
+}"
+
+iface_cleanup() {
+ ip link del d0 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+iface_cleanup
+
+ip link add d0 type dummy
+
+$NFT -f - <<< "$RULESET"
+
+GET="$($NFT list flowtable inet filter f)"
+$DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+
+GET="$($NFT list flowtable ip filter f2)"
+$DIFF -u <(echo "$EXPECTED2") <(echo "$GET")
+
+GET="$($NFT list flowtables ip)"
+$DIFF -u <(echo "$EXPECTED3") <(echo "$GET")
diff --git a/tests/shell/testcases/listing/0021ruleset_json_terse_0 b/tests/shell/testcases/listing/0021ruleset_json_terse_0
new file mode 100755
index 0000000..98a7ce8
--- /dev/null
+++ b/tests/shell/testcases/listing/0021ruleset_json_terse_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+$NFT flush ruleset
+$NFT add table ip test
+$NFT add chain ip test c
+$NFT add set ip test s { type ipv4_addr\; }
+$NFT add element ip test s { 192.168.3.4, 192.168.3.5 }
+
+if [ "$NFT_TEST_HAVE_json" != n ]; then
+ if $NFT -j -t list ruleset | grep '192\.168'
+ then
+ exit 1
+ fi
+fi
+
+if [ "$NFT_TEST_HAVE_json" = n ]; then
+ echo "Test partially skipped due to missing JSON support."
+ exit 77
+fi
diff --git a/tests/shell/testcases/listing/0022terse_0 b/tests/shell/testcases/listing/0022terse_0
new file mode 100755
index 0000000..4841771
--- /dev/null
+++ b/tests/shell/testcases/listing/0022terse_0
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ elements = { 10.10.10.10, 10.10.11.11 }
+ }
+
+ chain input {
+ type filter hook prerouting priority filter; policy accept;
+ ip saddr != { 10.10.10.100, 10.10.10.111 } ip saddr @example drop
+ }
+}"
+
+set -e
+
+$NFT -f - <<< "$RULESET"
+
+GET="$($NFT list ruleset)"
+if [ "$RULESET" != "$GET" ] ; then
+ $DIFF -u <(echo "$RULESET") <(echo "$GET")
+ exit 1
+fi
+
+EXPECTED="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ }
+
+ chain input {
+ type filter hook prerouting priority filter; policy accept;
+ ip saddr != { 10.10.10.100, 10.10.10.111 } ip saddr @example drop
+ }
+}"
+
+GET="$($NFT -t list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+EXPECTED="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ elements = { 10.10.10.10, 10.10.11.11 }
+ }
+}"
+
+GET="$($NFT list set inet filter example)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+EXPECTED="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ }
+}"
+
+GET="$($NFT -t list set inet filter example)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/dumps/0001ruleset_0.nft b/tests/shell/testcases/listing/dumps/0001ruleset_0.nft
new file mode 100644
index 0000000..1c9f40c
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0001ruleset_0.nft
@@ -0,0 +1,2 @@
+table ip test {
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0002ruleset_0.nft
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 0000000..1c9f40c
--- /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.nft b/tests/shell/testcases/listing/dumps/0004table_0.nft
new file mode 100644
index 0000000..56d035d
--- /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.nft b/tests/shell/testcases/listing/dumps/0005ruleset_ip_0.nft
new file mode 100644
index 0000000..c37261b
--- /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.nft b/tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.nft
new file mode 100644
index 0000000..c37261b
--- /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.nft b/tests/shell/testcases/listing/dumps/0007ruleset_inet_0.nft
new file mode 100644
index 0000000..c37261b
--- /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.nft b/tests/shell/testcases/listing/dumps/0008ruleset_arp_0.nft
new file mode 100644
index 0000000..c37261b
--- /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.nft b/tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.nft
new file mode 100644
index 0000000..c37261b
--- /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.nft b/tests/shell/testcases/listing/dumps/0010sets_0.nft
new file mode 100644
index 0000000..7303c40
--- /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.nft b/tests/shell/testcases/listing/dumps/0011sets_0.nft
new file mode 100644
index 0000000..4d0aeaf
--- /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.nft b/tests/shell/testcases/listing/dumps/0012sets_0.nft
new file mode 100644
index 0000000..7303c40
--- /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.nft b/tests/shell/testcases/listing/dumps/0013objects_0.nft
new file mode 100644
index 0000000..427db26
--- /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.nft b/tests/shell/testcases/listing/dumps/0014objects_0.nft
new file mode 100644
index 0000000..9281a1a
--- /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.nft b/tests/shell/testcases/listing/dumps/0015dynamic_0.nft
new file mode 100644
index 0000000..0f4244b
--- /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.nft b/tests/shell/testcases/listing/dumps/0016anonymous_0.nft
new file mode 100644
index 0000000..cb08933
--- /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.nft b/tests/shell/testcases/listing/dumps/0017objects_0.nft
new file mode 100644
index 0000000..e60e3af
--- /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.nft b/tests/shell/testcases/listing/dumps/0018data_0.nft
new file mode 100644
index 0000000..5d31855
--- /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.nft b/tests/shell/testcases/listing/dumps/0019set_0.nft
new file mode 100644
index 0000000..915922c
--- /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.nft b/tests/shell/testcases/listing/dumps/0020flowtable_0.nft
new file mode 100644
index 0000000..4a64e53
--- /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.nft b/tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.nft
new file mode 100644
index 0000000..13c8ac6
--- /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.nft b/tests/shell/testcases/listing/dumps/0022terse_0.nft
new file mode 100644
index 0000000..40665cb
--- /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/maps/0003map_add_many_elements_0 b/tests/shell/testcases/maps/0003map_add_many_elements_0
new file mode 100755
index 0000000..2b254c5
--- /dev/null
+++ b/tests/shell/testcases/maps/0003map_add_many_elements_0
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# test adding many map elements
+
+HOWMANY=31
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate_add() {
+ echo -n "{"
+ for ((i=HOWMANY; i>=1; i--)) ; do
+ for ((j=HOWMANY; j>=1; j--)) ; do
+ [ "$i" == 1 ] && [ "$j" == 1 ] && break
+ echo -n "10.0.${i}.${j} : 10.0.${i}.${j}, "
+ done
+ done
+ echo -n "}"
+}
+
+generate_test() {
+ count=0
+ elements=""
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ ((count++))
+ elements="${elements}10.0.${i}.${j} : 10.0.${i}.${j}"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ if [ "$count" == "2" ] ; then
+ count=0
+ elements="${elements},\\n\\t\\t\\t "
+ else
+ elements="${elements}, "
+ fi
+ done
+ done
+ echo -e "$elements"
+}
+
+echo "add table x
+add map x y { type ipv4_addr : ipv4_addr; }
+add element x y $(generate_add)" > $tmpfile
+
+set -e
+$NFT -f $tmpfile
+
+n=$HOWMANY
+echo "add element x y { 10.0.1.1 : 10.0.1.1 }" > $tmpfile
+$NFT -f $tmpfile
+
+EXPECTED="table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ elements = { "$(generate_test)" }
+ }
+}"
+GET=$($NFT list ruleset)
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
diff --git a/tests/shell/testcases/maps/0004interval_map_create_once_0 b/tests/shell/testcases/maps/0004interval_map_create_once_0
new file mode 100755
index 0000000..64f434a
--- /dev/null
+++ b/tests/shell/testcases/maps/0004interval_map_create_once_0
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+# test adding many elements to an interval map
+# this always works because nft is only called once
+
+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
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate_add() {
+ echo -n "{"
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ echo -n "10.${i}.${j}.0/24 : 10.0.${i}.${j}"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ echo -n ", "
+ done
+ done
+ echo -n "}"
+}
+
+generate_test() {
+ count=0
+ elements=""
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ ((count++))
+ elements="${elements}10.${i}.${j}.0/24 : 10.0.${i}.${j}"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ if [ "$count" == "2" ] ; then
+ count=0
+ elements="${elements},\\n\\t\\t\\t "
+ else
+ elements="${elements}, "
+ fi
+ done
+ done
+ echo -e "$elements"
+}
+
+echo "add table x
+add map x y { type ipv4_addr : ipv4_addr; flags interval; }
+add element x y $(generate_add)" > $tmpfile
+
+set -e
+$NFT -f $tmpfile
+
+EXPECTED="table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { "$(generate_test)" }
+ }
+}"
+GET=$($NFT list ruleset)
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+if [ "$HOWMANY" != 63 ] ; then
+ echo "Run a partial test due to NFT_TEST_SKIP_slow=y. Skip"
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/0005interval_map_add_many_elements_0 b/tests/shell/testcases/maps/0005interval_map_add_many_elements_0
new file mode 100755
index 0000000..0714963
--- /dev/null
+++ b/tests/shell/testcases/maps/0005interval_map_add_many_elements_0
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+# test adding many elements to an interval map
+# even with HOWMANY=2 there are memory allocation failures in the current
+# master - the patch fixes that
+# NOTE this is only an issue with two separate nft calls
+
+HOWMANY=2
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate_add() {
+ echo -n "{"
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ echo -n "10.${i}.${j}.0/24 : 10.0.${i}.${j}, "
+ done
+ done
+ echo -n "}"
+}
+
+generate_test() {
+ count=0
+ elements=""
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ ((count++))
+ elements="${elements}10.${i}.${j}.0/24 : 10.0.${i}.${j}"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ if [ "$count" == "2" ] ; then
+ count=0
+ elements="${elements},\\n\\t\\t\\t "
+ else
+ elements="${elements}, "
+ fi
+ done
+ done
+ echo -e "$elements"
+}
+
+echo "add table x
+add map x y { type ipv4_addr : ipv4_addr; flags interval; }
+add element x y $(generate_add)" > $tmpfile
+
+set -e
+$NFT -f $tmpfile
+
+n=$HOWMANY
+echo "add element x y { 10.${n}.${n}.0/24 : 10.0.${n}.${n} }" > $tmpfile
+
+$NFT -f $tmpfile
diff --git a/tests/shell/testcases/maps/0006interval_map_overlap_0 b/tests/shell/testcases/maps/0006interval_map_overlap_0
new file mode 100755
index 0000000..4606ce3
--- /dev/null
+++ b/tests/shell/testcases/maps/0006interval_map_overlap_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# test adding elements to an interval map
+# shows how disjoint intervals are seen as overlaps
+# NOTE this is only an issue with two separate nft calls
+
+n=1
+RULESET="add table x
+add map x y { type ipv4_addr : ipv4_addr; flags interval; }
+add element x y { 10.0.${n}.0/24 : 10.0.0.${n} }"
+
+set -e
+$NFT -f - <<< "$RULESET"
+
+n=2
+$NFT "add element x y { 10.0.${n}.0/24 : 10.0.0.${n} }"
diff --git a/tests/shell/testcases/maps/0007named_ifname_dtype_0 b/tests/shell/testcases/maps/0007named_ifname_dtype_0
new file mode 100755
index 0000000..b5c5116
--- /dev/null
+++ b/tests/shell/testcases/maps/0007named_ifname_dtype_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# support for ifname in named maps
+
+EXPECTED="table inet t {
+ map m1 {
+ type ifname : ipv4_addr
+ elements = { \"eth0\" : 1.1.1.1 }
+ }
+
+ chain c {
+ ip daddr set iifname map @m1
+ ip daddr set oifname map @m1
+ }
+}"
+
+set -e
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0008interval_map_delete_0 b/tests/shell/testcases/maps/0008interval_map_delete_0
new file mode 100755
index 0000000..39ea312
--- /dev/null
+++ b/tests/shell/testcases/maps/0008interval_map_delete_0
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="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 accept
+ meta mark 0x00000003 counter accept
+ counter
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
+$NFT delete element filter m { 127.0.0.2 }
+$NFT delete element filter m { 127.0.0.3 }
+$NFT add element filter m { 127.0.0.3 : 0x3 }
+$NFT add element filter m { 127.0.0.2 : 0x2 }
+
+GET=$($NFT -s list ruleset)
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/maps/0009vmap_0 b/tests/shell/testcases/maps/0009vmap_0
new file mode 100755
index 0000000..d31e160
--- /dev/null
+++ b/tests/shell/testcases/maps/0009vmap_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table inet filter {
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap { 22 : jump ssh_input }
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority -300; policy accept;
+ iif vmap { "lo" counter : jump wan_input }
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0010concat_map_0 b/tests/shell/testcases/maps/0010concat_map_0
new file mode 100755
index 0000000..4848d97
--- /dev/null
+++ b/tests/shell/testcases/maps/0010concat_map_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table inet x {
+ map z {
+ type ipv4_addr . inet_proto . inet_service : ipv4_addr . inet_service
+ elements = {
+ 1.1.1.1 . tcp . 20 : 2.2.2.2 . 30
+ }
+ }
+
+ chain y {
+ type nat hook prerouting priority dstnat;
+ dnat ip addr . port to ip saddr . ip protocol . tcp dport map @z
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0011vmap_0 b/tests/shell/testcases/maps/0011vmap_0
new file mode 100755
index 0000000..3e6fa78
--- /dev/null
+++ b/tests/shell/testcases/maps/0011vmap_0
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table inet filter {
+ map portmap {
+ type inet_service : verdict
+ counter
+ }
+
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap @portmap
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority -300; policy accept;
+ iif vmap { "lo" : jump wan_input }
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
+
+if [ "$NFT_TEST_HAVE_catchall_element" != n ]; then
+ $NFT 'add element inet filter portmap { 22 : jump ssh_input, * : drop }'
+fi
+
+if [ "$NFT_TEST_HAVE_catchall_element" = n ]; then
+ echo "Ran partial tests due to NFT_TEST_HAVE_catchall_element=n (skipped)"
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/0012map_0 b/tests/shell/testcases/maps/0012map_0
new file mode 100755
index 0000000..49e51b7
--- /dev/null
+++ b/tests/shell/testcases/maps/0012map_0
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="define interfaces = { eth0, eth1 }
+
+table ip x {
+ map z {
+ type ifname : verdict
+ elements = { \$interfaces : drop, lo : accept }
+ }
+ chain y {
+ iifname vmap { lo : accept, \$interfaces : drop }
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
+
+EXPECTED="table ip x {
+ map w {
+ typeof ip saddr . meta mark : verdict
+ flags interval
+ counter
+ elements = {
+ 127.0.0.1-127.0.0.4 . 0x123434-0xb00122 : accept,
+ }
+ }
+
+ chain k {
+ type filter hook input priority filter + 1; policy accept;
+ meta mark set 0x123434
+ ip saddr . meta mark vmap @w
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0013map_0 b/tests/shell/testcases/maps/0013map_0
new file mode 100755
index 0000000..70d7fd3
--- /dev/null
+++ b/tests/shell/testcases/maps/0013map_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+flush ruleset
+
+add table ip filter
+add chain ip filter FORWARD { type filter hook forward priority 0; policy drop; }
+add map ip filter forwport { type ipv4_addr . inet_proto . inet_service: verdict; flags interval; counter; }
+add rule ip filter FORWARD iifname enp0s8 ip daddr . ip protocol . th dport vmap @forwport counter
+add element ip filter forwport { 10.133.89.138 . tcp . 8081: accept }"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/maps/0014destroy_0 b/tests/shell/testcases/maps/0014destroy_0
new file mode 100755
index 0000000..ee81e3c
--- /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 0000000..e110ee4
--- /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 0000000..e01adb4
--- /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 0000000..09db315
--- /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/maps/anon_objmap_concat b/tests/shell/testcases/maps/anon_objmap_concat
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/maps/anon_objmap_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/anonymous_snat_map_0 b/tests/shell/testcases/maps/anonymous_snat_map_0
new file mode 100755
index 0000000..32aac8a
--- /dev/null
+++ b/tests/shell/testcases/maps/anonymous_snat_map_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# anonymous map can be added to a snat rule
+
+set -e
+$NFT add table nat
+$NFT add chain nat postrouting
+$NFT add rule nat postrouting snat ip saddr map {1.1.1.1 : 2.2.2.2}
diff --git a/tests/shell/testcases/maps/different_map_types_1 b/tests/shell/testcases/maps/different_map_types_1
new file mode 100755
index 0000000..a7e831f
--- /dev/null
+++ b/tests/shell/testcases/maps/different_map_types_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# must fail: expr MAP { expr : type1, expr : type2, .. } expr
+
+set -e
+
+$NFT add table ip filter
+$NFT add chain ip filter output { type filter hook output priority 0 \; }
+
+$NFT add rule ip filter output meta mark set tcp dport map { 22 : 1, 23 : 192.168.0.1 } || exit 0
+
+echo "E: Added two different types of expression to map"
+exit 1
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 0000000..c651af0
--- /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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.nft
new file mode 100644
index 0000000..ab992c4
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.nft
@@ -0,0 +1,8 @@
+table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { 10.1.1.0/24 : 10.0.1.1, 10.1.2.0/24 : 10.0.1.2,
+ 10.2.1.0/24 : 10.0.2.1, 10.2.2.0/24 : 10.0.2.2 }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.nft b/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.nft
new file mode 100644
index 0000000..1f5343f
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.nft
@@ -0,0 +1,7 @@
+table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { 10.0.1.0/24 : 10.0.0.1, 10.0.2.0/24 : 10.0.0.2 }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.nft b/tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.nft
new file mode 100644
index 0000000..878e7c0
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.nft
@@ -0,0 +1,11 @@
+table inet t {
+ map m1 {
+ type ifname : ipv4_addr
+ elements = { "eth0" : 1.1.1.1 }
+ }
+
+ chain c {
+ ip daddr set iifname map @m1
+ ip daddr set oifname map @m1
+ }
+}
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 0000000..a470a34
--- /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.nft b/tests/shell/testcases/maps/dumps/0009vmap_0.nft
new file mode 100644
index 0000000..c37574a
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0009vmap_0.nft
@@ -0,0 +1,13 @@
+table inet filter {
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap { 22 : jump ssh_input }
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority raw; policy accept;
+ iif vmap { "lo" counter packets 0 bytes 0 : jump wan_input }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0010concat_map_0.nft b/tests/shell/testcases/maps/dumps/0010concat_map_0.nft
new file mode 100644
index 0000000..2f796b5
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0010concat_map_0.nft
@@ -0,0 +1,11 @@
+table inet x {
+ map z {
+ type ipv4_addr . inet_proto . inet_service : ipv4_addr . inet_service
+ elements = { 1.1.1.1 . tcp . 20 : 2.2.2.2 . 30 }
+ }
+
+ chain y {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat ip to ip saddr . ip protocol . tcp dport map @z
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0011vmap_0.nft b/tests/shell/testcases/maps/dumps/0011vmap_0.nft
new file mode 100644
index 0000000..4a72b5e
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0011vmap_0.nft
@@ -0,0 +1,19 @@
+table inet filter {
+ map portmap {
+ type inet_service : verdict
+ counter
+ elements = { 22 counter packets 0 bytes 0 : jump ssh_input, * counter packets 0 bytes 0 : drop }
+ }
+
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap @portmap
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority raw; policy accept;
+ iif vmap { "lo" : jump wan_input }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0012map_0.nft b/tests/shell/testcases/maps/dumps/0012map_0.nft
new file mode 100644
index 0000000..895490c
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0012map_0.nft
@@ -0,0 +1,25 @@
+table ip x {
+ map z {
+ type ifname : verdict
+ elements = { "lo" : accept,
+ "eth0" : drop,
+ "eth1" : drop }
+ }
+
+ 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 y {
+ iifname vmap { "lo" : accept, "eth0" : drop, "eth1" : drop }
+ }
+
+ 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.nft b/tests/shell/testcases/maps/dumps/0013map_0.nft
new file mode 100644
index 0000000..1455877
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0013map_0.nft
@@ -0,0 +1,13 @@
+table ip filter {
+ map forwport {
+ type ipv4_addr . inet_proto . inet_service : verdict
+ flags interval
+ counter
+ elements = { 10.133.89.138 . tcp . 8081 counter packets 0 bytes 0 : accept }
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter; policy drop;
+ iifname "enp0s8" ip daddr . ip protocol . th dport vmap @forwport counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0014destroy_0.nft b/tests/shell/testcases/maps/dumps/0014destroy_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /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.nft b/tests/shell/testcases/maps/dumps/0016map_leak_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0016map_leak_0.nft
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 0000000..796dd72
--- /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.nft b/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.nft
diff --git a/tests/shell/testcases/maps/dumps/anon_objmap_concat.nft b/tests/shell/testcases/maps/dumps/anon_objmap_concat.nft
new file mode 100644
index 0000000..23aca0a
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/anon_objmap_concat.nft
@@ -0,0 +1,16 @@
+table inet filter {
+ ct helper sip-5060u {
+ type "sip" protocol udp
+ l3proto ip
+ }
+
+ ct helper sip-5060t {
+ type "sip" protocol tcp
+ l3proto ip
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ct helper set ip protocol . th dport map { udp . 10000-20000 : "sip-5060u", tcp . 10000-20000 : "sip-5060t" }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/anonymous_snat_map_0.nft b/tests/shell/testcases/maps/dumps/anonymous_snat_map_0.nft
new file mode 100644
index 0000000..5009560
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/anonymous_snat_map_0.nft
@@ -0,0 +1,5 @@
+table ip nat {
+ chain postrouting {
+ snat to ip saddr map { 1.1.1.1 : 2.2.2.2 }
+ }
+}
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 0000000..3c18b5c
--- /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.nft b/tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.nft
new file mode 100644
index 0000000..37c48bf
--- /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_with_flags_0.nft b/tests/shell/testcases/maps/dumps/map_with_flags_0.nft
new file mode 100644
index 0000000..c96b1ed
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_with_flags_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ flags timeout
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/named_snat_map_0.nft b/tests/shell/testcases/maps/dumps/named_snat_map_0.nft
new file mode 100644
index 0000000..a7c5751
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_snat_map_0.nft
@@ -0,0 +1,10 @@
+table ip nat {
+ map m {
+ type ipv4_addr : ipv4_addr
+ elements = { 1.1.1.1 : 2.2.2.2 }
+ }
+
+ chain postrouting {
+ snat to ip saddr map @m
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/nat_addr_port.nft b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
new file mode 100644
index 0000000..c8493b3
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
@@ -0,0 +1,129 @@
+table ip ipfoo {
+ map t1 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map x {
+ type ipv4_addr : ipv4_addr
+ }
+
+ map y {
+ type ipv4_addr : ipv4_addr . inet_service
+ elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+ }
+
+ map z {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat to ip daddr map @x
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip to ip saddr map @y
+ dnat ip to ip saddr . tcp dport map @z
+ dnat to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip to numgen inc mod 2 map @t2
+ }
+}
+table ip6 ip6foo {
+ map t1 {
+ typeof numgen inc mod 2 : ip6 daddr
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x {
+ type ipv6_addr : ipv6_addr
+ }
+
+ map y {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+
+ map z {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat to ip6 daddr map @x
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 to ip6 saddr map @y
+ dnat ip6 to ip6 saddr . tcp dport map @z
+ dnat to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip6 to numgen inc mod 2 map @t2
+ }
+}
+table inet inetfoo {
+ map t1v4 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2v4 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map t1v6 {
+ typeof numgen inc mod 2 : ip6 daddr
+ }
+
+ map t2v6 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x4 {
+ type ipv4_addr : ipv4_addr
+ }
+
+ map y4 {
+ type ipv4_addr : ipv4_addr . inet_service
+ }
+
+ map z4 {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ map x6 {
+ type ipv6_addr : ipv6_addr
+ }
+
+ map y6 {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+
+ map z6 {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat ip to ip daddr map @x4
+ ip saddr 10.1.1.1 dnat ip to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat ip to 10.2.3.4:4242
+ meta l4proto tcp dnat ip to ip saddr map @y4
+ dnat ip to ip saddr . tcp dport map @z4
+ dnat ip to numgen inc mod 2 map @t1v4
+ meta l4proto tcp dnat ip to numgen inc mod 2 map @t2v4
+ dnat ip6 to ip6 daddr map @x6
+ ip6 saddr dead::1 dnat ip6 to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat ip6 to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 to ip6 saddr map @y6
+ dnat ip6 to ip6 saddr . tcp dport map @z6
+ dnat ip6 to numgen inc mod 2 map @t1v6
+ meta l4proto tcp dnat ip6 to numgen inc mod 2 map @t2v6
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_integer_0.nft b/tests/shell/testcases/maps/dumps/typeof_integer_0.nft
new file mode 100644
index 0000000..19c24fe
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_integer_0.nft
@@ -0,0 +1,20 @@
+table inet t {
+ map m1 {
+ typeof udp length . @ih,32,32 : verdict
+ flags interval
+ elements = { 20-80 . 0x14 : accept,
+ 1-10 . 0xa : drop }
+ }
+
+ map m2 {
+ typeof udp length . @ih,32,32 : verdict
+ elements = { 30 . 0x1e : drop,
+ 20 . 0x24 : accept }
+ }
+
+ chain c {
+ udp length . @nh,32,32 vmap @m1
+ udp length . @nh,32,32 vmap @m2
+ udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_0.nft b/tests/shell/testcases/maps/dumps/typeof_maps_0.nft
new file mode 100644
index 0000000..a5c0a60
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_0.nft
@@ -0,0 +1,36 @@
+table inet t {
+ map m1 {
+ typeof osf name : ct mark
+ elements = { "Linux" : 0x00000001 }
+ }
+
+ map m2 {
+ typeof vlan id : meta mark
+ elements = { 1 : 0x00000001, 4095 : 0x00004095 }
+ }
+
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
+ map m4 {
+ typeof iifname . ip protocol . th dport : verdict
+ elements = { "eth0" . tcp . 22 : accept }
+ }
+
+ map m5 {
+ typeof ipsec in reqid . iifname : verdict
+ elements = { 23 . "eth0" : accept }
+ }
+
+ chain c {
+ ct mark set osf name map @m1
+ meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
+ iifname . ip protocol . th dport vmap @m4
+ iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+ ipsec in reqid . iifname vmap @m5
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.nft b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.nft
new file mode 100644
index 0000000..9134673
--- /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 0000000..1ca98d8
--- /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 0000000..f8b574f
--- /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.nft b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft
new file mode 100644
index 0000000..698219c
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft
@@ -0,0 +1,21 @@
+table ip kube-nfproxy-v4 {
+ map sticky-set-svc-M53CN2XYVUHRQ7UB {
+ type ipv4_addr : mark
+ size 65535
+ timeout 6m
+ }
+
+ map sticky-set-svc-153CN2XYVUHRQ7UB {
+ typeof ip daddr : meta mark
+ size 65535
+ timeout 1m
+ }
+
+ chain k8s-nfproxy-sep-TMVEFT7EX55F4T62 {
+ update @sticky-set-svc-M53CN2XYVUHRQ7UB { ip saddr : 0x00000002 }
+ }
+
+ chain k8s-nfproxy-sep-GMVEFT7EX55F4T62 {
+ update @sticky-set-svc-153CN2XYVUHRQ7UB { ip saddr : 0x00000003 }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_raw_0.nft b/tests/shell/testcases/maps/dumps/typeof_raw_0.nft
new file mode 100644
index 0000000..476169f
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_raw_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ map y {
+ typeof ip saddr . @ih,32,32 : verdict
+ elements = { 1.1.1.1 . 0x14 : accept,
+ 7.7.7.7 . 0x86 : accept,
+ 7.7.7.8 . 0x97 : drop }
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 vmap @y
+ ip saddr . @nh,32,32 vmap { 4.4.4.4 . 0x34 : accept, 5.5.5.5 . 0x45 : drop }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.nft b/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.nft
new file mode 100644
index 0000000..beb5ffb
--- /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.nft b/tests/shell/testcases/maps/dumps/vmap_timeout.nft
new file mode 100644
index 0000000..095f894
--- /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/map_catchall_double_deactivate b/tests/shell/testcases/maps/map_catchall_double_deactivate
new file mode 100755
index 0000000..651c08a
--- /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_with_flags_0 b/tests/shell/testcases/maps/map_with_flags_0
new file mode 100755
index 0000000..68bd80d
--- /dev/null
+++ b/tests/shell/testcases/maps/map_with_flags_0
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table x
+$NFT add map x y { type ipv4_addr : ipv4_addr\; flags timeout\; }
diff --git a/tests/shell/testcases/maps/named_snat_map_0 b/tests/shell/testcases/maps/named_snat_map_0
new file mode 100755
index 0000000..addb9f7
--- /dev/null
+++ b/tests/shell/testcases/maps/named_snat_map_0
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# nameds map can be addedd to a snat rule
+
+set -e
+$NFT add table nat
+$NFT add chain nat postrouting
+$NFT add map nat m { type ipv4_addr : ipv4_addr\; }
+$NFT add element nat m {1.1.1.1: 2.2.2.2}
+$NFT add rule nat postrouting snat ip saddr map @m
diff --git a/tests/shell/testcases/maps/nat_addr_port b/tests/shell/testcases/maps/nat_addr_port
new file mode 100755
index 0000000..2804d48
--- /dev/null
+++ b/tests/shell/testcases/maps/nat_addr_port
@@ -0,0 +1,207 @@
+#!/bin/bash
+
+# skeleton
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip ipfoo {
+ map t1 {
+ typeof numgen inc mod 2 : ip daddr;
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map x {
+ type ipv4_addr : ipv4_addr
+ }
+ map y {
+ type ipv4_addr : ipv4_addr . inet_service
+ elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+ }
+ map z {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat to ip daddr map @x
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip addr . port to ip saddr map @y
+ meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z
+ dnat ip to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2
+ }
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip ipfoo c ip saddr 10.1.1.2 dnat to 10.2.3.4:4242' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip ipfoo c dnat to ip daddr map @y' && exit 1
+
+# skeleton 6
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip6 ip6foo {
+ map t1 {
+ typeof numgen inc mod 2 : ip6 daddr;
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x {
+ type ipv6_addr : ipv6_addr
+ }
+ map y {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+ map z {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat to ip6 daddr map @x
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr . tcp dport map @z
+ dnat ip6 to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2
+ }
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip6 ip6foo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip6 ip6foo c dnat to ip daddr map @y' && exit 1
+
+# skeleton inet
+$NFT -f /dev/stdin <<EOF || exit 1
+table inet inetfoo {
+ map t1v4 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2v4 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport;
+ }
+
+ map t1v6 {
+ typeof numgen inc mod 2 : ip6 daddr;
+ }
+
+ map t2v6 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x4 {
+ type ipv4_addr : ipv4_addr
+ }
+ map y4 {
+ type ipv4_addr : ipv4_addr . inet_service
+ }
+ map z4 {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+ map x6 {
+ type ipv6_addr : ipv6_addr
+ }
+ map y6 {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+ map z6 {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat ip to ip daddr map @x4
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip addr . port to ip saddr map @y4
+ meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z4
+ dnat ip to numgen inc mod 2 map @t1v4
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2v4
+ dnat ip6 to ip6 daddr map @x6
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y6
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr . tcp dport map @z6
+ dnat ip6 to numgen inc mod 2 map @t1v6
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2v6
+ }
+}
+EOF
+
+# should fail: map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @x6' && exit 1
+
+# should fail: map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c dnat to ip6 daddr map @x4' && exit 1
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'inet inetfoo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @y4' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip daddr map @y6' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip6 daddr map @y4' && exit 1
+
+# fail: inet_service, but expect ipv4_addr
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map a {
+ type ipv4_addr : inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+# fail: maps to inet_service . inet_service, not addr . service
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map b {
+ type ipv4_addr : inet_service . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+# fail: only accept exactly two sub-expressions: 'addr . service'
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map b {
+ type ipv4_addr : inet_addr . inet_service . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+exit 0
diff --git a/tests/shell/testcases/maps/typeof_integer_0 b/tests/shell/testcases/maps/typeof_integer_0
new file mode 100755
index 0000000..0deff5e
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_integer_0
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+EXPECTED="table inet t {
+ map m1 {
+ typeof udp length . @ih,32,32 : verdict
+ flags interval
+ elements = { 20-80 . 0x14 : accept, 1-10 . 0xa : drop }
+ }
+
+ map m2 {
+ typeof udp length . @ih,32,32 : verdict
+ elements = { 20 . 0x24 : accept, 30 . 0x1e : drop }
+ }
+
+ chain c {
+ udp length . @nh,32,32 vmap @m1
+ udp length . @nh,32,32 vmap @m2
+ udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+ }
+}"
+
+$NFT add element inet t m1 { 90-100 . 40 : drop }
+$NFT delete element inet t m2 { 20 . 20 : accept }
+
+set -e
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/maps/typeof_maps_0 b/tests/shell/testcases/maps/typeof_maps_0
new file mode 100755
index 0000000..98517fd
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_0
@@ -0,0 +1,101 @@
+#!/bin/bash
+
+# support for strings and integers in named maps.
+# without typeof, this is 'type string' and 'type integer',
+# but neither could be used because it lacks size information.
+
+set -e
+
+die() {
+ printf '%s\n' "$*"
+ exit 1
+}
+
+INPUT_OSF_CT="
+ ct mark set osf name map @m1"
+if [ "$NFT_TEST_HAVE_osf" = n ] ; then
+ INPUT_OSF_CT=
+fi
+
+INPUT="table inet t {
+ map m1 {
+ typeof osf name : ct mark
+ elements = { Linux : 0x00000001 }
+ }
+
+ map m2 {
+ typeof vlan id : mark
+ elements = { 1 : 0x1,
+ 4095 : 0x4095 }
+ }
+
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
+ map m4 {
+ typeof iifname . ip protocol . th dport : verdict
+ elements = { eth0 . tcp . 22 : accept }
+ }
+
+ map m5 {
+ typeof ipsec in reqid . meta iifname : verdict
+ elements = { 23 . eth0 : accept }
+ }
+
+ chain c {$INPUT_OSF_CT
+ ether type vlan meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
+ iifname . ip protocol . th dport vmap @m4
+ iifname . ip protocol . th dport vmap { \"eth0\" . tcp . 22 : accept, \"eth1\" . udp . 67 : drop }
+ ipsec in reqid . meta iifname vmap @m5
+ }
+}"
+
+EXPECTED="table inet t {
+ map m1 {
+ typeof osf name : ct mark
+ elements = { \"Linux\" : 0x00000001 }
+ }
+
+ map m2 {
+ typeof vlan id : meta mark
+ elements = { 1 : 0x00000001, 4095 : 0x00004095 }
+ }
+
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
+ map m4 {
+ typeof iifname . ip protocol . th dport : verdict
+ elements = { \"eth0\" . tcp . 22 : accept }
+ }
+
+ map m5 {
+ typeof ipsec in reqid . iifname : verdict
+ elements = { 23 . \"eth0\" : accept }
+ }
+
+ chain c {$INPUT_OSF_CT
+ meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
+ iifname . ip protocol . th dport vmap @m4
+ iifname . ip protocol . th dport vmap { \"eth0\" . tcp . 22 : accept, \"eth1\" . udp . 67 : drop }
+ ipsec in reqid . iifname vmap @m5
+ }
+}"
+
+$NFT -f - <<< "$INPUT" || die $'nft command failed to process input:\n'">$INPUT<"
+
+$DIFF -u <($NFT list ruleset) - <<<"$EXPECTED" || die $'diff failed between ruleset and expected data.\nExpected:\n'">$EXPECTED<"
+
+
+if [ "$NFT_TEST_HAVE_osf" = n ] ; then
+ echo "Partial test due to NFT_TEST_HAVE_osf=n. Skip"
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/typeof_maps_add_delete b/tests/shell/testcases/maps/typeof_maps_add_delete
new file mode 100755
index 0000000..5e2f8ec
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_add_delete
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+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 0000000..07820b7
--- /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 0000000..2a52ea0
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_concat_update_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# check update statement does print both concatentations (key and data).
+
+EXPECTED="table ip foo {
+ map pinned {
+ typeof ip saddr . ct original proto-dst : ip daddr . tcp dport
+ size 65535
+ flags dynamic,timeout
+ timeout 6m
+ }
+ chain pr {
+ update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ meta l4proto tcp update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/maps/typeof_maps_update_0 b/tests/shell/testcases/maps/typeof_maps_update_0
new file mode 100755
index 0000000..c233b13
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_update_0
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# check update statement doesn't print "invalid dtype" on the data element.
+
+EXPECTED="table ip kube-nfproxy-v4 {
+ map sticky-set-svc-M53CN2XYVUHRQ7UB {
+ type ipv4_addr : mark
+ size 65535
+ timeout 6m
+ }
+
+ map sticky-set-svc-153CN2XYVUHRQ7UB {
+ typeof ip daddr : meta mark
+ size 65535
+ timeout 1m
+ }
+
+ chain k8s-nfproxy-sep-TMVEFT7EX55F4T62 {
+ update @sticky-set-svc-M53CN2XYVUHRQ7UB { ip saddr : 0x2 }
+ }
+ chain k8s-nfproxy-sep-GMVEFT7EX55F4T62 {
+ update @sticky-set-svc-153CN2XYVUHRQ7UB { ip saddr : 0x3 }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/maps/typeof_raw_0 b/tests/shell/testcases/maps/typeof_raw_0
new file mode 100755
index 0000000..bcd2c6d
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_raw_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+EXPECTED="table ip x {
+ map y {
+ typeof ip saddr . @ih,32,32: verdict
+ elements = { 1.1.1.1 . 0x14 : accept, 2.2.2.2 . 0x1e : drop }
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 vmap @y
+ ip saddr . @nh,32,32 vmap { 4.4.4.4 . 0x34 : accept, 5.5.5.5 . 0x45 : drop}
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+$NFT add element ip x y { 7.7.7.7 . 0x86 : accept, 7.7.7.8 . 0x97 : drop }
+$NFT delete element ip x y { 2.2.2.2 . 0x1e : drop }
diff --git a/tests/shell/testcases/maps/vmap_mark_bitwise_0 b/tests/shell/testcases/maps/vmap_mark_bitwise_0
new file mode 100755
index 0000000..0d93355
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_mark_bitwise_0
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+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 0000000..0cd965f
--- /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/netns/0001nft-f_0 b/tests/shell/testcases/netns/0001nft-f_0
new file mode 100755
index 0000000..a591f2c
--- /dev/null
+++ b/tests/shell/testcases/netns/0001nft-f_0
@@ -0,0 +1,99 @@
+#!/bin/bash
+
+# test a kernel netns loading a simple ruleset
+
+IP=$(which ip)
+if [ ! -x "$IP" ] ; then
+ echo "E: no ip binary" >&2
+ exit 1
+fi
+
+RULESET="table ip t {
+ set s {
+ type ipv4_addr
+ elements = { 1.1.0.0 }
+ }
+
+ chain c {
+ ct state new
+ udp dport { 12345, 54321 }
+ ip saddr @s drop
+ jump other
+ }
+
+ chain other {
+ }
+}
+table ip6 t {
+ set s {
+ type ipv6_addr
+ elements = { fe00::1 }
+ }
+
+ chain c {
+ ct state new
+ udp dport { 12345, 54321 }
+ ip6 saddr @s drop
+ jump other
+ }
+
+ chain other {
+ }
+}
+table inet t {
+ set s {
+ type ipv6_addr
+ elements = { fe00::1 }
+ }
+
+ chain c {
+ ct state new
+ udp dport { 12345, 54321 }
+ ip6 saddr @s drop
+ jump other
+ }
+
+ chain other {
+ }
+}
+table bridge t {
+ chain c {
+ jump other
+ }
+
+ chain other {
+ accept
+ }
+}
+table arp t {
+ chain c {
+ jump other
+ }
+
+ chain other {
+ accept
+ }
+}"
+
+# netns
+NETNS_NAME=$(basename "$0")
+$IP netns add $NETNS_NAME
+if [ $? -ne 0 ] ; then
+ echo "E: unable to create netns" >&2
+ exit 1
+fi
+
+$IP netns exec $NETNS_NAME $NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load ruleset in netns" >&2
+ $IP netns del $NETNS_NAME
+ exit 1
+fi
+
+KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
+$IP netns del $NETNS_NAME
+if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ exit 1
+fi
+exit 0
diff --git a/tests/shell/testcases/netns/0002loosecommands_0 b/tests/shell/testcases/netns/0002loosecommands_0
new file mode 100755
index 0000000..231f1fb
--- /dev/null
+++ b/tests/shell/testcases/netns/0002loosecommands_0
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# test a kernel netns loading a simple ruleset
+
+IP=$(which ip)
+if [ ! -x "$IP" ] ; then
+ echo "E: no ip binary" >&2
+ exit 1
+fi
+
+function netns_exec()
+{
+ # $1: netns_name $2: command
+ $IP netns exec $1 $2
+ if [ $? -ne 0 ] ; then
+ echo "E: failed to execute command in netns $1: $2" >&2
+ $IP netns del $1
+ exit 1
+ fi
+}
+
+NETNS_NAME=$(basename "$0")
+$IP netns add $NETNS_NAME
+if [ $? -ne 0 ] ; then
+ echo "E: unable to create netns" >&2
+ exit 1
+fi
+
+netns_exec $NETNS_NAME "$NFT add table ip t"
+netns_exec $NETNS_NAME "$NFT add chain ip t c"
+netns_exec $NETNS_NAME "$NFT add chain ip t other"
+netns_exec $NETNS_NAME "$NFT add set ip t s { type ipv4_addr; }"
+netns_exec $NETNS_NAME "$NFT add element ip t s {1.1.0.0 }"
+netns_exec $NETNS_NAME "$NFT add rule ip t c ct state new"
+netns_exec $NETNS_NAME "$NFT add rule ip t c udp dport { 12345, 54321 }"
+netns_exec $NETNS_NAME "$NFT add rule ip t c ip saddr @s drop"
+netns_exec $NETNS_NAME "$NFT add rule ip t c jump other"
+
+RULESET="table ip t {
+ set s {
+ type ipv4_addr
+ elements = { 1.1.0.0 }
+ }
+
+ chain c {
+ ct state new
+ udp dport { 12345, 54321 }
+ ip saddr @s drop
+ jump other
+ }
+
+ chain other {
+ }
+}"
+
+KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
+$IP netns del $NETNS_NAME
+if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/netns/0003many_0 b/tests/shell/testcases/netns/0003many_0
new file mode 100755
index 0000000..afe9117
--- /dev/null
+++ b/tests/shell/testcases/netns/0003many_0
@@ -0,0 +1,113 @@
+#!/bin/bash
+
+# test using many netns
+
+# arbitry value of 'many'
+HOWMANY=20
+
+IP=$(which ip)
+if [ ! -x "$IP" ] ; then
+ echo "E: no ip binary" >&2
+ exit 1
+fi
+
+RULESET="table ip t {
+ set s {
+ type ipv4_addr
+ elements = { 1.1.0.0 }
+ }
+
+ chain c {
+ ct state new
+ udp dport { 12345, 54321 }
+ ip saddr @s drop
+ jump other
+ }
+
+ chain other {
+ }
+}
+table ip6 t {
+ set s {
+ type ipv6_addr
+ elements = { fe00::1 }
+ }
+
+ chain c {
+ ct state new
+ udp dport { 12345, 54321 }
+ ip6 saddr @s drop
+ jump other
+ }
+
+ chain other {
+ }
+}
+table inet t {
+ set s {
+ type ipv6_addr
+ elements = { fe00::1 }
+ }
+
+ chain c {
+ ct state new
+ udp dport { 12345, 54321 }
+ ip6 saddr @s drop
+ jump other
+ }
+
+ chain other {
+ }
+}
+table bridge t {
+ chain c {
+ jump other
+ }
+
+ chain other {
+ accept
+ }
+}
+table arp t {
+ chain c {
+ jump other
+ }
+
+ chain other {
+ accept
+ }
+}"
+
+function test_netns()
+{
+ local NETNS_NAME=$1
+ $IP netns add $NETNS_NAME
+ if [ $? -ne 0 ] ; then
+ echo "E: unable to create netns" >&2
+ exit 1
+ fi
+
+ $IP netns exec $NETNS_NAME $NFT -f - <<< "$RULESET"
+ if [ $? -ne 0 ] ; then
+ echo "E: unable to load ruleset in netns" >&2
+ $IP netns del $NETNS_NAME
+ exit 1
+ fi
+
+ KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
+ if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
+ echo "E: ruleset in netns $NETNS_NAME differs from the loaded" >&2
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $IP netns del $NETNS_NAME
+ exit 1
+ fi
+
+ $IP netns del $NETNS_NAME
+}
+
+for i in $(seq 1 $HOWMANY) ; do
+ NETNS_NAME="$netns${i}_$(basename "$0")"
+ test_netns $NETNS_NAME
+done
+
+exit 0
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0001nft-f_0.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0002loosecommands_0.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0003many_0.nft
diff --git a/tests/shell/testcases/nft-f/0001define_slash_0 b/tests/shell/testcases/nft-f/0001define_slash_0
new file mode 100755
index 0000000..93c4811
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0001define_slash_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# tests for commit 85d6803 (parser_bison: initializer_expr must use rhs_expr)
+
+RULESET="
+define net = 1.1.1.1/24
+"
+
+set -e
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0002rollback_rule_0 b/tests/shell/testcases/nft-f/0002rollback_rule_0
new file mode 100755
index 0000000..8a9ca84
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0002rollback_rule_0
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# test a kernel rollback operation
+# fail reason: rule
+
+GOOD_RULESET="table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}"
+
+BAD_RULESET="flush ruleset
+table ip t2 {
+ chain c2 {
+ this is an invalid rule
+ }
+}"
+
+$NFT -f - <<< "$GOOD_RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+$NFT -f - <<< "$BAD_RULESET" 2>/dev/null
+if [ $? -eq 0 ] ; then
+ echo "E: bogus ruleset loaded?" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/nft-f/0003rollback_jump_0 b/tests/shell/testcases/nft-f/0003rollback_jump_0
new file mode 100755
index 0000000..6fb6f4e
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0003rollback_jump_0
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# test a kernel rollback operation
+# fail reason: invalid jump
+
+GOOD_RULESET="table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}"
+
+BAD_RULESET="flush ruleset
+table ip t2 {
+ chain c2 {
+ jump other
+ }
+}"
+
+$NFT -f - <<< "$GOOD_RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+$NFT -f - <<< "$BAD_RULESET" 2>/dev/null
+if [ $? -eq 0 ] ; then
+ echo "E: bogus ruleset loaded?" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/nft-f/0004rollback_set_0 b/tests/shell/testcases/nft-f/0004rollback_set_0
new file mode 100755
index 0000000..bcc55df
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0004rollback_set_0
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# test a kernel rollback operation
+# fail reason: invalid set
+
+GOOD_RULESET="table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}"
+
+BAD_RULESET="flush ruleset
+table ip t2 {
+ set s2 {
+ type invalid
+ }
+}"
+
+$NFT -f - <<< "$GOOD_RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+$NFT -f - <<< "$BAD_RULESET" 2>/dev/null
+if [ $? -eq 0 ] ; then
+ echo "E: bogus ruleset loaded?" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/nft-f/0005rollback_map_0 b/tests/shell/testcases/nft-f/0005rollback_map_0
new file mode 100755
index 0000000..913595d
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0005rollback_map_0
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# test a kernel rollback operation
+# fail reason: invalid map
+
+GOOD_RULESET="table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}"
+
+BAD_RULESET="flush ruleset
+table ip t2 {
+ chain c2 {
+ tcp dport map { 22222: jump other, 11111: jump invalid }
+ }
+
+ chain other {
+ }
+}"
+
+$NFT -f - <<< "$GOOD_RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+$NFT -f - <<< "$BAD_RULESET" 2>/dev/null
+if [ $? -eq 0 ] ; then
+ echo "E: bogus ruleset loaded?" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/nft-f/0006action_object_0 b/tests/shell/testcases/nft-f/0006action_object_0
new file mode 100755
index 0000000..ddee661
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0006action_object_0
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+# test loading a ruleset with the 'action object' pattern
+
+set -e
+
+FAMILIES="ip ip6 inet arp bridge"
+
+generate1()
+{
+ local family=$1
+ echo "
+ add table $family t
+ add chain $family t c
+ add rule $family t c accept
+ add set $family t s {type inet_service;}
+ add element $family t s {8080}
+ insert rule $family t c meta l4proto tcp tcp dport @s accept
+ add rule $family t c meta l4proto tcp tcp dport {9090, 8080}
+ add map $family t m {type inet_service:verdict;}
+ add element $family t m {10080:drop}
+ insert rule $family t c meta l4proto tcp tcp dport vmap @m
+ add rule $family t c meta l4proto udp udp sport vmap {1111:accept, 2222:drop}
+ "
+}
+
+generate2()
+{
+ local family=$1
+ echo "
+ flush chain $family t c
+ delete element $family t m {10080:drop}
+ delete element $family t s {8080}
+ delete chain $family t c
+ delete table $family t
+ "
+}
+
+RULESET=$(for family in $FAMILIES ; do
+ generate1 $family
+done)
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load ruleset 1" >&2
+ exit 1
+fi
+
+RULESET=$(for family in $FAMILIES ; do
+ generate2 $family
+done)
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load ruleset 2" >&2
+ exit 1
+fi
+
+exit 0
diff --git a/tests/shell/testcases/nft-f/0007action_object_set_segfault_1 b/tests/shell/testcases/nft-f/0007action_object_set_segfault_1
new file mode 100755
index 0000000..6cbd386
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0007action_object_set_segfault_1
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# test for a segfault if bad syntax was used in set declaration
+# and the set is referenced in the same batch
+
+RULESET="
+add table t
+add chain t c
+add set t s {type ipv4_addr\;}
+add rule t c ip saddr @s
+"
+
+$NFT -f - <<< "$RULESET" 2>/dev/null && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0008split_tables_0 b/tests/shell/testcases/nft-f/0008split_tables_0
new file mode 100755
index 0000000..2631aed
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0008split_tables_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet filter {
+ chain ssh {
+ type filter hook input priority 0; policy accept;
+ tcp dport 22 accept;
+ }
+}
+
+table inet filter {
+ chain input {
+ type filter hook input priority 1; policy accept;
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/nft-f/0009variable_0 b/tests/shell/testcases/nft-f/0009variable_0
new file mode 100755
index 0000000..e073d86
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0009variable_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define concat-set-variable = { 10.10.10.10 . 25, 10.10.10.10 . 143 }
+
+table inet forward {
+ set concat-set-variable {
+ type ipv4_addr . inet_service
+ elements = \$concat-set-variable
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0010variable_0 b/tests/shell/testcases/nft-f/0010variable_0
new file mode 100755
index 0000000..69c80c7
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0010variable_0
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define whitelist_v4 = { 1.1.1.1 }
+
+table inet filter {
+ set whitelist_v4 { type ipv4_addr; }
+}
+add element inet filter whitelist_v4 \$whitelist_v4
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0011manydefines_0 b/tests/shell/testcases/nft-f/0011manydefines_0
new file mode 100755
index 0000000..aac0670
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0011manydefines_0
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# tests many defines in a single nft -f run
+
+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
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate1()
+{
+ for ((i=0; i<=HOWMANY; i++)) ; do
+ echo "define data_${i} = ${i}"
+ done
+}
+
+generate2()
+{
+ for ((i=0; i<=HOWMANY; i++)) ; do
+ echo "iifname \$data_${i}"
+ done
+}
+
+echo " $(generate1)
+table t {
+ chain c {
+ $(generate2)
+ }
+}" > $tmpfile
+
+set -e
+$NFT -f $tmpfile
+
+if [ "$HOWMANY" != 20000 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/nft-f/0012different_defines_0 b/tests/shell/testcases/nft-f/0012different_defines_0
new file mode 100755
index 0000000..fe22858
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0012different_defines_0
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# tests different spots, datatypes and usages for nft defines
+
+RULESET="
+define d_iifname = whatever
+define d_oifname = \$d_iifname
+define d_iif = lo
+define d_oif = \$d_iif
+define d_mark = 123
+define d_state = new,established,related
+define d_ipv4 = 10.0.0.0
+define d_ipv4_2 = 10.0.0.2
+define d_ipv6 = fe0::1
+define d_ipv6_2 = fe0::2
+define d_ports = 100-222
+define d_qnum = 0
+define d_qnumr = 1-42
+
+table inet t {
+ chain c {
+ iifname \$d_iifname oifname \$d_oifname iif \$d_iif oif \$d_oif
+ iifname { \$d_iifname , \$d_oifname } iif { \$d_iif , \$d_oif } meta mark \$d_mark
+ ct state \$d_state
+ ct state != \$d_state
+ ip saddr \$d_ipv4 ip daddr \$d_ipv4_2 ip saddr \$d_ipv4
+ ip6 daddr \$d_ipv6 ip6 saddr \$d_ipv6_2
+ ip saddr vmap { \$d_ipv4 : drop , \$d_ipv4_2 : accept }
+ ip6 daddr vmap { \$d_ipv6 : drop , \$d_ipv6_2 : accept }
+ ip6 saddr . ip6 nexthdr { \$d_ipv6 . udp, \$d_ipv6_2 . tcp }
+ ip daddr . meta iif vmap { \$d_ipv4 . \$d_iif : accept }
+ tcp dport \$d_ports
+ udp dport vmap { \$d_ports : accept }
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue num \$d_qnum bypass
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue num \$d_qnumr
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue flags bypass,fanout num \$d_qnumr
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue to symhash mod 2
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue flags bypass to jhash tcp dport . tcp sport mod 4
+ }
+}"
+
+set -e
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0013defines_1 b/tests/shell/testcases/nft-f/0013defines_1
new file mode 100755
index 0000000..b633088
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0013defines_1
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Tests use of variable before definition.
+
+set -e
+
+RULESET="
+define var2 = \$var1
+define var1 = lo
+
+table ip t {
+ chain c {
+ iif \$var2
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0014defines_1 b/tests/shell/testcases/nft-f/0014defines_1
new file mode 100755
index 0000000..35f2536
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0014defines_1
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Tests redefinition of an existing variable.
+
+set -e
+
+RULESET="
+define var1 = lo
+define var1 = lo
+
+table ip t {
+ chain c {
+ iif \$var1
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0015defines_1 b/tests/shell/testcases/nft-f/0015defines_1
new file mode 100755
index 0000000..935cb45
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0015defines_1
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Tests recursive definition of a variable.
+
+set -e
+
+RULESET="
+define var1 = \$var1
+
+table ip t {
+ chain c {
+ iif \$var1
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0016redefines_1 b/tests/shell/testcases/nft-f/0016redefines_1
new file mode 100755
index 0000000..1f59f6b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0016redefines_1
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+table ip x {
+ chain y {
+ define unused = 4.4.4.4
+ define address = { 1.1.1.1, 2.2.2.2 }
+ ip saddr \$address
+ redefine address = { 3.3.3.3, 4.4.4.4 }
+ ip saddr \$address
+ undefine unused
+ }
+}"
+
+EXPECTED="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 }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+GET="$($NFT list ruleset)"
+
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+exit 0
diff --git a/tests/shell/testcases/nft-f/0017ct_timeout_obj_0 b/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
new file mode 100755
index 0000000..cfb7895
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_cttimeout)
+
+EXPECTED='table ip filter {
+ ct timeout cttime{
+ protocol tcp
+ l3proto ip
+ policy = { established : 123, close : 12 }
+ }
+
+ chain c {
+ ct timeout set "cttime"
+ }
+}'
+
+set -e
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/nft-f/0018ct_expectation_obj_0 b/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
new file mode 100755
index 0000000..4f9872f
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+EXPECTED='table ip filter {
+ ct expectation ctexpect{
+ protocol tcp
+ dport 9876
+ timeout 1m
+ size 12
+ l3proto ip
+ }
+
+ chain c {
+ ct expectation set "ctexpect"
+ }
+}'
+
+set -e
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/nft-f/0018jump_variable_0 b/tests/shell/testcases/nft-f/0018jump_variable_0
new file mode 100755
index 0000000..003a1bd
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0018jump_variable_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Tests use of variables in jump statements
+
+set -e
+
+RULESET="
+define dest = ber
+
+table ip foo {
+ chain bar {
+ jump \$dest
+ }
+
+ chain ber {
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0019jump_variable_1 b/tests/shell/testcases/nft-f/0019jump_variable_1
new file mode 100755
index 0000000..bda861c
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0019jump_variable_1
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Tests use of variables in jump statements
+
+set -e
+
+RULESET="
+define dest = { 1024 }
+
+table ip foo {
+ chain bar {
+ jump \$dest
+ }
+
+ chain ber {
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0020jump_variable_1 b/tests/shell/testcases/nft-f/0020jump_variable_1
new file mode 100755
index 0000000..f753058
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0020jump_variable_1
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Tests use of variables in jump statements
+
+set -e
+
+RULESET="
+define dest = *
+
+table ip foo {
+ chain bar {
+ jump \$dest
+ }
+
+ chain ber {
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0021list_ruleset_0 b/tests/shell/testcases/nft-f/0021list_ruleset_0
new file mode 100755
index 0000000..37729b4
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0021list_ruleset_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# Tests use of variables in jump statements
+
+set -e
+
+RULESET="table filter {
+ chain prerouting {
+ type filter hook prerouting priority -50
+ }
+}
+list ruleset
+"
+
+exec $NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0022variables_0 b/tests/shell/testcases/nft-f/0022variables_0
new file mode 100755
index 0000000..ee17a62
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0022variables_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define test1 = @y
+
+table ip x {
+ set y {
+ type ipv4_addr
+ flags dynamic,timeout
+ }
+
+ chain z {
+ type filter hook input priority filter; policy accept;
+ add \$test1 { ip saddr }
+ update \$test1 { ip saddr timeout 30s }
+ ip saddr \$test1
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0023check_1 b/tests/shell/testcases/nft-f/0023check_1
new file mode 100755
index 0000000..42793b6
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0023check_1
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+RULESET="table ip foo {
+ chain bar {
+ type filter hook prerouting priority 0;
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+$NFT -c add rule foo bar fib saddr . oif type local && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0024priority_0 b/tests/shell/testcases/nft-f/0024priority_0
new file mode 100755
index 0000000..586f5c3
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0024priority_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+RULESET="
+table inet statelessnat {
+ chain prerouting {
+ type filter hook prerouting priority -100;
+ ip daddr set numgen inc mod 16 map { 0-7 : 10.0.1.1, 8- 15 : 10.0.1.2 }
+ }
+ chain postrouting {
+ type filter hook postrouting priority 100
+ }
+}"
+
+exec $NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0025empty_dynset_0 b/tests/shell/testcases/nft-f/0025empty_dynset_0
new file mode 100755
index 0000000..fbdb579
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0025empty_dynset_0
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip foo {
+ set inflows {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . \"veth1\" . 10.3.0.99 . 5201 counter packets 0 bytes 0 }
+ }
+
+ set inflows6 {
+ type ipv6_addr . inet_service . ifname . ipv6_addr . inet_service
+ flags dynamic
+ }
+
+ set inflows_ratelimit {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . \"veth1\" . 10.3.0.99 . 5201 limit rate 1/second counter packets 0 bytes 0 }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+# inflows_ratelimit will be dumped without 'limit rate .. counter' on old kernels.
+if [ "$NFT_TEST_HAVE_set_with_two_expressions" = n ]; then
+ echo "Partial test due to NFT_TEST_HAVE_set_with_two_expressions=n."
+ exit 77
+fi
diff --git a/tests/shell/testcases/nft-f/0026listing_0 b/tests/shell/testcases/nft-f/0026listing_0
new file mode 100755
index 0000000..0f2f27c
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0026listing_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# This is like "flush ruleset" except only flushes THIS ruleset, not ALL rulesets.
+# In particular, it leaves the dynamic sshguard/fail2ban deny lists untouched.
+RULESET="add table A
+delete table A
+table A {
+ chain B {
+ tcp dport {1,2} accept
+ }
+}
+list ruleset"
+
+exec $NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0027split_chains_0 b/tests/shell/testcases/nft-f/0027split_chains_0
new file mode 100755
index 0000000..de1e5a0
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0027split_chains_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet filter {
+ chain x {
+ }
+}
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy accept;
+ jump x
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 0
+exit 1
diff --git a/tests/shell/testcases/nft-f/0028variable_cmdline_0 b/tests/shell/testcases/nft-f/0028variable_cmdline_0
new file mode 100755
index 0000000..a2bbd5d
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0028variable_cmdline_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+
+RULESET="table inet filter {
+ set whitelist_v4 { type ipv4_addr; }
+}
+add element inet filter whitelist_v4 \$whitelist_v4
+"
+
+# this is intentional: exercise error path
+$NFT --define whitelist_v4="{ wrong }" -f - <<< "$RULESET"
+$NFT --define whitelist_v4="{ 1.1.1.1, \$wrong }" -f - <<< "$RULESET"
+
+set -e
+
+$NFT --define whitelist_v4="{ 1.1.1.1, 2.2.2.2 }" -f - <<< "$RULESET"
+$NFT --define x={5.5.5.5} --define whitelist_v4="{ 3.3.3.3, 4.4.4.4, \$x }" -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0029split_file_0 b/tests/shell/testcases/nft-f/0029split_file_0
new file mode 100755
index 0000000..0cc547a
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0029split_file_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet filter {
+ set whitelist_v4 {
+ type ipv4_addr;
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority filter;
+ }
+}
+"
+
+$NFT -f - <<< "$RULESET"
+
+RULESET="table inet filter {
+ chain prerouting {
+ ip daddr @whitelist_v4
+ }
+}
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0030variable_reuse_0 b/tests/shell/testcases/nft-f/0030variable_reuse_0
new file mode 100755
index 0000000..8afc54a
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0030variable_reuse_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define test = { 1.1.1.1 }
+
+table ip x {
+ set y {
+ type ipv4_addr
+ elements = { 2.2.2.2, \$test }
+ }
+
+ set z {
+ type ipv4_addr
+ elements = { 3.3.3.3, \$test }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0031vmap_string_0 b/tests/shell/testcases/nft-f/0031vmap_string_0
new file mode 100755
index 0000000..2af846a
--- /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 0000000..94fc840
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0001define_slash_0.nft
new file mode 100644
index 0000000..e69de29
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0002rollback_rule_0.nft
new file mode 100644
index 0000000..3fad909
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0002rollback_rule_0.nft
@@ -0,0 +1,16 @@
+table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.nft b/tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.nft
new file mode 100644
index 0000000..3fad909
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.nft
@@ -0,0 +1,16 @@
+table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0004rollback_set_0.nft b/tests/shell/testcases/nft-f/dumps/0004rollback_set_0.nft
new file mode 100644
index 0000000..3fad909
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0004rollback_set_0.nft
@@ -0,0 +1,16 @@
+table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0005rollback_map_0.nft b/tests/shell/testcases/nft-f/dumps/0005rollback_map_0.nft
new file mode 100644
index 0000000..3fad909
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0005rollback_map_0.nft
@@ -0,0 +1,16 @@
+table ip t {
+ set t {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+
+ chain c {
+ ct state new
+ tcp dport { 22222, 33333 }
+ ip saddr @t drop
+ jump other
+ }
+
+ chain other {
+ }
+}
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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.nft
new file mode 100644
index 0000000..e69de29
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0008split_tables_0.nft
new file mode 100644
index 0000000..d7e7808
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0008split_tables_0.nft
@@ -0,0 +1,10 @@
+table inet filter {
+ chain ssh {
+ type filter hook input priority filter; policy accept;
+ tcp dport 22 accept
+ }
+
+ chain input {
+ type filter hook input priority filter + 1; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0009variable_0.nft b/tests/shell/testcases/nft-f/dumps/0009variable_0.nft
new file mode 100644
index 0000000..7f59a27
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0009variable_0.nft
@@ -0,0 +1,7 @@
+table inet forward {
+ set concat-set-variable {
+ type ipv4_addr . inet_service
+ elements = { 10.10.10.10 . 25,
+ 10.10.10.10 . 143 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0010variable_0.nft b/tests/shell/testcases/nft-f/dumps/0010variable_0.nft
new file mode 100644
index 0000000..1f3d05e
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0010variable_0.nft
@@ -0,0 +1,6 @@
+table inet filter {
+ set whitelist_v4 {
+ type ipv4_addr
+ elements = { 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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0011manydefines_0.nodump
diff --git a/tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft b/tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft
new file mode 100644
index 0000000..4734b2f
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft
@@ -0,0 +1,21 @@
+table inet t {
+ chain c {
+ iifname "whatever" oifname "whatever" iif "lo" oif "lo"
+ iifname { "whatever" } iif { "lo" } meta mark 0x0000007b
+ ct state established,related,new
+ ct state != established | related | new
+ ip saddr 10.0.0.0 ip daddr 10.0.0.2 ip saddr 10.0.0.0
+ ip6 daddr fe0::1 ip6 saddr fe0::2
+ ip saddr vmap { 10.0.0.0 : drop, 10.0.0.2 : accept }
+ ip6 daddr vmap { fe0::1 : drop, fe0::2 : accept }
+ ip6 saddr . ip6 nexthdr { fe0::2 . tcp, fe0::1 . udp }
+ ip daddr . iif vmap { 10.0.0.0 . "lo" : accept }
+ tcp dport 100-222
+ udp dport vmap { 100-222 : accept }
+ tcp sport 1 tcp dport 1 oifname "foobar" queue flags bypass to 0
+ tcp sport 1 tcp dport 1 oifname "foobar" queue to 1-42
+ tcp sport 1 tcp dport 1 oifname "foobar" queue flags bypass,fanout to 1-42
+ tcp sport 1 tcp dport 1 oifname "foobar" queue to symhash mod 2
+ tcp sport 1 tcp dport 1 oifname "foobar" queue flags bypass to jhash tcp dport . tcp sport mod 4
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0013defines_1.nft b/tests/shell/testcases/nft-f/dumps/0013defines_1.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0013defines_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0014defines_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0015defines_1.nft
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 0000000..65b7f49
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft
new file mode 100644
index 0000000..c5d9649
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft
@@ -0,0 +1,11 @@
+table ip filter {
+ ct timeout cttime {
+ protocol tcp
+ l3proto ip
+ policy = { established : 2m3s, close : 12s }
+ }
+
+ chain c {
+ ct timeout set "cttime"
+ }
+}
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 0000000..396185e
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.nft
new file mode 100644
index 0000000..0ddaf07
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.nft
@@ -0,0 +1,8 @@
+table ip foo {
+ chain bar {
+ jump ber
+ }
+
+ chain ber {
+ }
+}
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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0020jump_variable_1.nft
new file mode 100644
index 0000000..e69de29
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0021list_ruleset_0.nft
new file mode 100644
index 0000000..b2cd401
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0021list_ruleset_0.nft
@@ -0,0 +1,5 @@
+table ip filter {
+ chain prerouting {
+ type filter hook prerouting priority -50; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0022variables_0.nft b/tests/shell/testcases/nft-f/dumps/0022variables_0.nft
new file mode 100644
index 0000000..d30f4d5
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0022variables_0.nft
@@ -0,0 +1,14 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ }
+
+ chain z {
+ type filter hook input priority filter; policy accept;
+ add @y { ip saddr }
+ update @y { ip saddr timeout 30s }
+ ip saddr @y
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0023check_1.nft b/tests/shell/testcases/nft-f/dumps/0023check_1.nft
new file mode 100644
index 0000000..04b9e70
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0024priority_0.nft
new file mode 100644
index 0000000..cd7fc50
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0024priority_0.nft
@@ -0,0 +1,10 @@
+table inet statelessnat {
+ chain prerouting {
+ type filter hook prerouting priority dstnat; policy accept;
+ ip daddr set numgen inc mod 16 map { 0-7 : 10.0.1.1, 8-15 : 10.0.1.2 }
+ }
+
+ chain postrouting {
+ type filter hook postrouting priority srcnat; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft
new file mode 100644
index 0000000..33b9e4f
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft
@@ -0,0 +1,18 @@
+table ip foo {
+ set inflows {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . "veth1" . 10.3.0.99 . 5201 counter packets 0 bytes 0 }
+ }
+
+ set inflows6 {
+ type ipv6_addr . inet_service . ifname . ipv6_addr . inet_service
+ flags dynamic
+ }
+
+ set inflows_ratelimit {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . "veth1" . 10.3.0.99 . 5201 limit rate 1/second burst 5 packets counter packets 0 bytes 0 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0026listing_0.nft b/tests/shell/testcases/nft-f/dumps/0026listing_0.nft
new file mode 100644
index 0000000..fd0bb68
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0027split_chains_0.nft
new file mode 100644
index 0000000..39198be
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0027split_chains_0.nft
@@ -0,0 +1,9 @@
+table inet filter {
+ chain x {
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ jump x
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft b/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft
new file mode 100644
index 0000000..aa08112
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft
@@ -0,0 +1,8 @@
+table inet filter {
+ set whitelist_v4 {
+ type ipv4_addr
+ elements = { 1.1.1.1, 2.2.2.2,
+ 3.3.3.3, 4.4.4.4,
+ 5.5.5.5 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0029split_file_0.nft b/tests/shell/testcases/nft-f/dumps/0029split_file_0.nft
new file mode 100644
index 0000000..32d5c0e
--- /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.nft b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft
new file mode 100644
index 0000000..635901f
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft
@@ -0,0 +1,11 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ elements = { 1.1.1.1, 2.2.2.2 }
+ }
+
+ set z {
+ type ipv4_addr
+ elements = { 1.1.1.1, 3.3.3.3 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.nft b/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.nft
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 0000000..f29dfb2
--- /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 0000000..480b694
--- /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 != syn / fin,syn,rst,ack 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 / syn,rst 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 0000000..763e41a
--- /dev/null
+++ b/tests/shell/testcases/nft-f/sample-ruleset
@@ -0,0 +1,262 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_chain_binding)
+
+$NFT -f /dev/stdin <<"EOF"
+define public_if = eth0
+define trusted_if = eth1
+define voip_if = eth2.10
+define guest_if = eth2.20
+define home_if = { $trusted_if, $voip_if, $guest_if }
+define home_ipv6_if = { $trusted_if, $voip_if, $guest_if }
+
+define masq_ip = { 192.168.1.0/24, 192.168.2.0/24, 192.168.3.0/24, 192.168.4.0/24 }
+define masq_if = $public_if
+
+define host1_ip = 192.168.1.10
+define host2_ip = 192.168.2.20
+define host3_ip = 192.168.3.30
+define host4_ip = 192.168.4.40
+
+define proxy_port = 8443
+
+define private_ip = { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
+define private_ip6 = { fe80::/64, fd00::/8 }
+define bogons_ip = { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 }
+define bogons_ip6 = { ::/3, 2001:0002::/48, 2001:0003::/32, 2001:10::/28, 2001:20::/28, 2001::/32, 2001:db8::/32, 2002::/16, 3000::/4, 4000::/2, 8000::/1 }
+
+define sip_whitelist_ip6 = { 2001:db8::1/128, 2001:db8::2/128 }
+define smtps_whitelist_ip = 10.0.0.1
+define protocol_whitelist = { tcp, udp, icmp, ipv6-icmp }
+
+table inet filter {
+ map if_input {
+ type ifname : verdict;
+ elements = { $public_if : jump public_input, $trusted_if : jump home_input, $voip_if : jump home_input, $guest_if : jump home_input }
+ }
+ map if_forward {
+ type ifname : verdict;
+ elements = { $public_if : jump public_forward, $trusted_if : jump trusted_forward, $voip_if : jump voip_forward, $guest_if : jump guest_forward }
+ }
+ map if_output {
+ type ifname : verdict;
+ elements = { $public_if : jump public_output, $trusted_if : jump home_output, $voip_if : jump home_output, $guest_if : jump home_output }
+ }
+
+ set ipv4_blacklist { type ipv4_addr; flags interval; auto-merge; }
+ set ipv6_blacklist { type ipv6_addr; flags interval; auto-merge; }
+ set limit_src_ip { type ipv4_addr; flags dynamic, timeout; size 1024; }
+ set limit_src_ip6 { type ipv6_addr; flags dynamic, timeout; size 1024; }
+
+ chain PREROUTING_RAW {
+ type filter hook prerouting priority raw;
+
+ meta l4proto != $protocol_whitelist counter drop
+ tcp flags syn jump {
+ tcp option maxseg size 1-500 counter drop
+ tcp sport 0 counter drop
+ }
+ rt type 0 counter drop
+ }
+
+ chain PREROUTING_MANGLE {
+ type filter hook prerouting priority mangle;
+
+ ct state vmap { invalid : jump ct_invalid_pre, untracked : jump ct_untracked_pre, new : jump ct_new_pre, related : jump rpfilter }
+ }
+ chain ct_invalid_pre {
+ counter drop
+ }
+ chain ct_untracked_pre {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld-listener-query, mld2-listener-report } return
+ counter drop
+ }
+ chain ct_new_pre {
+ jump rpfilter
+
+ tcp flags & (fin|syn|rst|ack) != syn counter drop
+
+ iifname $public_if meta nfproto vmap { ipv4 : jump blacklist_input_ipv4, ipv6 : jump blacklist_input_ipv6 }
+ }
+ chain rpfilter {
+ ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp sport bootpc udp dport bootps return
+ ip6 saddr ::/128 ip6 daddr . icmpv6 type { ff02::1:ff00:0/104 . nd-neighbor-solicit, ff02::16 . mld2-listener-report } return
+
+ fib saddr . iif oif eq 0 counter drop
+ }
+ chain blacklist_input_ipv4{
+ ip saddr $bogons_ip counter drop
+ ip saddr @ipv4_blacklist counter drop
+ }
+ chain blacklist_input_ipv6{
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 return
+ udp sport dhcpv6-server ip6 saddr fe80::/64 return
+
+ ip6 saddr $bogons_ip6 counter drop
+ ip6 saddr @ipv6_blacklist counter drop
+ }
+
+ chain INPUT {
+ type filter hook input priority filter; policy drop;
+
+ iif lo accept
+
+ ct state established,related accept
+
+ iifname vmap @if_input
+
+ log prefix "NFT REJECT IN " flags ether flags ip options limit rate 5/second burst 10 packets reject
+ }
+ chain public_input {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 ip6 hoplimit 255 accept
+
+ udp sport dhcpv6-server udp dport dhcpv6-client ip6 saddr fe80::/64 accept
+ fib daddr type { broadcast, multicast, anycast } counter drop
+
+ counter drop
+ }
+ chain home_input {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+
+ udp sport bootpc udp dport bootps accept
+ udp sport dhcpv6-client udp dport dhcpv6-server iifname $home_ipv6_if accept
+
+ fib daddr type { broadcast, multicast, anycast } counter drop
+
+ icmp type echo-request accept
+ icmpv6 type echo-request accept
+
+ tcp dport ssh iifname $trusted_if accept
+
+ meta l4proto { tcp, udp } th dport domain jump {
+ ip6 saddr != $private_ip6 counter reject
+ accept
+ }
+
+ udp dport ntp accept
+
+ tcp dport $proxy_port accept
+ }
+
+ chain FORWARD_MANGLE {
+ type filter hook forward priority mangle;
+
+ oifname $public_if jump {
+ ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+ tcp flags & (syn|rst) == syn tcp option maxseg size set rt mtu
+ }
+ }
+ chain blacklist_output_ipv4 {
+ ip daddr $bogons_ip goto log_blacklist
+ ip daddr @ipv4_blacklist goto log_blacklist
+ }
+ chain blacklist_output_ipv6 {
+ icmpv6 type . ip6 daddr { nd-router-solicit . ff02::2/128, nd-neighbor-solicit . ff02::1:ff00:0/104, nd-neighbor-advert . fe80::/64, nd-neighbor-advert . ff02::1/128, nd-neighbor-advert . ff02::1:ff00:0/104, mld2-listener-report . ff02::16/128 } return
+ udp dport dhcpv6-server ip6 daddr ff02::1:2 return
+
+ ip6 daddr $bogons_ip6 goto log_blacklist
+ ip6 daddr @ipv6_blacklist goto log_blacklist
+ }
+ chain log_blacklist {
+ log prefix "NFT BLACKLIST " flags ether flags ip options limit rate 5/minute burst 10 packets drop
+ counter drop
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter; policy drop;
+
+ ct state established,related accept
+
+ fib daddr type { broadcast, multicast, anycast } counter drop
+
+ iifname vmap @if_forward
+
+ log prefix "NFT REJECT FWD " flags ether flags ip options limit rate 5/second burst 10 packets reject
+ }
+ chain public_forward {
+ udp dport { 5060, 7078-7097 } oifname $voip_if jump {
+ ip6 saddr $sip_whitelist_ip6 accept
+ meta nfproto ipv6 log prefix "NFT DROP SIP " flags ether flags ip options limit rate 5/second burst 10 packets drop
+ }
+
+ counter drop
+ }
+ chain trusted_forward {
+ oifname $public_if accept
+
+ icmp type echo-request accept
+ icmpv6 type echo-request accept
+
+ ip daddr { $host3_ip, $host4_ip } tcp dport vmap { ssh : accept, https : accept, http : drop }
+
+ ip daddr $host2_ip jump {
+ tcp dport { http, https, printer, ipp, 9100 } accept
+ udp dport snmp accept
+ }
+ }
+ chain voip_forward {
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } oifname $public_if accept
+
+ ip6 daddr $sip_whitelist_ip6 jump {
+ udp dport { 3478, 5060 } accept
+ udp sport { 7078-7097 } accept
+ tcp dport 5061 accept
+ }
+
+ tcp dport 587 ip daddr $smtps_whitelist_ip accept
+ tcp dport http oifname $public_if counter reject
+ }
+ chain guest_forward {
+ oifname $public_if accept
+ }
+
+ chain OUTPUT {
+ type filter hook output priority filter; policy drop;
+
+ oif lo accept
+
+ ct state vmap { established : accept, related : accept, invalid : jump ct_invalid_out, untracked : jump ct_untracked_out }
+
+ oifname vmap @if_output
+
+ log prefix "NFT REJECT OUT " flags ether flags ip options limit rate 5/second burst 10 packets reject
+ }
+ chain ct_invalid_out {
+ counter drop
+ }
+ chain ct_untracked_out {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld-listener-query, mld2-listener-report } return
+ counter drop
+ }
+ chain public_output {
+ ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+
+ icmp type { destination-unreachable, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+
+ udp dport dhcpv6-server ip6 saddr fe80::/64 ip6 daddr ff02::1:2 accept
+
+ udp dport { domain, ntp } accept
+ tcp dport { https, 587, domain-s } accept
+ }
+ chain home_output {
+ icmp type { destination-unreachable, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+
+ udp sport dhcpv6-server udp dport dhcpv6-client ip6 saddr fe80::/64 oifname $home_ipv6_if accept
+ udp sport bootps udp dport bootpc ip saddr $private_ip accept
+ tcp dport ssh ip daddr $host1_ip accept
+ }
+
+ chain POSTROUTING_SRCNAT {
+ type nat hook postrouting priority srcnat;
+
+ meta nfproto ipv4 ip saddr $masq_ip oifname $masq_if masquerade
+ }
+}
+EOF
diff --git a/tests/shell/testcases/nft-i/0001define_0 b/tests/shell/testcases/nft-i/0001define_0
new file mode 100755
index 0000000..62e1b6d
--- /dev/null
+++ b/tests/shell/testcases/nft-i/0001define_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+# test if using defines in interactive nft sessions works
+
+$NFT -i >/dev/null <<EOF
+add table inet t
+add chain inet t c
+define ports = { 22, 443 }
+add rule inet t c tcp dport \$ports accept
+add rule inet t c udp dport \$ports accept
+EOF
+
+$NFT -i >/dev/null <<EOF
+define port = 22
+flush chain inet t c
+redefine port = 443
+delete chain inet t c
+undefine port
+delete table inet t
+EOF
diff --git a/tests/shell/testcases/nft-i/dumps/0001define_0.nft b/tests/shell/testcases/nft-i/dumps/0001define_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/nft-i/dumps/0001define_0.nft
diff --git a/tests/shell/testcases/optimizations/dependency_kill b/tests/shell/testcases/optimizations/dependency_kill
new file mode 100755
index 0000000..904eecf
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dependency_kill
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table bridge foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip6 foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table netdev foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table inet foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ meta nfproto ipv4 udp dport 67
+ meta nfproto ipv6 udp dport 67
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/dumps/dependency_kill.nft b/tests/shell/testcases/optimizations/dumps/dependency_kill.nft
new file mode 100644
index 0000000..1781f7b
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/dependency_kill.nft
@@ -0,0 +1,42 @@
+table bridge foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip foo {
+ chain bar {
+ udp dport 67
+ meta protocol ip6 udp dport 67
+ udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip6 foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ udp dport 67
+ ether type ip udp dport 67
+ udp dport 67
+ }
+}
+table netdev foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table inet foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ meta nfproto ipv4 udp dport 67
+ meta nfproto ipv6 udp dport 67
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat.nft b/tests/shell/testcases/optimizations/dumps/merge_nat.nft
new file mode 100644
index 0000000..48d18a6
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat.nft
@@ -0,0 +1,40 @@
+table ip test1 {
+ chain y {
+ oif "lo" accept
+ dnat to ip saddr map { 4.4.4.4 : 1.1.1.1, 5.5.5.5 : 2.2.2.2 }
+ }
+}
+table ip test2 {
+ chain y {
+ oif "lo" accept
+ dnat ip to tcp dport map { 80 : 1.1.1.1 . 8001, 81 : 2.2.2.2 . 9001 }
+ ip saddr { 10.141.11.0/24, 10.141.13.0/24 } masquerade
+ }
+}
+table ip 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
+ }
+}
+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
+ }
+}
+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.nft b/tests/shell/testcases/optimizations/dumps/merge_reject.nft
new file mode 100644
index 0000000..c29ad6d
--- /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.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts.nft
new file mode 100644
index 0000000..b56ea3e
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip daddr { 192.168.0.1, 192.168.0.2, 192.168.0.3 } counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft
new file mode 100644
index 0000000..f56cea1
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft
@@ -0,0 +1,18 @@
+table ip x {
+ chain y {
+ iifname . ip saddr . ip daddr { "eth1" . 1.1.1.1 . 2.2.2.3, "eth1" . 1.1.1.2 . 2.2.2.4, "eth1" . 1.1.1.2 . 2.2.3.0/24, "eth1" . 1.1.1.2 . 2.2.4.0-2.2.4.10, "eth2" . 1.1.1.3 . 2.2.2.5 } accept
+ ip protocol . th dport { tcp . 22, udp . 67 }
+ }
+
+ chain c1 {
+ udp dport . iifname { 51820 . "foo", 514 . "bar", 67 . "bar" } accept
+ }
+
+ chain c2 {
+ udp dport . iifname { 100 . "foo", 51820 . "foo", 514 . "bar", 67 . "bar" } accept
+ }
+
+ chain c3 {
+ udp dport . iifname { 100 . "foo", 51820 . "foo", 514 . "bar", 67 . "bar", 100 . "test", 51820 . "test" } accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft
new file mode 100644
index 0000000..780aa09
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft
@@ -0,0 +1,9 @@
+table ip x {
+ chain x {
+ meta pkttype . udp dport vmap { broadcast . 547 : accept, broadcast . 67 : accept, multicast . 1900 : drop }
+ }
+
+ chain y {
+ ip saddr . ip daddr vmap { 1.1.1.1 . 2.2.2.2 : accept, 2.2.2.2 . 3.3.3.3 : drop, 4.4.4.4 . 5.5.5.5 : accept }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft
new file mode 100644
index 0000000..8ecbd92
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft
@@ -0,0 +1,13 @@
+table ip x {
+ chain y {
+ ct state vmap { invalid : drop, established : accept, related : accept }
+ }
+
+ chain z {
+ tcp dport vmap { 1 : accept, 2-3 : drop, 4 : accept }
+ }
+
+ chain w {
+ ip saddr vmap { 1.1.1.1 counter packets 0 bytes 0 : accept, 1.1.1.2 counter packets 0 bytes 0 : drop }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft b/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft
new file mode 100644
index 0000000..1884711
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft
@@ -0,0 +1,31 @@
+table inet x {
+ chain nat_dns_dnstc {
+ meta l4proto udp redirect to :5300
+ drop
+ }
+
+ chain nat_dns_this_5301 {
+ meta l4proto udp redirect to :5301
+ drop
+ }
+
+ chain nat_dns_saturn_5301 {
+ meta nfproto ipv4 meta l4proto udp dnat ip to 240.0.1.2:5301
+ drop
+ }
+
+ chain nat_dns_saturn_5302 {
+ meta nfproto ipv4 meta l4proto udp dnat ip to 240.0.1.2:5302
+ drop
+ }
+
+ chain nat_dns_saturn_5303 {
+ meta nfproto ipv4 meta l4proto udp dnat ip to 240.0.1.2:5303
+ drop
+ }
+
+ chain nat_dns_acme {
+ udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : goto nat_dns_dnstc, 62-78 . 0xe31393032383939353831343037320e : goto nat_dns_this_5301, 62-78 . 0xe31363436323733373931323934300e : goto nat_dns_saturn_5301, 62-78 . 0xe32393535373539353636383732310e : goto nat_dns_saturn_5302, 62-78 . 0xe38353439353637323038363633390e : goto nat_dns_saturn_5303 }
+ drop
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft b/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
new file mode 100644
index 0000000..c981acf
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
@@ -0,0 +1,20 @@
+table ip x {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain filter_in_tcp {
+ }
+
+ chain filter_in_udp {
+ }
+
+ chain y {
+ update @s { ip saddr limit rate 12/minute burst 30 packets } accept
+ tcp dport vmap { 80 : accept, 81 : accept, 443 : accept, 8000-8100 : accept, 24000-25000 : accept }
+ meta l4proto vmap { tcp : goto filter_in_tcp, udp : goto filter_in_udp }
+ log
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/not_mergeable.nft b/tests/shell/testcases/optimizations/dumps/not_mergeable.nft
new file mode 100644
index 0000000..02b8920
--- /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.nft b/tests/shell/testcases/optimizations/dumps/ruleset.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/ruleset.nft
diff --git a/tests/shell/testcases/optimizations/dumps/single_anon_set.nft b/tests/shell/testcases/optimizations/dumps/single_anon_set.nft
new file mode 100644
index 0000000..3f70303
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/single_anon_set.nft
@@ -0,0 +1,16 @@
+table ip test {
+ chain test {
+ ip saddr 127.0.0.1 accept
+ iif "lo" accept
+ tcp dport != 22 drop
+ ip saddr 127.0.0.0/8 accept
+ ip saddr 127.0.0.1-192.168.7.3 accept
+ tcp sport 1-1023 drop
+ ip daddr { 192.168.7.1, 192.168.7.5 } accept
+ tcp dport { 80, 443 } accept
+ ip daddr . tcp dport { 192.168.0.1 . 22 } accept
+ meta mark set ip daddr map { 192.168.0.1 : 0x00000001 }
+ ct state { established, related } accept
+ meta mark { 0x0000000a counter packets 0 bytes 0 }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/single_anon_set.nft.input b/tests/shell/testcases/optimizations/dumps/single_anon_set.nft.input
new file mode 100644
index 0000000..ecc5691
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/single_anon_set.nft.input
@@ -0,0 +1,38 @@
+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
+
+ # with stateful statement
+ meta mark { 0x0000000a counter }
+ }
+}
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 0000000..9c10b74
--- /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.nft b/tests/shell/testcases/optimizations/dumps/skip_non_eq.nft
new file mode 100644
index 0000000..6df3865
--- /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.nft b/tests/shell/testcases/optimizations/dumps/skip_unsupported.nft
new file mode 100644
index 0000000..f24855e
--- /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.nft b/tests/shell/testcases/optimizations/dumps/variables.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/variables.nft
diff --git a/tests/shell/testcases/optimizations/merge_nat b/tests/shell/testcases/optimizations/merge_nat
new file mode 100755
index 0000000..3a57d94
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_nat
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip test1 {
+ chain y {
+ oif lo accept
+ ip saddr 4.4.4.4 dnat to 1.1.1.1
+ ip saddr 5.5.5.5 dnat to 2.2.2.2
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip test2 {
+ chain y {
+ oif lo accept
+ tcp dport 80 dnat to 1.1.1.1:8001
+ tcp dport 81 dnat to 2.2.2.2:9001
+ ip saddr 10.141.11.0/24 masquerade
+ ip saddr 10.141.13.0/24 masquerade
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip 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
+
+RULESET="table ip test4 {
+ chain y {
+ oif lo accept
+ ip daddr 1.1.1.1 tcp dport 80 dnat to 4.4.4.4:8000
+ ip daddr 2.2.2.2 tcp dport 81 dnat to 3.3.3.3:9000
+ tcp dport 83 redirect to :8083
+ tcp dport 84 redirect to :8084
+ tcp dport 85 redirect
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+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 0000000..c0ef9ca
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_reject
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ meta l4proto tcp ip daddr 172.30.33.70 tcp dport 3306 counter packets 0 bytes 0 drop
+ meta l4proto tcp ip daddr 172.30.33.71 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip daddr 172.30.238.117 tcp dport 8080 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip daddr 172.30.254.251 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip daddr 172.30.254.252 tcp dport 3306 counter packets 0 bytes 0 reject with tcp reset
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip6 x {
+ chain y {
+ meta l4proto tcp ip6 daddr aaaa::2 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip6 daddr aaaa::3 tcp dport 8080 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip6 daddr aaaa::4 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip6 daddr aaaa::5 tcp dport 3306 counter packets 0 bytes 0 reject with tcp reset
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts b/tests/shell/testcases/optimizations/merge_stmts
new file mode 100755
index 0000000..ec7a9dd
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ ip daddr 192.168.0.1 counter accept comment "test1"
+ ip daddr 192.168.0.2 counter accept comment "test2"
+ ip daddr 192.168.0.3 counter accept comment "test3"
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts_concat b/tests/shell/testcases/optimizations/merge_stmts_concat
new file mode 100755
index 0000000..9679d86
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts_concat
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ meta iifname eth1 ip saddr 1.1.1.1 ip daddr 2.2.2.3 accept
+ meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.2.4 accept
+ meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.3.0/24 accept
+ meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.4.0-2.2.4.10 accept
+ meta iifname eth2 ip saddr 1.1.1.3 ip daddr 2.2.2.5 accept
+ ip protocol . th dport { tcp . 22, udp . 67 }
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip x {
+ chain c1 {
+ udp dport 51820 iifname "foo" accept
+ udp dport { 67, 514 } iifname "bar" accept
+ }
+
+ chain c2 {
+ udp dport { 51820, 100 } iifname "foo" accept
+ udp dport { 67, 514 } iifname "bar" accept
+ }
+
+ chain c3 {
+ udp dport { 51820, 100 } iifname { "foo", "test" } accept
+ udp dport { 67, 514 } iifname "bar" accept
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts_concat_vmap b/tests/shell/testcases/optimizations/merge_stmts_concat_vmap
new file mode 100755
index 0000000..657d0ae
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts_concat_vmap
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain x {
+ meta pkttype broadcast udp dport { 67, 547 } accept
+ meta pkttype multicast udp dport 1900 drop
+ }
+ chain y {
+ ip saddr 1.1.1.1 ip daddr 2.2.2.2 accept
+ ip saddr 4.4.4.4 ip daddr 5.5.5.5 accept
+ ip saddr 2.2.2.2 ip daddr 3.3.3.3 drop
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts_vmap b/tests/shell/testcases/optimizations/merge_stmts_vmap
new file mode 100755
index 0000000..6e0f076
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts_vmap
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ ct state invalid drop
+ ct state established,related accept
+ }
+ chain z {
+ tcp dport { 1 } accept
+ tcp dport 2-3 drop
+ tcp dport 4 accept
+ }
+ chain w {
+ ip saddr 1.1.1.1 counter accept
+ ip saddr 1.1.1.2 counter drop
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_vmap_raw b/tests/shell/testcases/optimizations/merge_vmap_raw
new file mode 100755
index 0000000..f3dc072
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_vmap_raw
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet x {
+ chain nat_dns_dnstc { meta l4proto udp redirect to :5300 ; drop ; }
+ chain nat_dns_this_5301 { meta l4proto udp redirect to :5301 ; drop ; }
+ chain nat_dns_saturn_5301 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5301 ; drop ; }
+ chain nat_dns_saturn_5302 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5302 ; drop ; }
+ chain nat_dns_saturn_5303 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5303 ; drop ; }
+
+ chain nat_dns_acme {
+ udp length 47-63 @th,160,128 0x0e373135363130333131303735353203 \
+ goto nat_dns_dnstc
+
+ udp length 62-78 @th,160,128 0x0e31393032383939353831343037320e \
+ goto nat_dns_this_5301
+
+ udp length 62-78 @th,160,128 0x0e31363436323733373931323934300e \
+ goto nat_dns_saturn_5301
+
+ udp length 62-78 @th,160,128 0x0e32393535373539353636383732310e \
+ goto nat_dns_saturn_5302
+
+ udp length 62-78 @th,160,128 0x0e38353439353637323038363633390e \
+ goto nat_dns_saturn_5303
+
+ drop
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_vmaps b/tests/shell/testcases/optimizations/merge_vmaps
new file mode 100755
index 0000000..e2e4be1
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_vmaps
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ set s {
+ type ipv4_addr
+ flags dynamic
+ }
+ chain filter_in_tcp {
+ }
+ chain filter_in_udp {
+ }
+ chain y {
+ update @s { ip saddr limit rate 12/minute burst 30 packets } accept
+ tcp dport vmap {
+ 80 : accept,
+ 81 : accept,
+ 443 : accept,
+ }
+ tcp dport vmap {
+ 8000-8100 : accept,
+ 24000-25000 : accept,
+ }
+ meta l4proto tcp goto filter_in_tcp
+ meta l4proto udp goto filter_in_udp
+ log
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/not_mergeable b/tests/shell/testcases/optimizations/not_mergeable
new file mode 100755
index 0000000..ddb2f0f
--- /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 0000000..ef2652d
--- /dev/null
+++ b/tests/shell/testcases/optimizations/ruleset
@@ -0,0 +1,168 @@
+#!/bin/bash
+
+RULESET="table inet uni {
+ chain gtfo {
+ reject with icmpx type host-unreachable
+ drop
+ }
+
+ chain filter_in_tcp {
+ tcp dport vmap {
+ 80 : accept,
+ 81 : accept,
+ 443 : accept,
+ 931 : accept,
+ 5001 : accept,
+ 5201 : accept,
+ }
+ tcp dport vmap {
+ 6800-6999 : accept,
+ 33434-33499 : accept,
+ }
+
+ drop
+ }
+
+ chain filter_in_udp {
+ udp dport vmap {
+ 53 : accept,
+ 123 : accept,
+ 846 : accept,
+ 849 : accept,
+ 5001 : accept,
+ 5201 : accept,
+ }
+ udp dport vmap {
+ 5300-5399 : accept,
+ 6800-6999 : accept,
+ 33434-33499 : accept,
+ }
+
+ drop
+ }
+
+ chain filter_in {
+ type filter hook input priority 0; policy drop;
+
+ ct state vmap {
+ invalid : drop,
+ established : accept,
+ related : accept,
+ untracked : accept,
+ }
+
+ ct status vmap {
+ dnat : accept,
+ snat : accept,
+ }
+
+ iif lo accept
+
+ meta iifgroup {100-199} accept
+
+ meta l4proto tcp goto filter_in_tcp
+ meta l4proto udp goto filter_in_udp
+
+ icmp type vmap {
+ echo-request : accept,
+ }
+ ip6 nexthdr icmpv6 icmpv6 type vmap {
+ echo-request : accept,
+ }
+ }
+
+ chain filter_fwd_ifgroup {
+ meta iifgroup . oifgroup vmap {
+ 100 . 10 : accept,
+ 100 . 100 : accept,
+ 100 . 101 : accept,
+ 101 . 101 : accept,
+ }
+ goto gtfo
+ }
+
+ chain filter_fwd {
+ type filter hook forward priority 0; policy drop;
+
+ fib daddr type broadcast drop
+
+ ct state vmap {
+ invalid : drop,
+ established : accept,
+ related : accept,
+ untracked : accept,
+ }
+
+ ct status vmap {
+ dnat : accept,
+ snat : accept,
+ }
+
+ meta iifgroup {100-199} goto filter_fwd_ifgroup
+ }
+
+ chain nat_fwd_tun {
+ meta l4proto tcp redirect to :15
+ udp dport 53 redirect to :13
+ goto gtfo
+ }
+
+ chain nat_dns_dnstc { meta l4proto udp redirect to :5300 ; drop ; }
+ chain nat_dns_this_5301 { meta l4proto udp redirect to :5301 ; drop ; }
+ chain nat_dns_moon_5301 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5301 ; drop ; }
+ chain nat_dns_moon_5302 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5302 ; drop ; }
+ chain nat_dns_moon_5303 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5303 ; drop ; }
+
+ chain nat_dns_acme {
+ udp length 47-63 @th,160,128 0x0e373135363130333131303735353203 \
+ goto nat_dns_dnstc
+
+ udp length 62-78 @th,160,128 0x0e31393032383939353831343037320e \
+ goto nat_dns_this_5301
+
+ udp length 62-78 @th,160,128 0x0e31363436323733373931323934300e \
+ goto nat_dns_moon_5301
+
+ udp length 62-78 @th,160,128 0x0e32393535373539353636383732310e \
+ goto nat_dns_moon_5302
+
+ udp length 62-78 @th,160,128 0x0e38353439353637323038363633390e \
+ goto nat_dns_moon_5303
+
+ drop
+ }
+
+ chain nat_prerouting {
+ type nat hook prerouting priority -100; policy accept;
+
+ iifgroup 10 udp dport 53 goto nat_dns_acme
+ iifgroup 10 accept
+
+ ip daddr 198.19.0.0/16 goto nat_fwd_tun
+ ip6 daddr fc00::/8 goto nat_fwd_tun
+
+ tcp dport 53 redirect to :25302
+ udp dport 53 redirect to :25302
+ }
+
+ chain nat_output {
+ type nat hook output priority -100; policy accept;
+
+ ip daddr 198.19.0.0/16 goto nat_fwd_tun
+ ip6 daddr fc00::/8 goto nat_fwd_tun
+ }
+
+ chain nat_postrouting {
+ type nat hook postrouting priority 100; policy accept;
+
+ oif != lo masquerade
+ }
+
+ chain mangle_forward {
+ type filter hook forward priority -150; policy accept;
+
+ tcp flags & (syn | rst) == syn tcp option maxseg size set rt mtu
+ }
+}"
+
+$NFT -o -c -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/single_anon_set b/tests/shell/testcases/optimizations/single_anon_set
new file mode 100755
index 0000000..7275e36
--- /dev/null
+++ b/tests/shell/testcases/optimizations/single_anon_set
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+# 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
+
+$NFT -f "$dumpfile".input
diff --git a/tests/shell/testcases/optimizations/skip_merge b/tests/shell/testcases/optimizations/skip_merge
new file mode 100755
index 0000000..8af976c
--- /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 0000000..431ed0a
--- /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 0000000..6baa828
--- /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 0000000..fa98606
--- /dev/null
+++ b/tests/shell/testcases/optimizations/variables
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define addrv4_vpnnet = 10.1.0.0/16
+
+table ip nat {
+ chain postrouting {
+ type nat hook postrouting priority 0; policy accept;
+
+ ip saddr \$addrv4_vpnnet counter masquerade fully-random comment \"masquerade ipv4\"
+ }
+}"
+
+$NFT -c -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optionals/comments_0 b/tests/shell/testcases/optionals/comments_0
new file mode 100755
index 0000000..ab85936
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# comments are shown
+
+$NFT add table test
+$NFT add chain test test
+$NFT add rule test test tcp dport 22 counter accept comment test_comment
+$NFT -a list table test | grep 'accept comment \"test_comment\"' >/dev/null
diff --git a/tests/shell/testcases/optionals/comments_chain_0 b/tests/shell/testcases/optionals/comments_chain_0
new file mode 100755
index 0000000..fba961c
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_chain_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+EXPECTED='table ip test_table {
+ chain test_chain {
+ comment "test"
+ }
+}
+'
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/optionals/comments_handles_0 b/tests/shell/testcases/optionals/comments_handles_0
new file mode 100755
index 0000000..a01df1d
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_handles_0
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# handles and comments mix well
+
+$NFT add table test
+$NFT add chain test test
+$NFT add rule test test tcp dport 22 counter accept comment test_comment
+set -e
+$NFT -a list table test | grep 'accept comment \"test_comment\" # handle '[[:digit:]]$ >/dev/null
+$NFT list table test | grep 'accept comment \"test_comment\"' | grep -v '# handle '[[:digit:]]$ >/dev/null
diff --git a/tests/shell/testcases/optionals/comments_objects_0 b/tests/shell/testcases/optionals/comments_objects_0
new file mode 100755
index 0000000..7437c77
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_objects_0
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+EXPECTED='table ip filter {
+ quota q {
+ over 1200 bytes
+ comment "test1"
+ }
+
+ counter c {
+ packets 0 bytes 0
+ comment "test2"
+ }
+
+ ct helper h {
+ type "sip" protocol tcp
+ l3proto ip
+ comment "test3"
+ }
+
+ ct expectation e {
+ protocol tcp
+ dport 666
+ timeout 100ms
+ size 96
+ l3proto ip
+ comment "test4"
+ }
+
+ limit l {
+ rate 400/hour
+ comment "test5"
+ }
+
+ synproxy s {
+ mss 1460
+ wscale 2
+ comment "test6"
+ }
+}
+'
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/optionals/comments_objects_dup_0 b/tests/shell/testcases/optionals/comments_objects_dup_0
new file mode 100755
index 0000000..79d975a
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_objects_dup_0
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+EXPECTED='table ip filter {
+ quota q {
+ over 1200 bytes
+ comment "test1"
+ comment "test1"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ counter c {
+ packets 0 bytes 0
+ comment "test2"
+ comment "test2"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ ct helper h {
+ type "sip" protocol tcp
+ l3proto ip
+ comment "test3"
+ comment "test3"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ ct expectation e {
+ protocol tcp
+ dport 666
+ timeout 100ms
+ size 96
+ l3proto ip
+ comment "test4"
+ comment "test4"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ limit l {
+ rate 400/hour
+ comment "test5"
+ comment "test5"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ synproxy s {
+ mss 1460
+ wscale 2
+ comment "test6"
+ comment "test6"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
diff --git a/tests/shell/testcases/optionals/comments_table_0 b/tests/shell/testcases/optionals/comments_table_0
new file mode 100755
index 0000000..a0dfd74
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_table_0
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+# comments are shown
+
+$NFT add table test { comment \"test_comment\"\; }
diff --git a/tests/shell/testcases/optionals/delete_object_handles_0 b/tests/shell/testcases/optionals/delete_object_handles_0
new file mode 100755
index 0000000..9b65e67
--- /dev/null
+++ b/tests/shell/testcases/optionals/delete_object_handles_0
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+set -e
+$NFT add table test-ip
+$NFT add counter test-ip https-traffic
+$NFT add quota test-ip https-quota 25 mbytes
+$NFT add map test-ip ports { type inet_service : quota \; }
+$NFT add table ip6 test-ip6
+$NFT add quota ip6 test-ip6 http-quota over 25 mbytes
+$NFT add counter ip6 test-ip6 http-traffic
+$NFT add quota ip6 test-ip6 ssh-quota 10 mbytes
+
+counter_handle=$($NFT -a list ruleset | awk '/https-traffic/{print $NF}')
+quota_handle=$($NFT -a list ruleset | awk '/ssh-quota/{print $NF}')
+$NFT delete counter test-ip handle $counter_handle
+$NFT delete quota ip6 test-ip6 handle $quota_handle
+
+EXPECTED="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
+ }
+}"
+
+GET="$($NFT list ruleset)"
+
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/optionals/dumps/comments_0.nft b/tests/shell/testcases/optionals/dumps/comments_0.nft
new file mode 100644
index 0000000..f47e0d5
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_0.nft
@@ -0,0 +1,5 @@
+table ip test {
+ chain test {
+ tcp dport 22 counter packets 0 bytes 0 accept comment "test_comment"
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_chain_0.nft b/tests/shell/testcases/optionals/dumps/comments_chain_0.nft
new file mode 100644
index 0000000..be3d8f3
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_chain_0.nft
@@ -0,0 +1,5 @@
+table ip test_table {
+ chain test_chain {
+ comment "test"
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_handles_0.nft b/tests/shell/testcases/optionals/dumps/comments_handles_0.nft
new file mode 100644
index 0000000..f47e0d5
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_handles_0.nft
@@ -0,0 +1,5 @@
+table ip test {
+ chain test {
+ tcp dport 22 counter packets 0 bytes 0 accept comment "test_comment"
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_objects_0.nft b/tests/shell/testcases/optionals/dumps/comments_objects_0.nft
new file mode 100644
index 0000000..b760ced
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_objects_0.nft
@@ -0,0 +1,37 @@
+table ip filter {
+ quota q {
+ comment "test1"
+ over 1200 bytes
+ }
+
+ counter c {
+ comment "test2"
+ packets 0 bytes 0
+ }
+
+ ct helper h {
+ comment "test3"
+ type "sip" protocol tcp
+ l3proto ip
+ }
+
+ ct expectation e {
+ comment "test4"
+ protocol tcp
+ dport 666
+ timeout 100ms
+ size 96
+ l3proto ip
+ }
+
+ limit l {
+ comment "test5"
+ rate 400/hour
+ }
+
+ synproxy s {
+ comment "test6"
+ mss 1460
+ wscale 2
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft b/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft
diff --git a/tests/shell/testcases/optionals/dumps/comments_table_0.nft b/tests/shell/testcases/optionals/dumps/comments_table_0.nft
new file mode 100644
index 0000000..32ae3c2
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_table_0.nft
@@ -0,0 +1,3 @@
+table ip test {
+ comment "test_comment"
+}
diff --git a/tests/shell/testcases/optionals/dumps/delete_object_handles_0.nft b/tests/shell/testcases/optionals/dumps/delete_object_handles_0.nft
new file mode 100644
index 0000000..aac03cc
--- /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.nft b/tests/shell/testcases/optionals/dumps/handles_0.nft
new file mode 100644
index 0000000..085c6cf
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/handles_0.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/handles_1.nft b/tests/shell/testcases/optionals/dumps/handles_1.nft
new file mode 100644
index 0000000..085c6cf
--- /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.nft b/tests/shell/testcases/optionals/dumps/log_prefix_0.nft
new file mode 100644
index 0000000..8c11d69
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/log_prefix_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ct state invalid log prefix "invalid state match, logging:"
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/update_object_handles_0.nft b/tests/shell/testcases/optionals/dumps/update_object_handles_0.nft
new file mode 100644
index 0000000..f391b63
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/update_object_handles_0.nft
@@ -0,0 +1,9 @@
+table ip test-ip {
+ counter traffic-counter {
+ packets 0 bytes 0
+ }
+
+ quota traffic-quota {
+ 50 mbytes
+ }
+}
diff --git a/tests/shell/testcases/optionals/handles_0 b/tests/shell/testcases/optionals/handles_0
new file mode 100755
index 0000000..80f3c5b
--- /dev/null
+++ b/tests/shell/testcases/optionals/handles_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# handles are shown last
+
+$NFT add table test
+$NFT add chain test test
+$NFT add rule test test tcp dport 22 counter accept
+$NFT -a list table test | grep 'accept # handle '[[:digit:]]$ >/dev/null
diff --git a/tests/shell/testcases/optionals/handles_1 b/tests/shell/testcases/optionals/handles_1
new file mode 100755
index 0000000..c00abfe
--- /dev/null
+++ b/tests/shell/testcases/optionals/handles_1
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# handles are not shown if not asked for them
+
+$NFT add table test
+$NFT add chain test test
+$NFT add rule test test tcp dport 22 counter accept
+( $NFT list table test | grep 'accept # handle '[[:digit:]]$ >/dev/null ) && exit 1
+
+exit 0
diff --git a/tests/shell/testcases/optionals/log_prefix_0 b/tests/shell/testcases/optionals/log_prefix_0
new file mode 100755
index 0000000..513a9e7
--- /dev/null
+++ b/tests/shell/testcases/optionals/log_prefix_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+TMP=$(mktemp)
+
+RULESET='define test = "state"
+define foo = "match, logging"
+
+table x {
+ chain y {
+ ct state invalid log prefix "invalid $test $foo:"
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/optionals/update_object_handles_0 b/tests/shell/testcases/optionals/update_object_handles_0
new file mode 100755
index 0000000..8b12b8c
--- /dev/null
+++ b/tests/shell/testcases/optionals/update_object_handles_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+$NFT add table test-ip
+$NFT add counter test-ip traffic-counter
+$NFT add counter test-ip traffic-counter
+$NFT add quota test-ip traffic-quota 25 mbytes
+$NFT add quota test-ip traffic-quota 50 mbytes
+
+EXPECTED="table ip test-ip {
+ counter traffic-counter {
+ packets 0 bytes 0
+ }
+
+ quota traffic-quota {
+ 50 mbytes
+ }
+}"
+
+GET="$($NFT list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/owner/0001-flowtable-uaf b/tests/shell/testcases/owner/0001-flowtable-uaf
new file mode 100755
index 0000000..c07e8d6
--- /dev/null
+++ b/tests/shell/testcases/owner/0001-flowtable-uaf
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_table_flag_owner)
+
+set -e
+
+$NFT -f - <<EOF
+table t {
+ flags owner
+ flowtable f {
+ hook ingress priority 0
+ devices = { lo }
+ }
+}
+EOF
+
+# trigger uaf.
+$NFT -f - <<EOF
+table t {
+ flags owner
+ flowtable f {
+ hook ingress priority 0
+ devices = { lo }
+ }
+}
+EOF
diff --git a/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft b/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/packetpath/dumps/vlan_8021ad_tag.nodump
diff --git a/tests/shell/testcases/packetpath/vlan_8021ad_tag b/tests/shell/testcases/packetpath/vlan_8021ad_tag
new file mode 100755
index 0000000..379a571
--- /dev/null
+++ b/tests/shell/testcases/packetpath/vlan_8021ad_tag
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1ifname-$rnd"
+ns2="nft2ifname-$rnd"
+
+cleanup()
+{
+ ip netns del "$ns1"
+ ip netns del "$ns2"
+}
+
+trap cleanup EXIT
+
+set -e
+
+ip netns add "$ns1"
+ip netns add "$ns2"
+ip -net "$ns1" link set lo up
+ip -net "$ns2" link set lo up
+
+ip link add veth0 netns $ns1 type veth peer name veth0 netns $ns2
+
+ip -net "$ns1" link set veth0 addr da:d3:00:01:02:03
+
+ip -net "$ns1" link add vlan123 link veth0 type vlan id 123 proto 802.1ad
+ip -net "$ns2" link add vlan123 link veth0 type vlan id 123 proto 802.1ad
+
+
+for dev in veth0 vlan123; do
+ ip -net "$ns1" link set $dev up
+ ip -net "$ns2" link set $dev up
+done
+
+ip -net "$ns1" addr add 10.1.1.1/24 dev vlan123
+ip -net "$ns2" addr add 10.1.1.2/24 dev vlan123
+
+ip netns exec "$ns2" $NFT -f /dev/stdin <<"EOF"
+table netdev t {
+ chain c {
+ type filter hook ingress device veth0 priority filter;
+ ether saddr da:d3:00:01:02:03 ether type 8021ad vlan id 123 ip daddr 10.1.1.2 icmp type echo-request counter
+ }
+}
+EOF
+
+ip netns exec "$ns1" ping -c 1 10.1.1.2
+
+ip netns exec "$ns2" $NFT list ruleset
+ip netns exec "$ns2" $NFT list chain netdev t c | grep 'counter packets 1 bytes 84'
diff --git a/tests/shell/testcases/parsing/describe b/tests/shell/testcases/parsing/describe
new file mode 100755
index 0000000..2ee072e
--- /dev/null
+++ b/tests/shell/testcases/parsing/describe
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+errmsg='Error: unknown ip option type/field'
+
+str=$($NFT describe ip option rr value 2>&1 | head -n 1)
+
+[ "$str" = "$errmsg" ] && exit 0
diff --git a/tests/shell/testcases/parsing/dumps/describe.nft b/tests/shell/testcases/parsing/dumps/describe.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/describe.nft
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 0000000..1583275
--- /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.nft b/tests/shell/testcases/parsing/dumps/log.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/log.nft
diff --git a/tests/shell/testcases/parsing/dumps/octal.nft b/tests/shell/testcases/parsing/dumps/octal.nft
new file mode 100644
index 0000000..e69de29
--- /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 0000000..fac0afa
--- /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 0000000..0b89d58
--- /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 0000000..09ac26e
--- /dev/null
+++ b/tests/shell/testcases/parsing/octal
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+$NFT add table t || exit 1
+$NFT add chain t c || exit 1
+$NFT add rule t c 'ip saddr 01 continue comment "0.0.0.1"' || exit 1
+$NFT add rule t c 'ip saddr 08 continue comment "error"' && {
+ echo "'"ip saddr 08"'" not rejected 1>&2
+ exit 1
+}
+$NFT delete table t || exit 1
+
+exit 0
+
diff --git a/tests/shell/testcases/rule_management/0001addinsertposition_0 b/tests/shell/testcases/rule_management/0001addinsertposition_0
new file mode 100755
index 0000000..237e9e3
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0001addinsertposition_0
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965 and the related fix
+# (regarding rule management with a given position/handle spec)
+
+set -e
+
+RULESET="flush ruleset
+table ip t {
+ chain c {
+ accept
+ accept
+ }
+}"
+
+EXPECTED="table ip t {
+ chain c {
+ accept
+ drop
+ accept
+ }
+}"
+
+for arg in "position 2" "handle 2" "index 0"; do
+ $NFT -f - <<< "$RULESET"
+ $NFT add rule t c $arg drop || {
+ $NFT list ruleset
+ exit 1
+ }
+
+ GET="$($NFT list ruleset)"
+ if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+ fi
+done
+
+for arg in "position 3" "handle 3" "index 1"; do
+ $NFT -f - <<< "$RULESET"
+ $NFT insert rule t c $arg drop
+
+ GET="$($NFT list ruleset)"
+ if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+ fi
+done
+
+EXPECTED="table ip t {
+ chain c {
+ accept
+ accept
+ drop
+ }
+}"
+
+for arg in "position 3" "handle 3" "index 1"; do
+ $NFT -f - <<< "$RULESET"
+ $NFT add rule t c $arg drop
+
+ GET="$($NFT list ruleset)"
+ if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+ fi
+done
+
+EXPECTED="table ip t {
+ chain c {
+ drop
+ accept
+ accept
+ }
+}"
+
+for arg in "position 2" "handle 2" "index 0"; do
+ $NFT -f - <<< "$RULESET"
+ $NFT insert rule t c $arg drop
+
+ GET="$($NFT list ruleset)"
+ if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+ fi
+done
diff --git a/tests/shell/testcases/rule_management/0002addinsertlocation_1 b/tests/shell/testcases/rule_management/0002addinsertlocation_1
new file mode 100755
index 0000000..920032f
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0002addinsertlocation_1
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# test rule adding with invalid position/handle/index value
+
+RULESET="flush ruleset
+table ip t {
+ chain c {
+ accept
+ accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+for cmd in add insert; do
+ for keyword in position handle index; do
+ $NFT $cmd rule t c $keyword 5 drop 2>/dev/null || continue
+
+ echo "E: invalid $keyword value allowed in $cmd command" >&2
+ exit 1
+ done
+done
+exit 0
diff --git a/tests/shell/testcases/rule_management/0003insert_0 b/tests/shell/testcases/rule_management/0003insert_0
new file mode 100755
index 0000000..c343d57
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0003insert_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965
+# (regarding rule management with a given position/handle spec)
+
+set -e
+$NFT add table t
+$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/0004replace_0 b/tests/shell/testcases/rule_management/0004replace_0
new file mode 100755
index 0000000..c3329af
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0004replace_0
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965 and the related fix
+# (regarding rule management with a given position/handle spec)
+
+set -e
+$NFT add table t
+$NFT add chain t c
+$NFT add rule t c accept # should have handle 2
+$NFT replace rule t c handle 2 drop
diff --git a/tests/shell/testcases/rule_management/0005replace_1 b/tests/shell/testcases/rule_management/0005replace_1
new file mode 100755
index 0000000..d8d6447
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0005replace_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965 and the related fix
+# (regarding rule management with a given position/handle spec)
+
+set -e
+$NFT add table t
+$NFT add chain t c
+# kernel should return ENOENT
+
+$NFT replace rule t c handle 2 drop 2>/dev/null || exit 0
+echo "E: missing kernel ENOENT" >&2
+exit 1
diff --git a/tests/shell/testcases/rule_management/0006replace_1 b/tests/shell/testcases/rule_management/0006replace_1
new file mode 100755
index 0000000..b728310
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0006replace_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965 and the related fix
+# (regarding rule management with a given position/handle spec)
+
+set -e
+$NFT add table t
+$NFT add chain t c
+
+# position keyword with replace action is not allowed, this should fail
+$NFT replace rule t c position 2 drop 2>/dev/null || exit 0
+echo "E: allowed replace with position specification" >&2
+exit 1
diff --git a/tests/shell/testcases/rule_management/0007delete_0 b/tests/shell/testcases/rule_management/0007delete_0
new file mode 100755
index 0000000..11376cc
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0007delete_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965 and the related fix
+# (regarding rule management with a given position/handle spec)
+
+set -e
+$NFT add table t
+$NFT add chain t c
+$NFT add rule t c accept # should have handle 2
+$NFT add rule t c drop # should have handle 3
+$NFT delete rule t c handle 2
diff --git a/tests/shell/testcases/rule_management/0008delete_1 b/tests/shell/testcases/rule_management/0008delete_1
new file mode 100755
index 0000000..d1900d6
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0008delete_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965 and the related fix
+# (regarding rule management with a given position/handle spec)
+
+set -e
+$NFT add table t
+$NFT add chain t c
+
+# this should fail, we don't allow delete with position
+$NFT delete rule t c position 2 drop 2>/dev/null || exit 0
+echo "E: allowed position spec with delete action" >&2
+exit 1
diff --git a/tests/shell/testcases/rule_management/0009delete_1 b/tests/shell/testcases/rule_management/0009delete_1
new file mode 100755
index 0000000..8751fec
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0009delete_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# tests for Netfilter bug #965 and the related fix
+# (regarding rule management with a given position/handle spec)
+
+set -e
+$NFT add table t
+$NFT add chain t c
+
+# kernel ENOENT
+$NFT delete rule t c handle 3333 2>/dev/null || exit 0
+echo "E: missing kernel ENOENT" >&2
+exit 1
diff --git a/tests/shell/testcases/rule_management/0010replace_0 b/tests/shell/testcases/rule_management/0010replace_0
new file mode 100755
index 0000000..cd69a89
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0010replace_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# test for kernel commit ca08987885a147643817d02bf260bc4756ce8cd4
+# ("netfilter: nf_tables: deactivate expressions in rule replecement routine")
+
+set -e
+$NFT add table t
+$NFT add chain t c1
+$NFT add chain t c2
+$NFT add rule ip t c1 jump c2
+$NFT replace rule ip t c1 handle 3 accept
+$NFT flush ruleset
diff --git a/tests/shell/testcases/rule_management/0011reset_0 b/tests/shell/testcases/rule_management/0011reset_0
new file mode 100755
index 0000000..33eadd9
--- /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 0000000..a058150
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.nft
new file mode 100644
index 0000000..527d79d
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.nft
new file mode 100644
index 0000000..b76cd93
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0003insert_0.nft
new file mode 100644
index 0000000..b1875ab
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0003insert_0.nft
@@ -0,0 +1,8 @@
+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.nft b/tests/shell/testcases/rule_management/dumps/0004replace_0.nft
new file mode 100644
index 0000000..e20952e
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0004replace_0.nft
@@ -0,0 +1,5 @@
+table ip t {
+ chain c {
+ drop
+ }
+}
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 0000000..1e0d1d6
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0006replace_1.nft
new file mode 100644
index 0000000..1e0d1d6
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0007delete_0.nft
new file mode 100644
index 0000000..e20952e
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0007delete_0.nft
@@ -0,0 +1,5 @@
+table ip t {
+ chain c {
+ drop
+ }
+}
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 0000000..1e0d1d6
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0009delete_1.nft
new file mode 100644
index 0000000..1e0d1d6
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0010replace_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0010replace_0.nft
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 0000000..3b4f5a1
--- /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.nft b/tests/shell/testcases/rule_management/dumps/0012destroy_0.nft
new file mode 100644
index 0000000..1e0d1d6
--- /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/0001named_interval_0 b/tests/shell/testcases/sets/0001named_interval_0
new file mode 100755
index 0000000..612eee0
--- /dev/null
+++ b/tests/shell/testcases/sets/0001named_interval_0
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# This is the most basic testscase:
+# * creating a valid interval set
+# * referencing it from a valid rule
+
+RULESET="
+table inet t {
+ set s1 {
+ type ipv4_addr
+ flags interval
+ elements = { 10.0.0.0-11.0.0.0, 172.16.0.0/16 }
+ }
+ set s2 {
+ type ipv6_addr
+ flags interval
+ elements = { fe00::/64, fe11::-fe22::}
+ }
+ set s3 {
+ type inet_proto
+ flags interval
+ elements = { 10-20, 50-60}
+ }
+ set s4 {
+ type inet_service
+ flags interval
+ elements = {8080-8082, 0-1024, 10000-40000}
+ }
+ chain c {
+ ip saddr @s1 accept
+ ip6 daddr @s2 accept
+ ip protocol @s3 accept
+ ip6 nexthdr @s3 accept
+ tcp dport @s4 accept
+ }
+}"
+
+set -e
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0002named_interval_automerging_0 b/tests/shell/testcases/sets/0002named_interval_automerging_0
new file mode 100755
index 0000000..6889863
--- /dev/null
+++ b/tests/shell/testcases/sets/0002named_interval_automerging_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# This testscase checks the automerging of adjacent intervals
+
+set -e
+
+$NFT add table t
+$NFT add set t s { type ipv4_addr \; flags interval \; }
+$NFT add element t s { 192.168.0.0/24, 192.168.1.0/24 }
+$NFT list ruleset | grep "192.168.0.0/23" >/dev/null || exit 0
+echo "E: automerging of adjacent intervals happened unexpectedly." >&2
+exit 1
diff --git a/tests/shell/testcases/sets/0003named_interval_missing_flag_0 b/tests/shell/testcases/sets/0003named_interval_missing_flag_0
new file mode 100755
index 0000000..e0b7f74
--- /dev/null
+++ b/tests/shell/testcases/sets/0003named_interval_missing_flag_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# This testscase checks the nft checking of flags in named intervals
+
+set -e
+$NFT add table t
+$NFT add set t s { type ipv4_addr \; }
+if $NFT add element t s { 192.168.0.0/24, 192.168.1.0/24 } 2>/dev/null ; then
+ echo "E: accepted interval in named set without proper flags" >&2
+ exit 1
+fi
+exit 0
diff --git a/tests/shell/testcases/sets/0004named_interval_shadow_0 b/tests/shell/testcases/sets/0004named_interval_shadow_0
new file mode 100755
index 0000000..827423d
--- /dev/null
+++ b/tests/shell/testcases/sets/0004named_interval_shadow_0
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# This testscase checks the nft checking of shadowed elements
+
+set -e
+$NFT add table inet t
+$NFT add set inet t s { type ipv6_addr \; flags interval \; }
+$NFT add element inet t s { fe00::/64 }
+if $NFT add element inet t s { fe00::/48 } 2>/dev/null ; then
+ echo "E: accepted shadowed element in named set" >&2
+ exit 1
+fi
+exit 0
diff --git a/tests/shell/testcases/sets/0005named_interval_shadow_0 b/tests/shell/testcases/sets/0005named_interval_shadow_0
new file mode 100755
index 0000000..14fcbdc
--- /dev/null
+++ b/tests/shell/testcases/sets/0005named_interval_shadow_0
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# This testscase checks the nft checking of shadowed elements
+
+set -e
+$NFT add table inet t
+$NFT add set inet t s { type ipv6_addr \; flags interval \; }
+$NFT add element inet t s { fe00::/48 }
+if $NFT add element inet t s { fe00::/64 } 2>/dev/null ; then
+ echo "E: accepted shadowed element in named set" >&2
+ exit 1
+fi
+exit 0
diff --git a/tests/shell/testcases/sets/0006create_set_0 b/tests/shell/testcases/sets/0006create_set_0
new file mode 100755
index 0000000..ca36cf7
--- /dev/null
+++ b/tests/shell/testcases/sets/0006create_set_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# This testscase checks for add and create set commands.
+
+set -e
+$NFT add table t
+$NFT add set t s { type ipv4_addr \; }
+if $NFT create set t s { type ipv4_addr \; } 2>/dev/null ; then
+ echo "E: accepted set creation that already exists" >&2
+ exit 1
+fi
+$NFT add set t s { type ipv4_addr \; }
+
+exit 0
diff --git a/tests/shell/testcases/sets/0007create_element_0 b/tests/shell/testcases/sets/0007create_element_0
new file mode 100755
index 0000000..47b3559
--- /dev/null
+++ b/tests/shell/testcases/sets/0007create_element_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# This testcase checks for add and create element commands.
+
+set -e
+$NFT add table t
+$NFT add set t s { type ipv4_addr \; }
+$NFT add element t s { 1.1.1.1 }
+if $NFT create element t s { 1.1.1.1 } 2>/dev/null ; then
+ echo "E: accepted element creation that already exists" >&2
+ exit 1
+fi
+$NFT add element t s { 1.1.1.1 }
+
+exit 0
diff --git a/tests/shell/testcases/sets/0008comments_interval_0 b/tests/shell/testcases/sets/0008comments_interval_0
new file mode 100755
index 0000000..98c709c
--- /dev/null
+++ b/tests/shell/testcases/sets/0008comments_interval_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# This test netfilter bug #1090
+# https://bugzilla.netfilter.org/show_bug.cgi?id=1090
+
+$NFT add table t
+$NFT add set t s {type ipv4_addr \; flags interval \;}
+$NFT add element t s { 1.1.1.1 comment "test" }
+if ! $NFT list ruleset | grep test >/dev/null ; then
+ echo "E: missing comment in set element" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0008create_verdict_map_0 b/tests/shell/testcases/sets/0008create_verdict_map_0
new file mode 100755
index 0000000..e501049
--- /dev/null
+++ b/tests/shell/testcases/sets/0008create_verdict_map_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+RULESET="
+table ip t {
+ map sourcemap {
+ type ipv4_addr : verdict;
+ }
+ chain postrouting {
+ ip saddr vmap @sourcemap accept
+ }
+}
+add chain t c
+add element t sourcemap { 100.123.10.2 : jump c }
+"
+
+set -e
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0009comments_timeout_0 b/tests/shell/testcases/sets/0009comments_timeout_0
new file mode 100755
index 0000000..4e3f80c
--- /dev/null
+++ b/tests/shell/testcases/sets/0009comments_timeout_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Test that comments are added to set elements in timemout sets.
+
+$NFT flush ruleset
+$NFT add table t
+$NFT add set t s {type ipv4_addr \; flags timeout \;}
+$NFT add element t s { 1.1.1.1 comment "test" }
+if ! $NFT list ruleset | grep test >/dev/null ; then
+ echo "E: missing comment in set element" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0010comments_0 b/tests/shell/testcases/sets/0010comments_0
new file mode 100755
index 0000000..4467a3b
--- /dev/null
+++ b/tests/shell/testcases/sets/0010comments_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# Test that comments are added to set elements in standard sets.
+
+$NFT add table inet t
+$NFT add set inet t s {type ipv6_addr \; }
+$NFT add element inet t s { ::1 comment "test" }
+if ! $NFT list ruleset | grep test >/dev/null ; then
+ echo "E: missing comment in set element" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0011add_many_elements_0 b/tests/shell/testcases/sets/0011add_many_elements_0
new file mode 100755
index 0000000..c37b2f0
--- /dev/null
+++ b/tests/shell/testcases/sets/0011add_many_elements_0
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# 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
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate() {
+ echo -n "{"
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ echo -n "10.0.${i}.${j}"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ echo -n ", "
+ done
+ done
+ echo -n "}"
+}
+
+echo "add table x
+add set x y { type ipv4_addr; }
+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
new file mode 100755
index 0000000..6445160
--- /dev/null
+++ b/tests/shell/testcases/sets/0012add_delete_many_elements_0
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# 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
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate() {
+ echo -n "{"
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ echo -n "10.0.${i}.${j}"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ echo -n ", "
+ done
+ done
+ echo -n "}"
+}
+
+echo "add table x
+add set x y { type ipv4_addr; }
+add element x y $(generate)
+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
new file mode 100755
index 0000000..c0925dd
--- /dev/null
+++ b/tests/shell/testcases/sets/0013add_delete_many_elements_0
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# 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
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate() {
+ echo -n "{"
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ echo -n "10.0.${i}.${j}"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ echo -n ", "
+ done
+ done
+ echo -n "}"
+}
+
+set -e
+
+echo "add table x
+add set x y { type ipv4_addr; }
+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/0014malformed_set_is_not_defined_0 b/tests/shell/testcases/sets/0014malformed_set_is_not_defined_0
new file mode 100755
index 0000000..b34d71f
--- /dev/null
+++ b/tests/shell/testcases/sets/0014malformed_set_is_not_defined_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# This tests for the bug corrected in commit 5afa5a164ff1c066af1ec56d875b91562882bd50.
+# Sets were added to the table before checking for errors, and not removed from
+# the table on error, leading to an uninitialized set in the table, causing a
+# segfault for rules that tried to use it.
+# In this case, nft should error out because the set doesn't exist instead of
+# segfaulting
+
+RULESET="
+add table t
+add chain t c
+add set t s {type ipv4_addr\;}
+add rule t c ip saddr @s
+"
+
+$NFT -f - <<< "$RULESET"
+ret=$?
+
+trap - EXIT
+if [[ $ret -eq 1 ]]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0015rulesetflush_0 b/tests/shell/testcases/sets/0015rulesetflush_0
new file mode 100755
index 0000000..855d289
--- /dev/null
+++ b/tests/shell/testcases/sets/0015rulesetflush_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+RULESET="flush ruleset
+add table t
+add chain t c
+
+table inet filter {
+ set blacklist_v4 { type ipv4_addr; flags interval; }
+}
+
+add element inet filter blacklist_v4 {
+192.168.0.1/24,
+}"
+
+$NFT -f - <<< "$RULESET"
+
+# make sure flush ruleset works right
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0016element_leak_0 b/tests/shell/testcases/sets/0016element_leak_0
new file mode 100755
index 0000000..5675db3
--- /dev/null
+++ b/tests/shell/testcases/sets/0016element_leak_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# This tests for a bug where a repeated element is added and the set
+# elements counter is incorrectly increased.
+
+set -e
+$NFT add table x
+$NFT add set x s {type ipv4_addr\; size 2\;}
+$NFT add element x s {1.1.1.1}
+$NFT add element x s {1.1.1.1}
+$NFT add element x s {1.1.1.1}
diff --git a/tests/shell/testcases/sets/0017add_after_flush_0 b/tests/shell/testcases/sets/0017add_after_flush_0
new file mode 100755
index 0000000..0390b03
--- /dev/null
+++ b/tests/shell/testcases/sets/0017add_after_flush_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# This tests for a bug where elements can't be added after flushing a
+# full set with the flag NFTNL_SET_DESC_SIZE set
+
+set -e
+$NFT add table x
+$NFT add set x s {type ipv4_addr\; size 2\;}
+$NFT add element x s {1.1.1.1}
+$NFT add element x s {1.1.1.2}
+$NFT flush set x s
+$NFT add element x s {1.1.1.1}
diff --git a/tests/shell/testcases/sets/0018set_check_size_1 b/tests/shell/testcases/sets/0018set_check_size_1
new file mode 100755
index 0000000..bc70560
--- /dev/null
+++ b/tests/shell/testcases/sets/0018set_check_size_1
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+$NFT add table x
+$NFT add set x s {type ipv4_addr\; size 2\;}
+$NFT add element x s {1.1.1.1}
+$NFT add element x s {1.1.1.2}
+
+$NFT add element x s {1.1.1.3} || exit 0
+echo "E: Accepted 3rd element in a table with max size of 2" 1>&2
+exit 1
diff --git a/tests/shell/testcases/sets/0019set_check_size_0 b/tests/shell/testcases/sets/0019set_check_size_0
new file mode 100755
index 0000000..c209708
--- /dev/null
+++ b/tests/shell/testcases/sets/0019set_check_size_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+$NFT add table x
+$NFT add set x s {type ipv4_addr\; size 2\;}
+$NFT add element x s {1.1.1.1}
+$NFT add element x s {1.1.1.2}
+
+$NFT add element x s { 1.1.1.3 } 2>/dev/null
+if [ $? -eq 0 ]; then
+ echo "E: set is full, but element was added" >&2
+ exit 1
+fi
+#
+# Try again, this helps us catch incorrect set->nelems decrement from abort path
+#
+$NFT add element x s { 1.1.1.3 } 2>/dev/null
+if [ $? -eq 0 ]; then
+ echo "E: set is full, but element was added" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0020comments_0 b/tests/shell/testcases/sets/0020comments_0
new file mode 100755
index 0000000..44d451a
--- /dev/null
+++ b/tests/shell/testcases/sets/0020comments_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# Test that comments are added to set elements in standard sets.
+# Explicitly test bitmap backend set implementation.
+
+$NFT add table inet t
+$NFT add set inet t s {type inet_service \; }
+$NFT add element inet t s { 22 comment "test" }
+if ! $NFT list ruleset | grep test >/dev/null ; then
+ echo "E: missing comment in set element" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0021nesting_0 b/tests/shell/testcases/sets/0021nesting_0
new file mode 100755
index 0000000..0b90dc7
--- /dev/null
+++ b/tests/shell/testcases/sets/0021nesting_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+
+RULESET='
+define set1 = {
+ 2.2.2.0/24,
+ 3.3.3.0/24,
+}
+define set2 = {
+ $set1,
+ 1.1.1.0/24
+}
+table ip x {
+ chain y {
+ ip saddr { 3.3.3.0/24, $set2 }
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0022type_selective_flush_0 b/tests/shell/testcases/sets/0022type_selective_flush_0
new file mode 100755
index 0000000..6062913
--- /dev/null
+++ b/tests/shell/testcases/sets/0022type_selective_flush_0
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# This tests the selectiveness of flush command on structures that use the
+# generic set infrastructure (sets, maps and meters).
+
+RULESET="
+add table t
+add chain t c
+add set t s {type ipv4_addr;}
+add map t m {type ipv4_addr : inet_service;}
+add rule t c tcp dport 80 meter f size 1024 {ip saddr limit rate 10/second}
+"
+
+$NFT -f - <<< "$RULESET"
+
+# Commands that should be invalid
+
+declare -a cmds=(
+ "flush set t m" "flush set t f"
+ "flush map t s" "flush map t f"
+ "flush meter t s" "flush meter t m"
+ )
+
+for i in "${cmds[@]}"
+do
+ $NFT "$i" &>/dev/null
+ ret=$?
+
+ if [ $ret -eq 0 ]; then
+ exit 1
+ fi
+done
diff --git a/tests/shell/testcases/sets/0023incomplete_add_set_command_0 b/tests/shell/testcases/sets/0023incomplete_add_set_command_0
new file mode 100755
index 0000000..b7535f7
--- /dev/null
+++ b/tests/shell/testcases/sets/0023incomplete_add_set_command_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# This testscase checks bug identified and fixed in the commit Id "c6cd7c22548a"
+# Before the commit c6cd7c22548a, nft returns 139 (i.e, segmentation fault) which
+# indicates the bug but after the commit it returns 1.
+
+$NFT add table t
+$NFT add set t c
+
+ret=$?
+if [ $ret -ne 1 ] ;
+then
+ echo "E: returned $ret instead of 1" >&2
+ exit 1
+fi
+
diff --git a/tests/shell/testcases/sets/0024named_objects_0 b/tests/shell/testcases/sets/0024named_objects_0
new file mode 100755
index 0000000..6d21e38
--- /dev/null
+++ b/tests/shell/testcases/sets/0024named_objects_0
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+# This is the testscase:
+# * creating valid named objects
+# * referencing them from a valid rule
+
+RULESET="
+table inet x {
+ counter user123 {
+ packets 12 bytes 1433
+ }
+ counter user321 {
+ packets 12 bytes 1433
+ }
+ quota user123 {
+ over 2000 bytes
+ }
+ 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
+ }
+ map test {
+ 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
+ }
+}"
+
+set -e
+$NFT -f - <<< "$RULESET"
+
+EXPECTED="table inet x {
+ counter user321 {
+ packets 12 bytes 1433
+ }
+}"
+
+GET="$($NFT reset counter inet x user321)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0025anonymous_set_0 b/tests/shell/testcases/sets/0025anonymous_set_0
new file mode 100755
index 0000000..74777d8
--- /dev/null
+++ b/tests/shell/testcases/sets/0025anonymous_set_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Adding anonymous sets
+
+set -e
+
+$NFT add table t
+$NFT add chain t c { type filter hook output priority 0 \; }
+# set: IP addresses
+$NFT add rule t c ip daddr { \
+ 192.168.0.1, \
+ 192.168.0.2, \
+ 192.168.0.3, \
+}
+
+#set : tcp ports
+$NFT add rule t c meta oifname \"doesntexist\" tcp dport { 22, 23 } counter
diff --git a/tests/shell/testcases/sets/0026named_limit_0 b/tests/shell/testcases/sets/0026named_limit_0
new file mode 100755
index 0000000..11f1f5d
--- /dev/null
+++ b/tests/shell/testcases/sets/0026named_limit_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# This is the testscase:
+# * creating valid named limits
+# * referencing them from a valid rule
+
+RULESET="
+table ip filter {
+ limit http-traffic {
+ rate 1/second
+ }
+ chain input {
+ type filter hook input priority 0; policy accept;
+ limit name tcp dport map { 80 : "http-traffic", 443 : "http-traffic"}
+ }
+}"
+
+set -e
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0027ipv6_maps_ipv4_0 b/tests/shell/testcases/sets/0027ipv6_maps_ipv4_0
new file mode 100755
index 0000000..87603c5
--- /dev/null
+++ b/tests/shell/testcases/sets/0027ipv6_maps_ipv4_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Tests IPv4 Mapped IPv6 addresses.
+
+set -e
+
+RULESET="
+table inet t {
+ set s {
+ type ipv6_addr
+ flags interval
+ elements = { ::ffff:0.0.0.0/96 }
+ }
+}
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0028autoselect_0 b/tests/shell/testcases/sets/0028autoselect_0
new file mode 100755
index 0000000..23f43a2
--- /dev/null
+++ b/tests/shell/testcases/sets/0028autoselect_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# This testscase checks kernel picks a suitable set backends.
+# Ruleset attempts to update from packet path, so set backend
+# needs an ->update() implementation.
+
+set -e
+
+$NFT add table t
+$NFT add set t s1 { type inet_proto \; flags dynamic \; }
+$NFT add set t s2 { type ipv4_addr \; flags dynamic \; }
+$NFT add set t s3 { type ipv4_addr \; size 1024\; flags dynamic \; }
+$NFT add chain t c {type filter hook input priority 0 \; }
+
+$NFT add rule t c meta iifname foobar add @s1 { ip protocol }
+$NFT add rule t c meta iifname foobar add @s2 { ip daddr }
+$NFT add rule t c meta iifname foobar add @s3 { ip daddr }
diff --git a/tests/shell/testcases/sets/0028delete_handle_0 b/tests/shell/testcases/sets/0028delete_handle_0
new file mode 100755
index 0000000..c6d1253
--- /dev/null
+++ b/tests/shell/testcases/sets/0028delete_handle_0
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+set -e
+$NFT add table test-ip
+$NFT add set test-ip x { type ipv4_addr\; }
+$NFT add set test-ip y { type inet_service \; timeout 3h45s \;}
+$NFT add set test-ip z { type ipv4_addr\; flags constant , interval\;}
+$NFT add set test-ip c {type ipv4_addr \; flags timeout \; elements={192.168.1.1 timeout 10s, 192.168.1.2 timeout 30s} \;}
+
+set_handle=$($NFT -a list ruleset | awk '/set c/{print $NF}')
+$NFT delete set test-ip handle $set_handle
+
+EXPECTED="table ip test-ip {
+ set x {
+ type ipv4_addr
+ }
+
+ set y {
+ type inet_service
+ timeout 3h45s
+ }
+
+ set z {
+ type ipv4_addr
+ flags constant,interval
+ }
+}"
+
+GET="$($NFT list ruleset)"
+
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/sets/0029named_ifname_dtype_0 b/tests/shell/testcases/sets/0029named_ifname_dtype_0
new file mode 100755
index 0000000..2dbcd22
--- /dev/null
+++ b/tests/shell/testcases/sets/0029named_ifname_dtype_0
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+# support for ifname in named sets
+
+EXPECTED="table inet t {
+ set s {
+ type ifname
+ elements = { \"eth0\" }
+ }
+
+ set sc {
+ type inet_service . ifname
+ elements = { \"ssh\" . \"eth0\" }
+ }
+
+ set nv {
+ type ifname . mark
+ }
+
+ set z {
+ typeof ct zone
+ elements = { 1 }
+ }
+
+ set m {
+ typeof meta mark
+ elements = { 1 }
+ }
+
+ map cz {
+ typeof meta iifname : ct zone
+ elements = { \"veth4\" : 1 }
+ }
+
+ map cm {
+ typeof meta iifname : ct mark
+ elements = { \"veth4\" : 1 }
+ }
+
+ chain c {
+ iifname @s accept
+ oifname @s accept
+ tcp dport . meta iifname @sc accept
+ meta iifname . meta mark @nv accept
+ }
+}"
+
+set -e
+$NFT -f - <<< "$EXPECTED"
+$NFT add element inet t s '{ "eth1" }'
+$NFT add element inet t s '{ "eth2", "eth3", "veth1" }'
+
+$NFT add element inet t sc '{ 80 . "eth0" }'
+$NFT add element inet t sc '{ 80 . "eth0" }' || true
+$NFT add element inet t sc '{ 80 . "eth1" }'
+$NFT add element inet t sc '{ 81 . "eth0" }'
+
+$NFT add element inet t nv '{ "eth0" . 1 }'
+$NFT add element inet t nv '{ "eth0" . 2 }'
+
+$NFT add element inet t z '{ 2, 3, 4, 5, 6 }'
+$NFT add element inet t cz '{ "eth0" : 1, "eth1" : 2 }'
+
+$NFT add element inet t m '{ 2, 3, 4, 5, 6 }'
+$NFT add element inet t cm '{ "eth0" : 1, "eth1" : 2 }'
diff --git a/tests/shell/testcases/sets/0030add_many_elements_interval_0 b/tests/shell/testcases/sets/0030add_many_elements_interval_0
new file mode 100755
index 0000000..32a705b
--- /dev/null
+++ b/tests/shell/testcases/sets/0030add_many_elements_interval_0
@@ -0,0 +1,44 @@
+#!/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
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
+
+generate() {
+ echo -n "{"
+ for ((i=1; i<=HOWMANY; i++)) ; do
+ for ((j=1; j<=HOWMANY; j++)) ; do
+ echo -n "10.${i}.${j}.0/24"
+ [ "$i" == "$HOWMANY" ] && [ "$j" == "$HOWMANY" ] && break
+ echo -n ", "
+ done
+ done
+ echo -n "}"
+}
+
+echo "add table x
+add set x y { type ipv4_addr; flags interval; }
+add element x y $(generate)" > $tmpfile
+
+set -e
+$NFT -f $tmpfile
+
+if [ "$HOWMANY" != 255 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/0031set_timeout_size_0 b/tests/shell/testcases/sets/0031set_timeout_size_0
new file mode 100755
index 0000000..9a4a27f
--- /dev/null
+++ b/tests/shell/testcases/sets/0031set_timeout_size_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+RULESET="add table x
+add set x y { type ipv4_addr; size 128; timeout 30s; flags dynamic; }
+add chain x test
+add rule x test set update ip saddr timeout 1d2h3m4s10ms @y
+add rule x test set update ip daddr timeout 100ms @y"
+
+set -e
+$NFT -f - <<< "$RULESET"
+$NFT list chain x test | grep -q 'update @y { ip saddr timeout 1d2h3m4s\(10\|8\)ms }'
+$NFT list chain x test | grep -q 'update @y { ip daddr timeout 100ms }'
diff --git a/tests/shell/testcases/sets/0032restore_set_simple_0 b/tests/shell/testcases/sets/0032restore_set_simple_0
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/sets/0032restore_set_simple_0
@@ -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/0033add_set_simple_flat_0 b/tests/shell/testcases/sets/0033add_set_simple_flat_0
new file mode 100755
index 0000000..86be0c9
--- /dev/null
+++ b/tests/shell/testcases/sets/0033add_set_simple_flat_0
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+RULESET="add table ip x
+add set x setA {type ipv4_addr . inet_service . ipv4_addr; flags timeout;}
+add set x setB {type ipv4_addr . inet_service; flags timeout;}
+"
+
+set -e
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0034get_element_0 b/tests/shell/testcases/sets/0034get_element_0
new file mode 100755
index 0000000..3343529
--- /dev/null
+++ b/tests/shell/testcases/sets/0034get_element_0
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+RC=0
+
+check() { # (set, elems, expected)
+ out=$($NFT get element ip t $1 "{ $2 }")
+ out=$(grep "elements =" <<< "$out")
+ out="${out#* \{ }"
+ out="${out% \}}"
+ [[ "$out" == "$3" ]] && return
+ echo "ERROR: asked for '$2' in set $1, expecting '$3' but got '$out'"
+ ((RC++))
+}
+
+RULESET="add table ip t
+add set ip t s { type inet_service; flags interval; }
+add element ip t s { 10, 20-30, 40, 50-60 }
+add set ip t ips { type ipv4_addr; flags interval; }
+add element ip t ips { 10.0.0.1, 10.0.0.5-10.0.0.8 }
+add element ip t ips { 10.0.0.128/25, 10.0.1.0/24, 10.0.2.3-10.0.2.12 }
+add set ip t cs { type ipv4_addr . inet_service; flags interval; }
+add element ip t cs { 10.0.0.1 . 22, 10.1.0.0/16 . 1-1024 }
+add element ip t cs { 10.2.0.1-10.2.0.8 . 1024-65535 }
+"
+
+$NFT -f - <<< "$RULESET"
+
+# simple cases, (non-)existing values and ranges
+check s 10 10
+check s 11 ""
+check s 20-30 20-30
+check s 15-18 ""
+
+# multiple single elements, ranges smaller than present
+check s "10, 40" "10, 40"
+check s "22-24, 26-28" "20-30, 20-30"
+check s 21-29 20-30
+
+# mixed single elements and ranges
+check s "10, 20" "10, 20-30"
+check s "10, 22" "10, 20-30"
+check s "10, 22-24" "10, 20-30"
+
+# non-existing ranges matching elements
+check s 10-40 ""
+check s 10-20 ""
+check s 10-25 ""
+check s 25-55 ""
+
+# playing with IPs, ranges and prefixes
+check ips 10.0.0.1 10.0.0.1
+check ips 10.0.0.2 ""
+check ips 10.0.1.0/24 10.0.1.0/24
+check ips 10.0.1.2/31 10.0.1.0/24
+check ips 10.0.1.0 10.0.1.0/24
+check ips 10.0.1.3 10.0.1.0/24
+check ips 10.0.1.255 10.0.1.0/24
+check ips 10.0.2.3-10.0.2.12 10.0.2.3-10.0.2.12
+check ips 10.0.2.10 10.0.2.3-10.0.2.12
+check ips 10.0.2.12 10.0.2.3-10.0.2.12
+
+# test concatenated ranges, i.e. Pi, Pa and Po
+check cs "10.0.0.1 . 22" "10.0.0.1 . 22"
+check cs "10.0.0.1 . 23" ""
+check cs "10.0.0.2 . 22" ""
+check cs "10.1.0.1 . 42" "10.1.0.0/16 . 1-1024"
+check cs "10.1.1.0/24 . 10-20" "10.1.0.0/16 . 1-1024"
+check cs "10.2.0.3 . 20000" "10.2.0.1-10.2.0.8 . 1024-65535"
+
+exit $RC
diff --git a/tests/shell/testcases/sets/0035add_set_elements_flat_0 b/tests/shell/testcases/sets/0035add_set_elements_flat_0
new file mode 100755
index 0000000..d914ba9
--- /dev/null
+++ b/tests/shell/testcases/sets/0035add_set_elements_flat_0
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+RULESET="add table ip x
+add set x y {type ipv4_addr; flags interval;}
+add element x y { 10.0.24.0/24 }
+"
+
+set -e
+$NFT -f - <<< "$RULESET"
+$NFT delete element x y { 10.0.24.0/24 }
diff --git a/tests/shell/testcases/sets/0036add_set_element_expiration_0 b/tests/shell/testcases/sets/0036add_set_element_expiration_0
new file mode 100755
index 0000000..0fd016e
--- /dev/null
+++ b/tests/shell/testcases/sets/0036add_set_element_expiration_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+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 30m expires 15m }"
+
+test_output=$($NFT -e -f - <<< "$RULESET" 2>&1 | grep -v '# new generation' | drop_seconds)
+
+if [ "$test_output" != "$EXPECTED" ] ; then
+ $DIFF -u <(echo "$test_output") <(echo "$EXPECTED")
+ exit 1
+fi
+
+$NFT "add chain ip x c; add rule ip x c ip saddr @y"
diff --git a/tests/shell/testcases/sets/0037_set_with_inet_service_0 b/tests/shell/testcases/sets/0037_set_with_inet_service_0
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/sets/0037_set_with_inet_service_0
@@ -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/0038meter_list_0 b/tests/shell/testcases/sets/0038meter_list_0
new file mode 100755
index 0000000..e9e0f6f
--- /dev/null
+++ b/tests/shell/testcases/sets/0038meter_list_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+#
+# Listing meters should not include dynamic sets in the output
+#
+
+set -e
+
+RULESET="
+ add table t
+ add set t s { type ipv4_addr; size 256; flags dynamic,timeout; }
+ add chain t c
+ add rule t c tcp dport 80 meter m size 128 { ip saddr limit rate 10/second }
+"
+
+expected_output="table ip t {
+ meter m {
+ type ipv4_addr
+ size 128
+ flags dynamic
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+test_output=$($NFT list meters)
+
+test "$test_output" = "$expected_output"
+
diff --git a/tests/shell/testcases/sets/0039delete_interval_0 b/tests/shell/testcases/sets/0039delete_interval_0
new file mode 100755
index 0000000..19df16e
--- /dev/null
+++ b/tests/shell/testcases/sets/0039delete_interval_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Make sure nft allows to delete existing ranges only
+
+RULESET="
+table t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.1.0-192.168.1.254, 192.168.1.255 }
+ }
+}"
+
+$NFT -f - <<< "$RULESET" || { echo "E: Can't load basic ruleset" 1>&2; exit 1; }
+
+$NFT delete element t s '{ 192.168.1.0/24 }' 2>/dev/null || exit 0
+echo "E: Deletion of non-existing range allowed" 1>&2
diff --git a/tests/shell/testcases/sets/0040get_host_endian_elements_0 b/tests/shell/testcases/sets/0040get_host_endian_elements_0
new file mode 100755
index 0000000..caf6a4a
--- /dev/null
+++ b/tests/shell/testcases/sets/0040get_host_endian_elements_0
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+RULESET="table ip t {
+ set s {
+ type mark
+ flags interval
+ elements = {
+ 0x23-0x42, 0x1337
+ }
+ }
+}"
+
+$NFT -f - <<< "$RULESET" || { echo "can't apply basic ruleset"; exit 1; }
+
+$NFT get element ip t s '{ 0x23-0x42 }' || {
+ echo "can't find existing range 0x23-0x42"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x26-0x28 }' || {
+ echo "can't find existing sub-range 0x26-0x28"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x26-0x99 }' && {
+ echo "found non-existing range 0x26-0x99"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x55-0x99 }' && {
+ echo "found non-existing range 0x55-0x99"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x55 }' && {
+ echo "found non-existing element 0x55"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x1337 }' || {
+ echo "can't find existing element 0x1337"
+ exit 1
+}
diff --git a/tests/shell/testcases/sets/0041interval_0 b/tests/shell/testcases/sets/0041interval_0
new file mode 100755
index 0000000..42fc6cc
--- /dev/null
+++ b/tests/shell/testcases/sets/0041interval_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.2.195, 192.168.2.196,
+ 192.168.2.197, 192.168.2.198 }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+$NFT 'delete element t s { 192.168.2.195, 192.168.2.196 }; add element t s { 192.168.2.196 }' 2>/dev/null
+$NFT get element t s { 192.168.2.196, 192.168.2.197, 192.168.2.198 } 1>/dev/null
+$NFT 'delete element t s { 192.168.2.196, 192.168.2.197 }; add element t s { 192.168.2.197 }' 2>/dev/null
+$NFT get element t s { 192.168.2.197, 192.168.2.198 } 1>/dev/null
+$NFT 'delete element t s { 192.168.2.198, 192.168.2.197 }; add element t s { 192.168.2.196, 192.168.2.197, 192.168.2.195 }' 1>/dev/null
+$NFT get element t s { 192.168.2.196, 192.168.2.197, 192.168.2.195 } 1>/dev/null
+$NFT delete element t s { 192.168.2.196, 192.168.2.197, 192.168.2.195 } 2>/dev/null
+$NFT create element t s { 192.168.2.196} 2>/dev/null
+$NFT get element t s { 192.168.2.196 } 1>/dev/null
diff --git a/tests/shell/testcases/sets/0042update_set_0 b/tests/shell/testcases/sets/0042update_set_0
new file mode 100755
index 0000000..a8e9e05
--- /dev/null
+++ b/tests/shell/testcases/sets/0042update_set_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip t {
+ set set1 {
+ type ether_addr
+ }
+
+ set set2 {
+ type ether_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain c {
+ ether daddr @set1 add @set2 { ether daddr counter }
+ }
+}"
+
+$NFT -f - <<< "$RULESET" || { echo "can't apply basic ruleset"; exit 1; }
diff --git a/tests/shell/testcases/sets/0043concatenated_ranges_0 b/tests/shell/testcases/sets/0043concatenated_ranges_0
new file mode 100755
index 0000000..83d7435
--- /dev/null
+++ b/tests/shell/testcases/sets/0043concatenated_ranges_0
@@ -0,0 +1,194 @@
+#!/bin/bash -e
+#
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+#
+# 0043concatenated_ranges_0 - Add, get, list, timeout for concatenated ranges
+#
+# Cycle over supported data types, forming concatenations of three fields, for
+# all possible permutations, and:
+# - add entries to set
+# - list them
+# - get entries by specifying a value matching ranges for all fields
+# - delete them
+# - check that they can't be deleted again
+# - add them with 1s timeout
+# - check that they are not listed after 1s, just once, for the first entry
+# - delete them
+# - make sure they can't be deleted again
+
+TYPES="ipv4_addr ipv6_addr ether_addr inet_proto inet_service mark"
+
+RULESPEC_ipv4_addr="ip saddr"
+ELEMS_ipv4_addr="192.0.2.1 198.51.100.0/25 203.0.113.0-203.0.113.129"
+ADD_ipv4_addr="192.0.2.252/31"
+GET_ipv4_addr="198.51.100.127 198.51.100.0/25"
+
+RULESPEC_ipv6_addr="ip6 daddr"
+ELEMS_ipv6_addr="2001:db8:c0c:c0de::1-2001:db8:cacc::a 2001:db8::1 2001:db8:dada:da::/64"
+ADD_ipv6_addr="2001:db8::d1ca:d1ca"
+GET_ipv6_addr="2001:db8::1 2001:db8::1"
+
+RULESPEC_ether_addr="ether saddr"
+ELEMS_ether_addr="00:0a:c1:d1:f1:ed-00:0a:c1:dd:ec:af 00:0b:0c:ca:cc:10-c1:a0:c1:cc:10:00 f0:ca:cc:1a:b0:1a"
+ADD_ether_addr="00:be:1d:ed:ab:e1"
+GET_ether_addr="ac:c1:ac:c0:ce:c0 00:0b:0c:ca:cc:10-c1:a0:c1:cc:10:00"
+
+RULESPEC_inet_proto="meta l4proto"
+ELEMS_inet_proto="tcp udp icmp"
+ADD_inet_proto="sctp"
+GET_inet_proto="udp udp"
+
+RULESPEC_inet_service="tcp dport"
+ELEMS_inet_service="22-23 1024-32768 31337"
+ADD_inet_service="32769-65535"
+GET_inet_service="32768 1024-32768"
+
+RULESPEC_mark="mark"
+ELEMS_mark="0x00000064-0x000000c8 0x0000006f 0x0000fffd-0x0000ffff"
+ADD_mark="0x0000002a"
+GET_mark="0x0000006f 0x0000006f"
+
+tmp="$(mktemp)"
+trap "rm -f ${tmp}" EXIT
+
+render() {
+ eval "echo \"$(cat ${1})\""
+}
+
+cat <<'EOF' > "${tmp}"
+flush ruleset
+
+table inet filter {
+ ${setmap} test {
+ type ${ta} . ${tb} . ${tc} ${mapt}
+ flags interval,timeout
+ elements = { ${a1} . ${b1} . ${c1} ${mapv},
+ ${a2} . ${b2} . ${c2} ${mapv},
+ ${a3} . ${b3} . ${c3} ${mapv}, }
+ }
+
+ chain output {
+ type filter hook output priority 0; policy accept;
+ ${rule} @test counter
+ }
+}
+EOF
+
+timeout_tested=0
+run_test()
+{
+setmap="$1"
+for ta in ${TYPES}; do
+ eval a=\$ELEMS_${ta}
+ a1=${a%% *}; a2=$(expr "$a" : ".* \(.*\) .*"); a3=${a##* }
+ eval sa=\$RULESPEC_${ta}
+
+ mark=0
+ for tb in ${TYPES}; do
+ [ "${tb}" = "${ta}" ] && continue
+ if [ "${tb}" = "ipv6_addr" ]; then
+ [ "${ta}" = "ipv4_addr" ] && continue
+ elif [ "${tb}" = "ipv4_addr" ]; then
+ [ "${ta}" = "ipv6_addr" ] && continue
+ fi
+
+ eval b=\$ELEMS_${tb}
+ b1=${b%% *}; b2=$(expr "$b" : ".* \(.*\) .*"); b3=${b##* }
+ eval sb=\$RULESPEC_${tb}
+
+ for tc in ${TYPES}; do
+ [ "${tc}" = "${ta}" ] && continue
+ [ "${tc}" = "${tb}" ] && continue
+ if [ "${tc}" = "ipv6_addr" ]; then
+ [ "${ta}" = "ipv4_addr" ] && continue
+ [ "${tb}" = "ipv4_addr" ] && continue
+ elif [ "${tc}" = "ipv4_addr" ]; then
+ [ "${ta}" = "ipv6_addr" ] && continue
+ [ "${tb}" = "ipv6_addr" ] && continue
+ fi
+
+ echo "$setmap TYPE: ${ta} ${tb} ${tc}"
+
+ eval c=\$ELEMS_${tc}
+ c1=${c%% *}; c2=$(expr "$c" : ".* \(.*\) .*"); c3=${c##* }
+ eval sc=\$RULESPEC_${tc}
+
+ case "${setmap}" in
+ "set")
+ mapt=""
+ mapv=""
+ rule="${sa} . ${sb} . ${sc}"
+ ;;
+ "map")
+ mapt=": mark"
+ mark=42
+ mapv=$(printf " : 0x%08x" ${mark})
+ rule="meta mark set ${sa} . ${sb} . ${sc} map"
+ ;;
+ esac
+
+ render ${tmp} | ${NFT} -f -
+
+ [ $(${NFT} list ${setmap} inet filter test | \
+ grep -c -e "${a1} . ${b1} . ${c1}${mapv}" \
+ -e "${a2} . ${b2} . ${c2}${mapv}" \
+ -e "${a3} . ${b3} . ${c3}${mapv}") -eq 3 ]
+
+ ${NFT} delete element inet filter test \
+ "{ ${a1} . ${b1} . ${c1}${mapv} }"
+ ${NFT} delete element inet filter test \
+ "{ ${a1} . ${b1} . ${c1}${mapv} }" \
+ 2>/dev/null && exit 1
+
+ eval add_a=\$ADD_${ta}
+ eval add_b=\$ADD_${tb}
+ eval add_c=\$ADD_${tc}
+ ${NFT} add element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} timeout 2m${mapv}}"
+ [ $(${NFT} list ${setmap} inet filter test | \
+ grep -c "${add_a} . ${add_b} . ${add_c}") -eq 1 ]
+
+ eval get_a=\$GET_${ta}
+ eval get_b=\$GET_${tb}
+ eval get_c=\$GET_${tc}
+ exp_a=${get_a##* }; get_a=${get_a%% *}
+ exp_b=${get_b##* }; get_b=${get_b%% *}
+ exp_c=${get_c##* }; get_c=${get_c%% *}
+ [ $(${NFT} get element inet filter test \
+ "{ ${get_a} . ${get_b} . ${get_c}${mapv} }" | \
+ grep -c "${exp_a} . ${exp_b} . ${exp_c}") -eq 1 ]
+
+ ${NFT} "delete element inet filter test \
+ { ${a2} . ${b2} . ${c2}${mapv} };
+ delete element inet filter test \
+ { ${a3} . ${b3} . ${c3}${mapv} }"
+ ${NFT} "delete element inet filter test \
+ { ${a2} . ${b2} . ${c2}${mapv} };
+ delete element inet filter test \
+ { ${a3} . ${b3} . ${c3} ${mapv} }" \
+ 2>/dev/null && exit 1
+
+ if [ ${timeout_tested} -eq 1 ]; then
+ ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} ${mapv} }"
+ ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} ${mapv} }" \
+ 2>/dev/null && exit 1
+ continue
+ fi
+
+ ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} ${mapv}}"
+ ${NFT} add element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} timeout 1s${mapv}}"
+ sleep 1
+ [ $(${NFT} list ${setmap} inet filter test | \
+ grep -c "${add_a} . ${add_b} . ${add_c} ${mapv}") -eq 0 ]
+ timeout_tested=1
+ done
+ done
+done
+}
+
+run_test "set"
+run_test "map"
diff --git a/tests/shell/testcases/sets/0043concatenated_ranges_1 b/tests/shell/testcases/sets/0043concatenated_ranges_1
new file mode 100755
index 0000000..1be2889
--- /dev/null
+++ b/tests/shell/testcases/sets/0043concatenated_ranges_1
@@ -0,0 +1,23 @@
+#!/bin/bash -e
+#
+# 0043concatenated_ranges_1 - Insert and list subnets of different sizes
+
+check() {
+ $NFT add element "${1}" t s "{ ${2} . ${3} }"
+ [ "$( $NFT list set "${1}" t s | grep -c "${2} . ${3}" )" = 1 ]
+}
+
+$NFT add table ip6 t
+$NFT add table ip t
+
+$NFT add set ip6 t s '{ type ipv6_addr . ipv6_addr ; flags interval ; }'
+$NFT add set ip t s '{ type ipv4_addr . ipv4_addr ; flags interval ; }'
+
+for n in $(seq 32 127); do
+ h="$(printf %x "${n}")"
+ check ip6 "2001:db8::/${n}" "2001:db8:${h}::-2001:db8:${h}::${h}:1"
+done
+
+for n in $(seq 24 31); do
+ check ip "192.0.2.0/${n}" "192.0.2.$((n * 3))-192.0.2.$((n * 3 + 2))"
+done
diff --git a/tests/shell/testcases/sets/0044interval_overlap_0 b/tests/shell/testcases/sets/0044interval_overlap_0
new file mode 100755
index 0000000..71bf334
--- /dev/null
+++ b/tests/shell/testcases/sets/0044interval_overlap_0
@@ -0,0 +1,166 @@
+#!/bin/bash -e
+#
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+#
+# 0044interval_overlap_0 - Add overlapping and non-overlapping intervals
+#
+# Check that adding overlapping intervals to a set returns an error, unless:
+# - the inserted element overlaps entirely, that is, it's identical to an
+# existing one
+# - for concatenated ranges, the new element is less specific than any existing
+# overlapping element, as elements are evaluated in order of insertion
+#
+# Then, repeat the test with a set configured with a timeout, checking that:
+# - we can insert all the elements as described above
+# - once the timeout has expired, we can insert all the elements again, and old
+# elements are not present
+# - before the timeout expires again, we can re-add elements that are not
+# expected to fail, but old elements might be present
+#
+# If $NFT points to a libtool wrapper, and we're running on a slow machine or
+# kernel (e.g. KASan enabled), it might not be possible to execute hundreds of
+# commands within an otherwise reasonable 1 second timeout. Estimate a usable
+# timeout first, by counting commands and measuring against one nft rule timeout
+# itself, so that we can keep this fast for a binary $NFT on a reasonably fast
+# kernel.
+
+# Accept Interval List
+intervals_simple="
+ y 0 - 2 0-2
+ y 0 - 2 0-2
+ n 0 - 1 0-2
+ n 0 - 3 0-2
+ y 3 - 10 0-2, 3-10
+ n 3 - 9 0-2, 3-10
+ n 4 - 10 0-2, 3-10
+ n 4 - 9 0-2, 3-10
+ y 20 - 30 0-2, 3-10, 20-30
+ y 11 - 12 0-2, 3-10, 11-12, 20-30
+ y 13 - 19 0-2, 3-10, 11-12, 13-19, 20-30
+ n 25 - 40 0-2, 3-10, 11-12, 13-19, 20-30
+ y 50 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 50-60
+ y 31 - 49 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60
+ n 59 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60
+"
+
+intervals_concat="
+ y 0-2 . 0-3 0-2 . 0-3
+ y 0-2 . 0-3 0-2 . 0-3
+ n 0-1 . 0-2 0-2 . 0-3
+ y 10-20 . 30-40 0-2 . 0-3, 10-20 . 30-40
+ y 15-20 . 50-60 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60
+ y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ n 11-19 . 30-40 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ y 15-20 . 49-61 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29, 15-20 . 49-61
+"
+
+count_elements() {
+ pass=
+ interval=
+ elements=0
+ for t in ${intervals_simple} ${intervals_concat}; do
+ [ -z "${pass}" ] && pass="${t}" && continue
+ [ -z "${interval}" ] && interval="${t}" && continue
+ unset IFS
+
+ elements=$((elements + 1))
+
+ IFS='
+'
+ done
+ unset IFS
+}
+
+match_elements() {
+ skip=0
+ n=0
+ out=
+ for a in $($NFT list set t ${1})}; do
+ [ ${n} -eq 0 ] && { [ "${a}" = "elements" ] && n=1; continue; }
+ [ ${n} -eq 1 ] && { [ "${a}" = "=" ] && n=2; continue; }
+ [ ${n} -eq 2 ] && { [ "${a}" = "{" ] && n=3; continue; }
+
+ [ "${a}" = "}" ] && break
+
+ [ ${skip} -eq 1 ] && skip=0 && out="${out}," && continue
+ [ "${a}" = "expires" ] && skip=1 && continue
+
+ [ -n "${out}" ] && out="${out} ${a}" || out="${a}"
+
+ done
+
+ if [ "${out%,}" != "${2}" ]; then
+ echo "Expected: ${2}, got: ${out%,}"
+ return 1
+ fi
+}
+
+estimate_timeout() {
+ count_elements
+
+ $NFT add table t
+ $NFT add set t s '{ type inet_service ; flags timeout; timeout 1s; gc-interval 1s; }'
+ execs_1s=1
+ $NFT add element t s "{ 0 }"
+ while match_elements s "0" >/dev/null; do
+ execs_1s=$((execs_1s + 1))
+ done
+
+ timeout="$((elements / execs_1s * 3 / 2 + 1))"
+}
+
+add_elements() {
+ set="s"
+ pass=
+ interval=
+ IFS='
+'
+ for t in ${intervals_simple} switch ${intervals_concat}; do
+ [ "${t}" = "switch" ] && set="c" && continue
+ [ -z "${pass}" ] && pass="${t}" && continue
+ [ -z "${interval}" ] && interval="${t}" && continue
+ unset IFS
+
+ if [ "${pass}" = "y" ]; then
+ if ! $NFT add element t ${set} "{ ${interval} }"; then
+ echo "Failed to insert ${interval} given:"
+ $NFT list ruleset
+ exit 1
+ fi
+ else
+ if $NFT add element t ${set} "{ ${interval} }" 2>/dev/null; then
+ echo "Could insert ${interval} given:"
+ $NFT list ruleset
+ exit 1
+ fi
+ fi
+
+ [ "${1}" != "nomatch" ] && match_elements "${set}" "${t}"
+
+ pass=
+ interval=
+ IFS='
+'
+ done
+ unset IFS
+}
+
+$NFT add table t
+$NFT add set t s '{ type inet_service ; flags interval ; }'
+$NFT add set t c '{ type inet_service . inet_service ; flags interval ; }'
+add_elements
+
+$NFT flush ruleset
+estimate_timeout
+
+$NFT flush ruleset
+$NFT add table t
+$NFT add set t s "{ type inet_service ; flags interval,timeout; timeout ${timeout}s; gc-interval ${timeout}s; }"
+$NFT add set t c "{ type inet_service . inet_service ; flags interval,timeout ; timeout ${timeout}s; gc-interval ${timeout}s; }"
+add_elements
+
+sleep $((timeout * 3 / 2))
+add_elements
+
+add_elements nomatch
diff --git a/tests/shell/testcases/sets/0044interval_overlap_1 b/tests/shell/testcases/sets/0044interval_overlap_1
new file mode 100755
index 0000000..cdd0c84
--- /dev/null
+++ b/tests/shell/testcases/sets/0044interval_overlap_1
@@ -0,0 +1,38 @@
+#!/bin/bash -e
+#
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+#
+# 0044interval_overlap_1 - Single-sized intervals can never overlap partially
+#
+# Check that inserting, deleting, and inserting single-sized intervals again
+# never leads to a partial overlap. Specifically trigger rbtree rebalancing in
+# the process, to ensure different tree shapes of equivalent sets don't lead to
+# false positives, by deleting every second inserted item.
+
+xorshift() {
+ # Adaptation of Xorshift algorithm from:
+ # Marsaglia, G. (2003). Xorshift RNGs.
+ # Journal of Statistical Software, 8(14), 1 - 6.
+ # doi:http://dx.doi.org/10.18637/jss.v008.i14
+ # with triplet (5, 3, 1), suitable for 16-bit ranges.
+
+ : $((port ^= port << 5))
+ : $((port ^= port >> 3))
+ : $((port ^= port << 1))
+}
+
+$NFT add table t
+$NFT add set t s '{ type inet_service ; flags interval ; }'
+
+for op in add delete add; do
+ port=1
+ skip=0
+ for i in $(seq 1 500); do
+ xorshift
+ if [ "${op}" = "delete" ]; then
+ [ ${skip} -eq 0 ] && skip=1 && continue
+ skip=0
+ fi
+ $NFT ${op} element t s "{ { $((port % 32768 + 32768)) } }"
+ done
+done
diff --git a/tests/shell/testcases/sets/0045concat_ipv4_service b/tests/shell/testcases/sets/0045concat_ipv4_service
new file mode 100755
index 0000000..5b40f97
--- /dev/null
+++ b/tests/shell/testcases/sets/0045concat_ipv4_service
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+$NFT -f - <<EOF
+table inet t {
+ set s {
+ type ipv4_addr . inet_service
+ size 65536
+ flags dynamic,timeout
+ elements = { 192.168.7.1 . 22 }
+ }
+
+ chain c {
+ tcp dport 21 add @s { ip saddr . 22 timeout 60s }
+ }
+}
+EOF
diff --git a/tests/shell/testcases/sets/0046netmap_0 b/tests/shell/testcases/sets/0046netmap_0
new file mode 100755
index 0000000..60bda40
--- /dev/null
+++ b/tests/shell/testcases/sets/0046netmap_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+EXPECTED="table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24,
+ 10.141.12.0/24 : 192.168.3.0/24,
+ 10.141.13.0/24 : 192.168.4.0/24 }
+ }
+ }
+ table ip6 x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip6 prefix to ip6 saddr map { 2001:db8:1111::/64 : 2001:db8:2222::/64 }
+ }
+ }
+"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0047nat_0 b/tests/shell/testcases/sets/0047nat_0
new file mode 100755
index 0000000..4e53b7b
--- /dev/null
+++ b/tests/shell/testcases/sets/0047nat_0
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+EXPECTED="table ip x {
+ map y {
+ type ipv4_addr : interval ipv4_addr
+ flags interval
+ elements = { 10.141.10.0/24 : 192.168.2.2-192.168.2.4,
+ 10.141.11.0/24 : 192.168.4.2-192.168.4.3 }
+ }
+
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to iifname . ip saddr map { enp2s0 . 10.1.1.136 : 1.1.2.69 . 22, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ dnat ip to iifname . ip saddr map { enp2s0 . 10.1.1.136 : 1.1.2.69, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat to ip saddr map @y
+ }
+ }
+"
+
+set -e
+$NFT -f - <<< $EXPECTED
+$NFT add element x y { 10.141.12.0/24 : 192.168.5.10-192.168.5.20 }
+
+EXPECTED="table inet x {
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat to ip daddr . tcp dport map { 10.141.10.1 . 22 : 192.168.2.2, 10.141.11.2 . 2222 : 192.168.4.2 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat to ip saddr map { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2-192.168.4.3 }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0048set_counters_0 b/tests/shell/testcases/sets/0048set_counters_0
new file mode 100755
index 0000000..e62d25d
--- /dev/null
+++ b/tests/shell/testcases/sets/0048set_counters_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table ip x {
+ set y {
+ typeof ip saddr
+ counter
+ elements = { 192.168.10.35, 192.168.10.101, 192.168.10.135 }
+ }
+
+ chain z {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0049set_define_0 b/tests/shell/testcases/sets/0049set_define_0
new file mode 100755
index 0000000..1d512f7
--- /dev/null
+++ b/tests/shell/testcases/sets/0049set_define_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="define BASE_ALLOWED_INCOMING_TCP_PORTS = {22, 80, 443}
+define EXTRA_ALLOWED_INCOMING_TCP_PORTS = {}
+
+table inet filter {
+ chain input {
+ type filter hook input priority 0; policy drop;
+ tcp dport {\$BASE_ALLOWED_INCOMING_TCP_PORTS, \$EXTRA_ALLOWED_INCOMING_TCP_PORTS} ct state new counter accept
+ }
+}
+"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0050set_define_1 b/tests/shell/testcases/sets/0050set_define_1
new file mode 100755
index 0000000..c12de17
--- /dev/null
+++ b/tests/shell/testcases/sets/0050set_define_1
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="define BASE_ALLOWED_INCOMING_TCP_PORTS = {}
+
+table inet filter {
+ chain input {
+ type filter hook input priority 0; policy drop;
+ tcp dport {\$BASE_ALLOWED_INCOMING_TCP_PORTS} ct state new counter accept
+ }
+}
+"
+
+$NFT -f - <<< "$EXPECTED" &> /dev/null || exit 0
+echo "E: Accepted empty set" 1>&2
+exit 1
diff --git a/tests/shell/testcases/sets/0051set_interval_counter_0 b/tests/shell/testcases/sets/0051set_interval_counter_0
new file mode 100755
index 0000000..ea90e26
--- /dev/null
+++ b/tests/shell/testcases/sets/0051set_interval_counter_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table ip x {
+ set s {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 192.168.2.0/24 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @s
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0052overlap_0 b/tests/shell/testcases/sets/0052overlap_0
new file mode 100755
index 0000000..c296094
--- /dev/null
+++ b/tests/shell/testcases/sets/0052overlap_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="add table ip filter
+add set ip filter w_all {type ipv4_addr; flags interval; auto-merge}
+add element ip filter w_all {10.10.10.10, 10.10.10.11}
+"
+
+$NFT -f - <<< "$EXPECTED"
+
+EXPECTED="flush set ip filter w_all
+add element ip filter w_all {10.10.10.10, 10.10.10.253}
+"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0053echo_0 b/tests/shell/testcases/sets/0053echo_0
new file mode 100755
index 0000000..6bb03c2
--- /dev/null
+++ b/tests/shell/testcases/sets/0053echo_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="add table inet filter
+delete table inet filter
+
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy drop;
+ iifname { lo } ip saddr { 10.0.0.0/8 } ip daddr { 192.168.100.62 } tcp dport { 2001 } counter accept
+ }
+}
+"
+
+$NFT -ef - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0054comments_set_0 b/tests/shell/testcases/sets/0054comments_set_0
new file mode 100755
index 0000000..9c8f787
--- /dev/null
+++ b/tests/shell/testcases/sets/0054comments_set_0
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+
+# Test that comments are added to sets
+
+$NFT add table t
+$NFT add set t s {type ipv4_addr \; flags interval \; comment "test" \;}
+$NFT add map t m {type ipv4_addr : ipv4_addr \; flags interval \; comment \"another test\" \;}
diff --git a/tests/shell/testcases/sets/0055tcpflags_0 b/tests/shell/testcases/sets/0055tcpflags_0
new file mode 100755
index 0000000..a2b24eb
--- /dev/null
+++ b/tests/shell/testcases/sets/0055tcpflags_0
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+EXPECTED="add table ip test
+
+add set ip test tcp_good_flags { type tcp_flag ; flags constant ; elements = {
+ ( 0 | 0 | 0 |ack| 0 | 0 ), \
+ ( 0 | 0 | 0 |ack| 0 |urg), \
+ ( 0 | 0 | 0 |ack|psh| 0 ), \
+ ( 0 | 0 | 0 |ack|psh|urg), \
+ ( 0 | 0 |rst| 0 | 0 | 0 ), \
+ ( 0 | 0 |rst|ack| 0 | 0 ), \
+ ( 0 | 0 |rst|ack| 0 |urg), \
+ ( 0 | 0 |rst|ack|psh| 0 ), \
+ ( 0 | 0 |rst|ack|psh|urg), \
+ ( 0 |syn| 0 | 0 | 0 | 0 ), \
+ ( 0 |syn| 0 |ack| 0 | 0 ), \
+ ( 0 |syn| 0 |ack| 0 |urg), \
+ ( 0 |syn| 0 |ack|psh| 0 ), \
+ ( 0 |syn| 0 |ack|psh|urg), \
+ (fin| 0 | 0 |ack| 0 | 0 ), \
+ (fin| 0 | 0 |ack| 0 |urg), \
+ (fin| 0 | 0 |ack|psh| 0 ), \
+ (fin| 0 | 0 |ack|psh|urg) \
+} ; }"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0056dynamic_limit_0 b/tests/shell/testcases/sets/0056dynamic_limit_0
new file mode 100755
index 0000000..21fa0bf
--- /dev/null
+++ b/tests/shell/testcases/sets/0056dynamic_limit_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set ssh_meter {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 1m
+ elements = { 127.0.0.1 expires 52s44ms limit rate over 1/minute }
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ ip protocol icmp add @ssh_meter { ip saddr timeout 1m limit rate over 1/minute }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0057set_create_fails_0 b/tests/shell/testcases/sets/0057set_create_fails_0
new file mode 100755
index 0000000..5f0149a
--- /dev/null
+++ b/tests/shell/testcases/sets/0057set_create_fails_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set test {
+ type ipv4_addr
+ size 65535
+ elements = { 1.1.1.1 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+CMD="create element inet filter test { 1.1.1.1, 1.1.1.2, 1.1.1.3, 1.1.1.4, 1.1.1.5, 1.1.1.6, 1.1.1.7, 1.1.1.8, 1.1.1.9, 1.1.1.10, 1.1.1.11, 1.1.1.12, 1.1.1.13, 1.1.1.14, 1.1.1.15, 1.1.1.16, 1.1.1.17, 1.1.1.18, 1.1.1.19, 1.1.1.20, 1.1.1.21, 1.1.1.22, 1.1.1.23, 1.1.1.24, 1.1.1.25, 1.1.1.26, 1.1.1.27, 1.1.1.28, 1.1.1.29, 1.1.1.30, 1.1.1.31, 1.1.1.32, 1.1.1.33, 1.1.1.34, 1.1.1.35, 1.1.1.36, 1.1.1.37, 1.1.1.38, 1.1.1.39, 1.1.1.40, 1.1.1.41, 1.1.1.42, 1.1.1.43, 1.1.1.44, 1.1.1.45, 1.1.1.46, 1.1.1.47, 1.1.1.48, 1.1.1.49, 1.1.1.50, 1.1.1.51, 1.1.1.52, 1.1.1.53, 1.1.1.54, 1.1.1.55, 1.1.1.56, 1.1.1.57, 1.1.1.58, 1.1.1.59, 1.1.1.60, 1.1.1.61, 1.1.1.62, 1.1.1.63, 1.1.1.64, 1.1.1.65, 1.1.1.66, 1.1.1.67, 1.1.1.68, 1.1.1.69, 1.1.1.70, 1.1.1.71, 1.1.1.72, 1.1.1.73, 1.1.1.74, 1.1.1.75, 1.1.1.76, 1.1.1.77, 1.1.1.78, 1.1.1.79, 1.1.1.80, 1.1.1.81, 1.1.1.82, 1.1.1.83, 1.1.1.84, 1.1.1.85, 1.1.1.86, 1.1.1.87, 1.1.1.88, 1.1.1.89, 1.1.1.90, 1.1.1.91, 1.1.1.92, 1.1.1.93, 1.1.1.94, 1.1.1.95, 1.1.1.96, 1.1.1.97, 1.1.1.98, 1.1.1.99, 1.1.1.100, 1.1.1.101, 1.1.1.102, 1.1.1.103, 1.1.1.104, 1.1.1.105, 1.1.1.106, 1.1.1.107, 1.1.1.108, 1.1.1.109, 1.1.1.110, 1.1.1.111, 1.1.1.112, 1.1.1.113, 1.1.1.114, 1.1.1.115, 1.1.1.116, 1.1.1.117, 1.1.1.118, 1.1.1.119, 1.1.1.120, 1.1.1.121, 1.1.1.122, 1.1.1.123, 1.1.1.124, 1.1.1.125, 1.1.1.126, 1.1.1.127, 1.1.1.128, 1.1.1.129, 1.1.1.130, 1.1.1.131, 1.1.1.132, 1.1.1.133, 1.1.1.134, 1.1.1.135, 1.1.1.136, 1.1.1.137, 1.1.1.138, 1.1.1.139, 1.1.1.140, 1.1.1.141, 1.1.1.142, 1.1.1.143, 1.1.1.144, 1.1.1.145, 1.1.1.146, 1.1.1.147, 1.1.1.148, 1.1.1.149, 1.1.1.150, 1.1.1.151, 1.1.1.152, 1.1.1.153, 1.1.1.154, 1.1.1.155, 1.1.1.156, 1.1.1.157, 1.1.1.158, 1.1.1.159, 1.1.1.160, 1.1.1.161, 1.1.1.162, 1.1.1.163, 1.1.1.164, 1.1.1.165, 1.1.1.166, 1.1.1.167, 1.1.1.168, 1.1.1.169, 1.1.1.170, 1.1.1.171, 1.1.1.172, 1.1.1.173, 1.1.1.174, 1.1.1.175, 1.1.1.176, 1.1.1.177, 1.1.1.178, 1.1.1.179, 1.1.1.180, 1.1.1.181, 1.1.1.182, 1.1.1.183, 1.1.1.184, 1.1.1.185, 1.1.1.186, 1.1.1.187, 1.1.1.188, 1.1.1.189, 1.1.1.190, 1.1.1.191, 1.1.1.192, 1.1.1.193, 1.1.1.194, 1.1.1.195, 1.1.1.196, 1.1.1.197, 1.1.1.198, 1.1.1.199, 1.1.1.200, 1.1.1.201, 1.1.1.202, 1.1.1.203, 1.1.1.204, 1.1.1.205, 1.1.1.206, 1.1.1.207, 1.1.1.208, 1.1.1.209, 1.1.1.210, 1.1.1.211, 1.1.1.212, 1.1.1.213, 1.1.1.214, 1.1.1.215, 1.1.1.216, 1.1.1.217, 1.1.1.218, 1.1.1.219, 1.1.1.220, 1.1.1.221, 1.1.1.222, 1.1.1.223, 1.1.1.224, 1.1.1.225, 1.1.1.226, 1.1.1.227, 1.1.1.228, 1.1.1.229, 1.1.1.230, 1.1.1.231, 1.1.1.232, 1.1.1.233, 1.1.1.234, 1.1.1.235, 1.1.1.236, 1.1.1.237, 1.1.1.238, 1.1.1.239, 1.1.1.240, 1.1.1.241, 1.1.1.242, 1.1.1.243, 1.1.1.244, 1.1.1.245, 1.1.1.246, 1.1.1.247, 1.1.1.248, 1.1.1.249, 1.1.1.250, 1.1.1.251, 1.1.1.252, 1.1.1.253 }"
+
+# If this returns ENOSPC, then nft is sending a netlink message that is larger
+# than NFT_MNL_ACK_MAXSIZE. Make sure this returns EEXIST.
+$NFT -f - <<< $CMD 2>&1 >/dev/null | grep "File exists"
+[ "$?" -eq 0 ] && exit 0
diff --git a/tests/shell/testcases/sets/0058_setupdate_timeout_0 b/tests/shell/testcases/sets/0058_setupdate_timeout_0
new file mode 100755
index 0000000..52a658e
--- /dev/null
+++ b/tests/shell/testcases/sets/0058_setupdate_timeout_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set ssh_meter {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 30d
+ }
+
+ chain test {
+ add @ssh_meter { ip saddr timeout 30d }
+ }
+}"
+
+set -e
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/0059set_update_multistmt_0 b/tests/shell/testcases/sets/0059set_update_multistmt_0
new file mode 100755
index 0000000..2aeba2c
--- /dev/null
+++ b/tests/shell/testcases/sets/0059set_update_multistmt_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
+RULESET="table x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 1h
+ }
+ chain z {
+ type filter hook output priority 0;
+ update @y { ip daddr limit rate 1/second counter }
+ }
+}"
+
+set -e
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/0060set_multistmt_0 b/tests/shell/testcases/sets/0060set_multistmt_0
new file mode 100755
index 0000000..8e17444
--- /dev/null
+++ b/tests/shell/testcases/sets/0060set_multistmt_0
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
+RULESET="table x {
+ set y {
+ type ipv4_addr
+ limit rate 1/second counter
+ elements = { 5.5.5.5 limit rate 1/second counter packets 0 bytes 0 }
+ }
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}"
+
+$NFT -f - <<< $RULESET
+# should work
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 1.1.1.1 limit rate 1/second counter }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should fail
+$NFT add element x y { 2.2.2.2 limit rate 1/second }
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+# should fail
+$NFT add element x y { 3.3.3.3 counter limit rate 1/second }
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 4.4.4.4 }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+exit 0
diff --git a/tests/shell/testcases/sets/0060set_multistmt_1 b/tests/shell/testcases/sets/0060set_multistmt_1
new file mode 100755
index 0000000..04ef047
--- /dev/null
+++ b/tests/shell/testcases/sets/0060set_multistmt_1
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
+RULESET="table x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter quota 500 bytes
+ elements = { 1.2.3.4 counter packets 9 bytes 756 quota 500 bytes used 500 bytes }
+ }
+ chain y {
+ type filter hook output priority filter; policy accept;
+ update @y { ip daddr }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+# should work
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 1.1.1.1 }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 2.2.2.2 counter quota 1000 bytes }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+exit 0
diff --git a/tests/shell/testcases/sets/0061anonymous_automerge_0 b/tests/shell/testcases/sets/0061anonymous_automerge_0
new file mode 100755
index 0000000..2dfb800
--- /dev/null
+++ b/tests/shell/testcases/sets/0061anonymous_automerge_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ ip saddr { 1.1.1.1-1.1.1.2, 1.1.1.1 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/0062set_connlimit_0 b/tests/shell/testcases/sets/0062set_connlimit_0
new file mode 100755
index 0000000..48d589f
--- /dev/null
+++ b/tests/shell/testcases/sets/0062set_connlimit_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ set est-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ elements = { 84.245.120.167 ct count over 20 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+RULESET="table ip x {
+ set new-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ ct count over 20
+ elements = { 84.245.120.167 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/0063set_catchall_0 b/tests/shell/testcases/sets/0063set_catchall_0
new file mode 100755
index 0000000..edd015d
--- /dev/null
+++ b/tests/shell/testcases/sets/0063set_catchall_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+set -e
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ counter
+ elements = { 1.1.1.1, * }
+ }
+ set z {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 1.1.1.0/24 , * }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+$NFT delete element x y { \* }
+$NFT add element x y { \* }
diff --git a/tests/shell/testcases/sets/0064map_catchall_0 b/tests/shell/testcases/sets/0064map_catchall_0
new file mode 100755
index 0000000..fd28937
--- /dev/null
+++ b/tests/shell/testcases/sets/0064map_catchall_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+set -e
+
+RULESET="table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ elements = { 10.141.0.1 : 192.168.0.2, * : 192.168.0.3 }
+ }
+ map z {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+$NFT delete element x y { \* : 192.168.0.3 }
+$NFT add element x y { \* : 192.168.0.4 }
+
+$NFT add chain x y
+$NFT add rule x y snat to ip saddr map @z
+$NFT 'add rule x y snat to ip saddr map { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }'
+$NFT 'add rule x y snat to ip saddr . ip daddr map { 10.141.0.0/24 . 10.0.0.0/8 : 192.168.0.2, 192.168.9.0/24 . 192.168.10.0/24 : 192.168.0.4, * : 192.168.0.3 }'
diff --git a/tests/shell/testcases/sets/0065_icmp_postprocessing b/tests/shell/testcases/sets/0065_icmp_postprocessing
new file mode 100755
index 0000000..f838c3e
--- /dev/null
+++ b/tests/shell/testcases/sets/0065_icmp_postprocessing
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain foo {
+ icmp id 42
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT insert rule ip x foo index 0 accept
diff --git a/tests/shell/testcases/sets/0067nat_concat_interval_0 b/tests/shell/testcases/sets/0067nat_concat_interval_0
new file mode 100755
index 0000000..55cc0d4
--- /dev/null
+++ b/tests/shell/testcases/sets/0067nat_concat_interval_0
@@ -0,0 +1,71 @@
+#!/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 }
+
+EXPECTED="table ip nat {
+ map ipportmap2 {
+ type ipv4_addr . ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 192.168.1.2 . 192.168.2.2 : 127.0.0.1/8 . 42 - 43 }
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ ip protocol tcp dnat ip to ip saddr . ip daddr map @ipportmap2
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+EXPECTED="table ip nat {
+ map fwdtoip_th {
+ type ipv4_addr . inet_service : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 1.2.3.4 . 10000-20000 : 192.168.3.4 . 30000-40000 }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+$NFT add rule ip nat prerouting meta l4proto { tcp, udp } dnat to ip daddr . th dport map @fwdtoip_th
+
+EXPECTED="table ip nat {
+ map ipportmap4 {
+ typeof iifname . ip saddr : interval ip daddr
+ flags interval
+ elements = { enp2s0 . 10.1.1.136 : 1.1.2.69, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat to iifname . ip saddr map @ipportmap4
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+EXPECTED="table ip nat {
+ map ipportmap5 {
+ typeof iifname . ip saddr : interval ip daddr . tcp dport
+ flags interval
+ elements = { enp2s0 . 10.1.1.136 : 1.1.2.69 . 22, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ }
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to iifname . ip saddr map @ipportmap5
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0068interval_stack_overflow_0 b/tests/shell/testcases/sets/0068interval_stack_overflow_0
new file mode 100755
index 0000000..e61010c
--- /dev/null
+++ b/tests/shell/testcases/sets/0068interval_stack_overflow_0
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+set -e
+
+ruleset_file=$(mktemp)
+
+trap 'rm -f "$ruleset_file"' EXIT
+
+HOWMANY=255
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=30
+fi
+
+{
+ echo 'define big_set = {'
+ for ((i = 1; i < $HOWMANY; i++)); do
+ for ((j = 1; j < 255; j++)); do
+ echo "10.0.$i.$j,"
+ done
+ done
+ echo '10.1.0.0/24 }'
+} >"$ruleset_file"
+
+cat >>"$ruleset_file" <<\EOF
+table inet test68_table {
+ set test68_set {
+ type ipv4_addr
+ flags interval
+ elements = { $big_set }
+ }
+}
+EOF
+
+( ulimit -s 400 && $NFT -f "$ruleset_file" )
+
+if [ "$HOWMANY" != 255 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/0069interval_merge_0 b/tests/shell/testcases/sets/0069interval_merge_0
new file mode 100755
index 0000000..edb6422
--- /dev/null
+++ b/tests/shell/testcases/sets/0069interval_merge_0
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 1.2.3.0, 1.2.3.255, 1.2.3.0/24, 3.3.3.3, 4.4.4.4, 4.4.4.4-4.4.4.8, 3.3.3.4, 3.3.3.5 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 1.2.4.0, 3.3.3.6, 4.4.4.0/24 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT add element ip x y { 1.2.3.0-1.2.4.255, 3.3.3.5, 4.4.4.1 }
+$NFT add element ip x y { 1.2.3.0-1.2.4.255, 3.3.3.5, 4.4.5.0 }
diff --git a/tests/shell/testcases/sets/0070stacked_l2_headers b/tests/shell/testcases/sets/0070stacked_l2_headers
new file mode 100755
index 0000000..07820b7
--- /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 0000000..79e3ca7
--- /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 0000000..9886a9b
--- /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 0000000..0630595
--- /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 0000000..e7f65fc
--- /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 0000000..1dbac0b
--- /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 0000000..7699e9d
--- /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 0000000..4d90af9
--- /dev/null
+++ b/tests/shell/testcases/sets/concat_interval_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+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.nft b/tests/shell/testcases/sets/dumps/0001named_interval_0.nft
new file mode 100644
index 0000000..3049aa8
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0001named_interval_0.nft
@@ -0,0 +1,34 @@
+table inet t {
+ set s1 {
+ type ipv4_addr
+ flags interval
+ elements = { 10.0.0.0-11.0.0.0, 172.16.0.0/16 }
+ }
+
+ set s2 {
+ type ipv6_addr
+ flags interval
+ elements = { fe00::/64,
+ fe11::-fe22:: }
+ }
+
+ set s3 {
+ type inet_proto
+ flags interval
+ elements = { 10-20, 50-60 }
+ }
+
+ set s4 {
+ type inet_service
+ flags interval
+ elements = { 0-1024, 8080-8082, 10000-40000 }
+ }
+
+ chain c {
+ ip saddr @s1 accept
+ ip6 daddr @s2 accept
+ ip protocol @s3 accept
+ ip6 nexthdr @s3 accept
+ tcp dport @s4 accept
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.nft b/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.nft
new file mode 100644
index 0000000..452ee23
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.0.0/24, 192.168.1.0/24 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.nft b/tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.nft
new file mode 100644
index 0000000..70c32a8
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.nft
@@ -0,0 +1,5 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.nft b/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.nft
new file mode 100644
index 0000000..940030a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.nft
@@ -0,0 +1,7 @@
+table inet t {
+ set s {
+ type ipv6_addr
+ flags interval
+ elements = { fe00::/64 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.nft b/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.nft
new file mode 100644
index 0000000..4224d9d
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.nft
@@ -0,0 +1,7 @@
+table inet t {
+ set s {
+ type ipv6_addr
+ flags interval
+ elements = { fe00::/48 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0006create_set_0.nft b/tests/shell/testcases/sets/dumps/0006create_set_0.nft
new file mode 100644
index 0000000..70c32a8
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0006create_set_0.nft
@@ -0,0 +1,5 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0007create_element_0.nft b/tests/shell/testcases/sets/dumps/0007create_element_0.nft
new file mode 100644
index 0000000..169be11
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0007create_element_0.nft
@@ -0,0 +1,6 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ elements = { 1.1.1.1 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0008comments_interval_0.nft b/tests/shell/testcases/sets/dumps/0008comments_interval_0.nft
new file mode 100644
index 0000000..5e7a768
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0008comments_interval_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 1.1.1.1 comment "test" }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0008create_verdict_map_0.nft b/tests/shell/testcases/sets/dumps/0008create_verdict_map_0.nft
new file mode 100644
index 0000000..ab0fe80
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0008create_verdict_map_0.nft
@@ -0,0 +1,13 @@
+table ip t {
+ map sourcemap {
+ type ipv4_addr : verdict
+ elements = { 100.123.10.2 : jump c }
+ }
+
+ chain postrouting {
+ ip saddr vmap @sourcemap accept
+ }
+
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0009comments_timeout_0.nft b/tests/shell/testcases/sets/dumps/0009comments_timeout_0.nft
new file mode 100644
index 0000000..455ebe3
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0009comments_timeout_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags timeout
+ elements = { 1.1.1.1 comment "test" }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0010comments_0.nft b/tests/shell/testcases/sets/dumps/0010comments_0.nft
new file mode 100644
index 0000000..6e42ec4
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0010comments_0.nft
@@ -0,0 +1,6 @@
+table inet t {
+ set s {
+ type ipv6_addr
+ elements = { ::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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/sets/dumps/0012add_delete_many_elements_0.nft
new file mode 100644
index 0000000..e3d4aee
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0012add_delete_many_elements_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.nft b/tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.nft
new file mode 100644
index 0000000..e3d4aee
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ }
+}
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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/sets/dumps/0015rulesetflush_0.nft
new file mode 100644
index 0000000..f6eddbf
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0015rulesetflush_0.nft
@@ -0,0 +1,11 @@
+table ip t {
+ chain c {
+ }
+}
+table inet filter {
+ set blacklist_v4 {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.0.0/24 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0016element_leak_0.nft b/tests/shell/testcases/sets/dumps/0016element_leak_0.nft
new file mode 100644
index 0000000..9d2b0af
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0016element_leak_0.nft
@@ -0,0 +1,7 @@
+table ip x {
+ set s {
+ type ipv4_addr
+ size 2
+ elements = { 1.1.1.1 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0017add_after_flush_0.nft b/tests/shell/testcases/sets/dumps/0017add_after_flush_0.nft
new file mode 100644
index 0000000..9d2b0af
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0017add_after_flush_0.nft
@@ -0,0 +1,7 @@
+table ip x {
+ set s {
+ type ipv4_addr
+ size 2
+ elements = { 1.1.1.1 }
+ }
+}
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 0000000..8cd3707
--- /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.nft b/tests/shell/testcases/sets/dumps/0019set_check_size_0.nft
new file mode 100644
index 0000000..8cd3707
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0019set_check_size_0.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/0020comments_0.nft b/tests/shell/testcases/sets/dumps/0020comments_0.nft
new file mode 100644
index 0000000..8b7d60a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0020comments_0.nft
@@ -0,0 +1,6 @@
+table inet t {
+ set s {
+ type inet_service
+ elements = { 22 comment "test" }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0021nesting_0.nft b/tests/shell/testcases/sets/dumps/0021nesting_0.nft
new file mode 100644
index 0000000..6fd2a44
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0021nesting_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip saddr { 1.1.1.0/24, 2.2.2.0/24, 3.3.3.0/24 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft
new file mode 100644
index 0000000..0a4cb0a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft
@@ -0,0 +1,13 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ }
+
+ map m {
+ type ipv4_addr : inet_service
+ }
+
+ chain c {
+ tcp dport 80 meter f size 1024 { ip saddr limit rate 10/second burst 5 packets }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.nft b/tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.nft
new file mode 100644
index 0000000..985768b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.nft
@@ -0,0 +1,2 @@
+table ip t {
+}
diff --git a/tests/shell/testcases/sets/dumps/0024named_objects_0.nft b/tests/shell/testcases/sets/dumps/0024named_objects_0.nft
new file mode 100644
index 0000000..52d1bf6
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0024named_objects_0.nft
@@ -0,0 +1,50 @@
+table inet x {
+ counter user123 {
+ packets 12 bytes 1433
+ }
+
+ counter user321 {
+ packets 0 bytes 0
+ }
+
+ quota user123 {
+ over 2000 bytes
+ }
+
+ 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
+ }
+
+ map test {
+ 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 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/sets/dumps/0025anonymous_set_0.nft b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
new file mode 100644
index 0000000..5963699
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ chain c {
+ type filter hook output priority filter; policy accept;
+ ip daddr { 192.168.0.1, 192.168.0.2, 192.168.0.3 }
+ oifname "doesntexist" tcp dport { 22, 23 } counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0026named_limit_0.nft b/tests/shell/testcases/sets/dumps/0026named_limit_0.nft
new file mode 100644
index 0000000..e4daa28
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0026named_limit_0.nft
@@ -0,0 +1,10 @@
+table ip filter {
+ limit http-traffic {
+ rate 1/second
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ limit name tcp dport map { 80 : "http-traffic", 443 : "http-traffic" }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.nft b/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.nft
new file mode 100644
index 0000000..c49eefa
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.nft
@@ -0,0 +1,7 @@
+table inet t {
+ set s {
+ type ipv6_addr
+ flags interval
+ elements = { ::ffff:0.0.0.0/96 }
+ }
+}
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 0000000..0c60492
--- /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.nft b/tests/shell/testcases/sets/dumps/0028delete_handle_0.nft
new file mode 100644
index 0000000..0f25c76
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0028delete_handle_0.nft
@@ -0,0 +1,15 @@
+table ip test-ip {
+ set x {
+ type ipv4_addr
+ }
+
+ set y {
+ type inet_service
+ timeout 3h45s
+ }
+
+ set z {
+ type ipv4_addr
+ flags constant,interval
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft b/tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft
new file mode 100644
index 0000000..55cd4f2
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft
@@ -0,0 +1,57 @@
+table inet t {
+ set s {
+ type ifname
+ elements = { "eth0",
+ "eth1",
+ "eth2",
+ "eth3",
+ "veth1" }
+ }
+
+ set sc {
+ type inet_service . ifname
+ elements = { 22 . "eth0",
+ 80 . "eth0",
+ 81 . "eth0",
+ 80 . "eth1" }
+ }
+
+ set nv {
+ type ifname . mark
+ elements = { "eth0" . 0x00000001,
+ "eth0" . 0x00000002 }
+ }
+
+ set z {
+ typeof ct zone
+ elements = { 1, 2, 3, 4, 5,
+ 6 }
+ }
+
+ set m {
+ typeof meta mark
+ elements = { 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005,
+ 0x00000006 }
+ }
+
+ map cz {
+ typeof iifname : ct zone
+ elements = { "eth0" : 1,
+ "eth1" : 2,
+ "veth4" : 1 }
+ }
+
+ map cm {
+ typeof iifname : ct mark
+ elements = { "eth0" : 0x00000001,
+ "eth1" : 0x00000002,
+ "veth4" : 0x00000001 }
+ }
+
+ chain c {
+ iifname @s accept
+ oifname @s accept
+ tcp dport . iifname @sc accept
+ iifname . meta mark @nv accept
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0030add_many_elements_interval_0.nodump b/tests/shell/testcases/sets/dumps/0030add_many_elements_interval_0.nodump
new file mode 100644
index 0000000..e69de29
--- /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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.nft
new file mode 100644
index 0000000..86c5549
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.nft
@@ -0,0 +1,11 @@
+table ip filter {
+ 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/0033add_set_simple_flat_0.nft b/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.nft
new file mode 100644
index 0000000..d6174c5
--- /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.nft b/tests/shell/testcases/sets/dumps/0034get_element_0.nft
new file mode 100644
index 0000000..1c1dd97
--- /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.nft b/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.nft
new file mode 100644
index 0000000..ca69cee
--- /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 0000000..e69de29
--- /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.nft b/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.nft
new file mode 100644
index 0000000..68b1f7b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.nft
@@ -0,0 +1,16 @@
+table inet filter {
+ set myset {
+ type ipv4_addr . inet_proto . inet_service
+ elements = { 192.168.0.113 . tcp . 22,
+ 192.168.0.12 . tcp . 53,
+ 192.168.0.12 . udp . 53,
+ 192.168.0.12 . tcp . 80,
+ 192.168.0.13 . tcp . 80 }
+ }
+
+ chain forward {
+ type filter hook forward priority filter; policy drop;
+ ct state established,related accept
+ ct state new ip daddr . ip protocol . th dport @myset accept
+ }
+}
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 0000000..f274086
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0038meter_list_0.nft
@@ -0,0 +1,11 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ size 256
+ flags dynamic,timeout
+ }
+
+ chain c {
+ tcp dport 80 meter m size 128 { ip saddr limit rate 10/second burst 5 packets }
+ }
+}
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 0000000..1fc7657
--- /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.nft b/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.nft
new file mode 100644
index 0000000..f580c38
--- /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.nft b/tests/shell/testcases/sets/dumps/0041interval_0.nft
new file mode 100644
index 0000000..222d4d7
--- /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.nft b/tests/shell/testcases/sets/dumps/0042update_set_0.nft
new file mode 100644
index 0000000..56cc875
--- /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.nft b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.nft
new file mode 100644
index 0000000..f2077b9
--- /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.nft b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.nft
new file mode 100644
index 0000000..19d08d3
--- /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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0044interval_overlap_0.nodump
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 0000000..5b249a3
--- /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.nft b/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft
new file mode 100644
index 0000000..e548a17
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft
@@ -0,0 +1,12 @@
+table inet t {
+ set s {
+ type ipv4_addr . inet_service
+ size 65536
+ flags dynamic,timeout
+ elements = { 192.168.7.1 . 22 }
+ }
+
+ chain c {
+ tcp dport 21 add @s { ip saddr . 22 timeout 1m }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0046netmap_0.nft b/tests/shell/testcases/sets/dumps/0046netmap_0.nft
new file mode 100644
index 0000000..5ac6b34
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0046netmap_0.nft
@@ -0,0 +1,12 @@
+table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24, 10.141.12.0/24 : 192.168.3.0/24, 10.141.13.0/24 : 192.168.4.0/24 }
+ }
+}
+table ip6 x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip6 prefix to ip6 saddr map { 2001:db8:1111::/64 : 2001:db8:2222::/64 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0047nat_0.nft b/tests/shell/testcases/sets/dumps/0047nat_0.nft
new file mode 100644
index 0000000..9fa9fc7
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0047nat_0.nft
@@ -0,0 +1,30 @@
+table ip x {
+ map y {
+ type ipv4_addr : interval ipv4_addr
+ flags interval
+ elements = { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2/31,
+ 10.141.12.0/24 : 192.168.5.10-192.168.5.20 }
+ }
+
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip to ip saddr map @y
+ }
+}
+table inet x {
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat ip to ip daddr . tcp dport map { 10.141.10.1 . 22 : 192.168.2.2, 10.141.11.2 . 2222 : 192.168.4.2 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip to ip saddr map { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2/31 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0048set_counters_0.nft b/tests/shell/testcases/sets/dumps/0048set_counters_0.nft
new file mode 100644
index 0000000..2145f6b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0048set_counters_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set y {
+ typeof ip saddr
+ counter
+ elements = { 192.168.10.35 counter packets 0 bytes 0, 192.168.10.101 counter packets 0 bytes 0,
+ 192.168.10.135 counter packets 0 bytes 0 }
+ }
+
+ chain z {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0049set_define_0.nft b/tests/shell/testcases/sets/dumps/0049set_define_0.nft
new file mode 100644
index 0000000..998b387
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0049set_define_0.nft
@@ -0,0 +1,6 @@
+table inet filter {
+ 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.nft b/tests/shell/testcases/sets/dumps/0050set_define_1.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0050set_define_1.nft
diff --git a/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft
new file mode 100644
index 0000000..fd488a7
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set s {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 192.168.2.0/24 counter packets 0 bytes 0 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @s
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0052overlap_0.nft b/tests/shell/testcases/sets/dumps/0052overlap_0.nft
new file mode 100644
index 0000000..1cc02ad
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0052overlap_0.nft
@@ -0,0 +1,8 @@
+table ip filter {
+ set w_all {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 10.10.10.10, 10.10.10.253 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0053echo_0.nft b/tests/shell/testcases/sets/dumps/0053echo_0.nft
new file mode 100644
index 0000000..bb7c551
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0053echo_0.nft
@@ -0,0 +1,6 @@
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy drop;
+ iifname "lo" ip saddr 10.0.0.0/8 ip daddr 192.168.100.62 tcp dport 2001 counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0054comments_set_0.nft b/tests/shell/testcases/sets/dumps/0054comments_set_0.nft
new file mode 100644
index 0000000..7929924
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0054comments_set_0.nft
@@ -0,0 +1,13 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ comment "test"
+ }
+
+ map m {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ comment "another test"
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0055tcpflags_0.nft b/tests/shell/testcases/sets/dumps/0055tcpflags_0.nft
new file mode 100644
index 0000000..ffed542
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0055tcpflags_0.nft
@@ -0,0 +1,10 @@
+table ip test {
+ set tcp_good_flags {
+ type tcp_flag
+ flags constant
+ elements = { fin | 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.nft b/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.nft
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 0000000..de43d56
--- /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.nft b/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.nft
new file mode 100644
index 0000000..873adc6
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.nft
@@ -0,0 +1,12 @@
+table inet filter {
+ set ssh_meter {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 30d
+ }
+
+ chain test {
+ add @ssh_meter { ip saddr timeout 30d }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft b/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft
new file mode 100644
index 0000000..c1cc3b5
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 1h
+ }
+
+ chain z {
+ type filter hook output priority filter; policy accept;
+ update @y { ip daddr limit rate 1/second burst 5 packets counter }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft b/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft
new file mode 100644
index 0000000..df68fcd
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ limit rate 1/second burst 5 packets counter
+ elements = { 1.1.1.1 limit rate 1/second burst 5 packets counter packets 0 bytes 0, 4.4.4.4 limit rate 1/second burst 5 packets counter packets 0 bytes 0,
+ 5.5.5.5 limit rate 1/second burst 5 packets counter packets 0 bytes 0 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0060set_multistmt_1.nft b/tests/shell/testcases/sets/dumps/0060set_multistmt_1.nft
new file mode 100644
index 0000000..ac1bd26
--- /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.nft b/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.nft
new file mode 100644
index 0000000..04361f4
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip saddr { 1.1.1.1-1.1.1.2 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft
new file mode 100644
index 0000000..080d675
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft
@@ -0,0 +1,16 @@
+table ip x {
+ set est-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ elements = { 84.245.120.167 ct count over 20 }
+ }
+
+ set new-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ ct count over 20
+ elements = { 84.245.120.167 ct count over 20 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0063set_catchall_0.nft b/tests/shell/testcases/sets/dumps/0063set_catchall_0.nft
new file mode 100644
index 0000000..f0d42cc
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0063set_catchall_0.nft
@@ -0,0 +1,14 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ counter
+ elements = { 1.1.1.1 counter packets 0 bytes 0, * counter packets 0 bytes 0 }
+ }
+
+ set z {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 1.1.1.0/24 counter packets 0 bytes 0, * counter packets 0 bytes 0 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0064map_catchall_0.nft b/tests/shell/testcases/sets/dumps/0064map_catchall_0.nft
new file mode 100644
index 0000000..890ed2a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0064map_catchall_0.nft
@@ -0,0 +1,18 @@
+table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ elements = { 10.141.0.1 : 192.168.0.2, * : 192.168.0.4 }
+ }
+
+ map z {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }
+ }
+
+ chain y {
+ snat to ip saddr map @z
+ snat to ip saddr map { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }
+ snat to ip saddr . ip daddr map { 10.141.0.0/24 . 10.0.0.0/8 : 192.168.0.2, 192.168.9.0/24 . 192.168.10.0/24 : 192.168.0.4, * : 192.168.0.3 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft b/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft
new file mode 100644
index 0000000..461c7a7
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft
@@ -0,0 +1,6 @@
+table ip x {
+ chain foo {
+ accept
+ icmp type { echo-reply, echo-request } icmp id 42
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft b/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft
new file mode 100644
index 0000000..0215691
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft
@@ -0,0 +1,42 @@
+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
+ elements = { 192.168.1.2 . 192.168.2.2 : 127.0.0.0/8 . 42-43 }
+ }
+
+ map fwdtoip_th {
+ type ipv4_addr . inet_service : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 1.2.3.4 . 10000-20000 : 192.168.3.4 . 30000-40000 }
+ }
+
+ map ipportmap4 {
+ typeof iifname . ip saddr : interval ip daddr
+ flags interval
+ elements = { "enp2s0" . 10.1.1.136 : 1.1.2.69/32,
+ "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+
+ map ipportmap5 {
+ typeof iifname . ip saddr : interval ip daddr . tcp dport
+ flags interval
+ elements = { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22,
+ "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ ip protocol tcp dnat ip to ip saddr 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/0068interval_stack_overflow_0.nodump b/tests/shell/testcases/sets/dumps/0068interval_stack_overflow_0.nodump
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0068interval_stack_overflow_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/0069interval_merge_0.nft b/tests/shell/testcases/sets/dumps/0069interval_merge_0.nft
new file mode 100644
index 0000000..2d4e170
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0069interval_merge_0.nft
@@ -0,0 +1,9 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 1.2.3.0-1.2.4.255, 3.3.3.3-3.3.3.6,
+ 4.4.4.0-4.4.5.0 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
new file mode 100644
index 0000000..0057e9c
--- /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.nft b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft
new file mode 100644
index 0000000..4eed94c
--- /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.nft b/tests/shell/testcases/sets/dumps/0072destroy_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /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.nft b/tests/shell/testcases/sets/dumps/0073flat_interval_set.nft
new file mode 100644
index 0000000..20f5374
--- /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.nft b/tests/shell/testcases/sets/dumps/0074nested_interval_set.nft
new file mode 100644
index 0000000..20f5374
--- /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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/automerge_0.nodump
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 0000000..a3244fc
--- /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.nft b/tests/shell/testcases/sets/dumps/concat_interval_0.nft
new file mode 100644
index 0000000..61547c5
--- /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.nft b/tests/shell/testcases/sets/dumps/dynset_missing.nft
new file mode 100644
index 0000000..6c8ed32
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/dynset_missing.nft
@@ -0,0 +1,12 @@
+table ip test {
+ set dlist {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ udp dport 1234 update @dlist { ip daddr } counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/errors_0.nft b/tests/shell/testcases/sets/dumps/errors_0.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/errors_0.nft
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 0000000..c903e3f
--- /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.nft b/tests/shell/testcases/sets/dumps/inner_0.nft
new file mode 100644
index 0000000..925ca77
--- /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/reset_command_0.nodump b/tests/shell/testcases/sets/dumps/reset_command_0.nodump
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/reset_command_0.nodump
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 0000000..a45462b
--- /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.nft b/tests/shell/testcases/sets/dumps/sets_with_ifnames.nft
new file mode 100644
index 0000000..77a8baf
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/sets_with_ifnames.nft
@@ -0,0 +1,62 @@
+table inet testifsets {
+ set simple {
+ type ifname
+ elements = { "abcdef0",
+ "abcdef1",
+ "othername" }
+ }
+
+ set simple_wild {
+ type ifname
+ flags interval
+ elements = { "abcdef*",
+ "othername",
+ "ppp0" }
+ }
+
+ set concat {
+ type ipv4_addr . ifname
+ elements = { 10.1.2.2 . "abcdef0",
+ 10.1.2.2 . "abcdef1" }
+ }
+
+ set concat_wild {
+ type ipv4_addr . ifname
+ flags interval
+ elements = { 10.1.2.2 . "abcdef*",
+ 10.1.2.1 . "bar",
+ 1.1.2.0/24 . "abcdef0",
+ 12.2.2.0/24 . "abcdef*" }
+ }
+
+ map map_wild {
+ type ifname : verdict
+ flags interval
+ elements = { "abcdef*" : jump do_nothing,
+ "eth0" : jump do_nothing }
+ }
+
+ chain v4icmp {
+ iifname @simple counter packets 0 bytes 0
+ iifname @simple_wild counter packets 0 bytes 0
+ iifname { "eth0", "abcdef0" } counter packets 0 bytes 0
+ iifname { "abcdef*", "eth0" } counter packets 0 bytes 0
+ iifname vmap @map_wild
+ }
+
+ chain v4icmpc {
+ ip saddr . iifname @concat counter packets 0 bytes 0
+ ip saddr . iifname @concat_wild counter packets 0 bytes 0
+ ip saddr . iifname { 10.1.2.2 . "abcdef0" } counter packets 0 bytes 0
+ ip saddr . iifname { 10.1.2.2 . "abcdef*" } counter packets 0 bytes 0
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ip protocol icmp jump v4icmp
+ ip protocol icmp goto v4icmpc
+ }
+
+ chain do_nothing {
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/type_set_symbol.nft b/tests/shell/testcases/sets/dumps/type_set_symbol.nft
new file mode 100644
index 0000000..21209f6
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/type_set_symbol.nft
@@ -0,0 +1,16 @@
+table ip t {
+ set s1 {
+ type ipv4_addr . ipv4_addr . inet_service
+ size 65535
+ flags dynamic,timeout
+ timeout 3h
+ }
+
+ chain c1 {
+ update @s1 { ip saddr . 10.180.0.4 . 80 }
+ }
+
+ chain c2 {
+ ip saddr . 1.2.3.4 . 80 @s1 goto c1
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/typeof_raw_0.nft b/tests/shell/testcases/sets/dumps/typeof_raw_0.nft
new file mode 100644
index 0000000..4d6abaa
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_raw_0.nft
@@ -0,0 +1,12 @@
+table inet t {
+ set y {
+ typeof ip daddr . @ih,32,32
+ elements = { 1.1.1.1 . 0x14,
+ 2.2.2.2 . 0x20 }
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+ ip daddr . @nh,32,32 @y
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
new file mode 100644
index 0000000..6f5b83a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
@@ -0,0 +1,97 @@
+table inet t {
+ set s1 {
+ typeof osf name
+ elements = { "Linux" }
+ }
+
+ set s2 {
+ typeof vlan id
+ elements = { 2, 3, 103 }
+ }
+
+ set s3 {
+ typeof meta ibrpvid
+ elements = { 2, 3, 103 }
+ }
+
+ set s4 {
+ typeof frag frag-off
+ elements = { 1, 1024 }
+ }
+
+ set s5 {
+ typeof ip option ra value
+ elements = { 1, 1024 }
+ }
+
+ set s6 {
+ typeof tcp option maxseg size
+ elements = { 1, 1024 }
+ }
+
+ set s7 {
+ typeof sctp chunk init num-inbound-streams
+ elements = { 1, 4 }
+ }
+
+ set s8 {
+ typeof ip version
+ elements = { 4, 6 }
+ }
+
+ set s9 {
+ typeof ip hdrlength
+ elements = { 0, 1, 2, 3, 4,
+ 15 }
+ }
+
+ set s10 {
+ typeof iifname . ip saddr . ipsec in reqid
+ elements = { "eth0" . 10.1.1.2 . 42 }
+ }
+
+ set s11 {
+ typeof vlan id . ip saddr
+ elements = { 3567 . 1.2.3.4 }
+ }
+
+ chain c1 {
+ osf name @s1 accept
+ }
+
+ chain c2 {
+ vlan id @s2 accept
+ }
+
+ chain c4 {
+ frag frag-off @s4 accept
+ }
+
+ chain c5 {
+ ip option ra value @s5 accept
+ }
+
+ chain c6 {
+ tcp option maxseg size @s6 accept
+ }
+
+ chain c7 {
+ sctp chunk init num-inbound-streams @s7 accept
+ }
+
+ chain c8 {
+ ip version @s8 accept
+ }
+
+ chain c9 {
+ ip hdrlength @s9 accept
+ }
+
+ chain c10 {
+ iifname . ip saddr . ipsec in reqid @s10 accept
+ }
+
+ chain c11 {
+ vlan id . ip saddr @s11 accept
+ }
+}
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 0000000..89cbc83
--- /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 0000000..dbaf7cd
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
@@ -0,0 +1,12 @@
+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
+ }
+}
diff --git a/tests/shell/testcases/sets/dynset_missing b/tests/shell/testcases/sets/dynset_missing
new file mode 100755
index 0000000..fdf5f49
--- /dev/null
+++ b/tests/shell/testcases/sets/dynset_missing
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+set -e
+
+$NFT -f /dev/stdin <<EOF
+table ip test {
+ chain output { type filter hook output priority 0;
+ }
+}
+EOF
+
+# misses 'flags dynamic'
+$NFT 'add set ip test dlist {type ipv4_addr; }'
+
+# picks rhash backend because 'size' was also missing.
+$NFT 'add rule ip test output udp dport 1234 update @dlist { ip daddr } counter'
+
+tmpfile=$(mktemp)
+
+trap "rm -rf $tmpfile" EXIT
+
+# kernel has forced an 64k upper size, i.e. this restore file
+# has 'size 65536' but no 'flags dynamic'.
+$NFT list ruleset > $tmpfile
+
+# this restore works, because set is still the rhash backend.
+$NFT -f $tmpfile # success
+$NFT flush ruleset
+
+# fails without commit 'attempt to set_eval flag if dynamic updates requested',
+# because set in $tmpfile has 'size x' but no 'flags dynamic'.
+$NFT -f $tmpfile
diff --git a/tests/shell/testcases/sets/errors_0 b/tests/shell/testcases/sets/errors_0
new file mode 100755
index 0000000..27f65df
--- /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 0000000..1ce9304
--- /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 0000000..39d91bd
--- /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/reset_command_0 b/tests/shell/testcases/sets/reset_command_0
new file mode 100755
index 0000000..e663dac
--- /dev/null
+++ b/tests/shell/testcases/sets/reset_command_0
@@ -0,0 +1,93 @@
+#!/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 and expiry are reset: "
+NEW=$($NFT "get $elem")
+grep -q 'counter packets 0 bytes 0' <<< "$NEW"
+[[ $(expires_minutes <<< "$NEW") -gt 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 "reset command respects per-element timeout: "
+VAL=$($NFT get element t s '{ 2.0.0.2 . tcp . 22 }' | expires_minutes)
+[[ $VAL -lt 15 ]] # custom timeout applies
+[[ $VAL -gt 10 ]] # expires was reset
+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 0000000..82b6d3b
--- /dev/null
+++ b/tests/shell/testcases/sets/set_eval_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip nat {
+ set set_with_interval {
+ type ipv4_addr
+ flags interval
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto { tcp, udp } th dport 443 dnat to 10.0.0.1
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/sets_with_ifnames b/tests/shell/testcases/sets/sets_with_ifnames
new file mode 100755
index 0000000..9531c85
--- /dev/null
+++ b/tests/shell/testcases/sets/sets_with_ifnames
@@ -0,0 +1,150 @@
+#!/bin/bash
+
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+[ -z "$NFT" ] && exit 111
+
+$NFT -f "$dumpfile" || exit 1
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1ifname-$rnd"
+ns2="nft2ifname-$rnd"
+
+cleanup()
+{
+ ip netns del "$ns1"
+ ip netns del "$ns2"
+}
+
+trap cleanup EXIT
+
+# check a given element is (not) present in the set.
+lookup_elem()
+{
+ local setname=$1
+ local value=$2
+ local fail=$3
+ local expect_result=$4
+ local msg=$5
+
+ result=$(ip netns exec "$ns1" $NFT get element inet testifsets $setname { "$value" } 2>/dev/null | grep "$expect_result" )
+
+ if [ -z "$result" ] && [ $fail -ne 1 ] ; then
+ echo "empty result, expected $expect_result $msg"
+ ip netns exec "$ns1" $NFT get element inet testifsets $setname { "$value" }
+ exit 1
+ fi
+}
+
+check_elem_get()
+{
+ local setname=$1
+ local value=$2
+ local fail=$3
+ local expect_result=$4
+
+ # when query is 'abcde', and set has 'abc*', result is
+ # 'abc*', not 'abcde', so returned element can be different.
+ if [ -z "$expect_result" ]; then
+ expect_result=$ifname
+ fi
+
+ lookup_elem "$setname" "$value" "$fail" "$expect_result" ""
+}
+
+# same, but also delete and re-add the element.
+check_elem()
+{
+ local setname=$1
+ local value=$2
+
+ lookup_elem "$setname" "$value" "0" "$value" "initial check"
+
+ ip netns exec "$ns1" $NFT delete element inet testifsets $setname { "$value" }
+ if [ $? -ne 0 ]; then
+ ip netns exec "$ns1" $NFT list ruleset
+ echo "delete element $setname { $value } failed"
+ exit 1
+ fi
+
+ ip netns exec "$ns1" $NFT add element inet testifsets $setname { "$value" }
+
+ lookup_elem "$setname" "$value" "0" "$value" "check after add/del"
+}
+
+# send pings, check all rules with sets that contain abcdef1 match.
+# there are 4 rules in this chain, 4 should match.
+check_matching_icmp_ppp()
+{
+ pkt=$((RANDOM%10))
+ pkt=$((pkt+1))
+ ip netns exec "$ns1" ping -f -c $pkt 10.1.2.2
+
+ # replies should arrive via 'abcdeg', so, should NOT increment any counters.
+ ip netns exec "$ns1" ping -f -c 100 10.2.2.2
+
+ matches=$(ip netns exec "$ns1" $NFT list chain inet testifsets v4icmp | grep "counter packets $pkt " | wc -l)
+ want=3
+
+ if [ "$matches" -ne $want ] ;then
+ ip netns exec "$ns1" $NFT list ruleset
+ echo "Expected $want matching rules, got $matches, packets $pkt in v4icmp"
+ exit 1
+ fi
+
+ # same, for concat set type.
+
+ matches=$(ip netns exec "$ns1" $NFT list chain inet testifsets v4icmpc | grep "counter packets $pkt " | wc -l)
+
+ if [ "$matches" -ne $want ] ;then
+ ip netns exec "$ns1" $NFT list ruleset
+ echo "Expected $want matching rules, got $matches, packets $pkt in v4icmpc"
+ exit 1
+ fi
+}
+
+ip netns add "$ns1" || exit 111
+ip netns add "$ns2" || exit 111
+ip netns exec "$ns1" $NFT -f "$dumpfile" || exit 3
+
+for n in abcdef0 abcdef1 othername;do
+ check_elem simple $n
+done
+
+check_elem_get simple foo 1
+
+for n in ppp0 othername;do
+ check_elem simple_wild $n
+done
+
+check_elem_get simple_wild enoent 1
+check_elem simple_wild ppp0
+check_elem_get simple_wild abcdefghijk 0 'abcdef\*'
+
+check_elem_get concat '1.2.3.4 . "enoent"' 1
+check_elem_get concat '10.1.2.2 . "abcdef"' 1
+check_elem_get concat '10.1.2.1 . "abcdef1"' 1
+
+check_elem concat '10.1.2.2 . "abcdef0"'
+check_elem concat '10.1.2.2 . "abcdef1"'
+
+set -e
+ip -net "$ns1" link set lo up
+ip -net "$ns2" link set lo up
+ip netns exec "$ns1" ping -f -c 10 127.0.0.1
+
+ip link add abcdef1 netns $ns1 type veth peer name veth0 netns $ns2
+ip link add abcdeg netns $ns1 type veth peer name veth1 netns $ns2
+
+ip -net "$ns1" link set abcdef1 up
+ip -net "$ns2" link set veth0 up
+ip -net "$ns1" link set abcdeg up
+ip -net "$ns2" link set veth1 up
+
+ip -net "$ns1" addr add 10.1.2.1/24 dev abcdef1
+ip -net "$ns1" addr add 10.2.2.1/24 dev abcdeg
+
+ip -net "$ns2" addr add 10.1.2.2/24 dev veth0
+ip -net "$ns2" addr add 10.2.2.2/24 dev veth1
+
+check_matching_icmp_ppp
diff --git a/tests/shell/testcases/sets/type_set_symbol b/tests/shell/testcases/sets/type_set_symbol
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/sets/type_set_symbol
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/typeof_raw_0 b/tests/shell/testcases/sets/typeof_raw_0
new file mode 100755
index 0000000..66042eb
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_raw_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+EXPECTED="table inet t {
+ set y {
+ typeof ip daddr . @ih,32,32
+ elements = { 1.1.1.1 . 0x14, 2.2.2.2 . 0x20}
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+ ip daddr . @nh,32,32 @y
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/sets/typeof_sets_0 b/tests/shell/testcases/sets/typeof_sets_0
new file mode 100755
index 0000000..35c572c
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_sets_0
@@ -0,0 +1,226 @@
+#!/bin/bash
+
+# support for strings/typeof in named sets.
+# s1 and s2 are identical, they just use different
+# ways for declaration.
+
+set -e
+
+die() {
+ printf '%s\n' "$*"
+ exit 1
+}
+
+INPUT_OSF_SET="
+ set s1 {
+ typeof osf name
+ elements = { \"Linux\" }
+ }
+"
+INPUT_OSF_CHAIN="
+ chain c1 {
+ osf name @s1 accept
+ }
+"
+
+INPUT_SCTP_CHAIN="
+ chain c7 {
+ sctp chunk init num-inbound-streams @s7 accept
+ }
+"
+
+if [ "$NFT_TEST_HAVE_sctp_chunks" = n ] ; then
+ INPUT_SCTP_CHAIN=
+fi
+
+if [ "$NFT_TEST_HAVE_osf" = n ] ; then
+ if [ "$((RANDOM % 2))" -eq 1 ] ; then
+ # Regardless of $NFT_TEST_HAVE_osf, we can define the set.
+ # Randomly do so.
+ INPUT_OSF_SET=
+ fi
+ INPUT_OSF_CHAIN=
+fi
+
+INPUT="table inet t {$INPUT_OSF_SET
+ set s2 {
+ typeof vlan id
+ elements = { 2, 3, 103 }
+ }
+
+ set s3 {
+ typeof meta ibrpvid
+ elements = { 2, 3, 103 }
+ }
+
+ set s4 {
+ typeof frag frag-off
+ elements = { 1, 1024 }
+ }
+
+ set s5 {
+ typeof ip option ra value
+ elements = { 1, 1024 }
+ }
+
+ set s6 {
+ typeof tcp option maxseg size
+ elements = { 1, 1024 }
+ }
+
+ set s7 {
+ typeof sctp chunk init num-inbound-streams
+ elements = { 1, 4 }
+ }
+
+ set s8 {
+ typeof ip version
+ elements = { 4, 6 }
+ }
+
+ set s9 {
+ typeof ip hdrlength
+ elements = { 0, 1, 2, 3, 4, 15 }
+ }
+
+ set s10 {
+ typeof meta iifname . ip saddr . ipsec in reqid
+ elements = { \"eth0\" . 10.1.1.2 . 42 }
+ }
+
+ set s11 {
+ typeof vlan id . ip saddr
+ elements = { 3567 . 1.2.3.4 }
+ }
+$INPUT_OSF_CHAIN
+ chain c2 {
+ ether type vlan vlan id @s2 accept
+ }
+
+ chain c4 {
+ frag frag-off @s4 accept
+ }
+
+ chain c5 {
+ ip option ra value @s5 accept
+ }
+
+ chain c6 {
+ tcp option maxseg size @s6 accept
+ }
+$INPUT_SCTP_CHAIN
+ chain c8 {
+ ip version @s8 accept
+ }
+
+ chain c9 {
+ ip hdrlength @s9 accept
+ }
+
+ chain c10 {
+ meta iifname . ip saddr . ipsec in reqid @s10 accept
+ }
+
+ chain c11 {
+ ether type vlan vlan id . ip saddr @s11 accept
+ }
+}"
+
+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 }
+ }
+
+ set s4 {
+ typeof frag frag-off
+ elements = { 1, 1024 }
+ }
+
+ set s5 {
+ typeof ip option ra value
+ elements = { 1, 1024 }
+ }
+
+ set s6 {
+ typeof tcp option maxseg size
+ elements = { 1, 1024 }
+ }
+
+ set s7 {
+ typeof sctp chunk init num-inbound-streams
+ elements = { 1, 4 }
+ }
+
+ set s8 {
+ typeof ip version
+ elements = { 4, 6 }
+ }
+
+ set s9 {
+ typeof ip hdrlength
+ elements = { 0, 1, 2, 3, 4,
+ 15 }
+ }
+
+ set s10 {
+ typeof iifname . ip saddr . ipsec in reqid
+ elements = { \"eth0\" . 10.1.1.2 . 42 }
+ }
+
+ set s11 {
+ typeof vlan id . ip saddr
+ elements = { 3567 . 1.2.3.4 }
+ }
+$INPUT_OSF_CHAIN
+ chain c2 {
+ vlan id @s2 accept
+ }
+
+ chain c4 {
+ frag frag-off @s4 accept
+ }
+
+ chain c5 {
+ ip option ra value @s5 accept
+ }
+
+ chain c6 {
+ tcp option maxseg size @s6 accept
+ }
+$INPUT_SCTP_CHAIN
+ chain c8 {
+ ip version @s8 accept
+ }
+
+ chain c9 {
+ ip hdrlength @s9 accept
+ }
+
+ chain c10 {
+ iifname . ip saddr . ipsec in reqid @s10 accept
+ }
+
+ chain c11 {
+ vlan id . ip saddr @s11 accept
+ }
+}"
+
+
+$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
+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 0000000..e520270
--- /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 0000000..07820b7
--- /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/0001table_0 b/tests/shell/testcases/transactions/0001table_0
new file mode 100755
index 0000000..9929824
--- /dev/null
+++ b/tests/shell/testcases/transactions/0001table_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+delete table x
+add table x
+add table y"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0002table_0 b/tests/shell/testcases/transactions/0002table_0
new file mode 100755
index 0000000..c5f31a6
--- /dev/null
+++ b/tests/shell/testcases/transactions/0002table_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+delete table x
+add table x
+add chain x y { type nat hook prerouting priority 0; policy accept; }
+add table x { flags dormant; }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0003table_0 b/tests/shell/testcases/transactions/0003table_0
new file mode 100755
index 0000000..91186de
--- /dev/null
+++ b/tests/shell/testcases/transactions/0003table_0
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add table y
+flush ruleset"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+KERNEL_RULESET="$($NFT list ruleset)"
+if [ "" != "$KERNEL_RULESET" ] ; then
+ echo "Got a ruleset, but expected empty: "
+ echo "$KERNEL_RULESET"
+ exit 1
+fi
+
+RULESET="table ip x {
+}
+table ip y {
+}"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+RULESETFAIL="flush ruleset
+create table ip nat
+create table inet filter
+create chain ip nat testchain
+delete table ip testtable"
+
+# testtable doesn't exist, batch expected to fail
+$NFT -f - <<< "$RULESETFAIL" && exit 2
+
+KERNEL_RULESET="$($NFT list ruleset)"
+if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0010chain_0 b/tests/shell/testcases/transactions/0010chain_0
new file mode 100755
index 0000000..ce66bd6
--- /dev/null
+++ b/tests/shell/testcases/transactions/0010chain_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add chain x y
+flush ruleset
+add table w
+add chain w y"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0011chain_0 b/tests/shell/testcases/transactions/0011chain_0
new file mode 100755
index 0000000..3bed16d
--- /dev/null
+++ b/tests/shell/testcases/transactions/0011chain_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add chain x y
+delete chain x y
+add chain x y { type filter hook input priority 0; }
+add chain x y { policy drop; }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0012chain_0 b/tests/shell/testcases/transactions/0012chain_0
new file mode 100755
index 0000000..0d80ef4
--- /dev/null
+++ b/tests/shell/testcases/transactions/0012chain_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add chain x y
+flush ruleset
+add table x
+add chain x y { type filter hook input priority 0; }
+add chain x y { policy drop; }
+flush ruleset
+add table w
+add chain w y { type filter hook output priority 0; }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0013chain_0 b/tests/shell/testcases/transactions/0013chain_0
new file mode 100755
index 0000000..2756dd6
--- /dev/null
+++ b/tests/shell/testcases/transactions/0013chain_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add chain x y
+delete chain x y
+delete table x
+add table x
+add chain x y { type filter hook input priority 0; }
+add chain x y { policy drop; }
+flush ruleset
+add table w
+add chain w y { type filter hook output priority 0; }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0014chain_1 b/tests/shell/testcases/transactions/0014chain_1
new file mode 100755
index 0000000..cddc8a2
--- /dev/null
+++ b/tests/shell/testcases/transactions/0014chain_1
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+RULESET="add table x
+add chain x y
+delete chain x y
+delete chain x y"
+
+$NFT -f - <<< "$RULESET" 2>/dev/null || exit 0
+echo "E: allowing double-removal of chain" >&2
+exit 1
diff --git a/tests/shell/testcases/transactions/0015chain_0 b/tests/shell/testcases/transactions/0015chain_0
new file mode 100755
index 0000000..42950b3
--- /dev/null
+++ b/tests/shell/testcases/transactions/0015chain_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add chain x y
+add chain x z
+add rule x z jump y"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+RULESET="delete rule x z handle 3
+delete chain x z
+delete chain x y
+delete table x"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0020rule_0 b/tests/shell/testcases/transactions/0020rule_0
new file mode 100755
index 0000000..f8d2d37
--- /dev/null
+++ b/tests/shell/testcases/transactions/0020rule_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add chain x y
+add rule x y ip saddr 1.1.1.1 counter
+flush ruleset"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0021rule_0 b/tests/shell/testcases/transactions/0021rule_0
new file mode 100755
index 0000000..ee265ab
--- /dev/null
+++ b/tests/shell/testcases/transactions/0021rule_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add chain x y
+add rule x y ip saddr 1.1.1.1 counter
+flush ruleset
+add table x
+add chain x y
+add rule x y ip saddr 2.2.2.2 counter"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0022rule_1 b/tests/shell/testcases/transactions/0022rule_1
new file mode 100755
index 0000000..07be53f
--- /dev/null
+++ b/tests/shell/testcases/transactions/0022rule_1
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+RULESET="add table x
+add chain x y
+delete chain x y
+add rule x y jump y"
+
+# kernel must return ENOENT
+$NFT -f - <<< "$RULESET" 2>/dev/null || exit 0
+echo "E: allowing jump loop to unexisting chain"
+exit 1
diff --git a/tests/shell/testcases/transactions/0023rule_1 b/tests/shell/testcases/transactions/0023rule_1
new file mode 100755
index 0000000..e58c088
--- /dev/null
+++ b/tests/shell/testcases/transactions/0023rule_1
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+RULESET="add table x
+add chain x y
+add rule x y jump y"
+
+# kernel must return ELOOP
+$NFT -f - <<< "$RULESET" 2>/dev/null || exit 0
+echo "E: allowing jump to chain loop"
+exit 1
diff --git a/tests/shell/testcases/transactions/0024rule_0 b/tests/shell/testcases/transactions/0024rule_0
new file mode 100755
index 0000000..4c1ac41
--- /dev/null
+++ b/tests/shell/testcases/transactions/0024rule_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+RULESET="flush ruleset
+add table x
+add chain x y
+add rule x y accept comment rule1
+add rule x y accept comment rule4
+add rule x y index 0 accept comment rule2
+insert rule x y index 2 accept comment rule3"
+
+$NFT -f - <<< "$RULESET" && \
+ $NFT -f - <<< "$RULESET" && \
+ echo "$RULESET" | tr '\n' ';' | $NFT -i >/dev/null && \
+ exit 0
+echo "E: intra-transaction rule reference failed"
+exit 1
+
diff --git a/tests/shell/testcases/transactions/0025rule_0 b/tests/shell/testcases/transactions/0025rule_0
new file mode 100755
index 0000000..d72d5cf
--- /dev/null
+++ b/tests/shell/testcases/transactions/0025rule_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# make sure stored delete/replace rule commands are correctly applied
+
+set -e
+
+$NFT -f - <<EOF
+flush ruleset
+table x {
+ chain y {
+ accept
+ log
+ }
+}
+EOF
+
+$NFT -f - <<EOF
+replace rule x y handle 2 log
+delete rule x y handle 3
+add rule x y index 0 drop
+EOF
diff --git a/tests/shell/testcases/transactions/0030set_0 b/tests/shell/testcases/transactions/0030set_0
new file mode 100755
index 0000000..e17b42f
--- /dev/null
+++ b/tests/shell/testcases/transactions/0030set_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; }
+flush ruleset
+add table x"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0031set_0 b/tests/shell/testcases/transactions/0031set_0
new file mode 100755
index 0000000..b2133cf
--- /dev/null
+++ b/tests/shell/testcases/transactions/0031set_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; }
+delete set x y
+add set x y { type ipv4_addr; }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0032set_0 b/tests/shell/testcases/transactions/0032set_0
new file mode 100755
index 0000000..5882518
--- /dev/null
+++ b/tests/shell/testcases/transactions/0032set_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; }
+flush ruleset
+add table w
+add set w y { type ipv4_addr; }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0033set_0 b/tests/shell/testcases/transactions/0033set_0
new file mode 100755
index 0000000..6bd5893
--- /dev/null
+++ b/tests/shell/testcases/transactions/0033set_0
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; }
+delete set x y"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0034set_0 b/tests/shell/testcases/transactions/0034set_0
new file mode 100755
index 0000000..1580c32
--- /dev/null
+++ b/tests/shell/testcases/transactions/0034set_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; }
+add element x y { 1.1.1.1 }
+delete element x y { 1.1.1.1 }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0035set_0 b/tests/shell/testcases/transactions/0035set_0
new file mode 100755
index 0000000..0967fd4
--- /dev/null
+++ b/tests/shell/testcases/transactions/0035set_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; }
+add element x y { 1.1.1.1, 2.2.2.2 }
+delete element x y { 1.1.1.1 }
+delete element x y { 2.2.2.2 }
+add element x y { 3.3.3.3 }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0036set_1 b/tests/shell/testcases/transactions/0036set_1
new file mode 100755
index 0000000..45d922e
--- /dev/null
+++ b/tests/shell/testcases/transactions/0036set_1
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+RULESET="add table x
+add set x y { type ipv4_addr; }
+add element x y { 1.1.1.1, 2.2.2.2 }
+delete element x y { 1.1.1.1 }
+delete element x y { 1.1.1.1 }"
+
+$NFT -f - <<< "$RULESET" 2> /dev/null || exit 0
+# Kernel must return ENOENT
+echo "E: allowing double-removal of element"
+exit 1
diff --git a/tests/shell/testcases/transactions/0037set_0 b/tests/shell/testcases/transactions/0037set_0
new file mode 100755
index 0000000..2882863
--- /dev/null
+++ b/tests/shell/testcases/transactions/0037set_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; flags interval;}
+add element x y { 1.1.1.0/24 }
+delete element x y { 1.1.1.0/24 }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0038set_0 b/tests/shell/testcases/transactions/0038set_0
new file mode 100755
index 0000000..d7c2ba3
--- /dev/null
+++ b/tests/shell/testcases/transactions/0038set_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; flags interval;}
+add element x y { 192.168.0.0/24, 192.168.2.0/24 }
+delete element x y { 192.168.0.0/24 }
+delete element x y { 192.168.2.0/24 }
+add element x y { 192.168.4.0/24 }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0039set_0 b/tests/shell/testcases/transactions/0039set_0
new file mode 100755
index 0000000..d7c2ba3
--- /dev/null
+++ b/tests/shell/testcases/transactions/0039set_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table x
+add set x y { type ipv4_addr; flags interval;}
+add element x y { 192.168.0.0/24, 192.168.2.0/24 }
+delete element x y { 192.168.0.0/24 }
+delete element x y { 192.168.2.0/24 }
+add element x y { 192.168.4.0/24 }"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0040set_0 b/tests/shell/testcases/transactions/0040set_0
new file mode 100755
index 0000000..468816b
--- /dev/null
+++ b/tests/shell/testcases/transactions/0040set_0
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip filter {
+ map client_to_any {
+ type ipv4_addr : verdict
+ elements = { 1.2.3.4 : goto CIn_1 }
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter; policy accept;
+ goto client_to_any
+ }
+
+ chain client_to_any {
+ ip saddr vmap @client_to_any
+ }
+
+ chain CIn_1 {
+ }
+}"
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+GET="$($NFT list ruleset)"
+
+if [ "$RULESET" != "$GET" ] ; then
+ $DIFF -u <(echo "$RULESET") <(echo "$GET")
+ exit 1
+fi
+
+RULESET="delete element ip filter client_to_any { 1.2.3.4 : goto CIn_1 }
+delete chain ip filter CIn_1"
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0041nat_restore_0 b/tests/shell/testcases/transactions/0041nat_restore_0
new file mode 100755
index 0000000..9e1d6c9
--- /dev/null
+++ b/tests/shell/testcases/transactions/0041nat_restore_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+add table ip t
+add chain ip t c { type nat hook postrouting priority 0; }
+"
+
+$NFT -f - <<< "$RULESET"
+
+RULESET="
+flush ruleset
+$RULESET
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/transactions/0042_stateful_expr_0 b/tests/shell/testcases/transactions/0042_stateful_expr_0
new file mode 100755
index 0000000..918e721
--- /dev/null
+++ b/tests/shell/testcases/transactions/0042_stateful_expr_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+add table ip filter
+add counter ip filter c1
+add map ip filter m1 { type ipv4_addr : counter ;}
+add element ip filter m1 { 1 : c1 }
+add element ip filter m1 { 1 : c1 }
+delete element ip filter m1 { 1 }
+delete counter ip filter c1"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/transactions/0043set_1 b/tests/shell/testcases/transactions/0043set_1
new file mode 100755
index 0000000..a9135c1
--- /dev/null
+++ b/tests/shell/testcases/transactions/0043set_1
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+RULESET="add table ip test
+add set ip test foo { type ipv4_addr; }
+add chain ip test tc
+add element ip test foo { 1.2.3.4 }
+add rule ip test tc ip saddr { 1.2.3.4, 5.6.7.8 } accept
+delete table ip test
+add element ip test foo { 1.2.3.6 }"
+
+# kernel must return ENOENT
+$NFT -f - <<< "$RULESET" 2>/dev/null || exit 0
+echo "E: allowing element insertion on unexisting set"
+exit 1
diff --git a/tests/shell/testcases/transactions/0044rule_0 b/tests/shell/testcases/transactions/0044rule_0
new file mode 100755
index 0000000..a4da480
--- /dev/null
+++ b/tests/shell/testcases/transactions/0044rule_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+RULESET="add table ip test
+add chain ip test tc
+add rule ip test tc counter"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
+
+RULESET="delete rule ip test tc handle 2
+flush ruleset"
+
+$NFT -f - <<< "$RULESET"
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/transactions/0045anon-unbind_0 b/tests/shell/testcases/transactions/0045anon-unbind_0
new file mode 100755
index 0000000..1e16af1
--- /dev/null
+++ b/tests/shell/testcases/transactions/0045anon-unbind_0
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+RULESET='table inet filter {
+ chain antileak {
+ udp dport { 137, 138 } drop comment "NetBT"
+ }
+}'
+
+set -e
+$NFT -c -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/transactions/0046set_0 b/tests/shell/testcases/transactions/0046set_0
new file mode 100755
index 0000000..172e24d
--- /dev/null
+++ b/tests/shell/testcases/transactions/0046set_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+RULESET='add table ip filter
+add chain ip filter group_7933
+add map ip filter group_7933 { type ipv4_addr : classid; flags interval; }
+add rule ip filter group_7933 meta priority 0 meta priority set ip saddr map @group_7933 counter
+add element ip filter group_7933 { 10.4.22.0/24 : "1:0xc7cb" }
+'
+
+set -e
+$NFT -f - <<< "$RULESET"
+
+RULESET='delete element ip filter group_7933 { 10.4.22.0/24 }
+flush chain ip filter group_7933
+delete chain ip filter group_7933
+delete map ip filter group_7933'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/transactions/0047set_0 b/tests/shell/testcases/transactions/0047set_0
new file mode 100755
index 0000000..0a27231
--- /dev/null
+++ b/tests/shell/testcases/transactions/0047set_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+RULESET='add table ip filter
+add map ip filter group_10060 { type ipv4_addr : classid; flags interval; }
+add element ip filter group_10060 { 10.1.26.2/32 : "1:0xbbf8" }
+add element ip filter group_10060 { 10.1.26.3/32 : "1:0xc1ad" }
+add element ip filter group_10060 { 10.1.26.4/32 : "1:0xb2d7" }
+add element ip filter group_10060 { 10.1.26.5/32 : "1:0xf705" }
+add element ip filter group_10060 { 10.1.26.6/32 : "1:0xb895" }
+add element ip filter group_10060 { 10.1.26.7/32 : "1:0xec4c" }
+add element ip filter group_10060 { 10.1.26.8/32 : "1:0xde78" }
+add element ip filter group_10060 { 10.1.26.9/32 : "1:0xb4f3" }
+add element ip filter group_10060 { 10.1.26.10/32 : "1:0xdec6" }
+add element ip filter group_10060 { 10.1.26.11/32 : "1:0xb4c0" }
+add element ip filter group_10060 { 10.1.26.12/32 : "1:0xb4a2" }
+add element ip filter group_10060 { 10.1.26.13/32 : "1:0xa8ab" }
+add element ip filter group_10060 { 10.1.26.14/32 : "1:0xb3c1" }'
+
+set -e
+$NFT -f - <<< "$RULESET"
+
+RULESET='delete element ip filter group_10060 { 10.1.26.13/32 }
+delete element ip filter group_10060 { 10.1.26.14/32 }
+delete element ip filter group_10060 { 10.1.26.12/32 }'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/transactions/0048helpers_0 b/tests/shell/testcases/transactions/0048helpers_0
new file mode 100755
index 0000000..675a977
--- /dev/null
+++ b/tests/shell/testcases/transactions/0048helpers_0
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+RULESET='add table ip filter
+add chain ip filter filter { type filter hook prerouting priority mangle; policy accept; }
+add ct helper ip filter ftp { type "ftp" protocol tcp; };
+add rule ip filter filter tcp dport 33 ct helper set "ftp"'
+
+set -e
+$NFT -f - <<< "$RULESET"
+
+RULESET='flush chain ip filter filter
+delete chain filter filter
+delete ct helper ip filter ftp'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/transactions/0049huge_0 b/tests/shell/testcases/transactions/0049huge_0
new file mode 100755
index 0000000..f66953c
--- /dev/null
+++ b/tests/shell/testcases/transactions/0049huge_0
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# let's try to exceed transaction buffer space
+
+$NFT flush ruleset
+$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"
+done
+)
+test $($NFT -e -a -f - <<< "$RULESET" |grep "#[ ]\+handle[ ]\+[0-9]\+" |wc -l) -eq ${RULE_COUNT} || exit 1
+
+# same thing, but with JSON rules
+#
+$NFT flush ruleset
+$NFT add table inet test
+$NFT add chain inet test c
+
+RULESET=$(
+echo '{"nftables": ['
+for ((i = 0; i < $((${RULE_COUNT} - 1)); i++)); do
+ echo '{"add": {"rule": {"family": "inet", "table": "test", "chain": "c", "expr": [{"accept": null}], "comment": "rule'$i'"}}},'
+done
+ echo '{"add": {"rule": {"family": "inet", "table": "test", "chain": "c", "expr": [{"accept": null}], "comment": "rule'$((${RULE_COUNT} - 1))'"}}}'
+echo ']}'
+)
+
+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
+#
+$NFT flush ruleset
+
+RULESET='{"nftables": [{"metainfo": {"json_schema_version": 1}}, {"add": {"table": {"family": "inet", "name": "firewalld"}}}, {"add": {"table": {"family": "ip", "name": "firewalld"}}}, {"add": {"table": {"family": "ip6", "name": "firewalld"}}},
+{"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}]}}}]}'
+
+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/0050rule_1 b/tests/shell/testcases/transactions/0050rule_1
new file mode 100755
index 0000000..89e5f42
--- /dev/null
+++ b/tests/shell/testcases/transactions/0050rule_1
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet filter {
+ flowtable ftable {
+ hook ingress priority 0; devices = { eno1, eno0, x };
+ }
+
+chain forward {
+ type filter hook forward priority 0; policy drop;
+
+ ip protocol { tcp, udp } ct mark and 1 == 1 counter flow add @ftable
+ ip6 nexthdr { tcp, udp } ct mark and 2 == 2 counter flow add @ftable
+ ct mark and 30 == 30 ct state established,related log prefix \"nftables accept: \" level info accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
diff --git a/tests/shell/testcases/transactions/0051map_0 b/tests/shell/testcases/transactions/0051map_0
new file mode 100755
index 0000000..9ea5cd4
--- /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 0000000..4c3c6a2
--- /dev/null
+++ b/tests/shell/testcases/transactions/30s-stress
@@ -0,0 +1,637 @@
+#!/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 [ $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
+
+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
+}
+
+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
+ for flags in "" "interval" ; 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"
+ # 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"
+
+ # 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"
+ # 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"
+
+ # 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
+ for flags in "" "flags interval;" ; do
+ timeout=$((RANDOM%10))
+ timeout=$((timeout+1))
+ timeout="timeout ${timeout}s"
+
+ cnt=$((cnt+1))
+ 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
+ for flags in "" "interval" ; do
+ 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 0000000..2fd6181
--- /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 0000000..794b625
--- /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/dumps/0001table_0.nft b/tests/shell/testcases/transactions/dumps/0001table_0.nft
new file mode 100644
index 0000000..e4e5f9b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0001table_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+}
+table ip y {
+}
diff --git a/tests/shell/testcases/transactions/dumps/0002table_0.nft b/tests/shell/testcases/transactions/dumps/0002table_0.nft
new file mode 100644
index 0000000..429cbc3
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0002table_0.nft
@@ -0,0 +1,7 @@
+table ip x {
+ flags dormant
+
+ chain y {
+ type nat hook prerouting priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0003table_0.nft b/tests/shell/testcases/transactions/dumps/0003table_0.nft
new file mode 100644
index 0000000..e4e5f9b
--- /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.nft b/tests/shell/testcases/transactions/dumps/0010chain_0.nft
new file mode 100644
index 0000000..aa4a521
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0010chain_0.nft
@@ -0,0 +1,4 @@
+table ip w {
+ chain y {
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0011chain_0.nft b/tests/shell/testcases/transactions/dumps/0011chain_0.nft
new file mode 100644
index 0000000..df88ad4
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0011chain_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ type filter hook input priority filter; policy drop;
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0012chain_0.nft b/tests/shell/testcases/transactions/dumps/0012chain_0.nft
new file mode 100644
index 0000000..b9f5e43
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0012chain_0.nft
@@ -0,0 +1,5 @@
+table ip w {
+ chain y {
+ type filter hook output priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0013chain_0.nft b/tests/shell/testcases/transactions/dumps/0013chain_0.nft
new file mode 100644
index 0000000..b9f5e43
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0013chain_0.nft
@@ -0,0 +1,5 @@
+table ip w {
+ chain y {
+ type filter hook output priority filter; policy accept;
+ }
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0014chain_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0015chain_0.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0020rule_0.nft
diff --git a/tests/shell/testcases/transactions/dumps/0021rule_0.nft b/tests/shell/testcases/transactions/dumps/0021rule_0.nft
new file mode 100644
index 0000000..a6c4130
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0021rule_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip saddr 2.2.2.2 counter packets 0 bytes 0
+ }
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0022rule_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0023rule_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0024rule_0.nft b/tests/shell/testcases/transactions/dumps/0024rule_0.nft
new file mode 100644
index 0000000..7860ff6
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0024rule_0.nft
@@ -0,0 +1,8 @@
+table ip x {
+ chain y {
+ accept comment "rule1"
+ accept comment "rule2"
+ accept comment "rule3"
+ accept comment "rule4"
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0025rule_0.nft b/tests/shell/testcases/transactions/dumps/0025rule_0.nft
new file mode 100644
index 0000000..dcb61ae
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0025rule_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ chain y {
+ log
+ drop
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0030set_0.nft b/tests/shell/testcases/transactions/dumps/0030set_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0030set_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/transactions/dumps/0031set_0.nft b/tests/shell/testcases/transactions/dumps/0031set_0.nft
new file mode 100644
index 0000000..e3d4aee
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0031set_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0032set_0.nft b/tests/shell/testcases/transactions/dumps/0032set_0.nft
new file mode 100644
index 0000000..7d11892
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0032set_0.nft
@@ -0,0 +1,5 @@
+table ip w {
+ set y {
+ type ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0033set_0.nft b/tests/shell/testcases/transactions/dumps/0033set_0.nft
new file mode 100644
index 0000000..5d4d2ca
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0033set_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/transactions/dumps/0034set_0.nft b/tests/shell/testcases/transactions/dumps/0034set_0.nft
new file mode 100644
index 0000000..e3d4aee
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0034set_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0035set_0.nft b/tests/shell/testcases/transactions/dumps/0035set_0.nft
new file mode 100644
index 0000000..e111494
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0035set_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ elements = { 3.3.3.3 }
+ }
+}
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0036set_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0037set_0.nft b/tests/shell/testcases/transactions/dumps/0037set_0.nft
new file mode 100644
index 0000000..ca69cee
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0037set_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0038set_0.nft b/tests/shell/testcases/transactions/dumps/0038set_0.nft
new file mode 100644
index 0000000..651a11b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0038set_0.nft
@@ -0,0 +1,7 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.4.0/24 }
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0039set_0.nft b/tests/shell/testcases/transactions/dumps/0039set_0.nft
new file mode 100644
index 0000000..651a11b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0039set_0.nft
@@ -0,0 +1,7 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.4.0/24 }
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0040set_0.nft b/tests/shell/testcases/transactions/dumps/0040set_0.nft
new file mode 100644
index 0000000..a29232b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0040set_0.nft
@@ -0,0 +1,14 @@
+table ip filter {
+ map client_to_any {
+ type ipv4_addr : verdict
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter; policy accept;
+ goto client_to_any
+ }
+
+ chain client_to_any {
+ ip saddr vmap @client_to_any
+ }
+}
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 0000000..b718001
--- /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.nft b/tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.nft
new file mode 100644
index 0000000..e5cc63f
--- /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.nft b/tests/shell/testcases/transactions/dumps/0043set_1.nft
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0043set_1.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0044rule_0.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0045anon-unbind_0.nft
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 0000000..eb39c44
--- /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.nft b/tests/shell/testcases/transactions/dumps/0047set_0.nft
new file mode 100644
index 0000000..4da397b
--- /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.nft b/tests/shell/testcases/transactions/dumps/0048helpers_0.nft
new file mode 100644
index 0000000..eb39c44
--- /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.nft b/tests/shell/testcases/transactions/dumps/0049huge_0.nft
new file mode 100644
index 0000000..96f5a38
--- /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.nft b/tests/shell/testcases/transactions/dumps/0050rule_1.nft
new file mode 100644
index 0000000..e69de29
--- /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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0051map_0.nodump
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/30s-stress.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/anon_chain_loop.nft
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 0000000..e69de29
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/bad_expression.nft
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 0000000..038be1c
--- /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 0000000..831d461
--- /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/tests/shell/x b/tests/shell/x
new file mode 100644
index 0000000..4170e0a
--- /dev/null
+++ b/tests/shell/x
@@ -0,0 +1,5 @@
+testcases/json/dumps/0001set_statements_0.nft
+testcases/nft-f/0025empty_dynset_0
+testcases/sets/dumps/0022type_selective_flush_0.nft
+testcases/sets/dumps/0038meter_list_0.nft
+testcases/sets/dumps/0060set_multistmt_0.nft