diff options
20 files changed, 628 insertions, 86 deletions
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt index c7c267da..7bc24a8a 100644 --- a/doc/payload-expression.txt +++ b/doc/payload-expression.txt @@ -670,44 +670,6 @@ integer (24 bit) 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] diff --git a/src/cache.c b/src/cache.c index c000e32c..4b797ec7 100644 --- a/src/cache.c +++ b/src/cache.c @@ -297,6 +297,7 @@ static unsigned int evaluate_cache_reset(struct cmd *cmd, unsigned int flags, flags |= NFT_CACHE_TABLE; break; } + flags |= NFT_CACHE_REFRESH; return flags; } @@ -1177,14 +1178,27 @@ 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) +static bool nft_cache_needs_refresh(struct nft_cache *cache, unsigned int flags) { - return cache->flags & NFT_CACHE_REFRESH; + return (cache->flags & NFT_CACHE_REFRESH) || + (flags & NFT_CACHE_REFRESH); } -static bool nft_cache_is_updated(struct nft_cache *cache, uint16_t genid) +static bool nft_cache_is_updated(struct nft_cache *cache, unsigned int flags, + uint16_t genid) { - return genid && genid == cache->genid; + if (!genid) + return false; + + if (genid == cache->genid) + return true; + + if (genid == cache->genid + 1) { + cache->genid++; + return true; + } + + return false; } bool nft_cache_needs_update(struct nft_cache *cache) @@ -1207,9 +1221,9 @@ int nft_cache_update(struct nft_ctx *nft, unsigned int flags, replay: ctx.seqnum = cache->seqnum++; genid = mnl_genid_get(&ctx); - if (!nft_cache_needs_refresh(cache) && + if (!nft_cache_needs_refresh(cache, flags) && nft_cache_is_complete(cache, flags) && - nft_cache_is_updated(cache, genid)) + nft_cache_is_updated(cache, flags, genid)) return 0; if (cache->genid) @@ -256,7 +256,8 @@ static void nft_cmd_enoent(struct netlink_ctx *ctx, const struct cmd *cmd, static int nft_cmd_chain_error(struct netlink_ctx *ctx, struct cmd *cmd, struct mnl_err *err) { - struct chain *chain = cmd->chain; + struct chain *chain = cmd->chain, *existing_chain; + const struct table *table; int priority; switch (err->err) { @@ -270,6 +271,18 @@ static int nft_cmd_chain_error(struct netlink_ctx *ctx, struct cmd *cmd, return netlink_io_error(ctx, &chain->priority.loc, "Chains of type \"nat\" must have a priority value above -200"); + table = table_cache_find(&ctx->nft->cache.table_cache, + cmd->handle.table.name, cmd->handle.family); + if (table) { + existing_chain = chain_cache_find(table, cmd->handle.chain.name); + if (existing_chain && existing_chain != chain && + !strcmp(existing_chain->handle.chain.name, chain->handle.chain.name)) + return netlink_io_error(ctx, &chain->loc, + "Chain \"%s\" already exists in table %s '%s' with different declaration", + chain->handle.chain.name, + family2str(table->handle.family), table->handle.table.name); + } + return netlink_io_error(ctx, &chain->loc, "Chain of type \"%s\" is not supported, perhaps kernel support is missing?", chain->type.str); @@ -442,6 +455,9 @@ bool nft_cmd_collapse(struct list_head *cmds) continue; } + if (cmd->expr->etype == EXPR_VARIABLE) + continue; + if (!elems) { elems = cmd; continue; diff --git a/src/evaluate.c b/src/evaluate.c index 1682ba58..227f5da8 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -775,6 +775,46 @@ static bool proto_is_dummy(const struct proto_desc *desc) return desc == &proto_inet || desc == &proto_netdev; } +static int stmt_dep_conflict(struct eval_ctx *ctx, const struct stmt *nstmt) +{ + struct stmt *stmt; + + list_for_each_entry(stmt, &ctx->rule->stmts, list) { + if (stmt == nstmt) + break; + + if (stmt->ops->type != STMT_EXPRESSION || + stmt->expr->etype != EXPR_RELATIONAL || + stmt->expr->right->etype != EXPR_VALUE || + stmt->expr->left->etype != EXPR_PAYLOAD || + stmt->expr->left->etype != nstmt->expr->left->etype || + stmt->expr->left->len != nstmt->expr->left->len) + continue; + + if (stmt->expr->left->payload.desc != nstmt->expr->left->payload.desc || + stmt->expr->left->payload.inner_desc != nstmt->expr->left->payload.inner_desc || + stmt->expr->left->payload.base != nstmt->expr->left->payload.base || + stmt->expr->left->payload.offset != nstmt->expr->left->payload.offset) + continue; + + return stmt_binary_error(ctx, stmt, nstmt, + "conflicting statements"); + } + + return 0; +} + +static int rule_stmt_dep_add(struct eval_ctx *ctx, + struct stmt *nstmt, struct stmt *stmt) +{ + rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + + if (stmt_dep_conflict(ctx, nstmt) < 0) + return -1; + + return 0; +} + static int resolve_ll_protocol_conflict(struct eval_ctx *ctx, const struct proto_desc *desc, struct expr *payload) @@ -798,7 +838,8 @@ static int resolve_ll_protocol_conflict(struct eval_ctx *ctx, return err; desc = payload->payload.desc; - rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + if (rule_stmt_dep_add(ctx, nstmt, ctx->stmt) < 0) + return -1; } } else { unsigned int i; @@ -810,10 +851,6 @@ static int resolve_ll_protocol_conflict(struct eval_ctx *ctx, } } - /* 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 || ll_conflict_resolution_gen_dependency(ctx, link, payload, &nstmt) < 0) @@ -822,7 +859,8 @@ static int resolve_ll_protocol_conflict(struct eval_ctx *ctx, 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); + if (rule_stmt_dep_add(ctx, nstmt, ctx->stmt) < 0) + return -1; return 0; } @@ -850,7 +888,8 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr) if (payload_gen_dependency(ctx, payload, &nstmt) < 0) return -1; - rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + if (rule_stmt_dep_add(ctx, nstmt, ctx->stmt) < 0) + return -1; desc = pctx->protocol[base].desc; @@ -870,7 +909,10 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr) assert(pctx->stacked_ll_count); payload->payload.offset += pctx->stacked_ll[0]->length; - rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + + if (rule_stmt_dep_add(ctx, nstmt, ctx->stmt) < 0) + return -1; + return 1; } goto check_icmp; @@ -911,8 +953,8 @@ check_icmp: if (payload_gen_icmp_dependency(ctx, expr, &nstmt) < 0) return -1; - if (nstmt) - rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + if (nstmt && rule_stmt_dep_add(ctx, nstmt, ctx->stmt) < 0) + return -1; return 0; } @@ -988,7 +1030,8 @@ static int expr_evaluate_inner(struct eval_ctx *ctx, struct expr **exprp) if (payload_gen_inner_dependency(ctx, expr, &nstmt) < 0) return -1; - rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + if (rule_stmt_dep_add(ctx, nstmt, ctx->stmt) < 0) + return -1; proto_ctx_update(pctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, expr->payload.inner_desc); } @@ -1083,7 +1126,7 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct) base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (base == &proto_ip) ct->ct.nfproto = NFPROTO_IPV4; - else if (base == &proto_ip) + else if (base == &proto_ip6) ct->ct.nfproto = NFPROTO_IPV6; if (base) @@ -1119,7 +1162,9 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct) relational_expr_pctx_update(pctx, dep); nstmt = expr_stmt_alloc(&dep->location, dep); - rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + + if (rule_stmt_dep_add(ctx, nstmt, ctx->stmt) < 0) + return -1; return 0; } @@ -2061,6 +2106,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr) mappings->set_flags |= NFT_SET_MAP; switch (map->mappings->etype) { + case EXPR_VARIABLE: case EXPR_SET: if (ctx->ectx.key && ctx->ectx.key->etype == EXPR_CONCAT) { key = expr_clone(ctx->ectx.key); @@ -2104,6 +2150,11 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr) if (expr_evaluate(ctx, &map->mappings->set->init) < 0) return -1; + if (map->mappings->set->init->etype != EXPR_SET) { + return expr_error(ctx->msgs, map->mappings->set->init, + "Expression is not a map"); + } + 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) @@ -4576,6 +4627,7 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt) mappings->set_flags |= NFT_SET_OBJECT; switch (map->mappings->etype) { + case EXPR_VARIABLE: case EXPR_SET: key = constant_expr_alloc(&stmt->location, ctx->ectx.dtype, @@ -4595,6 +4647,11 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt) if (expr_evaluate(ctx, &map->mappings->set->init) < 0) return -1; + if (map->mappings->set->init->etype != EXPR_SET) { + return expr_error(ctx->msgs, map->mappings->set->init, + "Expression is not a map"); + } + 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) @@ -4615,8 +4672,9 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt) "Expression is not a map with objects"); break; default: - BUG("invalid mapping expression %s\n", - expr_name(map->mappings)); + return expr_binary_error(ctx->msgs, map->mappings, map->map, + "invalid mapping expression %s", + expr_name(map->mappings)); } if (!datatype_compatible(map->mappings->set->key->dtype, map->map->dtype)) diff --git a/src/netlink.c b/src/netlink.c index 0088b742..efb0b699 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -2096,6 +2096,7 @@ restart: /* Skip unknown and filtered expressions */ desc = lhs->payload.desc; if (lhs->dtype == &invalid_type || + lhs->payload.tmpl == &proto_unknown_template || desc->checksum_key == payload_hdr_field(lhs) || desc->format.filter & (1 << payload_hdr_field(lhs))) { expr_free(lhs); diff --git a/src/scanner.l b/src/scanner.l index e4d20e69..96c505bc 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -132,48 +132,47 @@ slash \/ timestring ([0-9]+d)?([0-9]+h)?([0-9]+m)?([0-9]+s)?([0-9]+ms)? hex4 ([[:xdigit:]]{1,4}) +rfc4291_broader (((:{hex4}){2})|(:{ip4addr})) 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})) +v670 ((:)((:{hex4}){5}){rfc4291_broader}) +v671 ((({hex4}:){1})((:{hex4}){4}){rfc4291_broader}) +v672 ((({hex4}:){2})((:{hex4}){3}){rfc4291_broader}) +v673 ((({hex4}:){3})((:{hex4}){2}){rfc4291_broader}) +v674 ((({hex4}:){4})((:{hex4}){1}){rfc4291_broader}) +v675 ((({hex4}:){5}){rfc4291_broader}) 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})) +v660 ((:)((:{hex4}){4}){rfc4291_broader}) +v661 ((({hex4}:){1})((:{hex4}){3}){rfc4291_broader}) +v662 ((({hex4}:){2})((:{hex4}){2}){rfc4291_broader}) +v663 ((({hex4}:){3})((:{hex4}){1}){rfc4291_broader}) +v664 ((({hex4}:){4}){rfc4291_broader}) 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})) +v650 ((:)((:{hex4}){3}){rfc4291_broader}) +v651 ((({hex4}:){1})((:{hex4}){2}){rfc4291_broader}) +v652 ((({hex4}:){2})((:{hex4}){1}){rfc4291_broader}) +v653 ((({hex4}:){3}){rfc4291_broader}) 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})) +v640 ((:)((:{hex4}){2}){rfc4291_broader}) +v641 ((({hex4}:){1})((:{hex4}){1}){rfc4291_broader}) +v642 ((({hex4}:){2}){rfc4291_broader}) v643 ((({hex4}:){3})((:{hex4}){1})) v644 ((({hex4}:){4})(:)) v64 ({v640}|{v641}|{v642}|{v643}|{v644}) -v630 ((:)((:{hex4}){3})) -v631 ((({hex4}:){1})((:{hex4}){2})) +v630 ((:)((:{hex4}){1}){rfc4291_broader}) +v631 ((({hex4}:){1}){rfc4291_broader}) v632 ((({hex4}:){2})((:{hex4}){1})) v633 ((({hex4}:){3})(:)) v63 ({v630}|{v631}|{v632}|{v633}) -v620 ((:)((:{hex4}){2})) -v620_rfc4291 ((:)(:{ip4addr})) +v620 ((:){rfc4291_broader}) v621 ((({hex4}:){1})((:{hex4}){1})) v622 ((({hex4}:){2})(:)) -v62_rfc4291 ((:)(:[fF]{4})(:{ip4addr})) -v62 ({v620}|{v621}|{v622}|{v62_rfc4291}|{v620_rfc4291}) +v62 ({v620}|{v621}|{v622}) v610 ((:)(:{hex4}{1})) v611 ((({hex4}:){1})(:)) v61 ({v610}|{v611}) diff --git a/tests/shell/testcases/chains/netdev_chain_dormant_autoremove b/tests/shell/testcases/chains/netdev_chain_dormant_autoremove new file mode 100755 index 00000000..0a684e56 --- /dev/null +++ b/tests/shell/testcases/chains/netdev_chain_dormant_autoremove @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +ip link add dummy0 type dummy +ip link add dummy1 type dummy +$NFT add table netdev test { flags dormant\; } +$NFT add chain netdev test ingress { type filter hook ingress devices = { "dummy0", "dummy1" } priority 0\; policy drop\; } +ip link del dummy0 diff --git a/tests/shell/testcases/maps/0024named_objects_1 b/tests/shell/testcases/maps/0024named_objects_1 new file mode 100755 index 00000000..a861e9e2 --- /dev/null +++ b/tests/shell/testcases/maps/0024named_objects_1 @@ -0,0 +1,31 @@ +#!/bin/bash + +# This is the test-case: +# * creating valid named objects and using map variables in statements + +RULESET=' +define counter_map = { 192.168.2.2 : "user123", 1.1.1.1 : "user123", 2.2.2.2 : "user123" } +define quota_map = { 192.168.2.2 : "user124", 192.168.2.3 : "user124" } + +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 + } + chain y { + type filter hook input priority 0; policy accept; + counter name ip saddr map $counter_map + quota name ip saddr map $quota_map drop + } +}' + +set -e +$NFT -f - <<< "$RULESET" diff --git a/tests/shell/testcases/maps/0024named_objects_2 b/tests/shell/testcases/maps/0024named_objects_2 new file mode 100755 index 00000000..584b5100 --- /dev/null +++ b/tests/shell/testcases/maps/0024named_objects_2 @@ -0,0 +1,23 @@ +#!/bin/bash + +# +# Test some error conditions for using variables to define maps +# + +set -e + +for m in "192.168.2.2" "{ 192.168.2.2, 1.1.1.1, 2.2.2.2 }"; do + + RULESET=" +define m = $m"' +table inet x { + chain y { + type filter hook input priority 0; policy accept; + counter name ip saddr map $m + } +}' + + $NFT -f - <<< "$RULESET" || rc=$? + test $rc = 1 + +done diff --git a/tests/shell/testcases/maps/anonymous_snat_map_1 b/tests/shell/testcases/maps/anonymous_snat_map_1 new file mode 100755 index 00000000..031de0c1 --- /dev/null +++ b/tests/shell/testcases/maps/anonymous_snat_map_1 @@ -0,0 +1,16 @@ +#!/bin/bash + +# Variable containing anonymous map can be added to a snat rule + +set -e + +RULESET=' +define m = {1.1.1.1 : 2.2.2.2} +table nat { + chain postrouting { + snat ip saddr map $m + } +} +' + +$NFT -f - <<< "$RULESET" diff --git a/tests/shell/testcases/maps/anonymous_snat_map_2 b/tests/shell/testcases/maps/anonymous_snat_map_2 new file mode 100755 index 00000000..90e02038 --- /dev/null +++ b/tests/shell/testcases/maps/anonymous_snat_map_2 @@ -0,0 +1,23 @@ +#!/bin/bash + +# +# Test some error conditions for using variables to define maps +# + +set -e + +for m in "1.1.1.1" "{1.1.1.1}"; do + + RULESET=" +define m = $m"' +table nat { + chain postrouting { + snat ip saddr map $m + } +} +' + + $NFT -f - <<< "$RULESET" || rc=$? + test $rc = 1 + +done diff --git a/tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft b/tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft new file mode 100644 index 00000000..e3fab16d --- /dev/null +++ b/tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft @@ -0,0 +1,147 @@ +{ + "nftables": [ + { + "metainfo": { + "version": "VERSION", + "release_name": "RELEASE_NAME", + "json_schema_version": 1 + } + }, + { + "table": { + "family": "inet", + "name": "x", + "handle": 0 + } + }, + { + "chain": { + "family": "inet", + "table": "x", + "name": "y", + "handle": 0, + "type": "filter", + "hook": "input", + "prio": 0, + "policy": "accept" + } + }, + { + "counter": { + "family": "inet", + "name": "user123", + "table": "x", + "handle": 0, + "packets": 12, + "bytes": 1433 + } + }, + { + "counter": { + "family": "inet", + "name": "user321", + "table": "x", + "handle": 0, + "packets": 12, + "bytes": 1433 + } + }, + { + "quota": { + "family": "inet", + "name": "user123", + "table": "x", + "handle": 0, + "bytes": 2000, + "used": 0, + "inv": true + } + }, + { + "quota": { + "family": "inet", + "name": "user124", + "table": "x", + "handle": 0, + "bytes": 2000, + "used": 0, + "inv": true + } + }, + { + "rule": { + "family": "inet", + "table": "x", + "chain": "y", + "handle": 0, + "expr": [ + { + "counter": { + "map": { + "key": { + "payload": { + "protocol": "ip", + "field": "saddr" + } + }, + "data": { + "set": [ + [ + "1.1.1.1", + "user123" + ], + [ + "2.2.2.2", + "user123" + ], + [ + "192.168.2.2", + "user123" + ] + ] + } + } + } + } + ] + } + }, + { + "rule": { + "family": "inet", + "table": "x", + "chain": "y", + "handle": 0, + "expr": [ + { + "quota": { + "map": { + "key": { + "payload": { + "protocol": "ip", + "field": "saddr" + } + }, + "data": { + "set": [ + [ + "192.168.2.2", + "user124" + ], + [ + "192.168.2.3", + "user124" + ] + ] + } + } + } + }, + { + "drop": null + } + ] + } + } + ] +} diff --git a/tests/shell/testcases/maps/dumps/0024named_objects_1.nft b/tests/shell/testcases/maps/dumps/0024named_objects_1.nft new file mode 100644 index 00000000..a8e99a3c --- /dev/null +++ b/tests/shell/testcases/maps/dumps/0024named_objects_1.nft @@ -0,0 +1,23 @@ +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 + } + + 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" } + quota name ip saddr map { 192.168.2.2 : "user124", 192.168.2.3 : "user124" } drop + } +} diff --git a/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft new file mode 100644 index 00000000..f4c55706 --- /dev/null +++ b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft @@ -0,0 +1,58 @@ +{ + "nftables": [ + { + "metainfo": { + "version": "VERSION", + "release_name": "RELEASE_NAME", + "json_schema_version": 1 + } + }, + { + "table": { + "family": "ip", + "name": "nat", + "handle": 0 + } + }, + { + "chain": { + "family": "ip", + "table": "nat", + "name": "postrouting", + "handle": 0 + } + }, + { + "rule": { + "family": "ip", + "table": "nat", + "chain": "postrouting", + "handle": 0, + "expr": [ + { + "snat": { + "addr": { + "map": { + "key": { + "payload": { + "protocol": "ip", + "field": "saddr" + } + }, + "data": { + "set": [ + [ + "1.1.1.1", + "2.2.2.2" + ] + ] + } + } + } + } + } + ] + } + } + ] +} diff --git a/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.nft b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.nft new file mode 100644 index 00000000..5009560c --- /dev/null +++ b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.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/packetpath/vlan_mangling b/tests/shell/testcases/packetpath/vlan_mangling new file mode 100755 index 00000000..b3f87c66 --- /dev/null +++ b/tests/shell/testcases/packetpath/vlan_mangling @@ -0,0 +1,75 @@ +#!/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 +ip -net "$ns2" link add vlan321 link veth0 type vlan id 321 + + +for dev in veth0 ; do + ip -net "$ns1" link set $dev up + ip -net "$ns2" link set $dev up +done +ip -net "$ns1" link set vlan123 up +ip -net "$ns2" link set vlan321 up + +ip -net "$ns1" addr add 10.1.1.1/24 dev vlan123 +ip -net "$ns2" addr add 10.1.1.2/24 dev vlan321 + +ip netns exec "$ns2" $NFT -f /dev/stdin <<"EOF" +table netdev t { + chain in_update_vlan { + vlan type arp vlan id set 321 counter + ip saddr 10.1.1.1 icmp type echo-request vlan id set 321 counter + } + + chain in { + type filter hook ingress device veth0 priority filter; + ether saddr da:d3:00:01:02:03 vlan id 123 jump in_update_vlan + } + + chain out_update_vlan { + vlan type arp vlan id set 123 counter + ip daddr 10.1.1.1 icmp type echo-reply vlan id set 123 counter + } + + chain out { + type filter hook egress device veth0 priority filter; + ether daddr da:d3:00:01:02:03 vlan id 321 jump out_update_vlan + } +} +EOF + +ip netns exec "$ns1" ping -c 1 10.1.1.2 + +set +e + +ip netns exec "$ns2" $NFT list ruleset +ip netns exec "$ns2" $NFT list table netdev t | grep 'counter packets' | grep 'counter packets 0 bytes 0' +if [ $? -eq 1 ] +then + exit 0 +fi + +exit 1 diff --git a/tests/shell/testcases/packetpath/vlan_qinq b/tests/shell/testcases/packetpath/vlan_qinq new file mode 100755 index 00000000..28655766 --- /dev/null +++ b/tests/shell/testcases/packetpath/vlan_qinq @@ -0,0 +1,73 @@ +#!/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 link veth0 name vlan10 type vlan proto 802.1ad id 10 +ip -net "$ns1" link add link vlan10 name vlan10.100 type vlan proto 802.1q id 100 + +ip -net "$ns2" link add link veth0 name vlan10 type vlan proto 802.1ad id 10 +ip -net "$ns2" link add link vlan10 name vlan10.100 type vlan proto 802.1q id 100 + +for dev in veth0 vlan10 vlan10.100; 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 vlan10.100 +ip -net "$ns2" addr add 10.1.1.2/24 dev vlan10.100 + +ip netns exec "$ns2" $NFT -f /dev/stdin <<"EOF" +table netdev t { + chain c1 { + type filter hook ingress device veth0 priority filter; + ether type 8021ad vlan id 10 vlan type 8021q vlan id 100 vlan type ip counter + } + + chain c2 { + type filter hook ingress device vlan10 priority filter; + vlan id 100 ip daddr 10.1.1.2 counter + } + + chain c3 { + type filter hook ingress device vlan10.100 priority filter; + ip daddr 10.1.1.2 counter + } +} +EOF + +ip netns exec "$ns1" ping -c 1 10.1.1.2 +ip netns exec "$ns2" $NFT list ruleset + +set +e + +ip netns exec "$ns2" $NFT list chain netdev t c1 | grep 'counter packets 0 bytes 0' +[[ $? -eq 0 ]] && exit 1 + +ip netns exec "$ns2" $NFT list chain netdev t c2 | grep 'counter packets 0 bytes 0' +[[ $? -eq 0 ]] && exit 1 + +ip netns exec "$ns2" $NFT list chain netdev t c3 | grep 'counter packets 0 bytes 0' +[[ $? -eq 0 ]] && exit 1 + +exit 0 diff --git a/tests/shell/testcases/sets/collapse_elem_0 b/tests/shell/testcases/sets/collapse_elem_0 index 7699e9da..52a42c2f 100755 --- a/tests/shell/testcases/sets/collapse_elem_0 +++ b/tests/shell/testcases/sets/collapse_elem_0 @@ -17,3 +17,9 @@ add element ip a x { 2 } add element ip6 a x { 2 }" $NFT -f - <<< $RULESET + +RULESET="define m = { 3, 4 } +add element ip a x \$m +add element ip a x { 5 }" + +$NFT -f - <<< $RULESET diff --git a/tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft b/tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft index c713828d..c8ff4347 100644 --- a/tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft +++ b/tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft @@ -23,7 +23,10 @@ "handle": 0, "elem": [ 1, - 2 + 2, + 3, + 4, + 5 ] } }, diff --git a/tests/shell/testcases/sets/dumps/collapse_elem_0.nft b/tests/shell/testcases/sets/dumps/collapse_elem_0.nft index a3244fc6..775f0ab1 100644 --- a/tests/shell/testcases/sets/dumps/collapse_elem_0.nft +++ b/tests/shell/testcases/sets/dumps/collapse_elem_0.nft @@ -1,7 +1,7 @@ table ip a { set x { type inet_service - elements = { 1, 2 } + elements = { 1, 2, 3, 4, 5 } } } table ip6 a { |