* [PATCH nft 01/10] include: fetch nf_tables.h updates
@ 2016-12-23 14:26 Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 02/10] src: remove SET_F_* flag definitions Pablo Neira Ayuso
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
Get header in sync with recent updates.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/nf_tables.h | 64 +++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index f030e59aa2ec..881d49e94569 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -4,6 +4,7 @@
#define NFT_TABLE_MAXNAMELEN 32
#define NFT_CHAIN_MAXNAMELEN 32
#define NFT_SET_MAXNAMELEN 32
+#define NFT_OBJ_MAXNAMELEN 32
#define NFT_USERDATA_MAXLEN 256
/**
@@ -85,6 +86,10 @@ enum nft_verdicts {
* @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)
*/
enum nf_tables_msg_types {
NFT_MSG_NEWTABLE,
@@ -105,6 +110,10 @@ enum nf_tables_msg_types {
NFT_MSG_NEWGEN,
NFT_MSG_GETGEN,
NFT_MSG_TRACE,
+ NFT_MSG_NEWOBJ,
+ NFT_MSG_GETOBJ,
+ NFT_MSG_DELOBJ,
+ NFT_MSG_GETOBJ_RESET,
NFT_MSG_MAX,
};
@@ -246,6 +255,7 @@ enum nft_rule_compat_attributes {
* @NFT_SET_MAP: set is used as a dictionary
* @NFT_SET_TIMEOUT: set uses timeouts
* @NFT_SET_EVAL: set contains expressions for evaluation
+ * @NFT_SET_OBJECT: set contains stateful objects
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
@@ -254,6 +264,7 @@ enum nft_set_flags {
NFT_SET_MAP = 0x8,
NFT_SET_TIMEOUT = 0x10,
NFT_SET_EVAL = 0x20,
+ NFT_SET_OBJECT = 0x40,
};
/**
@@ -295,6 +306,7 @@ enum nft_set_desc_attributes {
* @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_*)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -312,6 +324,7 @@ enum nft_set_attributes {
NFTA_SET_GC_INTERVAL,
NFTA_SET_USERDATA,
NFTA_SET_PAD,
+ NFTA_SET_OBJ_TYPE,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -335,6 +348,7 @@ enum nft_set_elem_flags {
* @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)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
@@ -346,6 +360,7 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_USERDATA,
NFTA_SET_ELEM_EXPR,
NFTA_SET_ELEM_PAD,
+ NFTA_SET_ELEM_OBJREF,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
@@ -974,6 +989,7 @@ enum nft_queue_attributes {
enum nft_quota_flags {
NFT_QUOTA_F_INV = (1 << 0),
+ NFT_QUOTA_F_DEPLETED = (1 << 1),
};
/**
@@ -981,12 +997,14 @@ enum nft_quota_flags {
*
* @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)
@@ -1131,6 +1149,26 @@ enum nft_fwd_attributes {
#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)
@@ -1178,6 +1216,32 @@ enum nft_fib_flags {
NFTA_FIB_F_OIF = 1 << 4, /* restrict to oif */
};
+#define NFT_OBJECT_UNSPEC 0
+#define NFT_OBJECT_COUNTER 1
+#define NFT_OBJECT_QUOTA 2
+#define __NFT_OBJECT_MAX 3
+#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)
+ */
+enum nft_object_attributes {
+ NFTA_OBJ_UNSPEC,
+ NFTA_OBJ_TABLE,
+ NFTA_OBJ_NAME,
+ NFTA_OBJ_TYPE,
+ NFTA_OBJ_DATA,
+ NFTA_OBJ_USE,
+ __NFTA_OBJ_MAX
+};
+#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
+
/**
* enum nft_trace_attributes - nf_tables trace netlink attributes
*
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 02/10] src: remove SET_F_* flag definitions
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 03/10] src: add used quota support Pablo Neira Ayuso
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
They map exactly one to one to we have in the kernel headers, so use
kernel definitions instead.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/rule.h | 15 ---------------
src/evaluate.c | 34 +++++++++++++++++-----------------
src/expression.c | 4 ++--
src/netlink.c | 8 ++++----
src/parser_bison.y | 6 +++---
src/rule.c | 32 ++++++++++++++++----------------
src/segtree.c | 4 ++--
7 files changed, 44 insertions(+), 59 deletions(-)
diff --git a/include/rule.h b/include/rule.h
index b9b4a19c9731..f74630c53d2b 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -195,21 +195,6 @@ extern void rule_print(const struct rule *rule);
extern struct rule *rule_lookup(const struct chain *chain, uint64_t handle);
/**
- * enum set_flags
- *
- * @SET_F_CONSTANT: Set content is constant
- * @SET_F_INTERVAL: set includes ranges and/or prefix expressions
- */
-enum set_flags {
- SET_F_ANONYMOUS = 0x1,
- SET_F_CONSTANT = 0x2,
- SET_F_INTERVAL = 0x4,
- SET_F_MAP = 0x8,
- SET_F_TIMEOUT = 0x10,
- SET_F_EVAL = 0x20,
-};
-
-/**
* struct set - nftables set
*
* @list: table set list node
diff --git a/src/evaluate.c b/src/evaluate.c
index 8a3da54e5b2d..557c61c814df 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -70,7 +70,7 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
struct handle h;
set = set_alloc(&expr->location);
- set->flags = SET_F_ANONYMOUS | expr->set_flags;
+ set->flags = NFT_SET_ANONYMOUS | expr->set_flags;
set->handle.set = xstrdup(name),
set->keytype = keytype;
set->keylen = keylen;
@@ -1060,7 +1060,7 @@ static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
return -1;
if (ctx->set &&
- !(ctx->set->flags & (SET_F_ANONYMOUS | SET_F_INTERVAL))) {
+ !(ctx->set->flags & (NFT_SET_ANONYMOUS | NFT_SET_INTERVAL))) {
switch (elem->key->ops->type) {
case EXPR_PREFIX:
return expr_error(ctx->msgs, elem,
@@ -1106,10 +1106,10 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
set->set_flags |= i->set_flags;
expr_free(i);
} else if (!expr_is_singleton(i))
- set->set_flags |= SET_F_INTERVAL;
+ set->set_flags |= NFT_SET_INTERVAL;
}
- set->set_flags |= SET_F_CONSTANT;
+ set->set_flags |= NFT_SET_CONSTANT;
set->dtype = ctx->ectx.dtype;
set->len = ctx->ectx.len;
@@ -1130,7 +1130,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
"Map expression can not be constant");
mappings = map->mappings;
- mappings->set_flags |= SET_F_MAP;
+ mappings->set_flags |= NFT_SET_MAP;
switch (map->mappings->ops->type) {
case EXPR_SET:
@@ -1173,7 +1173,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
- if (map->mappings->set->flags & SET_F_INTERVAL &&
+ if (map->mappings->set->flags & NFT_SET_INTERVAL &&
byteorder_conversion(ctx, &map->map, BYTEORDER_BIG_ENDIAN) < 0)
return -1;
@@ -1188,7 +1188,7 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
if (set == NULL)
return expr_error(ctx->msgs, mapping,
"mapping outside of map context");
- if (!(set->flags & SET_F_MAP))
+ if (!(set->flags & NFT_SET_MAP))
return set_error(ctx, set, "set is not a map");
expr_set_context(&ctx->ectx, set->keytype, set->keylen);
@@ -1481,7 +1481,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
right->dtype->desc);
/* Data for range lookups needs to be in big endian order */
- if (right->set->flags & SET_F_INTERVAL &&
+ if (right->set->flags & NFT_SET_INTERVAL &&
byteorder_conversion(ctx, &rel->left,
BYTEORDER_BIG_ENDIAN) < 0)
return -1;
@@ -1536,7 +1536,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
case EXPR_SET_REF:
assert(rel->op == OP_NEQ);
/* Data for range lookups needs to be in big endian order */
- if (right->set->flags & SET_F_INTERVAL &&
+ if (right->set->flags & NFT_SET_INTERVAL &&
byteorder_conversion(ctx, &rel->left, BYTEORDER_BIG_ENDIAN) < 0)
return -1;
break;
@@ -1847,9 +1847,9 @@ static int stmt_evaluate_flow(struct eval_ctx *ctx, struct stmt *stmt)
/* Declare an empty set */
key = stmt->flow.key;
set = set_expr_alloc(&key->location);
- set->set_flags |= SET_F_EVAL;
+ set->set_flags |= NFT_SET_EVAL;
if (key->timeout)
- set->set_flags |= SET_F_TIMEOUT;
+ set->set_flags |= NFT_SET_TIMEOUT;
setref = implicit_set_declaration(ctx, stmt->flow.table ?: "__ft%d",
key->dtype, key->len, set);
@@ -2549,7 +2549,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
return cmd_error(ctx, "Could not process rule: Table '%s' does not exist",
ctx->cmd->handle.table);
- type = set->flags & SET_F_MAP ? "map" : "set";
+ type = set->flags & NFT_SET_MAP ? "map" : "set";
if (set->keytype == NULL)
return set_error(ctx, set, "%s definition does not specify "
@@ -2560,7 +2560,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
return set_error(ctx, set, "unqualified key data type "
"specified in %s definition", type);
- if (set->flags & SET_F_MAP) {
+ if (set->flags & NFT_SET_MAP) {
if (set->datatype == NULL)
return set_error(ctx, set, "map definition does not "
"specify mapping data type");
@@ -2584,7 +2584,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
/* Default timeout value implies timeout support */
if (set->timeout)
- set->flags |= SET_F_TIMEOUT;
+ set->flags |= NFT_SET_TIMEOUT;
return 0;
}
@@ -2810,7 +2810,7 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
return cmd_error(ctx, "Could not process rule: Table '%s' does not exist",
cmd->handle.table);
set = set_lookup(table, cmd->handle.set);
- if (set == NULL || set->flags & (SET_F_MAP | SET_F_EVAL))
+ if (set == NULL || set->flags & (NFT_SET_MAP | NFT_SET_EVAL))
return cmd_error(ctx, "Could not process rule: Set '%s' does not exist",
cmd->handle.set);
return 0;
@@ -2820,7 +2820,7 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
return cmd_error(ctx, "Could not process rule: Table '%s' does not exist",
cmd->handle.table);
set = set_lookup(table, cmd->handle.set);
- if (set == NULL || !(set->flags & SET_F_EVAL))
+ if (set == NULL || !(set->flags & NFT_SET_EVAL))
return cmd_error(ctx, "Could not process rule: Flow table '%s' does not exist",
cmd->handle.set);
return 0;
@@ -2830,7 +2830,7 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
return cmd_error(ctx, "Could not process rule: Table '%s' does not exist",
cmd->handle.table);
set = set_lookup(table, cmd->handle.set);
- if (set == NULL || !(set->flags & SET_F_MAP))
+ if (set == NULL || !(set->flags & NFT_SET_MAP))
return cmd_error(ctx, "Could not process rule: Map '%s' does not exist",
cmd->handle.set);
return 0;
diff --git a/src/expression.c b/src/expression.c
index b7403c7009cd..1567870c631b 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -858,8 +858,8 @@ struct expr *map_expr_alloc(const struct location *loc, struct expr *arg,
static void set_ref_expr_print(const struct expr *expr)
{
- if (expr->set->flags & SET_F_ANONYMOUS) {
- if (expr->set->flags & SET_F_EVAL)
+ if (expr->set->flags & NFT_SET_ANONYMOUS) {
+ if (expr->set->flags & NFT_SET_EVAL)
printf("table %s", expr->set->handle.set);
else
expr_print(expr->set->init);
diff --git a/src/netlink.c b/src/netlink.c
index d6d00199d746..e37d3bf124a6 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1175,7 +1175,7 @@ static int netlink_add_set_batch(struct netlink_ctx *ctx,
nftnl_set_set_u32(nls, NFTNL_SET_ID, set->handle.set_id);
- if (!(set->flags & (SET_F_CONSTANT))) {
+ if (!(set->flags & NFT_SET_CONSTANT)) {
if (set->policy != NFT_SET_POL_PERFORMANCE)
nftnl_set_set_u32(nls, NFTNL_SET_POLICY, set->policy);
@@ -1505,7 +1505,7 @@ static int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
if (set->keytype->subtypes)
key = netlink_parse_concat_elem(set->keytype, key);
- if (!(set->flags & SET_F_INTERVAL) &&
+ if (!(set->flags & NFT_SET_INTERVAL) &&
key->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
@@ -1858,7 +1858,7 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
nls = netlink_set_alloc(nlh);
flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
- if (flags & SET_F_ANONYMOUS)
+ if (flags & NFT_SET_ANONYMOUS)
goto out;
switch (monh->format) {
@@ -1920,7 +1920,7 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
- if (set->flags & SET_F_ANONYMOUS)
+ if (set->flags & NFT_SET_ANONYMOUS)
goto out;
/* we want to 'delinearize' the set_elem, but don't
diff --git a/src/parser_bison.y b/src/parser_bison.y
index deaaf06fa1c6..0f3ad915b701 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1092,9 +1092,9 @@ set_flag_list : set_flag_list COMMA set_flag
| set_flag
;
-set_flag : CONSTANT { $$ = SET_F_CONSTANT; }
- | INTERVAL { $$ = SET_F_INTERVAL; }
- | TIMEOUT { $$ = SET_F_TIMEOUT; }
+set_flag : CONSTANT { $$ = NFT_SET_CONSTANT; }
+ | INTERVAL { $$ = NFT_SET_INTERVAL; }
+ | TIMEOUT { $$ = NFT_SET_TIMEOUT; }
;
map_block_alloc : /* empty */
diff --git a/src/rule.c b/src/rule.c
index f1bb6cfe04ea..988305b57615 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -263,9 +263,9 @@ static void set_print_declaration(const struct set *set,
const char *type;
uint32_t flags;
- if (set->flags & SET_F_MAP)
+ if (set->flags & NFT_SET_MAP)
type = "map";
- else if (set->flags & SET_F_EVAL)
+ else if (set->flags & NFT_SET_EVAL)
type = "flow table";
else
type = "set";
@@ -281,12 +281,12 @@ static void set_print_declaration(const struct set *set,
printf(" %s {%s", set->handle.set, opts->nl);
printf("%s%stype %s", opts->tab, opts->tab, set->keytype->name);
- if (set->flags & SET_F_MAP)
+ if (set->flags & NFT_SET_MAP)
printf(" : %s", set->datatype->name);
printf("%s", opts->stmt_separator);
- if (!(set->flags & (SET_F_CONSTANT))) {
+ if (!(set->flags & (NFT_SET_CONSTANT))) {
if (set->policy != NFT_SET_POL_PERFORMANCE) {
printf("%s%spolicy %s%s", opts->tab, opts->tab,
set_policy2str(set->policy),
@@ -302,19 +302,19 @@ static void set_print_declaration(const struct set *set,
flags = set->flags;
/* "timeout" flag is redundant if a default timeout exists */
if (set->timeout)
- flags &= ~SET_F_TIMEOUT;
+ flags &= ~NFT_SET_TIMEOUT;
- if (flags & (SET_F_CONSTANT | SET_F_INTERVAL | SET_F_TIMEOUT)) {
+ if (flags & (NFT_SET_CONSTANT | NFT_SET_INTERVAL | NFT_SET_TIMEOUT)) {
printf("%s%sflags ", opts->tab, opts->tab);
- if (set->flags & SET_F_CONSTANT) {
+ if (set->flags & NFT_SET_CONSTANT) {
printf("%sconstant", delim);
delim = ",";
}
- if (set->flags & SET_F_INTERVAL) {
+ if (set->flags & NFT_SET_INTERVAL) {
printf("%sinterval", delim);
delim = ",";
}
- if (set->flags & SET_F_TIMEOUT) {
+ if (set->flags & NFT_SET_TIMEOUT) {
printf("%stimeout", delim);
delim = ",";
}
@@ -770,7 +770,7 @@ static void table_print(const struct table *table)
table_print_options(table, &delim);
list_for_each_entry(set, &table->sets, list) {
- if (set->flags & SET_F_ANONYMOUS)
+ if (set->flags & NFT_SET_ANONYMOUS)
continue;
printf("%s", delim);
set_print(set);
@@ -888,7 +888,7 @@ static int do_add_chain(struct netlink_ctx *ctx, const struct handle *h,
static int __do_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
struct set *set, struct expr *expr, bool excl)
{
- if (set->flags & SET_F_INTERVAL &&
+ if (set->flags & NFT_SET_INTERVAL &&
set_to_intervals(ctx->msgs, set, expr, true) < 0)
return -1;
@@ -1006,7 +1006,7 @@ static int do_delete_setelems(struct netlink_ctx *ctx, const struct handle *h,
table = table_lookup(h);
set = set_lookup(table, h->set);
- if (set->flags & SET_F_INTERVAL &&
+ if (set->flags & NFT_SET_INTERVAL &&
set_to_intervals(ctx->msgs, set, expr, false) < 0)
return -1;
@@ -1080,14 +1080,14 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
list_for_each_entry(set, &table->sets, list) {
if (cmd->obj == CMD_OBJ_SETS &&
- (set->flags & SET_F_ANONYMOUS ||
- set->flags & SET_F_MAP))
+ (set->flags & NFT_SET_ANONYMOUS ||
+ set->flags & NFT_SET_MAP))
continue;
if (cmd->obj == CMD_OBJ_FLOWTABLES &&
- !(set->flags & SET_F_EVAL))
+ !(set->flags & NFT_SET_EVAL))
continue;
if (cmd->obj == CMD_OBJ_MAPS &&
- !(set->flags & SET_F_MAP))
+ !(set->flags & NFT_SET_MAP))
continue;
set_print_declaration(set, &opts);
printf("%s}%s", opts.tab, opts.nl);
diff --git a/src/segtree.c b/src/segtree.c
index 5b6cdd1d770d..db782f2293c0 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -403,7 +403,7 @@ static int set_to_segtree(struct list_head *msgs, struct set *set,
* Insert elements into tree
*/
for (n = 0; n < init->size; n++) {
- if (init->set_flags & SET_F_MAP &&
+ if (init->set_flags & NFT_SET_MAP &&
n < init->size - 1 &&
interval_conflict(intervals[n], intervals[n+1]))
return expr_binary_error(msgs,
@@ -426,7 +426,7 @@ static bool segtree_needs_first_segment(const struct set *set,
* 2) This set exists and it is empty.
* 3) This set is created with a number of initial elements.
*/
- if ((set->flags & SET_F_ANONYMOUS) ||
+ if ((set->flags & NFT_SET_ANONYMOUS) ||
(set->init && set->init->size == 0) ||
(set->init == init))
return true;
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 03/10] src: add used quota support
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 02/10] src: remove SET_F_* flag definitions Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 04/10] src: listing of stateful objects Pablo Neira Ayuso
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
table ip x {
chain y {
type filter hook forward priority 0; policy accept;
quota over 200 mbytes used 1143 kbytes drop
}
}
This patch allows us to list and to restore used quota.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/statement.h | 1 +
src/netlink_delinearize.c | 2 ++
src/netlink_linearize.c | 1 +
src/parser_bison.y | 21 +++++++++++++++++++--
src/scanner.l | 1 +
src/statement.c | 7 ++++++-
6 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/include/statement.h b/include/statement.h
index 277ff2f47c7f..d317ae368164 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -108,6 +108,7 @@ extern struct stmt *queue_stmt_alloc(const struct location *loc);
struct quota_stmt {
uint64_t bytes;
+ uint64_t used;
uint32_t flags;
};
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index cb0f6ac7b1a2..9a16926e3817 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -777,6 +777,8 @@ static void netlink_parse_quota(struct netlink_parse_ctx *ctx,
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;
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 0915038fecae..144068d23378 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -734,6 +734,7 @@ netlink_gen_quota_stmt(struct netlink_linearize_ctx *ctx,
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;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 0f3ad915b701..aea6e47d8b12 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -378,6 +378,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token UNTIL "until"
%token QUOTA "quota"
+%token USED "used"
%token NANOSECOND "nanosecond"
%token MICROSECOND "microsecond"
@@ -427,7 +428,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <string> identifier type_identifier string comment_spec
%destructor { xfree($$); } identifier type_identifier string comment_spec
-%type <val> time_spec
+%type <val> time_spec quota_used
%type <val> type_identifier_list
%type <datatype> data_type
@@ -1636,7 +1637,22 @@ quota_unit : BYTES { $$ = xstrdup("bytes"); }
| STRING { $$ = $1; }
;
-quota_stmt : QUOTA quota_mode NUM quota_unit
+quota_used : /* empty */ { $$ = 0; }
+ | USED NUM quota_unit
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $3, &rate);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = $2 * rate;
+ }
+ ;
+
+quota_stmt : QUOTA quota_mode NUM quota_unit quota_used
{
struct error_record *erec;
uint64_t rate;
@@ -1648,6 +1664,7 @@ quota_stmt : QUOTA quota_mode NUM quota_unit
}
$$ = quota_stmt_alloc(&@$);
$$->quota.bytes = $3 * rate;
+ $$->quota.used = $5;
$$->quota.flags = $2;
}
;
diff --git a/src/scanner.l b/src/scanner.l
index 625023f5257c..8aa4b08ba8fc 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -312,6 +312,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"over" { return OVER; }
"quota" { return QUOTA; }
+"used" { return USED; }
"nanosecond" { return NANOSECOND; }
"microsecond" { return MICROSECOND; }
diff --git a/src/statement.c b/src/statement.c
index e70eb51ec859..4d3ca55a4081 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -352,11 +352,16 @@ static void quota_stmt_print(const struct stmt *stmt)
{
bool inv = stmt->quota.flags & NFT_QUOTA_F_INV;
const char *data_unit;
- uint64_t bytes;
+ uint64_t bytes, used;
data_unit = get_rate(stmt->quota.bytes, &bytes);
printf("quota %s%"PRIu64" %s",
inv ? "over " : "", bytes, data_unit);
+
+ if (stmt->quota.used) {
+ data_unit = get_rate(stmt->quota.used, &used);
+ printf(" used %"PRIu64" %s", used, data_unit);
+ }
}
static const struct stmt_ops quota_stmt_ops = {
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 04/10] src: listing of stateful objects
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 02/10] src: remove SET_F_* flag definitions Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 03/10] src: add used quota support Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 05/10] src: add/create/delete " Pablo Neira Ayuso
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
This patch allows you to dump existing stateful objects, eg.
# nft list ruleset
table ip filter {
counter test {
packets 64 bytes 1268
}
quota test {
over 1 mbytes used 1268 bytes
}
chain input {
type filter hook input priority 0; policy accept;
quota name test drop
counter name test
}
}
# nft list quotas
table ip filter {
quota test {
over 1 mbytes used 1268 bytes
}
}
# nft list counters
table ip filter {
counter test {
packets 64 bytes 1268
}
}
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/mnl.h | 2 +
include/netlink.h | 4 ++
include/rule.h | 51 +++++++++++++++++++
include/statement.h | 3 ++
src/evaluate.c | 2 +
src/mnl.c | 59 ++++++++++++++++++++++
src/netlink.c | 67 +++++++++++++++++++++++++
src/parser_bison.y | 30 ++++++++++-
src/rule.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/scanner.l | 3 ++
src/statement.c | 2 +-
11 files changed, 360 insertions(+), 3 deletions(-)
diff --git a/include/mnl.h b/include/mnl.h
index 87db96afd369..ad036aefabbd 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -86,6 +86,8 @@ int mnl_nft_setelem_batch_flush(struct nftnl_set *nls, unsigned int flags,
uint32_t seqnum);
int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nftnl_set *nls);
+struct nftnl_obj_list *mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family,
+ const char *table);
struct nftnl_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock,
uint32_t family);
int mnl_nft_event_listener(struct mnl_socket *nf_sock,
diff --git a/include/netlink.h b/include/netlink.h
index 363b5251968f..ce577871761f 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -6,6 +6,7 @@
#include <libnftnl/rule.h>
#include <libnftnl/expr.h>
#include <libnftnl/set.h>
+#include <libnftnl/object.h>
#include <linux/netlink.h>
#include <linux/netfilter/nf_tables.h>
@@ -168,6 +169,9 @@ extern int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h,
extern int netlink_flush_setelems(struct netlink_ctx *ctx, const struct handle *h,
const struct location *loc);
+extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h,
+ const struct location *loc);
+
extern void netlink_dump_table(const struct nftnl_table *nlt);
extern void netlink_dump_chain(const struct nftnl_chain *nlc);
extern void netlink_dump_rule(const struct nftnl_rule *nlr);
diff --git a/include/rule.h b/include/rule.h
index f74630c53d2b..e0f891393276 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -34,6 +34,7 @@ struct position_spec {
* @table: table name
* @chain: chain name (chains and rules only)
* @set: set name (sets only)
+ * @obj: stateful object name (stateful object only)
* @handle: rule handle (rules only)
* @position: rule position (rules only)
* @set_id: set ID (sets only)
@@ -43,6 +44,7 @@ struct handle {
const char *table;
const char *chain;
const char *set;
+ const char *obj;
struct handle_spec handle;
struct position_spec position;
uint32_t set_id;
@@ -95,6 +97,7 @@ enum table_flags {
* @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
* @flags: table flags
* @refcnt: table reference counter
*/
@@ -105,6 +108,7 @@ struct table {
struct scope scope;
struct list_head chains;
struct list_head sets;
+ struct list_head objs;
enum table_flags flags;
unsigned int refcnt;
};
@@ -241,6 +245,45 @@ extern struct set *set_lookup_global(uint32_t family, const char *table,
extern void set_print(const struct set *set);
extern void set_print_plain(const struct set *s);
+#include <statement.h>
+
+struct counter {
+ uint64_t packets;
+ uint64_t bytes;
+};
+
+struct quota {
+ uint64_t bytes;
+ uint64_t used;
+ uint32_t flags;
+};
+
+/**
+ * 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
+ */
+struct obj {
+ struct list_head list;
+ struct location location;
+ struct handle handle;
+ uint32_t type;
+
+ union {
+ struct counter counter;
+ struct quota quota;
+ };
+};
+
+struct obj *obj_alloc(const struct location *loc);
+void obj_free(struct obj *obj);
+void obj_add_hash(struct obj *obj, struct table *table);
+void obj_print(const struct obj *n);
+const char *obj_type_name(enum stmt_types type);
+
/**
* enum cmd_ops - command operations
*
@@ -287,6 +330,10 @@ enum cmd_ops {
* @CMD_OBJ_EXPR: expression
* @CMD_OBJ_MONITOR: monitor
* @CMD_OBJ_EXPORT: export
+ * @CMD_OBJ_COUNTER: counter
+ * @CMD_OBJ_COUNTERS: multiple counters
+ * @CMD_OBJ_QUOTA: quota
+ * @CMD_OBJ_QUOTAS: multiple quotas
*/
enum cmd_obj {
CMD_OBJ_INVALID,
@@ -305,6 +352,10 @@ enum cmd_obj {
CMD_OBJ_FLOWTABLES,
CMD_OBJ_MAP,
CMD_OBJ_MAPS,
+ CMD_OBJ_COUNTER,
+ CMD_OBJ_COUNTERS,
+ CMD_OBJ_QUOTA,
+ CMD_OBJ_QUOTAS,
};
struct export {
diff --git a/include/statement.h b/include/statement.h
index d317ae368164..9d0f601f98a2 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -66,6 +66,7 @@ struct limit_stmt {
};
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;
@@ -301,4 +302,6 @@ extern void stmt_free(struct stmt *stmt);
extern void stmt_list_free(struct list_head *list);
extern void stmt_print(const struct stmt *stmt);
+const char *get_rate(uint64_t byte_rate, uint64_t *rate);
+
#endif /* NFTABLES_STATEMENT_H */
diff --git a/src/evaluate.c b/src/evaluate.c
index 557c61c814df..b3630c303920 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2845,6 +2845,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
return 0;
case CMD_OBJ_CHAINS:
case CMD_OBJ_SETS:
+ case CMD_OBJ_COUNTERS:
+ case CMD_OBJ_QUOTAS:
case CMD_OBJ_RULESET:
case CMD_OBJ_FLOWTABLES:
case CMD_OBJ_MAPS:
diff --git a/src/mnl.c b/src/mnl.c
index 257b630e2a26..534d02f4ff32 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -16,6 +16,7 @@
#include <libnftnl/rule.h>
#include <libnftnl/expr.h>
#include <libnftnl/set.h>
+#include <libnftnl/object.h>
#include <libnftnl/batch.h>
#include <linux/netfilter/nfnetlink.h>
@@ -795,6 +796,64 @@ err:
return NULL;
}
+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 mnl_socket *nf_sock, int family, const char *table)
+{
+ struct nftnl_obj_list *nln_list;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nftnl_obj *n;
+ struct nlmsghdr *nlh;
+ int ret;
+
+ n = nftnl_obj_alloc();
+ if (n == NULL)
+ memory_allocation_error();
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETOBJ, family,
+ NLM_F_DUMP | NLM_F_ACK, seq);
+ if (table != NULL)
+ nftnl_obj_set(n, NFTNL_OBJ_TABLE, table);
+ 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(nf_sock, 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;
+}
+
static int set_get_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_set *s = data;
diff --git a/src/netlink.c b/src/netlink.c
index e37d3bf124a6..bbf675f90def 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1608,6 +1608,73 @@ out:
return err;
}
+static struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
+ struct nftnl_obj *nlo)
+{
+ struct obj *obj;
+ uint32_t type;
+
+ obj = obj_alloc(&netlink_location);
+ obj->handle.family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
+ obj->handle.table =
+ xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE));
+ obj->handle.obj =
+ xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME));
+
+ 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);
+ }
+ obj->type = type;
+
+ return obj;
+}
+
+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_list_objs(struct netlink_ctx *ctx, const struct handle *h,
+ const struct location *loc)
+{
+ struct nftnl_obj_list *obj_cache;
+ int err;
+
+ obj_cache = mnl_nft_obj_dump(nf_sock, h->family, h->table);
+ if (obj_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return netlink_io_error(ctx, loc,
+ "Could not receive stateful object from kernel: %s",
+ strerror(errno));
+ }
+
+ err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx);
+ nftnl_obj_list_free(obj_cache);
+ return err;
+}
+
int netlink_batch_send(struct list_head *err_list)
{
return mnl_batch_talk(nf_sock, err_list);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index aea6e47d8b12..2213f3808db4 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -364,6 +364,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token PACKETS "packets"
%token BYTES "bytes"
+%token COUNTERS "counters"
+%token QUOTAS "quotas"
+
%token LOG "log"
%token PREFIX "prefix"
%token GROUP "group"
@@ -441,8 +444,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <handle> table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%type <handle> set_spec set_identifier
-%destructor { handle_free(&$$); } set_spec set_identifier
+%type <handle> set_spec set_identifier obj_spec
+%destructor { handle_free(&$$); } set_spec set_identifier obj_spec
%type <val> family_spec family_spec_explicit chain_policy prio_spec
%type <string> dev_spec quota_unit
@@ -872,6 +875,22 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_SET, &$2, &@$, NULL);
}
+ | COUNTERS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &$2, &@$, NULL);
+ }
+ | COUNTER obj_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ }
+ | QUOTAS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &$2, &@$, NULL);
+ }
+ | QUOTA obj_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+ }
| RULESET ruleset_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_RULESET, &$2, &@$, NULL);
@@ -1299,6 +1318,13 @@ set_identifier : identifier
}
;
+obj_spec : table_spec identifier
+ {
+ $$ = $1;
+ $$.obj = $2;
+ }
+ ;
+
handle_spec : HANDLE NUM
{
memset(&$$, 0, sizeof($$));
diff --git a/src/rule.c b/src/rule.c
index 988305b57615..05f0eb87b162 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -93,6 +93,12 @@ static int cache_init_objects(struct netlink_ctx *ctx, enum cmd_ops cmd)
return -1;
list_splice_tail_init(&ctx->list, &table->chains);
+ /* Don't check for errors on listings, this would break nft with
+ * old kernels with no stateful object support.
+ */
+ netlink_list_objs(ctx, &table->handle, &internal_location);
+ list_splice_tail_init(&ctx->list, &table->objs);
+
/* Skip caching other objects to speed up things: We only need
* a full cache when listing the existing ruleset.
*/
@@ -688,6 +694,7 @@ struct table *table_alloc(void)
table = xzalloc(sizeof(*table));
init_list_head(&table->chains);
init_list_head(&table->sets);
+ init_list_head(&table->objs);
init_list_head(&table->scope.symbols);
table->refcnt = 1;
@@ -762,6 +769,7 @@ static void table_print_options(const struct table *table, const char **delim)
static void table_print(const struct table *table)
{
struct chain *chain;
+ struct obj *obj;
struct set *set;
const char *delim = "";
const char *family = family2str(table->handle.family);
@@ -769,6 +777,11 @@ static void table_print(const struct table *table)
printf("table %s %s {\n", family, table->handle.table);
table_print_options(table, &delim);
+ list_for_each_entry(obj, &table->objs, list) {
+ printf("%s", delim);
+ obj_print(obj);
+ delim = "\n";
+ }
list_for_each_entry(set, &table->sets, list) {
if (set->flags & NFT_SET_ANONYMOUS)
continue;
@@ -1098,6 +1111,129 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
return 0;
}
+struct obj *obj_alloc(const struct location *loc)
+{
+ struct obj *obj;
+
+ obj = xzalloc(sizeof(*obj));
+ if (loc != NULL)
+ obj->location = *loc;
+ return obj;
+}
+
+void obj_free(struct obj *obj)
+{
+ handle_free(&obj->handle);
+ xfree(obj);
+}
+
+void obj_add_hash(struct obj *obj, struct table *table)
+{
+ list_add_tail(&obj->list, &table->objs);
+}
+
+static void obj_print_data(const struct obj *obj,
+ struct print_fmt_options *opts)
+{
+ switch (obj->type) {
+ case NFT_OBJECT_COUNTER:
+ printf(" %s {%s%s%s", obj->handle.obj,
+ opts->nl, opts->tab, opts->tab);
+ printf("packets %"PRIu64" bytes %"PRIu64"",
+ obj->counter.packets, obj->counter.bytes);
+ break;
+ case NFT_OBJECT_QUOTA: {
+ const char *data_unit;
+ uint64_t bytes;
+
+ printf(" %s {%s%s%s", obj->handle.obj,
+ opts->nl, opts->tab, opts->tab);
+ data_unit = get_rate(obj->quota.bytes, &bytes);
+ printf("%s%"PRIu64" %s",
+ obj->quota.flags & NFT_QUOTA_F_INV ? "over " : "",
+ bytes, data_unit);
+ if (obj->quota.used) {
+ data_unit = get_rate(obj->quota.used, &bytes);
+ printf(" used %"PRIu64" %s", bytes, data_unit);
+ }
+ }
+ break;
+ default:
+ printf("unknown {%s", opts->nl);
+ break;
+ }
+}
+
+static const char *obj_type_name_array[] = {
+ [NFT_OBJECT_COUNTER] = "counter",
+ [NFT_OBJECT_QUOTA] = "quota",
+};
+
+const char *obj_type_name(enum stmt_types type)
+{
+ assert(type <= NFT_OBJECT_QUOTA && obj_type_name_array[type]);
+
+ return obj_type_name_array[type];
+}
+
+static void obj_print_declaration(const struct obj *obj,
+ struct print_fmt_options *opts)
+{
+ printf("%s%s", opts->tab, obj_type_name(obj->type));
+
+ if (opts->family != NULL)
+ printf(" %s", opts->family);
+
+ if (opts->table != NULL)
+ printf(" %s", opts->table);
+
+ obj_print_data(obj, opts);
+
+ printf("%s%s}%s", opts->nl, opts->tab, opts->nl);
+}
+
+void obj_print(const struct obj *obj)
+{
+ struct print_fmt_options opts = {
+ .tab = "\t",
+ .nl = "\n",
+ .stmt_separator = "\n",
+ };
+
+ obj_print_declaration(obj, &opts);
+}
+
+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, &table_list, list) {
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
+ cmd->handle.family != table->handle.family)
+ continue;
+
+ printf("table %s %s {\n",
+ family2str(table->handle.family),
+ table->handle.table);
+
+ list_for_each_entry(obj, &table->objs, list) {
+ if (obj->type != type)
+ continue;
+
+ obj_print_declaration(obj, &opts);
+ }
+
+ printf("}\n");
+ }
+ return 0;
+}
+
static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
{
unsigned int family = cmd->handle.family;
@@ -1230,6 +1366,10 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return do_list_sets(ctx, cmd);
case CMD_OBJ_MAP:
return do_list_set(ctx, cmd, table);
+ case CMD_OBJ_COUNTERS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_COUNTER);
+ case CMD_OBJ_QUOTAS:
+ return do_list_obj(ctx, cmd, NFT_OBJECT_QUOTA);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
diff --git a/src/scanner.l b/src/scanner.l
index 8aa4b08ba8fc..cb9893203244 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -293,6 +293,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"packets" { return PACKETS; }
"bytes" { return BYTES; }
+"counters" { return COUNTERS; }
+"quotas" { return QUOTAS; }
+
"log" { return LOG; }
"prefix" { return PREFIX; }
"group" { return GROUP; }
diff --git a/src/statement.c b/src/statement.c
index 4d3ca55a4081..fbd78aafe69a 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -255,7 +255,7 @@ static const char *data_unit[] = {
NULL
};
-static const char *get_rate(uint64_t byte_rate, uint64_t *rate)
+const char *get_rate(uint64_t byte_rate, uint64_t *rate)
{
uint64_t res, prev, rest;
int i;
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 05/10] src: add/create/delete stateful objects
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
` (2 preceding siblings ...)
2016-12-23 14:26 ` [PATCH nft 04/10] src: listing of stateful objects Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 06/10] src: reset internal " Pablo Neira Ayuso
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
This patch allows you to add and to delete objects, eg.
# nft add quota filter test 1234567 bytes
# nft list quotas
table ip filter {
quota test {
1234567 bytes
}
}
# nft delete quota filter test
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/mnl.h | 5 ++
include/netlink.h | 5 ++
include/rule.h | 3 +-
src/evaluate.c | 5 ++
src/mnl.c | 30 ++++++++++
src/netlink.c | 95 +++++++++++++++++++++++++++++++
src/parser_bison.y | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/rule.c | 21 +++++++
8 files changed, 322 insertions(+), 3 deletions(-)
diff --git a/include/mnl.h b/include/mnl.h
index ad036aefabbd..d178bd27a75a 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -88,6 +88,11 @@ int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nftnl_set *nls);
struct nftnl_obj_list *mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family,
const char *table);
+int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum);
+int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum);
+
struct nftnl_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock,
uint32_t family);
int mnl_nft_event_listener(struct mnl_socket *nf_sock,
diff --git a/include/netlink.h b/include/netlink.h
index ce577871761f..841211c43760 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -171,12 +171,17 @@ extern int netlink_flush_setelems(struct netlink_ctx *ctx, const struct handle *
extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h,
const struct location *loc);
+extern int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct obj *obj, bool excl);
+extern int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct location *loc, enum stmt_types type);
extern void netlink_dump_table(const struct nftnl_table *nlt);
extern void netlink_dump_chain(const struct nftnl_chain *nlc);
extern void netlink_dump_rule(const struct nftnl_rule *nlr);
extern void netlink_dump_expr(const struct nftnl_expr *nle);
extern void netlink_dump_set(const struct nftnl_set *nls);
+extern void netlink_dump_obj(struct nftnl_obj *nlo);
extern int netlink_batch_send(struct list_head *err_list);
diff --git a/include/rule.h b/include/rule.h
index e0f891393276..88acbcc7b163 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -282,7 +282,7 @@ struct obj *obj_alloc(const struct location *loc);
void obj_free(struct obj *obj);
void obj_add_hash(struct obj *obj, struct table *table);
void obj_print(const struct obj *n);
-const char *obj_type_name(enum stmt_types type);
+const char *obj_type_name(uint32_t type);
/**
* enum cmd_ops - command operations
@@ -415,6 +415,7 @@ struct cmd {
struct table *table;
struct monitor *monitor;
struct export *export;
+ struct obj *object;
};
const void *arg;
};
diff --git a/src/evaluate.c b/src/evaluate.c
index b3630c303920..9bc3b7d6477a 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2758,6 +2758,9 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
return chain_evaluate(ctx, cmd->chain);
case CMD_OBJ_TABLE:
return table_evaluate(ctx, cmd->table);
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2778,6 +2781,8 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_RULE:
case CMD_OBJ_CHAIN:
case CMD_OBJ_TABLE:
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
diff --git a/src/mnl.c b/src/mnl.c
index 534d02f4ff32..9458e21bf8b4 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -796,6 +796,36 @@ err:
return NULL;
}
+int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
+ NFT_MSG_NEWOBJ,
+ nftnl_obj_get_u32(nln, NFTNL_OBJ_FAMILY),
+ NLM_F_CREATE | flags, seqnum);
+ nftnl_obj_nlmsg_build_payload(nlh, nln);
+ mnl_nft_batch_continue();
+
+ return 0;
+}
+
+int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
+ uint32_t seqnum)
+{
+ struct nlmsghdr *nlh;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
+ NFT_MSG_DELOBJ,
+ nftnl_obj_get_u32(nln, NFTNL_OBJ_FAMILY),
+ flags, seqnum);
+ nftnl_obj_nlmsg_build_payload(nlh, nln);
+ mnl_nft_batch_continue();
+
+ return 0;
+}
+
static int obj_cb(const struct nlmsghdr *nlh, void *data)
{
struct nftnl_obj_list *nln_list = data;
diff --git a/src/netlink.c b/src/netlink.c
index bbf675f90def..d11b3c01f264 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -21,6 +21,7 @@
#include <libnftnl/trace.h>
#include <libnftnl/chain.h>
#include <libnftnl/expr.h>
+#include <libnftnl/object.h>
#include <libnftnl/set.h>
#include <libnftnl/udata.h>
#include <libnftnl/common.h>
@@ -270,6 +271,51 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *expr)
return nlse;
}
+static struct nftnl_obj *
+__alloc_nftnl_obj(const struct handle *h, uint32_t type)
+{
+ struct nftnl_obj *nlo;
+
+ nlo = nftnl_obj_alloc();
+ if (nlo == NULL)
+ memory_allocation_error();
+
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, h->family);
+ nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, h->table);
+ if (h->obj != NULL)
+ nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, h->obj);
+
+ nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
+
+ return nlo;
+}
+
+static struct nftnl_obj *
+alloc_nftnl_obj(const struct handle *h, struct obj *obj)
+{
+ struct nftnl_obj *nlo;
+
+ nlo = __alloc_nftnl_obj(h, obj->type);
+
+ 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;
+ }
+ return nlo;
+}
+
void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
unsigned int len, struct nft_data_linearize *data)
{
@@ -1608,6 +1654,55 @@ out:
return err;
}
+void netlink_dump_obj(struct nftnl_obj *nln)
+{
+#ifdef DEBUG
+ char buf[4096];
+
+ if (!(debug_level & DEBUG_NETLINK))
+ return;
+
+ nftnl_obj_snprintf(buf, sizeof(buf), nln, 0, 0);
+ fprintf(stdout, "%s\n", buf);
+#endif
+}
+
+int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct obj *obj, bool excl)
+{
+ struct nftnl_obj *nlo;
+ int err;
+
+ nlo = alloc_nftnl_obj(h, obj);
+ netlink_dump_obj(nlo);
+
+ err = mnl_nft_obj_batch_add(nlo, excl ? NLM_F_EXCL : 0, ctx->seqnum);
+ if (err < 0)
+ netlink_io_error(ctx, &obj->location, "Could not add %s: %s",
+ obj_type_name(obj->type), strerror(errno));
+ nftnl_obj_free(nlo);
+
+ return err;
+}
+
+int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
+ struct location *loc, uint32_t type)
+{
+ struct nftnl_obj *nlo;
+ int err;
+
+ nlo = __alloc_nftnl_obj(h, type);
+ netlink_dump_obj(nlo);
+
+ err = mnl_nft_obj_batch_del(nlo, 0, ctx->seqnum);
+ if (err < 0)
+ netlink_io_error(ctx, loc, "Could not delete %s: %s",
+ obj_type_name(type), strerror(errno));
+ nftnl_obj_free(nlo);
+
+ return err;
+}
+
static struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
struct nftnl_obj *nlo)
{
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 2213f3808db4..fd3f0d8251a6 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -133,6 +133,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
struct stmt *stmt;
struct expr *expr;
struct set *set;
+ struct obj *obj;
+ struct counter *counter;
+ struct quota *quota;
const struct datatype *datatype;
struct handle_spec handle_spec;
struct position_spec position_spec;
@@ -444,8 +447,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <handle> table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%type <handle> set_spec set_identifier obj_spec
-%destructor { handle_free(&$$); } set_spec set_identifier obj_spec
+%type <handle> set_spec set_identifier obj_spec obj_identifier
+%destructor { handle_free(&$$); } set_spec set_identifier obj_spec obj_identifier
%type <val> family_spec family_spec_explicit chain_policy prio_spec
%type <string> dev_spec quota_unit
@@ -468,6 +471,9 @@ 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
+%destructor { obj_free($$); } obj_block_alloc
+
%type <list> stmt_list
%destructor { stmt_list_free($$); xfree($$); } stmt_list
%type <stmt> stmt match_stmt verdict_stmt
@@ -553,6 +559,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
+%destructor { obj_free($$); } counter_obj quota_obj
%type <expr> relational_expr
%destructor { expr_free($$); } relational_expr
@@ -616,6 +624,11 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%destructor { xfree($$); } monitor_event
%type <val> monitor_object monitor_format
+%type <counter> counter_config
+%destructor { xfree($$); } counter_config
+%type <quota> quota_config
+%destructor { xfree($$); } quota_config
+
%%
input : /* empty */
@@ -768,6 +781,23 @@ add_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3);
}
+ | COUNTER obj_spec
+ {
+ 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
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
;
replace_cmd : RULE ruleid_spec rule
@@ -817,6 +847,23 @@ create_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3);
}
+ | COUNTER obj_spec
+ {
+ 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
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj
+ {
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
;
insert_cmd : RULE rule_position rule
@@ -849,6 +896,14 @@ delete_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, &@$, $3);
}
+ | COUNTER obj_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ }
+ | QUOTA obj_spec
+ {
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+ }
;
list_cmd : TABLE table_spec
@@ -1043,6 +1098,28 @@ table_block : /* empty */ { $$ = $<table>-1; }
list_add_tail(&$4->list, &$1->sets);
$$ = $1;
}
+ | table_block COUNTER obj_identifier
+ obj_block_alloc '{' counter_block '}'
+ stmt_seperator
+ {
+ $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_seperator
+ {
+ $4->location = @3;
+ $4->type = NFT_OBJECT_QUOTA;
+ handle_merge(&$4->handle, &$3);
+ handle_free(&$3);
+ list_add_tail(&$4->list, &$1->objs);
+ $$ = $1;
+ }
;
chain_block_alloc : /* empty */
@@ -1193,6 +1270,32 @@ type_identifier_list : type_identifier
}
;
+obj_block_alloc : /* empty */
+ {
+ $$ = obj_alloc(NULL);
+ }
+ ;
+
+counter_block : /* empty */ { $$ = $<obj>-1; }
+ | counter_block common_block
+ | counter_block stmt_seperator
+ | counter_block counter_config
+ {
+ $1->counter = *$2;
+ $$ = $1;
+ }
+ ;
+
+quota_block : /* empty */ { $$ = $<obj>-1; }
+ | quota_block common_block
+ | quota_block stmt_seperator
+ | quota_block quota_config
+ {
+ $1->quota = *$2;
+ $$ = $1;
+ }
+ ;
+
type_identifier : STRING { $$ = $1; }
| MARK { $$ = xstrdup("mark"); }
| DSCP { $$ = xstrdup("dscp"); }
@@ -1325,6 +1428,13 @@ obj_spec : table_spec identifier
}
;
+obj_identifier : identifier
+ {
+ memset(&$$, 0, sizeof($$));
+ $$.obj = $1;
+ }
+ ;
+
handle_spec : HANDLE NUM
{
memset(&$$, 0, sizeof($$));
@@ -2325,6 +2435,53 @@ initializer_expr : rhs_expr
| list_rhs_expr
;
+counter_config : PACKETS NUM BYTES NUM
+ {
+ struct counter *counter;
+
+ counter = xzalloc(sizeof(*counter));
+ counter->packets = $2;
+ counter->bytes = $4;
+ $$ = counter;
+ }
+ ;
+
+counter_obj : counter_config
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_COUNTER;
+ $$->counter = *$1;
+ }
+ ;
+
+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);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+
+ quota = xzalloc(sizeof(*quota));
+ quota->bytes = $2 * rate;
+ quota->used = $4;
+ quota->flags = $1;
+ $$ = quota;
+ }
+ ;
+
+quota_obj : quota_config
+ {
+ $$ = obj_alloc(&@$);
+ $$->type = NFT_OBJECT_QUOTA;
+ $$->quota = *$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 05f0eb87b162..29b1450666db 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -44,6 +44,8 @@ void handle_merge(struct handle *dst, const struct handle *src)
dst->chain = xstrdup(src->chain);
if (dst->set == NULL && src->set != NULL)
dst->set = xstrdup(src->set);
+ if (dst->obj == NULL && src->obj != NULL)
+ dst->obj = xstrdup(src->obj);
if (dst->handle.id == 0)
dst->handle = src->handle;
if (dst->position.id == 0)
@@ -875,6 +877,10 @@ void cmd_free(struct cmd *cmd)
case CMD_OBJ_EXPORT:
export_free(cmd->export);
break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ obj_free(cmd->object);
+ break;
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -940,6 +946,7 @@ static int do_add_table(struct netlink_ctx *ctx, const struct handle *h,
bool excl)
{
struct chain *chain;
+ struct obj *obj;
struct set *set;
if (netlink_add_table(ctx, h, loc, table, excl) < 0)
@@ -951,6 +958,11 @@ static int do_add_table(struct netlink_ctx *ctx, const struct handle *h,
excl) < 0)
return -1;
}
+ list_for_each_entry(obj, &table->objs, list) {
+ handle_merge(&obj->handle, &table->handle);
+ if (netlink_add_obj(ctx, &obj->handle, obj, excl) < 0)
+ return -1;
+ }
list_for_each_entry(set, &table->sets, list) {
handle_merge(&set->handle, &table->handle);
if (do_add_set(ctx, &set->handle, set, excl) < 0)
@@ -980,6 +992,9 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
return do_add_set(ctx, &cmd->handle, cmd->set, excl);
case CMD_OBJ_SETELEM:
return do_add_setelems(ctx, &cmd->handle, cmd->expr, excl);
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ return netlink_add_obj(ctx, &cmd->handle, cmd->object, excl);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -1043,6 +1058,12 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
return netlink_delete_set(ctx, &cmd->handle, &cmd->location);
case CMD_OBJ_SETELEM:
return do_delete_setelems(ctx, &cmd->handle, cmd->expr);
+ case CMD_OBJ_COUNTER:
+ return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
+ NFT_OBJECT_COUNTER);
+ case CMD_OBJ_QUOTA:
+ return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
+ NFT_OBJECT_QUOTA);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 06/10] src: reset internal stateful objects
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
` (3 preceding siblings ...)
2016-12-23 14:26 ` [PATCH nft 05/10] src: add/create/delete " Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 07/10] parser_bison: allow RESET token from rhs Pablo Neira Ayuso
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
This patch allows you to atomically dump and reset stateful objects, eg.
# nft list counters
table ip filter {
counter test {
packets 1024 bytes 100000
}
}
# nft reset quotas table filter
counter test {
packets 1024 bytes 100000
}
# nft reset quotas table filter
counter test {
packets 0 bytes 0
}
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/mnl.h | 3 ++-
include/netlink.h | 6 ++++--
include/rule.h | 2 ++
src/evaluate.c | 1 +
src/mnl.c | 14 +++++++++++---
src/netlink.c | 24 +++++++++++++++++++++++-
src/parser_bison.y | 24 ++++++++++++++++++++++--
src/rule.c | 43 ++++++++++++++++++++++++++++++++++++++-----
src/scanner.l | 1 +
9 files changed, 104 insertions(+), 14 deletions(-)
diff --git a/include/mnl.h b/include/mnl.h
index d178bd27a75a..4a99972d4163 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -87,7 +87,8 @@ int mnl_nft_setelem_batch_flush(struct nftnl_set *nls, unsigned int flags,
int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nftnl_set *nls);
struct nftnl_obj_list *mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family,
- const char *table);
+ const char *table, uint32_t type,
+ bool reset);
int mnl_nft_obj_batch_add(struct nftnl_obj *nln, unsigned int flags,
uint32_t seqnum);
int mnl_nft_obj_batch_del(struct nftnl_obj *nln, unsigned int flags,
diff --git a/include/netlink.h b/include/netlink.h
index 841211c43760..450aba571a97 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -170,11 +170,13 @@ extern int netlink_flush_setelems(struct netlink_ctx *ctx, const struct handle *
const struct location *loc);
extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h,
- const struct location *loc);
+ const struct location *loc);
+extern int netlink_reset_objs(struct netlink_ctx *ctx, const struct handle *h,
+ const struct location *loc, uint32_t type);
extern int netlink_add_obj(struct netlink_ctx *ctx, const struct handle *h,
struct obj *obj, bool excl);
extern int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
- struct location *loc, enum stmt_types type);
+ struct location *loc, uint32_t type);
extern void netlink_dump_table(const struct nftnl_table *nlt);
extern void netlink_dump_chain(const struct nftnl_chain *nlc);
diff --git a/include/rule.h b/include/rule.h
index 88acbcc7b163..9028c84b0033 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -294,6 +294,7 @@ const char *obj_type_name(uint32_t type);
* @CMD_INSERT: insert object
* @CMD_DELETE: delete object
* @CMD_LIST: list container
+ * @CMD_RESET: reset container
* @CMD_FLUSH: flush container
* @CMD_RENAME: rename object
* @CMD_EXPORT: export the ruleset in a given format
@@ -308,6 +309,7 @@ enum cmd_ops {
CMD_INSERT,
CMD_DELETE,
CMD_LIST,
+ CMD_RESET,
CMD_FLUSH,
CMD_RENAME,
CMD_EXPORT,
diff --git a/src/evaluate.c b/src/evaluate.c
index 9bc3b7d6477a..cedf259fcba9 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3052,6 +3052,7 @@ int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_DELETE:
return cmd_evaluate_delete(ctx, cmd);
case CMD_LIST:
+ case CMD_RESET:
return cmd_evaluate_list(ctx, cmd);
case CMD_FLUSH:
return cmd_evaluate_flush(ctx, cmd);
diff --git a/src/mnl.c b/src/mnl.c
index 9458e21bf8b4..52cb7736e324 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -851,22 +851,30 @@ err_free:
struct nftnl_obj_list *
-mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family, const char *table)
+mnl_nft_obj_dump(struct mnl_socket *nf_sock, int family, const char *table,
+ uint32_t type, bool reset)
{
struct nftnl_obj_list *nln_list;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_obj *n;
struct nlmsghdr *nlh;
- int ret;
+ 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, NFT_MSG_GETOBJ, family,
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type, family,
NLM_F_DUMP | NLM_F_ACK, seq);
if (table != NULL)
nftnl_obj_set(n, NFTNL_OBJ_TABLE, table);
+ 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);
diff --git a/src/netlink.c b/src/netlink.c
index d11b3c01f264..68bed201a36d 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1755,7 +1755,29 @@ int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h,
struct nftnl_obj_list *obj_cache;
int err;
- obj_cache = mnl_nft_obj_dump(nf_sock, h->family, h->table);
+ obj_cache = mnl_nft_obj_dump(nf_sock, h->family, h->table,
+ NFT_OBJECT_UNSPEC, false);
+ if (obj_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return netlink_io_error(ctx, loc,
+ "Could not receive stateful objects from kernel: %s",
+ strerror(errno));
+ }
+
+ err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx);
+ nftnl_obj_list_free(obj_cache);
+ return err;
+}
+
+int netlink_reset_objs(struct netlink_ctx *ctx, const struct handle *h,
+ const struct location *loc, uint32_t type)
+{
+ struct nftnl_obj_list *obj_cache;
+ int err;
+
+ obj_cache = mnl_nft_obj_dump(nf_sock, h->family, h->table, type, true);
if (obj_cache == NULL) {
if (errno == EINTR)
return -1;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index fd3f0d8251a6..b571fbbed5f3 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -199,6 +199,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token INSERT "insert"
%token DELETE "delete"
%token LIST "list"
+%token RESET "reset"
%token FLUSH "flush"
%token RENAME "rename"
%token DESCRIBE "describe"
@@ -442,8 +443,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <cmd> line
%destructor { cmd_free($$); } line
-%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
-%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
+%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
+%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
%type <handle> table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
@@ -725,6 +726,7 @@ base_cmd : /* empty */ add_cmd { $$ = $1; }
| INSERT insert_cmd { $$ = $2; }
| DELETE delete_cmd { $$ = $2; }
| LIST list_cmd { $$ = $2; }
+ | RESET reset_cmd { $$ = $2; }
| FLUSH flush_cmd { $$ = $2; }
| RENAME rename_cmd { $$ = $2; }
| EXPORT export_cmd { $$ = $2; }
@@ -968,6 +970,24 @@ list_cmd : TABLE table_spec
}
;
+reset_cmd : COUNTERS ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$2, &@$, NULL);
+ }
+ | COUNTERS TABLE table_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$3, &@$, 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);
+ }
+ ;
+
flush_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_FLUSH, CMD_OBJ_TABLE, &$2, &@$, NULL);
diff --git a/src/rule.c b/src/rule.c
index 29b1450666db..9eeb436cd37a 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -95,11 +95,13 @@ static int cache_init_objects(struct netlink_ctx *ctx, enum cmd_ops cmd)
return -1;
list_splice_tail_init(&ctx->list, &table->chains);
- /* Don't check for errors on listings, this would break nft with
- * old kernels with no stateful object support.
- */
- netlink_list_objs(ctx, &table->handle, &internal_location);
- list_splice_tail_init(&ctx->list, &table->objs);
+ if (cmd != CMD_RESET) {
+ /* Don't check for errors on listings, this would break
+ * nft with old kernels with no stateful object support.
+ */
+ netlink_list_objs(ctx, &table->handle, &internal_location);
+ list_splice_tail_init(&ctx->list, &table->objs);
+ }
/* Skip caching other objects to speed up things: We only need
* a full cache when listing the existing ruleset.
@@ -1398,6 +1400,35 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return 0;
}
+static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ struct obj *obj, *next;
+ struct table *table;
+ uint32_t type;
+ int ret;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_COUNTERS:
+ type = NFT_OBJECT_COUNTER;
+ break;
+ case CMD_OBJ_QUOTAS:
+ type = NFT_OBJECT_QUOTA;
+ break;
+ default:
+ BUG("invalid command object type %u\n", cmd->obj);
+ }
+
+ ret = netlink_reset_objs(ctx, &cmd->handle, &cmd->location, type);
+ list_for_each_entry_safe(obj, next, &ctx->list, list) {
+ table = table_lookup(&obj->handle);
+ list_move(&obj->list, &table->objs);
+ }
+ if (ret < 0)
+ return ret;
+
+ return do_list_obj(ctx, cmd, type);
+}
+
static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
@@ -1518,6 +1549,8 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
return do_command_delete(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:
diff --git a/src/scanner.l b/src/scanner.l
index cb9893203244..1aa2e96b9f64 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -268,6 +268,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"insert" { return INSERT; }
"delete" { return DELETE; }
"list" { return LIST; }
+"reset" { return RESET; }
"flush" { return FLUSH; }
"rename" { return RENAME; }
"export" { return EXPORT; }
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 07/10] parser_bison: allow RESET token from rhs
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
` (4 preceding siblings ...)
2016-12-23 14:26 ` [PATCH nft 06/10] src: reset internal " Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 08/10] src: add stateful object reference expression Pablo Neira Ayuso
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
Stateful objects have introduced a RESET token in the parser. This breaks the
use of RESET from the rhs, to fix this:
1) I added a new rule to catch this case, thus, dccp doesn't break.
2) Update reject_opts so reject with tcp reset still works.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/parser_bison.y | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index b571fbbed5f3..5b829a243128 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1897,15 +1897,9 @@ reject_opts : /* empty */
$4);
$<stmt>0->reject.expr->dtype = &icmpx_code_type;
}
- | WITH TCP STRING
+ | WITH TCP RESET
{
- if (strcmp($3, "reset") == 0) {
- $<stmt>0->reject.type = NFT_REJECT_TCP_RST;
- } else {
- erec_queue(error(&@2, "unsupported reject type", $3),
- state->msgs);
- YYERROR;
- }
+ $<stmt>0->reject.type = NFT_REJECT_TCP_RST;
}
;
@@ -2721,6 +2715,12 @@ primary_rhs_expr : symbol_expr { $$ = $1; }
current_scope(state),
"ecn");
}
+ | RESET
+ {
+ $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+ current_scope(state),
+ "reset");
+ }
;
relational_op : EQ { $$ = OP_EQ; }
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 08/10] src: add stateful object reference expression
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
` (5 preceding siblings ...)
2016-12-23 14:26 ` [PATCH nft 07/10] parser_bison: allow RESET token from rhs Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 09/10] src: add support for stateful object maps Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 10/10] src: support for stateful object monitoring Pablo Neira Ayuso
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
This patch adds a new objref statement to refer to existing stateful
objects from rules, eg.
# nft add rule filter input counter name test counter
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/statement.h | 10 ++++++++++
src/evaluate.c | 16 ++++++++++++++++
src/netlink_delinearize.c | 33 +++++++++++++++++++++++++++++++++
src/netlink_linearize.c | 16 ++++++++++++++++
src/parser_bison.y | 13 +++++++++++++
src/scanner.l | 1 +
src/statement.c | 33 +++++++++++++++++++++++++++++++++
7 files changed, 122 insertions(+)
diff --git a/include/statement.h b/include/statement.h
index 9d0f601f98a2..8f874c881bd9 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -10,6 +10,13 @@ extern struct stmt *expr_stmt_alloc(const struct location *loc,
extern struct stmt *verdict_stmt_alloc(const struct location *loc,
struct expr *expr);
+struct objref_stmt {
+ uint32_t type;
+ struct expr *expr;
+};
+
+struct stmt *objref_stmt_alloc(const struct location *loc);
+
struct counter_stmt {
uint64_t packets;
uint64_t bytes;
@@ -212,6 +219,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
* @STMT_XT: XT statement
* @STMT_QUOTA: quota statement
* @STMT_NOTRACK: notrack statement
+ * @STMT_OBJREF: stateful object reference statement
*/
enum stmt_types {
STMT_INVALID,
@@ -235,6 +243,7 @@ enum stmt_types {
STMT_XT,
STMT_QUOTA,
STMT_NOTRACK,
+ STMT_OBJREF,
};
/**
@@ -292,6 +301,7 @@ struct stmt {
struct dup_stmt dup;
struct fwd_stmt fwd;
struct xt_stmt xt;
+ struct objref_stmt objref;
};
};
diff --git a/src/evaluate.c b/src/evaluate.c
index cedf259fcba9..b868f1bc283a 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2464,6 +2464,20 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
+static int stmt_evaluate_objref(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ if (stmt_evaluate_arg(ctx, stmt,
+ &string_type, NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
+ &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)
{
#ifdef DEBUG
@@ -2511,6 +2525,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_fwd(ctx, stmt);
case STMT_SET:
return stmt_evaluate_set(ctx, stmt);
+ case STMT_OBJREF:
+ return stmt_evaluate_objref(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 9a16926e3817..90fb9e670751 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1125,6 +1125,35 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
}
+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);
+ expr->dtype = &string_type;
+ expr->byteorder = BYTEORDER_HOST_ENDIAN;
+ } 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;
+}
+
static const struct {
const char *name;
void (*parse)(struct netlink_parse_ctx *ctx,
@@ -1156,6 +1185,7 @@ static const struct {
{ .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 },
@@ -2164,6 +2194,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
case STMT_XT:
stmt_xt_postprocess(&rctx, stmt, rule);
break;
+ case STMT_OBJREF:
+ expr_postprocess(&rctx, &stmt->objref.expr);
+ break;
default:
break;
}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 144068d23378..c9488b3212bc 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -689,6 +689,20 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
}
}
+static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("objref");
+ 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);
+
+ nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
static struct nftnl_expr *
netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
@@ -1225,6 +1239,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
break;
case STMT_NOTRACK:
return netlink_gen_notrack_stmt(ctx, stmt);
+ case STMT_OBJREF:
+ return netlink_gen_objref_stmt(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 5b829a243128..795b0ee210a3 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -365,6 +365,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token LABEL "label"
%token COUNTER "counter"
+%token NAME "name"
%token PACKETS "packets"
%token BYTES "bytes"
@@ -1623,6 +1624,12 @@ 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
@@ -1823,6 +1830,12 @@ quota_stmt : QUOTA quota_mode NUM quota_unit quota_used
$$->quota.used = $5;
$$->quota.flags = $2;
}
+ | QUOTA NAME stmt_expr
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_QUOTA;
+ $$->objref.expr = $3;
+ }
;
limit_mode : OVER { $$ = NFT_LIMIT_F_INV; }
diff --git a/src/scanner.l b/src/scanner.l
index 1aa2e96b9f64..69406bd0164e 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -291,6 +291,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"flow" { return FLOW; }
"counter" { return COUNTER; }
+"name" { return NAME; }
"packets" { return PACKETS; }
"bytes" { return BYTES; }
diff --git a/src/statement.c b/src/statement.c
index fbd78aafe69a..24a53ee1b0fc 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -161,6 +161,39 @@ struct stmt *counter_stmt_alloc(const struct location *loc)
return stmt;
}
+static const char *objref_type[NFT_OBJECT_MAX + 1] = {
+ [NFT_OBJECT_COUNTER] = "counter",
+ [NFT_OBJECT_QUOTA] = "quota",
+};
+
+static 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)
+{
+ printf("%s name ", objref_type_name(stmt->objref.type));
+ expr_print(stmt->objref.expr);
+}
+
+static const struct stmt_ops objref_stmt_ops = {
+ .type = STMT_OBJREF,
+ .name = "objref",
+ .print = objref_stmt_print,
+};
+
+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[LOG_DEBUG + 1] = {
[LOG_EMERG] = "emerg",
[LOG_ALERT] = "alert",
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 09/10] src: add support for stateful object maps
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
` (6 preceding siblings ...)
2016-12-23 14:26 ` [PATCH nft 08/10] src: add stateful object reference expression Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 10/10] src: support for stateful object monitoring Pablo Neira Ayuso
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
You can create these maps using explicit map declarations:
# nft add table filter
# nft add chain filter input { type filter hook input priority 0\; }
# nft add map filter badguys { type ipv4_addr : counter \; }
# nft add rule filter input counter name ip saddr map @badguys
# nft add counter filter badguy1
# nft add counter filter badguy2
# nft add element filter badguys { 192.168.2.3 : "badguy1" }
# nft add element filter badguys { 192.168.2.4 : "badguy2" }
Or through implicit map definitions:
table ip filter {
counter http-traffic {
packets 8 bytes 672
}
chain input {
type filter hook input priority 0; policy accept;
counter name tcp dport map { 80 : "http-traffic", 443 : "http-traffic"}
}
}
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/rule.h | 2 ++
src/evaluate.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++-
src/netlink.c | 40 ++++++++++++++++++++-----
src/netlink_delinearize.c | 29 +++++++++++++++++++
src/netlink_linearize.c | 26 +++++++++++++++--
src/parser_bison.y | 20 ++++++++++++-
src/rule.c | 5 +++-
7 files changed, 182 insertions(+), 14 deletions(-)
diff --git a/include/rule.h b/include/rule.h
index 9028c84b0033..86c0392f89af 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -212,6 +212,7 @@ extern struct rule *rule_lookup(const struct chain *chain, uint64_t handle);
* @keylen: key length
* @datatype: mapping data type
* @datalen: mapping data len
+ * @objtype: mapping object type
* @init: initializer
* @policy: set mechanism policy
* @desc: set mechanism desc
@@ -228,6 +229,7 @@ struct set {
unsigned int keylen;
const struct datatype *datatype;
unsigned int datalen;
+ uint32_t objtype;
struct expr *init;
uint32_t policy;
struct {
diff --git a/src/evaluate.c b/src/evaluate.c
index b868f1bc283a..cebc5a9ead7a 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1188,7 +1188,7 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
if (set == NULL)
return expr_error(ctx->msgs, mapping,
"mapping outside of map context");
- if (!(set->flags & NFT_SET_MAP))
+ if (!(set->flags & (NFT_SET_MAP | NFT_SET_OBJECT)))
return set_error(ctx, set, "set is not a map");
expr_set_context(&ctx->ectx, set->keytype, set->keylen);
@@ -2464,8 +2464,77 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
+static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *map = stmt->objref.expr;
+ struct expr *mappings;
+
+ 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->ops->type) {
+ case EXPR_SET:
+ mappings = implicit_set_declaration(ctx, "__objmap%d",
+ ctx->ectx.dtype,
+ ctx->ectx.len,
+ mappings);
+ mappings->set->datatype = &string_type;
+ mappings->set->datalen = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
+ mappings->set->objtype = stmt->objref.type;
+
+ map->mappings = mappings;
+
+ ctx->set = mappings->set;
+ if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
+ return -1;
+ ctx->set = NULL;
+
+ map->mappings->set->flags |=
+ map->mappings->set->init->set_flags;
+ case EXPR_SYMBOL:
+ if (expr_evaluate(ctx, &map->mappings) < 0)
+ return -1;
+ if (map->mappings->ops->type != EXPR_SET_REF ||
+ !(map->mappings->set->flags & NFT_SET_OBJECT))
+ return expr_error(ctx->msgs, map->mappings,
+ "Expression is not a map");
+ break;
+ default:
+ BUG("invalid mapping expression %s\n",
+ map->mappings->ops->name);
+ }
+
+ if (!datatype_equal(map->map->dtype, map->mappings->set->keytype))
+ return expr_binary_error(ctx->msgs, map->mappings, map->map,
+ "datatype mismatch, map expects %s, "
+ "mapping expression has type %s",
+ map->mappings->set->keytype->desc,
+ map->map->dtype->desc);
+
+ map->dtype = map->mappings->set->datatype;
+ 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->ops->type == EXPR_MAP)
+ return stmt_evaluate_objref_map(ctx, stmt);
+
if (stmt_evaluate_arg(ctx, stmt,
&string_type, NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
&stmt->objref.expr) < 0)
@@ -2585,6 +2654,9 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
if (set->datalen == 0 && set->datatype->type != TYPE_VERDICT)
return set_error(ctx, set, "unqualified mapping data "
"type specified in map definition");
+ } else if (set->flags & NFT_SET_OBJECT) {
+ set->datatype = &string_type;
+ set->datalen = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
}
ctx->set = set;
diff --git a/src/netlink.c b/src/netlink.c
index 68bed201a36d..97220f451343 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -205,7 +205,8 @@ struct nftnl_set *alloc_nftnl_set(const struct handle *h)
return nls;
}
-static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *expr)
+static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
+ const struct expr *expr)
{
const struct expr *elem, *key, *data;
struct nftnl_set_elem *nlse;
@@ -243,8 +244,7 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *expr)
nftnl_udata_buf_len(udbuf));
nftnl_udata_buf_free(udbuf);
}
-
- if (data != NULL) {
+ if (set->set_flags & NFT_SET_MAP && data != NULL) {
netlink_gen_data(data, &nld);
switch (data->ops->type) {
case EXPR_VERDICT:
@@ -263,6 +263,11 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *expr)
break;
}
}
+ if (set->set_flags & NFT_SET_OBJECT) {
+ 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)
nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS,
@@ -1110,7 +1115,7 @@ static struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
{
struct set *set;
const struct datatype *keytype, *datatype;
- uint32_t flags, key, data, data_len;
+ uint32_t flags, key, data, data_len, objtype = 0;
key = nftnl_set_get_u32(nls, NFTNL_SET_KEY_TYPE);
keytype = dtype_map_from_kernel(key);
@@ -1133,6 +1138,11 @@ static struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
} else
datatype = NULL;
+ if (flags & NFT_SET_OBJECT) {
+ objtype = nftnl_set_get_u32(nls, NFTNL_SET_OBJ_TYPE);
+ datatype = &string_type;
+ }
+
set = set_alloc(&netlink_location);
set->handle.family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
set->handle.table = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_TABLE));
@@ -1142,6 +1152,8 @@ static struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
set->keylen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE;
set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+ set->objtype = objtype;
+
set->datatype = datatype;
if (nftnl_set_is_set(nls, NFTNL_SET_DATA_LEN)) {
data_len = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN);
@@ -1214,6 +1226,9 @@ static int netlink_add_set_batch(struct netlink_ctx *ctx,
nftnl_set_set_u32(nls, NFTNL_SET_DATA_LEN,
set->datalen / BITS_PER_BYTE);
}
+ if (set->flags & NFT_SET_OBJECT)
+ 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)
@@ -1357,7 +1372,7 @@ static void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
const struct expr *expr;
list_for_each_entry(expr, &set->expressions, list) {
- nlse = alloc_nftnl_setelem(expr);
+ nlse = alloc_nftnl_setelem(set, expr);
nftnl_set_elem_add(nls, nlse);
}
}
@@ -1577,10 +1592,10 @@ static int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL);
expr->stmt = netlink_parse_set_expr(set, nle);
}
-
- if (flags & NFT_SET_ELEM_INTERVAL_END) {
+ if (flags & NFT_SET_ELEM_INTERVAL_END)
expr->flags |= EXPR_F_INTERVAL_END;
- } else {
+
+ if (set->flags & NFT_SET_MAP) {
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_DATA)) {
nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_DATA,
&nld.len);
@@ -1602,6 +1617,15 @@ static int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
expr = mapping_expr_alloc(&netlink_location, expr, data);
}
+ if (set->flags & NFT_SET_OBJECT) {
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_OBJREF,
+ &nld.len);
+ 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);
return 0;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 90fb9e670751..48968442d9bc 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1142,6 +1142,35 @@ static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
expr = netlink_alloc_value(&netlink_location, &nld);
expr->dtype = &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_lookup(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->keylen) {
+ left = netlink_parse_concat_expr(ctx, loc, sreg, set->keylen);
+ 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);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index c9488b3212bc..5030135cd5d5 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -692,14 +692,34 @@ static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
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");
- 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);
+ switch (expr->ops->type) {
+ 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);
+ 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->ops->type);
+ }
nftnl_rule_add_expr(ctx->nlr, nle);
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 795b0ee210a3..122e2496acde 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1218,7 +1218,6 @@ set_flag : CONSTANT { $$ = NFT_SET_CONSTANT; }
map_block_alloc : /* empty */
{
$$ = set_alloc(NULL);
- $$->flags |= NFT_SET_MAP;
}
;
@@ -1231,6 +1230,25 @@ map_block : /* empty */ { $$ = $<set>-1; }
{
$1->keytype = $3;
$1->datatype = $5;
+ $1->flags |= NFT_SET_MAP;
+ $$ = $1;
+ }
+ | map_block TYPE
+ data_type COLON COUNTER
+ stmt_seperator
+ {
+ $1->keytype = $3;
+ $1->objtype = NFT_OBJECT_COUNTER;
+ $1->flags |= NFT_SET_OBJECT;
+ $$ = $1;
+ }
+ | map_block TYPE
+ data_type COLON QUOTA
+ stmt_seperator
+ {
+ $1->keytype = $3;
+ $1->objtype = NFT_OBJECT_QUOTA;
+ $1->flags |= NFT_SET_OBJECT;
$$ = $1;
}
| map_block FLAGS set_flag_list stmt_seperator
diff --git a/src/rule.c b/src/rule.c
index 9eeb436cd37a..b97213e94954 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -273,7 +273,7 @@ static void set_print_declaration(const struct set *set,
const char *type;
uint32_t flags;
- if (set->flags & NFT_SET_MAP)
+ if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
type = "map";
else if (set->flags & NFT_SET_EVAL)
type = "flow table";
@@ -293,6 +293,8 @@ static void set_print_declaration(const struct set *set,
printf("%s%stype %s", opts->tab, opts->tab, set->keytype->name);
if (set->flags & NFT_SET_MAP)
printf(" : %s", set->datatype->name);
+ else if (set->flags & NFT_SET_OBJECT)
+ printf(" : %s", obj_type_name(set->objtype));
printf("%s", opts->stmt_separator);
@@ -913,6 +915,7 @@ static int __do_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
set_to_intervals(ctx->msgs, set, expr, true) < 0)
return -1;
+ expr->set_flags |= set->flags;
if (netlink_add_setelems(ctx, h, expr, excl) < 0)
return -1;
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH nft 10/10] src: support for stateful object monitoring
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
` (7 preceding siblings ...)
2016-12-23 14:26 ` [PATCH nft 09/10] src: add support for stateful object maps Pablo Neira Ayuso
@ 2016-12-23 14:26 ` Pablo Neira Ayuso
8 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2016-12-23 14:26 UTC (permalink / raw)
To: netfilter-devel
This patch extends the event monitoring infrastructure to catch events
of addition and removal of stateful objects.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/rule.h | 3 ++
src/netlink.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/rule.c | 25 +++++++++++
3 files changed, 162 insertions(+)
diff --git a/include/rule.h b/include/rule.h
index 86c0392f89af..878563d9fcbc 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -283,7 +283,10 @@ struct obj {
struct obj *obj_alloc(const struct location *loc);
void obj_free(struct obj *obj);
void obj_add_hash(struct obj *obj, struct table *table);
+struct obj *obj_lookup(const struct table *table, const char *name,
+ uint32_t type);
void obj_print(const struct obj *n);
+void obj_print_plain(const struct obj *obj);
const char *obj_type_name(uint32_t type);
/**
diff --git a/src/netlink.c b/src/netlink.c
index 97220f451343..5f478ff07319 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1923,6 +1923,19 @@ static struct nftnl_rule *netlink_rule_alloc(const struct nlmsghdr *nlh)
return nlr;
}
+static 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 msg)
{
switch (msg) {
@@ -2184,6 +2197,51 @@ out:
return MNL_CB_OK;
}
+static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
+ struct netlink_mon_handler *monh)
+{
+ struct nftnl_obj *nlo;
+ uint32_t family;
+ struct obj *obj;
+
+ nlo = netlink_obj_alloc(nlh);
+
+ switch (monh->format) {
+ case NFTNL_OUTPUT_DEFAULT:
+ switch (type) {
+ case NFT_MSG_NEWOBJ:
+ printf("add ");
+ obj = netlink_delinearize_obj(monh->ctx, nlo);
+ if (obj == NULL) {
+ nftnl_obj_free(nlo);
+ return MNL_CB_ERROR;
+ }
+ obj_print_plain(obj);
+ obj_free(obj);
+ printf("\n");
+ break;
+ case NFT_MSG_DELOBJ:
+ family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
+ printf("delete %s %s %s %s\n",
+ obj_type_name(nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE)),
+ family2str(family),
+ nftnl_obj_get_str(nlo, NFTNL_OBJ_TABLE),
+ nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME));
+ break;
+ }
+ break;
+ case NFTNL_OUTPUT_XML:
+ case NFTNL_OUTPUT_JSON:
+ nftnl_obj_fprintf(stdout, nlo, monh->format,
+ netlink_msg2nftnl_of(type));
+ fprintf(stdout, "\n");
+ break;
+ }
+
+ nftnl_obj_free(nlo);
+ return MNL_CB_OK;
+}
+
static void rule_map_decompose_cb(struct set *s, void *data)
{
if (s->flags & NFT_SET_INTERVAL)
@@ -2363,6 +2421,72 @@ static void netlink_events_cache_delsets(struct netlink_mon_handler *monh,
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_lookup(&obj->handle);
+ if (t == NULL) {
+ fprintf(stderr, "W: Unable to cache object: table not found.\n");
+ obj_free(obj);
+ goto out;
+ }
+
+ obj_add_hash(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 = 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);
+
+ t = table_lookup(&h);
+ if (t == NULL) {
+ fprintf(stderr, "W: Unable to cache object: table not found.\n");
+ goto out;
+ }
+
+ obj = obj_lookup(t, name, type);
+ if (obj == NULL) {
+ fprintf(stderr, "W: Unable to find object in cache\n");
+ goto out;
+ }
+
+ list_del(&obj->list);
+ 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)
{
@@ -2386,6 +2510,12 @@ static void netlink_events_cache_update(struct netlink_mon_handler *monh,
/* 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;
}
}
@@ -2697,6 +2827,10 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
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;
}
fflush(stdout);
diff --git a/src/rule.c b/src/rule.c
index b97213e94954..b6dc755e9621 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1158,6 +1158,19 @@ void obj_add_hash(struct obj *obj, struct table *table)
list_add_tail(&obj->list, &table->objs);
}
+struct obj *obj_lookup(const struct table *table, const char *name,
+ uint32_t type)
+{
+ struct obj *obj;
+
+ list_for_each_entry(obj, &table->objs, list) {
+ if (!strcmp(obj->handle.obj, name) &&
+ obj->type == type)
+ return obj;
+ }
+ return NULL;
+}
+
static void obj_print_data(const struct obj *obj,
struct print_fmt_options *opts)
{
@@ -1229,6 +1242,18 @@ void obj_print(const struct obj *obj)
obj_print_declaration(obj, &opts);
}
+void obj_print_plain(const struct obj *obj)
+{
+ struct print_fmt_options opts = {
+ .tab = "",
+ .nl = " ",
+ .table = obj->handle.table,
+ .family = family2str(obj->handle.family),
+ };
+
+ obj_print_declaration(obj, &opts);
+}
+
static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
{
struct print_fmt_options opts = {
--
2.1.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2016-12-23 14:27 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-12-23 14:26 [PATCH nft 01/10] include: fetch nf_tables.h updates Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 02/10] src: remove SET_F_* flag definitions Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 03/10] src: add used quota support Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 04/10] src: listing of stateful objects Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 05/10] src: add/create/delete " Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 06/10] src: reset internal " Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 07/10] parser_bison: allow RESET token from rhs Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 08/10] src: add stateful object reference expression Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 09/10] src: add support for stateful object maps Pablo Neira Ayuso
2016-12-23 14:26 ` [PATCH nft 10/10] src: support for stateful object monitoring Pablo Neira Ayuso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).