netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).