From: "Pablo M. Bermudo Garay" <pablombg@gmail.com>
To: netfilter-devel@vger.kernel.org
Cc: pablo@netfilter.org, "Pablo M. Bermudo Garay" <pablombg@gmail.com>
Subject: [PATCH nft 2/2] src: limit stateful object support
Date: Wed, 23 Aug 2017 22:42:56 +0200 [thread overview]
Message-ID: <20170823204256.31634-2-pablombg@gmail.com> (raw)
In-Reply-To: <20170823204256.31634-1-pablombg@gmail.com>
This patch adds support for a new type of stateful object: limit.
Creation, deletion and listing operations are supported.
Signed-off-by: Pablo M. Bermudo Garay <pablombg@gmail.com>
---
include/linux/netfilter/nf_tables.h | 3 +-
include/rule.h | 13 +++++
include/statement.h | 1 +
src/evaluate.c | 5 ++
src/netlink.c | 19 +++++++
src/parser_bison.y | 101 ++++++++++++++++++++++++++++++++++--
src/rule.c | 43 ++++++++++++++-
src/scanner.l | 1 +
src/statement.c | 3 +-
9 files changed, 183 insertions(+), 6 deletions(-)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 5441b19..f328944 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -1278,7 +1278,8 @@ enum nft_ct_helper_attributes {
#define NFT_OBJECT_COUNTER 1
#define NFT_OBJECT_QUOTA 2
#define NFT_OBJECT_CT_HELPER 3
-#define __NFT_OBJECT_MAX 4
+#define NFT_OBJECT_LIMIT 4
+#define __NFT_OBJECT_MAX 5
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
/**
diff --git a/include/rule.h b/include/rule.h
index 10ac0e2..94f7bb5 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -272,6 +272,14 @@ struct ct_helper {
uint8_t l4proto;
};
+struct limit {
+ uint64_t rate;
+ uint64_t unit;
+ uint32_t burst;
+ uint32_t type;
+ uint32_t flags;
+};
+
/**
* struct obj - nftables stateful object statement
*
@@ -291,6 +299,7 @@ struct obj {
struct counter counter;
struct quota quota;
struct ct_helper ct_helper;
+ struct limit limit;
};
};
@@ -357,6 +366,8 @@ enum cmd_ops {
* @CMD_OBJ_COUNTERS: multiple counters
* @CMD_OBJ_QUOTA: quota
* @CMD_OBJ_QUOTAS: multiple quotas
+ * @CMD_OBJ_LIMIT: limit
+ * @CMD_OBJ_LIMITS: multiple limits
*/
enum cmd_obj {
CMD_OBJ_INVALID,
@@ -381,6 +392,8 @@ enum cmd_obj {
CMD_OBJ_QUOTAS,
CMD_OBJ_CT_HELPER,
CMD_OBJ_CT_HELPERS,
+ CMD_OBJ_LIMIT,
+ CMD_OBJ_LIMITS,
};
struct export {
diff --git a/include/statement.h b/include/statement.h
index 6d8aaa8..2f702c3 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -325,5 +325,6 @@ 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/src/evaluate.c b/src/evaluate.c
index 3989d5e..a92a66d 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2997,6 +2997,7 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_LIMIT:
return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
@@ -3022,6 +3023,7 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_LIMIT:
return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
@@ -3111,9 +3113,12 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
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_LIMIT:
+ return cmd_evaluate_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
case CMD_OBJ_COUNTERS:
case CMD_OBJ_QUOTAS:
case CMD_OBJ_CT_HELPERS:
+ case CMD_OBJ_LIMITS:
case CMD_OBJ_SETS:
if (cmd->handle.table == NULL)
return 0;
diff --git a/src/netlink.c b/src/netlink.c
index f6eb08f..a165809 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -328,6 +328,13 @@ alloc_nftnl_obj(const struct handle *h, struct obj *obj)
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_HELPER_L3PROTO,
obj->ct_helper.l3proto);
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;
default:
BUG("Unknown type %d\n", obj->type);
break;
@@ -1743,6 +1750,18 @@ static struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
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_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;
}
obj->type = type;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ca86df5..e410298 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -142,6 +142,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
struct counter *counter;
struct quota *quota;
struct ct *ct;
+ struct limit *limit;
const struct datatype *datatype;
struct handle_spec handle_spec;
struct position_spec position_spec;
@@ -393,6 +394,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token COUNTERS "counters"
%token QUOTAS "quotas"
+%token LIMITS "limits"
%token LOG "log"
%token PREFIX "prefix"
@@ -501,7 +503,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <set> map_block_alloc map_block
%destructor { set_free($$); } map_block_alloc
-%type <obj> obj_block_alloc counter_block quota_block ct_block
+%type <obj> obj_block_alloc counter_block quota_block ct_block limit_block
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list
@@ -589,8 +591,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%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
-%destructor { obj_free($$); } counter_obj quota_obj ct_obj_alloc
+%type <obj> counter_obj quota_obj ct_obj_alloc limit_obj
+%destructor { obj_free($$); } counter_obj quota_obj ct_obj_alloc limit_obj
%type <expr> relational_expr
%destructor { expr_free($$); } relational_expr
@@ -661,6 +663,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%destructor { xfree($$); } counter_config
%type <quota> quota_config
%destructor { xfree($$); } quota_config
+%type <limit> limit_config
+%destructor { xfree($$); } limit_config
%type <expr> tcp_hdr_expr
%destructor { expr_free($$); } tcp_hdr_expr
@@ -864,6 +868,10 @@ add_cmd : TABLE table_spec
$$ = cmd_alloc_obj_ct(CMD_ADD, type, &$3, &@$, $4);
}
+ | LIMIT obj_spec limit_obj
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3);
+ }
;
replace_cmd : RULE ruleid_spec rule
@@ -943,6 +951,10 @@ create_cmd : TABLE table_spec
$$ = cmd_alloc_obj_ct(CMD_CREATE, type, &$3, &@$, $4);
}
+ | LIMIT obj_spec limit_obj
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2, &@$, $3);
+ }
;
insert_cmd : RULE rule_position rule
@@ -996,6 +1008,10 @@ delete_cmd : TABLE table_spec
$$ = cmd_alloc_obj_ct(CMD_DELETE, type, &$3, &@$, $4);
}
+ | LIMIT obj_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL);
+ }
;
list_cmd : TABLE table_spec
@@ -1050,6 +1066,18 @@ list_cmd : TABLE table_spec
{
$$ = 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
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMIT, &$2, &@$, NULL);
+ }
| RULESET ruleset_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_RULESET, &$2, &@$, NULL);
@@ -1311,6 +1339,17 @@ table_block : /* empty */ { $$ = $<table>-1; }
list_add_tail(&$5->list, &$1->objs);
$$ = $1;
}
+ | table_block LIMIT obj_identifier
+ obj_block_alloc '{' limit_block '}'
+ stmt_separator
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_LIMIT;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
;
chain_block_alloc : /* empty */
@@ -1516,6 +1555,15 @@ ct_block : /* empty */ { $$ = $<obj>-1; }
}
;
+limit_block : /* empty */ { $$ = $<obj>-1; }
+ | limit_block common_block
+ | limit_block stmt_separator
+ | limit_block limit_config
+ {
+ $1->limit = *$2;
+ $$ = $1;
+ }
+ ;
type_identifier : STRING { $$ = $1; }
| MARK { $$ = xstrdup("mark"); }
@@ -1989,6 +2037,12 @@ limit_stmt : LIMIT RATE limit_mode NUM SLASH time_unit limit_burst
$$->limit.type = NFT_LIMIT_PKT_BYTES;
$$->limit.flags = $3;
}
+ | LIMIT NAME stmt_expr
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_LIMIT;
+ $$->objref.expr = $3;
+ }
;
quota_mode : OVER { $$ = NFT_QUOTA_F_INV; }
@@ -2745,6 +2799,47 @@ ct_obj_alloc :
}
;
+limit_config : RATE limit_mode NUM SLASH time_unit limit_burst
+ {
+ struct limit *limit;
+ limit = xzalloc(sizeof(*limit));
+ limit->rate = $3;
+ limit->unit = $5;
+ limit->burst = $6;
+ limit->type = NFT_LIMIT_PKTS;
+ limit->flags = $2;
+ $$ = limit;
+ }
+ | RATE limit_mode NUM STRING limit_burst
+ {
+ struct limit *limit;
+ struct error_record *erec;
+ uint64_t rate, unit;
+
+ erec = rate_parse(&@$, $4, &rate, &unit);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ limit = xzalloc(sizeof(*limit));
+ limit->rate = rate * $3;
+ limit->unit = unit;
+ limit->burst = $5;
+ limit->type = NFT_LIMIT_PKT_BYTES;
+ limit->flags = $2;
+ $$ = limit;
+ }
+ ;
+
+limit_obj : limit_config
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_LIMIT;
+ $$->limit = *$1;
+ }
+ ;
+
relational_expr : expr /* implicit */ rhs_expr
{
$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
diff --git a/src/rule.c b/src/rule.c
index ef12bec..ae973bd 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -959,6 +959,7 @@ void cmd_free(struct cmd *cmd)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_LIMIT:
obj_free(cmd->object);
break;
default:
@@ -1046,6 +1047,7 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_LIMIT:
return netlink_add_obj(ctx, &cmd->handle, cmd->object, flags);
default:
BUG("invalid command object type %u\n", cmd->obj);
@@ -1132,6 +1134,9 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_CT_HELPER:
return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_LIMIT:
+ return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
+ NFT_OBJECT_LIMIT);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -1292,6 +1297,37 @@ static void obj_print_data(const struct obj *obj,
printf("\t\tl3proto %s", family2str(obj->ct_helper.l3proto));
break;
}
+ case NFT_OBJECT_LIMIT: {
+ bool inv = obj->limit.flags & NFT_LIMIT_F_INV;
+ const char *data_unit;
+ uint64_t rate;
+
+ printf(" %s {%s%s%s", obj->handle.obj,
+ opts->nl, opts->tab, opts->tab);
+ switch (obj->limit.type) {
+ case NFT_LIMIT_PKTS:
+ printf("limit rate %s%" PRIu64 "/%s",
+ inv ? "over " : "", obj->limit.rate,
+ get_unit(obj->limit.unit));
+ if (obj->limit.burst > 0)
+ printf(" burst %u packets", obj->limit.burst);
+ break;
+ case NFT_LIMIT_PKT_BYTES:
+ data_unit = get_rate(obj->limit.rate, &rate);
+
+ printf("limit 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);
+ printf(" burst %"PRIu64" %s", burst, data_unit);
+ }
+ break;
+ }
+ }
+ break;
default:
printf("unknown {%s", opts->nl);
break;
@@ -1302,11 +1338,12 @@ static const char *obj_type_name_array[] = {
[NFT_OBJECT_COUNTER] = "counter",
[NFT_OBJECT_QUOTA] = "quota",
[NFT_OBJECT_CT_HELPER] = "",
+ [NFT_OBJECT_LIMIT] = "limit",
};
const char *obj_type_name(enum stmt_types type)
{
- assert(type <= NFT_OBJECT_CT_HELPER && obj_type_name_array[type]);
+ assert(type <= NFT_OBJECT_MAX && obj_type_name_array[type]);
return obj_type_name_array[type];
}
@@ -1315,6 +1352,7 @@ 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,
};
uint32_t obj_type_to_cmd(uint32_t type)
@@ -1546,6 +1584,9 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_CT_HELPER:
case CMD_OBJ_CT_HELPERS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_LIMITS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
diff --git a/src/scanner.l b/src/scanner.l
index b6ba32d..ef424e4 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -300,6 +300,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"counters" { return COUNTERS; }
"quotas" { return QUOTAS; }
+"limits" { return LIMITS; }
"log" { return LOG; }
"prefix" { return PREFIX; }
diff --git a/src/statement.c b/src/statement.c
index 58f8aaf..0b2c28b 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -175,6 +175,7 @@ static const char *objref_type[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_COUNTER] = "counter",
[NFT_OBJECT_QUOTA] = "quota",
[NFT_OBJECT_CT_HELPER] = "cthelper",
+ [NFT_OBJECT_LIMIT] = "limit",
};
static const char *objref_type_name(uint32_t type)
@@ -286,7 +287,7 @@ struct stmt *log_stmt_alloc(const struct location *loc)
return stmt_alloc(loc, &log_stmt_ops);
}
-static const char *get_unit(uint64_t u)
+const char *get_unit(uint64_t u)
{
switch (u) {
case 1: return "second";
--
2.14.1
next prev parent reply other threads:[~2017-08-23 20:43 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-23 20:42 [PATCH nft 1/2] parser: fix typo Pablo M. Bermudo Garay
2017-08-23 20:42 ` Pablo M. Bermudo Garay [this message]
2017-08-23 21:06 ` [PATCH nft 2/2] src: limit stateful object support Pablo M. Bermudo Garay
2017-08-23 21:51 ` Pablo Neira Ayuso
2017-08-24 9:20 ` Pablo M. Bermudo Garay
2017-08-23 22:24 ` [PATCH nft 1/2] parser: fix typo Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170823204256.31634-2-pablombg@gmail.com \
--to=pablombg@gmail.com \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.