Re: [nft RFC PATCH 6/6] src: add events reporting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Feb 18, 2014 at 12:18:38AM +0100, Arturo Borrero Gonzalez wrote:
> This patch adds a basic events reporting option to nft.
> 
> Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx>
> ---
>  include/mnl.h     |    3 +
>  include/netlink.h |    8 ++
>  include/rule.h    |    3 +
>  src/evaluate.c    |    1 
>  src/mnl.c         |   45 ++++++++---
>  src/netlink.c     |  223 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/parser.y      |   60 ++++++++++++++
>  src/rule.c        |   14 +++
>  src/scanner.l     |    2 
>  9 files changed, 343 insertions(+), 16 deletions(-)
> 
> diff --git a/include/mnl.h b/include/mnl.h
> index f4de27d..ece7ee7 100644
> --- a/include/mnl.h
> +++ b/include/mnl.h
> @@ -67,4 +67,7 @@ int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls);
>  
>  struct nft_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock,
>  					 uint32_t family);
> +int mnl_nft_event_listener(struct mnl_socket *nf_sock,
> +			   int (*cb)(const struct nlmsghdr *nlh, void *data),
> +			   void *cb_data);
>  #endif /* _NFTABLES_MNL_H_ */
> diff --git a/include/netlink.h b/include/netlink.h
> index 1e6655c..70de811 100644
> --- a/include/netlink.h
> +++ b/include/netlink.h
> @@ -149,4 +149,12 @@ extern int netlink_io_error(struct netlink_ctx *ctx,
>  extern struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx,
>  						const struct handle *h,
>  						const struct location *loc);
> +struct netlink_ev_handler {
> +	uint32_t		selector;
> +	uint32_t		format;
> +	struct netlink_ctx	*ctx;
> +	const struct location	*loc;
> +};
> +
> +extern int netlink_events(struct netlink_ev_handler *evhandler);
>  #endif /* NFTABLES_NETLINK_H */
> diff --git a/include/rule.h b/include/rule.h
> index 9791cea..49173df 100644
> --- a/include/rule.h
> +++ b/include/rule.h
> @@ -210,6 +210,7 @@ extern void set_print_plain(const struct set *s);
>   * @CMD_FLUSH:		flush container
>   * @CMD_RENAME:		rename object
>   * @CMD_EXPORT:		export the ruleset in a given format
> + * @CMD_EVENT:		event listener
>   */
>  enum cmd_ops {
>  	CMD_INVALID,
> @@ -221,6 +222,7 @@ enum cmd_ops {
>  	CMD_FLUSH,
>  	CMD_RENAME,
>  	CMD_EXPORT,
> +	CMD_EVENT,
>  };
>  
>  /**
> @@ -276,6 +278,7 @@ struct cmd {
>  	};
>  	const void		*arg;
>  	uint32_t		format;
> +	uint32_t		event_selector;
>  };
>  
>  extern struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
> diff --git a/src/evaluate.c b/src/evaluate.c
> index f10d0d9..80d16f4 100644
> --- a/src/evaluate.c
> +++ b/src/evaluate.c
> @@ -1410,6 +1410,7 @@ int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
>  	case CMD_FLUSH:
>  	case CMD_RENAME:
>  	case CMD_EXPORT:
> +	case CMD_EVENT:
>  		return 0;
>  	default:
>  		BUG("invalid command operation %u\n", cmd->op);
> diff --git a/src/mnl.c b/src/mnl.c
> index e825fb0..7e34b31 100644
> --- a/src/mnl.c
> +++ b/src/mnl.c
> @@ -34,24 +34,16 @@ uint32_t mnl_seqnum_alloc(void)
>  }
>  
>  static int
> -mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
> -	 int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
> +mnl_talk_recv(struct mnl_socket *nf_sock, int seqnum, uint32_t portid,
> +	      int (*cb)(const struct nlmsghdr *nlh, void *data),
> +	      void *cb_data)
>  {
> -	char buf[MNL_SOCKET_BUFFER_SIZE];
> -	uint32_t portid = mnl_socket_get_portid(nf_sock);
>  	int ret;
> -
> -#ifdef DEBUG
> -	if (debug_level & DEBUG_MNL)
> -		mnl_nlmsg_fprintf(stdout, data, len, sizeof(struct nfgenmsg));
> -#endif
> -
> -	if (mnl_socket_sendto(nf_sock, data, len) < 0)
> -		return -1;
> +	char buf[MNL_SOCKET_BUFFER_SIZE];
>  
>  	ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
>  	while (ret > 0) {
> -		ret = mnl_cb_run(buf, ret, seq, portid, cb, cb_data);
> +		ret = mnl_cb_run(buf, ret, seqnum, portid, cb, cb_data);
>  		if (ret <= 0)
>  			goto out;
>  
> @@ -64,6 +56,23 @@ out:
>  	return ret;
>  }
>  
> +static int
> +mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
> +	 int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
> +{
> +	uint32_t portid = mnl_socket_get_portid(nf_sock);
> +
> +#ifdef DEBUG
> +	if (debug_level & DEBUG_MNL)
> +		mnl_nlmsg_fprintf(stdout, data, len, sizeof(struct nfgenmsg));
> +#endif
> +
> +	if (mnl_socket_sendto(nf_sock, data, len) < 0)
> +		return -1;
> +
> +	return mnl_talk_recv(nf_sock, seq, portid, cb, cb_data);
> +}
> +
>  /*
>   * Batching
>   */
> @@ -805,3 +814,13 @@ out:
>  	nft_ruleset_free(rs);
>  	return NULL;
>  }
> +
> +/*
> + * events
> + */
> +int mnl_nft_event_listener(struct mnl_socket *nf_sock,
> +			   int (*cb)(const struct nlmsghdr *nlh, void *data),
> +			   void *cb_data)
> +{
> +	return mnl_talk_recv(nf_sock, 0, 0, cb, cb_data);
> +}
> diff --git a/src/netlink.c b/src/netlink.c
> index cd5e64a..efa52bf 100644
> --- a/src/netlink.c
> +++ b/src/netlink.c
> @@ -20,6 +20,7 @@
>  #include <libnftnl/chain.h>
>  #include <libnftnl/expr.h>
>  #include <libnftnl/set.h>
> +#include <linux/netfilter/nfnetlink.h>
>  #include <linux/netfilter/nf_tables.h>
>  #include <linux/netfilter.h>
>  
> @@ -1010,3 +1011,225 @@ struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx,
>  
>  	return rs;
>  }
> +
> +static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
> +				   struct netlink_ev_handler *evh)
> +{
> +	struct nft_table *nlt;
> +	uint32_t family;
> +	char buf[4096];
> +
> +	nlt = nft_table_alloc();
> +	if (nlt == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_table_nlmsg_parse(nlh, nlt) < 0) {
> +		netlink_io_error(evh->ctx, evh->loc,
> +				"Could not parse table: %s",
> +				strerror(errno));

I think you should exit on parsing errors.

> +		goto err;
> +	}
> +
> +	if (evh->format == NFT_OUTPUT_DEFAULT) {
> +		if (type == NFT_MSG_NEWTABLE)
> +			printf("add table ");
> +		else
> +			printf("delete table ");
> +
> +		family = nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY);
> +
> +		printf("%s %s\n", family2str(family),
> +		       nft_table_attr_get_str(nlt, NFT_TABLE_ATTR_NAME));
> +	} else {
> +		nft_table_snprintf(buf, sizeof(buf), nlt, evh->format, 0);
> +		printf("%s\t# %s table\n", buf,
> +		       type == NFT_MSG_NEWTABLE ? "add" : "del");
> +	}
> +
> +err:
> +	nft_table_free(nlt);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
> +				   struct netlink_ev_handler *evh)
> +{
> +	struct nft_chain *nlc;
> +	struct chain *c;
> +	uint32_t family;
> +	char buf[4096];
> +
> +	nlc = nft_chain_alloc();
> +	if (nlc == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_chain_nlmsg_parse(nlh, nlc) < 0) {
> +		netlink_io_error(evh->ctx, evh->loc,
> +				 "Could not parse chain: %s",
> +				 strerror(errno));
> +		goto out;
> +	}
> +
> +	if (evh->format == NFT_OUTPUT_DEFAULT) {
> +		if (type == NFT_MSG_NEWCHAIN) {

         Better use switch (type) {
                        case NFT_MSG_NEWCHAIN:
                                ...

> +			printf("add ");
> +			c = netlink_delinearize_chain(evh->ctx, nlc);
> +			chain_print_plain(c);
> +			printf("\n");
> +			chain_free(c);
> +			goto out;
> +		}
> +
> +		printf("delete chain ");
> +
> +		family = nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY);
> +		printf("%s %s %s\n", family2str(family),
> +		       nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_TABLE),
> +		       nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_NAME));
> +	} else {
> +		nft_chain_snprintf(buf, sizeof(buf), nlc, evh->format, 0);
> +		printf("%s\t# %s chain\n", buf,
> +		       type == NFT_MSG_NEWCHAIN ? "add" : "del");
> +	}
> +
> +out:
> +	nft_chain_free(nlc);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
> +				 struct netlink_ev_handler *evh)
> +{
> +	struct nft_set *nls;
> +	struct set *set;
> +	uint32_t family, flags;
> +	char buf[4096];
> +
> +	nls = nft_set_alloc();
> +	if (nls == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_set_nlmsg_parse(nlh, nls) < 0) {
> +		netlink_io_error(evh->ctx, evh->loc,
> +				 "Could not parse set: %s",
> +				 strerror(errno));
> +		goto out;
> +	}
> +
> +	flags = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FLAGS);
> +	if (flags & SET_F_ANONYMOUS && type == NFT_MSG_DELSET)
> +		goto out;
> +
> +	if (evh->format == NFT_OUTPUT_DEFAULT) {
> +		set = netlink_delinearize_set(evh->ctx, nls);
> +		family = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY);
> +
> +		if (type == NFT_MSG_NEWSET) {
> +			printf("add ");
> +			set_print_plain(set);
> +		} else {
> +			printf("delete set %s %s %s",
> +			       family2str(family),
> +			       nft_set_attr_get_str(nls, NFT_SET_ATTR_TABLE),
> +			       nft_set_attr_get_str(nls, NFT_SET_ATTR_NAME));
> +		}
> +
> +		printf("\n");
> +
> +	} else {
> +		nft_set_snprintf(buf, sizeof(buf), nls, evh->format, 0);
> +		printf("%s\t# %s set\n", buf,
> +		       type == NFT_MSG_NEWSET ? "add" : "del");
> +	}
> +
> +out:
> +	nft_set_free(nls);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
> +				  struct netlink_ev_handler *evh)
> +{
> +	struct nft_rule *nlr;
> +	uint32_t family, handle;
> +	char buf[4096];
> +
> +	nlr = nft_rule_alloc();
> +	if (nlr == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_rule_nlmsg_parse(nlh, nlr) < 0) {
> +		netlink_io_error(evh->ctx, evh->loc,
> +				 "Could not parse rule: %s",
> +				 strerror(errno));
> +		goto out;
> +	}
> +
> +	if (evh->format == NFT_OUTPUT_DEFAULT) {
> +		family = nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY);
> +		handle = nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_HANDLE);
> +
> +		if (type == NFT_MSG_NEWRULE)
> +			printf("add rule ");
> +		else
> +			printf("delete rule ");
> +
> +		printf("%s %s %s handle %u\n", family2str(family),
> +		       nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_TABLE),
> +		       nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_CHAIN),
> +		       handle);
> +	} else {
> +		nft_rule_snprintf(buf, sizeof(buf), nlr, evh->format, 0);
> +		printf("%s\t# %s rule\n", buf,
> +		       type == NFT_MSG_NEWRULE ? "add" : "del");
> +	}
> +
> +out:
> +	nft_rule_free(nlr);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
> +{
> +	int ret = MNL_CB_OK;
> +	int type = nlh->nlmsg_type & 0xFF;
> +	struct netlink_ev_handler *evh = (struct netlink_ev_handler *)data;
> +
> +	if (!(evh->selector & (1 << type)))
> +		return ret;
> +
> +	switch (type) {
> +	case NFT_MSG_NEWTABLE:
> +	case NFT_MSG_DELTABLE:
> +		ret = netlink_events_table_cb(nlh, type, evh);
> +		break;
> +	case NFT_MSG_NEWCHAIN:
> +	case NFT_MSG_DELCHAIN:
> +		ret = netlink_events_chain_cb(nlh, type, evh);
> +		break;
> +	case NFT_MSG_NEWSET:
> +	case NFT_MSG_DELSET:
> +		ret = netlink_events_set_cb(nlh, type, evh);
> +		break;
> +	case NFT_MSG_NEWRULE:
> +	case NFT_MSG_DELRULE:
> +		ret = netlink_events_rule_cb(nlh, type, evh);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +int netlink_events(struct netlink_ev_handler *evhandler)
> +{
> +	if (mnl_socket_bind(nf_sock, (1 << (NFNLGRP_NFTABLES-1)),
> +			    MNL_SOCKET_AUTOPID) < 0)
> +		return netlink_io_error(evhandler->ctx, evhandler->loc,
> +					"Could not bind to socket: %s",
> +					strerror(errno));
> +
> +	fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, 0);
> +	return mnl_nft_event_listener(nf_sock, netlink_events_cb, evhandler);
> +}
> diff --git a/src/parser.y b/src/parser.y
> index 07613e2..79a42ac 100644
> --- a/src/parser.y
> +++ b/src/parser.y
> @@ -169,6 +169,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
>  %token ELEMENT			"element"
>  %token MAP			"map"
>  %token HANDLE			"handle"
> +%token ALL			"all"
>  
>  %token INET			"inet"
>  
> @@ -181,6 +182,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
>  %token RENAME			"rename"
>  %token DESCRIBE			"describe"
>  %token EXPORT			"export"
> +%token EVENT			"event"
>  
>  %token ACCEPT			"accept"
>  %token DROP			"drop"
> @@ -360,8 +362,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 create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd
> -%destructor { cmd_free($$); }	base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd
> +%type <cmd>			base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd event_cmd
> +%destructor { cmd_free($$); }	base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd event_cmd
>  
>  %type <handle>			table_spec tables_spec chain_spec chain_identifier ruleid_spec
>  %destructor { handle_free(&$$); } table_spec tables_spec chain_spec chain_identifier ruleid_spec
> @@ -376,6 +378,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
>  %type <rule>			rule
>  %destructor { rule_free($$); }	rule
>  
> +%type <val>			event_selector
> +
>  %type <val>			set_flag_list	set_flag
>  
>  %type <set>			set_block_alloc set_block
> @@ -484,7 +488,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
>  %destructor { expr_free($$); }	ct_expr
>  %type <val>			ct_key
>  
> -%type <val>			export_format
> +%type <val>			export_format	event_format
>  
>  %%
>  
> @@ -584,6 +588,7 @@ base_cmd		:	/* empty */	add_cmd		{ $$ = $1; }
>  			|	FLUSH		flush_cmd	{ $$ = $2; }
>  			|	RENAME		rename_cmd	{ $$ = $2; }
>  			|	EXPORT		export_cmd	{ $$ = $2; }
> +			|	EVENT		event_cmd	{ $$ = $2; }
>  			|	DESCRIBE	primary_expr
>  			{
>  				expr_describe($2);
> @@ -751,6 +756,55 @@ export_cmd		:	export_format
>  			}
>  			;
>  
> +event_cmd		:	event_selector	event_format
> +			{
> +				struct handle h = { .family = NFPROTO_UNSPEC };
> +				$$ = cmd_alloc(CMD_EVENT, CMD_OBJ_RULESET, &h, &@$, NULL);
> +				$$->event_selector = $1;
> +				$$->format = $2;
> +			}
> +			;
> +
> +event_selector		:	ALL
> +			{
> +				$$ |= (1 << NFT_MSG_NEWRULE);
> +				$$ |= (1 << NFT_MSG_DELRULE);
> +				$$ |= (1 << NFT_MSG_NEWSET);
> +				$$ |= (1 << NFT_MSG_DELSET);
> +				$$ |= (1 << NFT_MSG_NEWCHAIN);
> +				$$ |= (1 << NFT_MSG_DELCHAIN);
> +				$$ |= (1 << NFT_MSG_NEWTABLE);
> +				$$ |= (1 << NFT_MSG_DELTABLE);
> +			}
> +			|	TABLE
> +			{
> +				$$ |= (1 << NFT_MSG_NEWTABLE);
> +				$$ |= (1 << NFT_MSG_DELTABLE);
> +			}
> +			|	CHAIN
> +			{
> +				$$ |= (1 << NFT_MSG_NEWCHAIN);
> +				$$ |= (1 << NFT_MSG_DELCHAIN);
> +			}
> +			|	SET
> +			{
> +				$$ |= (1 << NFT_MSG_NEWSET);
> +				$$ |= (1 << NFT_MSG_DELSET);
> +			}
> +			|	RULE
> +			{
> +				$$ |= (1 << NFT_MSG_NEWRULE);
> +				$$ |= (1 << NFT_MSG_DELRULE);
> +			}
> +			;
> +
> +event_format		:	/* empty */
> +			{
> +				$$ = NFT_OUTPUT_DEFAULT;
> +			}
> +			|	export_format
> +			;
> +
>  table_block_alloc	:	/* empty */
>  			{
>  				$$ = table_alloc();
> diff --git a/src/rule.c b/src/rule.c
> index 4301faa..30a8529 100644
> --- a/src/rule.c
> +++ b/src/rule.c
> @@ -790,6 +790,18 @@ static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
>  	return 0;
>  }
>  
> +static int do_command_event(struct netlink_ctx *ctx, struct cmd *cmd)
> +{
> +	struct netlink_ev_handler evhandler;
> +
> +	evhandler.selector = cmd->event_selector;
> +	evhandler.format = cmd->format;
> +	evhandler.ctx = ctx;
> +	evhandler.loc = &cmd->location;
> +
> +	return netlink_events(&evhandler);
> +}
> +
>  int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
>  {
>  	switch (cmd->op) {
> @@ -809,6 +821,8 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
>  		return do_command_rename(ctx, cmd);
>  	case CMD_EXPORT:
>  		return do_command_export(ctx, cmd);
> +	case CMD_EVENT:
> +		return do_command_event(ctx, cmd);
>  	default:
>  		BUG("invalid command object type %u\n", cmd->obj);
>  	}
> diff --git a/src/scanner.l b/src/scanner.l
> index e4cb398..70b781a 100644
> --- a/src/scanner.l
> +++ b/src/scanner.l
> @@ -238,6 +238,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
>  "element"		{ return ELEMENT; }
>  "map"			{ return MAP; }
>  "handle"		{ return HANDLE; }
> +"all"			{ return ALL; }
>  
>  "accept"		{ return ACCEPT; }
>  "drop"			{ return DROP; }
> @@ -256,6 +257,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
>  "flush"			{ return FLUSH; }
>  "rename"		{ return RENAME; }
>  "export"		{ return EXPORT; }
> +"event"			{ return EVENT; }
>  
>  "position"		{ return POSITION; }
>  
> 
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux