Re: [nft PATCH 8/8] src: add events reporting

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

 



On Mon, Apr 14, 2014 at 12:17:46PM +0200, Arturo Borrero Gonzalez wrote:
> diff --git a/src/mnl.c b/src/mnl.c
> index e825fb0..1e8eaf2 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, uint32_t seqnum, uint32_t portid,
> +	      int (*cb)(const struct nlmsghdr *nlh, void *data),
> +	      void *cb_data)

Please, now that you're revisiting this, rename it to:

nft_mnl_recv()

and while at it rename mnl_talk() to nft_mnl_talk().

I would like to avoid a clash with some new function in libmnl in the
future. That name selection I made was not very good idea indeed.

Thanks.

>  {
> -	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 5a9e42e..d5b84fa 100644
> --- a/src/netlink.c
> +++ b/src/netlink.c
> @@ -21,6 +21,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>
>  
> @@ -33,6 +34,7 @@
>  #include <erec.h>
>  
>  static struct mnl_socket *nf_sock;
> +static struct mnl_socket *nf_mon_sock;
>  
>  const struct input_descriptor indesc_netlink = {
>  	.name	= "netlink",
> @@ -43,12 +45,18 @@ const struct location netlink_location = {
>  	.indesc	= &indesc_netlink,
>  };
>  
> -static void __init netlink_open_sock(void)
> +static struct mnl_socket *nfsock_open(void)
>  {
> -	nf_sock = mnl_socket_open(NETLINK_NETFILTER);
> -	if (nf_sock == NULL)
> +	struct mnl_socket *s = mnl_socket_open(NETLINK_NETFILTER);
> +	if (s == NULL)
>  		netlink_open_error();
>  
> +	return s;
> +}
> +
> +static void __init netlink_open_sock(void)
> +{
> +	nf_sock = nfsock_open();
>  	fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK);
>  	mnl_batch_init();
>  }
> @@ -56,6 +64,20 @@ static void __init netlink_open_sock(void)
>  static void __exit netlink_close_sock(void)
>  {
>  	mnl_socket_close(nf_sock);
> +	if (nf_mon_sock)
> +		mnl_socket_close(nf_mon_sock);
> +}
> +
> +static void netlink_open_mon_sock(void)
> +{
> +	nf_mon_sock = nfsock_open();
> +}
> +
> +void __noreturn netlink_abi_error(void)
> +{
> +	fprintf(stderr, "E: Contact urgently your Linux kernel vendor. "
> +		"Netlink ABI is broken: %s\n", strerror(errno));
> +	exit(NFT_EXIT_FAILURE);
>  }
>  
>  int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc,
> @@ -1062,3 +1084,529 @@ struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx,
>  
>  	return rs;
>  }
> +
> +static void netlink_events_printf_wrapper(const char *content,
> +					  uint32_t format, int type)
> +{
> +	const char *type_str = "unknown";
> +
> +	switch (type) {
> +	case NFT_MSG_NEWTABLE:
> +	case NFT_MSG_NEWCHAIN:
> +	case NFT_MSG_NEWSET:
> +	case NFT_MSG_NEWRULE:
> +	case NFT_MSG_NEWSETELEM:
> +		type_str = "add";
> +		break;
> +	case NFT_MSG_DELTABLE:
> +	case NFT_MSG_DELCHAIN:
> +	case NFT_MSG_DELSET:
> +	case NFT_MSG_DELRULE:
> +	case NFT_MSG_DELSETELEM:
> +		type_str = "del";
> +		break;
> +	}
> +
> +	switch (format) {
> +	case NFT_OUTPUT_XML:
> +		printf("<event><type>%s</type>"
> +		       "<nftables>%s</nftables></event>\n",
> +		       type_str, content);
> +		break;
> +	case NFT_OUTPUT_JSON:
> +		printf("{event:{type:\"%s\",{\"nftables\":[\"%s\"]}}}\n",
> +		       type_str, content);
> +		break;
> +	default:
> +		BUG("Unknown monitor output format.\n");
> +	}
> +}

This chunk, I'd like to see it in the library.

> +static struct nft_table *netlink_nlmsghdr2nltable(const struct nlmsghdr *nlh)

Perhaps netlink_table_alloc(const struct nlmsghdr *nlh) ?

> +{
> +	struct nft_table *nlt = nft_table_alloc();
> +	if (nlt == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_table_nlmsg_parse(nlh, nlt) < 0)
> +		netlink_abi_error();
> +
> +	return nlt;
> +}
> +
> +static struct nft_chain *netlink_nlmsghdr2nlchain(const struct nlmsghdr *nlh)

netlink_chain_alloc ?

> +{
> +	struct nft_chain *nlc = nft_chain_alloc();
> +	if (nlc == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_chain_nlmsg_parse(nlh, nlc) < 0)
> +		netlink_abi_error();
> +
> +	return nlc;
> +}
> +
> +static struct nft_set *netlink_nlmsghdr2nlset(const struct nlmsghdr *nlh)
> +{

netlink_set_alloc

> +	struct nft_set *nls = nft_set_alloc();
> +	if (nls == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_set_nlmsg_parse(nlh, nls) < 0)
> +		netlink_abi_error();
> +
> +	return nls;
> +}
> +
> +static struct nft_set *netlink_nlmsghdr2nlsetelem(const struct nlmsghdr *nlh)

netlink_setelem_alloc

> +{
> +	struct nft_set *nls = nft_set_alloc();
> +	if (nls == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_set_elems_nlmsg_parse(nlh, nls) < 0)
> +		netlink_abi_error();
> +
> +	return nls;
> +}
> +
> +static struct nft_set_elem *netlink_nlset_first_elem(struct nft_set *nls)
> +{
> +	struct nft_set_elems_iter *nlsei;
> +	struct nft_set_elem *nlse;

I remember you asked to have this in the library, go ahead add some
helper there.

Otherwise, rename this to netlink_set_get_first_elem?

> +
> +	/* only first, useful for set_elem event reporting from kernel */
> +	nlsei = nft_set_elems_iter_create(nls);
> +	if (nlsei == NULL)
> +		memory_allocation_error();
> +
> +	nlse = nft_set_elems_iter_cur(nlsei);
> +	if (nlse == NULL)
> +		memory_allocation_error();
> +
> +	nft_set_elems_iter_destroy(nlsei);
> +
> +	return nlse;
> +}
> +
> +static struct nft_rule *netlink_nlmsghdr2nlrule(const struct nlmsghdr *nlh)
> +{
> +	struct nft_rule *nlr = nft_rule_alloc();
> +	if (nlr == NULL)
> +		memory_allocation_error();
> +
> +	if (nft_rule_nlmsg_parse(nlh, nlr) < 0)
> +		netlink_abi_error();
> +
> +	return nlr;
> +}
> +
> +static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
> +				   struct netlink_mon_handler *monh)
> +{
> +	uint32_t family;
> +	char buf[4096];
> +	struct nft_table *nlt = netlink_nlmsghdr2nltable(nlh);
> +
> +	if (monh->format == NFT_OUTPUT_DEFAULT) {
> +		if (type == NFT_MSG_NEWTABLE)
> +			printf("add table ");
> +		else
> +			printf("delete table ");

You have to check nlh->nlmsg_flags & NLM_F_EXCL here to catch table
updates.

> +
> +		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, monh->format, 0);
> +		netlink_events_printf_wrapper(buf, monh->format, type);
> +	}
> +
> +	nft_table_free(nlt);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
> +				   struct netlink_mon_handler *monh)
> +{
> +	struct chain *c;
> +	uint32_t family;
> +	char buf[4096];
> +	struct nft_chain *nlc = netlink_nlmsghdr2nlchain(nlh);
> +
> +	if (monh->format == NFT_OUTPUT_DEFAULT) {
> +		if (type == NFT_MSG_NEWCHAIN) {

Same thing here, catch chain updates.

> +			printf("add ");
> +			c = netlink_delinearize_chain(monh->ctx, nlc);
> +			chain_print_plain(c);
> +			chain_free(c);
> +		} else {
> +			family = nft_chain_attr_get_u32(nlc,
> +							NFT_CHAIN_ATTR_FAMILY);
> +			printf("delete chain %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, monh->format, 0);
> +		netlink_events_printf_wrapper(buf, monh->format, type);
> +	}
> +
> +	nft_chain_free(nlc);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
> +				 struct netlink_mon_handler *monh)
> +{
> +	struct set *set;
> +	uint32_t family, flags;
> +	char buf[4096];
> +	struct nft_set *nls = netlink_nlmsghdr2nlset(nlh);
> +
> +	flags = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FLAGS);
> +	if (flags & SET_F_ANONYMOUS)
> +		goto out;
> +
> +	if (monh->format == NFT_OUTPUT_DEFAULT) {
> +		if (type == NFT_MSG_NEWSET) {
> +			printf("add ");
> +			set = netlink_delinearize_set(monh->ctx, nls);
> +			set_print_plain(set);
> +			set_free(set);
> +		} else {
> +			family = nft_set_attr_get_u32(nls,
> +						      NFT_SET_ATTR_FAMILY);
> +			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, monh->format, 0);
> +		netlink_events_printf_wrapper(buf, monh->format, type);
> +	}
> +
> +out:
> +	nft_set_free(nls);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
> +				     struct netlink_mon_handler *monh)
> +{
> +	struct nft_set_elem *nlse;
> +	struct set *dummyset;
> +	struct set *set;
> +	const char *setname, *table;
> +	uint32_t family;
> +	char buf[4096];
> +	struct nft_set *nls = netlink_nlmsghdr2nlsetelem(nlh);
> +
> +	table = nft_set_attr_get_str(nls, NFT_SET_ATTR_TABLE);
> +	setname = nft_set_attr_get_str(nls, NFT_SET_ATTR_NAME);
> +	family = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY);
> +
> +	set = set_lookup_global(family, table, setname);
> +	if (set == NULL) {
> +		fprintf(stderr, "W: Received event for an unknown set.");
> +		goto out;
> +	}
> +
> +	if (monh->format == NFT_OUTPUT_DEFAULT) {
> +		if (set->flags & SET_F_ANONYMOUS)
> +			goto out;
> +
> +		nlse = netlink_nlset_first_elem(nls);
> +
> +		/* we want to 'delinearize' the set_elem, but don't modify the
> +		 * original cached set. This path is only used by named sets,
> +		 * so use a dummy set.
> +		 */
> +		dummyset = set_alloc(monh->loc);
> +		dummyset->keytype = set->keytype;
> +		dummyset->datatype = set->datatype;
> +		dummyset->init = set_expr_alloc(monh->loc);
> +
> +		if (netlink_delinearize_setelem(nlse, dummyset) < 0) {
> +			set_free(dummyset);
> +			goto out;
> +		}
> +
> +		if (type == NFT_MSG_NEWSETELEM)
> +			printf("add ");
> +		else
> +			printf("delete ");
> +
> +		printf("element %s %s %s ", family2str(family), table, setname);
> +		expr_print(dummyset->init);
> +		printf("\n");
> +
> +		set_free(dummyset);
> +	} else {
> +		nft_set_snprintf(buf, sizeof(buf), nls, monh->format, 0);
> +		netlink_events_printf_wrapper(buf, monh->format, type);
> +	}
> +
> +out:
> +	/* nlse is freed here */
> +	nft_set_free(nls);
> +	return MNL_CB_OK;
> +}
> +
> +static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
> +				  struct netlink_mon_handler *monh)
> +{
> +	struct rule *r;
> +	char buf[4096];
> +	uint32_t fam;
> +	const char *family;
> +	const char *table;
> +	const char *chain;
> +	uint64_t handle;
> +	struct nft_rule *nlr = netlink_nlmsghdr2nlrule(nlh);
> +
> +	if (monh->format == NFT_OUTPUT_DEFAULT) {
> +		fam = nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY);
> +		family = family2str(fam);
> +		table = nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_TABLE);
> +		chain = nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_CHAIN);
> +		handle = nft_rule_attr_get_u64(nlr, NFT_RULE_ATTR_HANDLE);
> +
> +		if (type == NFT_MSG_NEWRULE) {
> +			r = netlink_delinearize_rule(monh->ctx, nlr);
> +
> +			printf("add rule %s %s %s", family, table, chain);
> +			rule_print(r);
> +			printf("\n");
> +
> +			rule_free(r);
> +			goto out;
> +		}
> +
> +		printf("delete rule %s %s %s handle %u\n",
> +		       family, table, chain, (unsigned int)handle);
> +	} else {
> +		nft_rule_snprintf(buf, sizeof(buf), nlr, monh->format, 0);
> +		netlink_events_printf_wrapper(buf, monh->format, type);
> +	}
> +
> +out:
> +	nft_rule_free(nlr);
> +	return MNL_CB_OK;
> +}
> +
> +static void netlink_events_cache_addtable(struct netlink_mon_handler *monh,
> +					  const struct nlmsghdr *nlh)
> +{
> +	struct table *t;
> +	struct nft_table *nlt = netlink_nlmsghdr2nltable(nlh);
> +
> +	t = netlink_delinearize_table(monh->ctx, nlt);
> +	table_add_hash(t);
> +
> +	nft_table_free(nlt);
> +}
> +
> +static void netlink_events_cache_deltable(struct netlink_mon_handler *monh,
> +					  const struct nlmsghdr *nlh)
> +{
> +	struct table *t;
> +	struct handle h;
> +	struct nft_table *nlt = netlink_nlmsghdr2nltable(nlh);
> +
> +	h.family = nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY);
> +	h.table = nft_table_attr_get_str(nlt, NFT_TABLE_ATTR_NAME);
> +
> +	t = table_lookup(&h);
> +	if (t == NULL)
> +		goto out;
> +
> +	list_del(&t->list);
> +	table_free(t);
> +
> +out:
> +	nft_table_free(nlt);
> +}
> +
> +static void netlink_events_cache_addset(struct netlink_mon_handler *monh,
> +					const struct nlmsghdr *nlh)
> +{
> +	struct set *s;
> +	LIST_HEAD(msgs);
> +	struct table *t;
> +	struct netlink_ctx set_tmpctx;
> +	struct nft_set *nls = netlink_nlmsghdr2nlset(nlh);
> +
> +	memset(&set_tmpctx, 0, sizeof(set_tmpctx));
> +	init_list_head(&set_tmpctx.list);
> +	init_list_head(&msgs);
> +	set_tmpctx.msgs = &msgs;
> +
> +	s = netlink_delinearize_set(&set_tmpctx, nls);
> +	s->init = set_expr_alloc(monh->loc);
> +
> +	t = table_lookup(&s->handle);
> +	if (t == NULL) {
> +		fprintf(stderr, "W: Unable to cache set: table not found.\n");
> +		goto out;
> +	}
> +
> +	set_add_hash(s, t);
> +out:
> +	nft_set_free(nls);
> +}
> +
> +static void netlink_events_cache_addsetelem(struct netlink_mon_handler *monh,
> +					    const struct nlmsghdr *nlh)
> +{
> +	struct set *set;
> +	struct nft_set_elem *nlse;
> +	const char *table, *setname;
> +	struct nft_set *nls = netlink_nlmsghdr2nlsetelem(nlh);
> +
> +	table = nft_set_attr_get_str(nls, NFT_SET_ATTR_TABLE);
> +	setname = nft_set_attr_get_str(nls, NFT_SET_ATTR_NAME);
> +
> +	set = set_lookup_global(nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
> +				table, setname);
> +	if (set == NULL) {
> +		fprintf(stderr,
> +			"W: Unable to cache set_elem. Set not found.\n");
> +		goto out;
> +	}
> +
> +	nlse = netlink_nlset_first_elem(nls);
> +
> +	if (netlink_delinearize_setelem(nlse, set) < 0)
> +		fprintf(stderr,
> +			"W: Unable to cache set_elem. Delinearize failed.\n");
> +out:
> +	/* nlse is freed inside nft_set_free() */
> +	nft_set_free(nls);
> +}
> +
> +static void netlink_events_cache_delsets(struct netlink_mon_handler *monh,
> +					 const struct nlmsghdr *nlh)
> +{
> +	struct set *s;
> +	uint32_t family;
> +	struct nft_rule_expr *nlre;
> +	struct nft_rule_expr_iter *nlrei;
> +	const char *expr_name, *set_name, *table;
> +	struct nft_rule *nlr = netlink_nlmsghdr2nlrule(nlh);
> +
> +	nlrei = nft_rule_expr_iter_create(nlr);
> +	if (nlrei == NULL)
> +		memory_allocation_error();
> +
> +	family = nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY);
> +	table = nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_TABLE);
> +
> +	nlre = nft_rule_expr_iter_next(nlrei);
> +	while (nlre != NULL) {
> +		expr_name = nft_rule_expr_get_str(nlre,
> +						  NFT_RULE_EXPR_ATTR_NAME);
> +		if (strcmp(expr_name, "lookup") != 0)
> +			goto next;
> +
> +		set_name = nft_rule_expr_get_str(nlre, NFT_EXPR_LOOKUP_SET);
> +		s = set_lookup_global(family, table, set_name);
> +		if (s == NULL)
> +			goto next;
> +
> +		list_del(&s->list);
> +		set_free(s);
> +next:
> +		nlre = nft_rule_expr_iter_next(nlrei);
> +	}
> +	nft_rule_expr_iter_destroy(nlrei);
> +
> +	nft_rule_free(nlr);
> +}
> +
> +static void netlink_events_cache_update(struct netlink_mon_handler *monh,
> +					const struct nlmsghdr *nlh, int type)
> +{
> +	if (!monh->cache_needed)
> +		return;
> +
> +	switch (type) {
> +	case NFT_MSG_NEWTABLE:
> +		netlink_events_cache_addtable(monh, nlh);
> +		break;
> +	case NFT_MSG_DELTABLE:
> +		netlink_events_cache_deltable(monh, nlh);
> +		break;
> +	case NFT_MSG_NEWSET:
> +		netlink_events_cache_addset(monh, nlh);
> +		break;
> +	case NFT_MSG_NEWSETELEM:
> +		netlink_events_cache_addsetelem(monh, nlh);
> +		break;
> +	case NFT_MSG_DELRULE:
> +		/* there are no notification for anon-set deletion */
> +		netlink_events_cache_delsets(monh, nlh);
> +		break;
> +	}
> +}
> +
> +static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
> +{
> +	int ret = MNL_CB_OK;
> +	int type = nlh->nlmsg_type & 0xFF;
> +	struct netlink_mon_handler *monh = (struct netlink_mon_handler *)data;
> +
> +	netlink_events_cache_update(monh, nlh, type);
> +
> +	if (!(monh->monitor_flags & (1 << type)))
> +		return ret;
> +
> +	switch (type) {
> +	case NFT_MSG_NEWTABLE:
> +	case NFT_MSG_DELTABLE:
> +		ret = netlink_events_table_cb(nlh, type, monh);
> +		break;
> +	case NFT_MSG_NEWCHAIN:
> +	case NFT_MSG_DELCHAIN:
> +		ret = netlink_events_chain_cb(nlh, type, monh);
> +		break;
> +	case NFT_MSG_NEWSET:
> +	case NFT_MSG_DELSET:		/* nft {add|delete} set */
> +		ret = netlink_events_set_cb(nlh, type, monh);
> +		break;
> +	case NFT_MSG_NEWSETELEM:
> +	case NFT_MSG_DELSETELEM:	/* nft {add|delete} element */
> +		ret = netlink_events_setelem_cb(nlh, type, monh);
> +		break;
> +	case NFT_MSG_NEWRULE:
> +	case NFT_MSG_DELRULE:
> +		ret = netlink_events_rule_cb(nlh, type, monh);
> +		break;
> +	default:
> +		BUG("Unknow event received from netlink.\n");
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +int netlink_monitor(struct netlink_mon_handler *monhandler)
> +{
> +	netlink_open_mon_sock();
> +
> +	if (mnl_socket_bind(nf_mon_sock, (1 << (NFNLGRP_NFTABLES-1)),
> +			    MNL_SOCKET_AUTOPID) < 0)
> +		return netlink_io_error(monhandler->ctx, monhandler->loc,
> +					"Could not bind to netlink socket %s",
> +					strerror(errno));
> +
> +	return mnl_nft_event_listener(nf_mon_sock, netlink_events_cb,
> +				      monhandler);
> +}
> diff --git a/src/parser.y b/src/parser.y
> index af34857..4f6b59b 100644
> --- a/src/parser.y
> +++ b/src/parser.y
> @@ -163,12 +163,16 @@ static void location_update(struct location *loc, struct location *rhs, int n)
>  %token TABLE			"table"
>  %token TABLES			"tables"
>  %token CHAIN			"chain"
> +%token CHAINS			"chains"
>  %token RULE			"rule"
> +%token RULES			"rules"
>  %token SETS			"sets"
>  %token SET			"set"
>  %token ELEMENT			"element"
>  %token MAP			"map"
>  %token HANDLE			"handle"
> +%token ADDED			"added"
> +%token DELETED			"deleted"
>  
>  %token INET			"inet"
>  
> @@ -181,6 +185,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
>  %token RENAME			"rename"
>  %token DESCRIBE			"describe"
>  %token EXPORT			"export"
> +%token MONITOR			"monitor"
>  
>  %token ACCEPT			"accept"
>  %token DROP			"drop"
> @@ -362,8 +367,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 monitor_cmd
> +%destructor { cmd_free($$); }	base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_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
> @@ -491,7 +496,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	output_format	monitor_flags
>  
>  %%
>  
> @@ -591,6 +596,7 @@ base_cmd		:	/* empty */	add_cmd		{ $$ = $1; }
>  			|	FLUSH		flush_cmd	{ $$ = $2; }
>  			|	RENAME		rename_cmd	{ $$ = $2; }
>  			|	EXPORT		export_cmd	{ $$ = $2; }
> +			|	MONITOR		monitor_cmd	{ $$ = $2; }
>  			|	DESCRIBE	primary_expr
>  			{
>  				expr_describe($2);
> @@ -758,6 +764,84 @@ export_cmd		:	export_format
>  			}
>  			;
>  
> +monitor_cmd		:	monitor_flags	output_format
> +			{
> +				struct handle h = { .family = NFPROTO_UNSPEC };
> +				$$ = cmd_alloc(CMD_MONITOR, CMD_OBJ_RULESET, &h, &@$, NULL);
> +				$$->monitor_flags = $1;
> +				$$->format = $2;
> +			}
> +			;
> +
> +monitor_flags		:	/* empty */
> +			{
> +				$$ |= (1 << NFT_MSG_NEWRULE);
> +				$$ |= (1 << NFT_MSG_DELRULE);
> +				$$ |= (1 << NFT_MSG_NEWSET);
> +				$$ |= (1 << NFT_MSG_DELSET);
> +				$$ |= (1 << NFT_MSG_NEWSETELEM);
> +				$$ |= (1 << NFT_MSG_DELSETELEM);
> +				$$ |= (1 << NFT_MSG_NEWCHAIN);
> +				$$ |= (1 << NFT_MSG_DELCHAIN);
> +				$$ |= (1 << NFT_MSG_NEWTABLE);
> +				$$ |= (1 << NFT_MSG_DELTABLE);
> +			}
> +			|	ADDED
> +			{
> +				$$ |= (1 << NFT_MSG_NEWRULE);
> +				$$ |= (1 << NFT_MSG_NEWSET);
> +				$$ |= (1 << NFT_MSG_NEWSETELEM);
> +				$$ |= (1 << NFT_MSG_NEWCHAIN);
> +				$$ |= (1 << NFT_MSG_NEWTABLE);
> +			}
> +			|	DELETED
> +			{
> +				$$ |= (1 << NFT_MSG_DELRULE);
> +				$$ |= (1 << NFT_MSG_DELSET);
> +				$$ |= (1 << NFT_MSG_DELSETELEM);
> +				$$ |= (1 << NFT_MSG_DELCHAIN);
> +				$$ |= (1 << NFT_MSG_DELTABLE);
> +			}
> +			|	TABLES
> +			{
> +				$$ |= (1 << NFT_MSG_NEWTABLE);	$$ |= (1 << NFT_MSG_DELTABLE);
> +			}
> +			|	ADDED 	TABLES 	{	$$ |= (1 << NFT_MSG_NEWTABLE); }
> +			|	DELETED	TABLES	{	$$ |= (1 << NFT_MSG_DELTABLE); }
> +			|	CHAIN
> +			{
> +				$$ |= (1 << NFT_MSG_NEWCHAIN);	$$ |= (1 << NFT_MSG_DELCHAIN);
> +			}
> +			|	ADDED	CHAINS	{	$$ |= (1 << NFT_MSG_NEWCHAIN); }
> +			|	DELETED	CHAINS	{	$$ |= (1 << NFT_MSG_DELCHAIN); }
> +			|	SETS
> +			{
> +				$$ |= (1 << NFT_MSG_NEWSET);	$$ |= (1 << NFT_MSG_DELSET);
> +			}
> +			|	ADDED	SETS 	{ 	$$ |= (1 << NFT_MSG_NEWSET); }
> +			|	DELETED SETS	{	$$ |= (1 << NFT_MSG_DELSET); }
> +			|	RULE
> +			{
> +				$$ |= (1 << NFT_MSG_NEWRULE);	$$ |= (1 << NFT_MSG_DELRULE);
> +			}
> +			|	ADDED 	RULES	{	$$ |= (1 << NFT_MSG_NEWRULE); }
> +			|	DELETED RULES	{	$$ |= (1 << NFT_MSG_DELRULE); }
> +			|	ELEMENTS
> +			{
> +				$$ |= (1 << NFT_MSG_NEWSETELEM);
> +				$$ |= (1 << NFT_MSG_DELSETELEM);
> +			}
> +			|	ADDED	ELEMENTS	{	$$ |= (1 << NFT_MSG_NEWSETELEM); }
> +			|	DELETED ELEMENTS	{	$$ |= (1 << NFT_MSG_DELSETELEM); }
> +			;
> +
> +output_format		:	/* empty */
> +			{
> +				$$ = NFT_OUTPUT_DEFAULT;
> +			}
> +			|	export_format
> +			;
> +
>  table_block_alloc	:	/* empty */
>  			{
>  				$$ = table_alloc();
> diff --git a/src/rule.c b/src/rule.c
> index 858149e..43a3e11 100644
> --- a/src/rule.c
> +++ b/src/rule.c
> @@ -77,6 +77,22 @@ void set_free(struct set *set)
>  	xfree(set);
>  }
>  
> +struct set *set_clone(const struct set *set)
> +{
> +	struct set *newset = set_alloc(&set->location);
> +
> +	newset->list = set->list;
> +	handle_merge(&newset->handle, &set->handle);
> +	newset->flags = set->flags;
> +	newset->keytype = set->keytype;
> +	newset->keylen = set->keylen;
> +	newset->datatype = set->datatype;
> +	newset->datalen = set->datalen;
> +	newset->init = expr_clone(set->init);
> +
> +	return newset;
> +}
> +
>  void set_add_hash(struct set *set, struct table *table)
>  {
>  	list_add_tail(&set->list, &table->sets);
> @@ -93,6 +109,22 @@ struct set *set_lookup(const struct table *table, const char *name)
>  	return NULL;
>  }
>  
> +struct set *set_lookup_global(uint32_t family, const char *table,
> +			      const char *name)
> +{
> +	struct handle h;
> +	struct table *t;
> +
> +	h.family = family;
> +	h.table = table;
> +
> +	t = table_lookup(&h);
> +	if (t == NULL)
> +		return NULL;
> +
> +	return set_lookup(t, name);
> +}
> +
>  struct print_fmt_options {
>  	const char	*tab;
>  	const char	*nl;
> @@ -808,6 +840,61 @@ static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
>  	return 0;
>  }
>  
> +static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
> +{
> +	struct table *t, *nt;
> +	struct set *s, *ns;
> +	struct netlink_ctx set_ctx;
> +	LIST_HEAD(msgs);
> +	struct handle set_handle;
> +	struct netlink_mon_handler monhandler;
> +
> +	/* cache only needed if monitoring:
> +	 *  - new rules in default format
> +	 *  - new elements
> +	 */
> +	if (((cmd->monitor_flags & (1 << NFT_MSG_NEWRULE)) &&
> +	    (cmd->format == NFT_OUTPUT_DEFAULT)) ||
> +	    (cmd->monitor_flags & (1 << NFT_MSG_NEWSETELEM)))
> +		monhandler.cache_needed = true;
> +	else
> +		monhandler.cache_needed = false;
> +
> +	if (monhandler.cache_needed) {
> +		memset(&set_ctx, 0, sizeof(set_ctx));
> +		init_list_head(&msgs);
> +		set_ctx.msgs = &msgs;
> +
> +		if (netlink_list_tables(ctx, &cmd->handle, &cmd->location) < 0)
> +			return -1;
> +
> +		list_for_each_entry_safe(t, nt, &ctx->list, list) {
> +			set_handle.family = t->handle.family;
> +			set_handle.table = t->handle.table;
> +
> +			init_list_head(&set_ctx.list);
> +
> +			if (netlink_list_sets(&set_ctx, &set_handle,
> +					      &cmd->location) < 0)
> +				return -1;
> +
> +			list_for_each_entry_safe(s, ns, &set_ctx.list, list) {
> +				s->init = set_expr_alloc(&cmd->location);
> +				set_add_hash(s, t);
> +			}
> +
> +			table_add_hash(t);
> +		}
> +	}
> +
> +	monhandler.monitor_flags = cmd->monitor_flags;
> +	monhandler.format = cmd->format;
> +	monhandler.ctx = ctx;
> +	monhandler.loc = &cmd->location;
> +
> +	return netlink_monitor(&monhandler);
> +}
> +
>  int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
>  {
>  	switch (cmd->op) {
> @@ -827,6 +914,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_MONITOR:
> +		return do_command_monitor(ctx, cmd);
>  	default:
>  		BUG("invalid command object type %u\n", cmd->obj);
>  	}
> diff --git a/src/scanner.l b/src/scanner.l
> index 47c5933..26b4737 100644
> --- a/src/scanner.l
> +++ b/src/scanner.l
> @@ -232,12 +232,16 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
>  "table"			{ return TABLE; }
>  "tables"		{ return TABLES; }
>  "chain"			{ return CHAIN; }
> +"chains"		{ return CHAINS; }
>  "rule"			{ return RULE; }
> +"rules"			{ return RULES; }
>  "sets"			{ return SETS; }
>  "set"			{ return SET; }
>  "element"		{ return ELEMENT; }
>  "map"			{ return MAP; }
>  "handle"		{ return HANDLE; }
> +"added"			{ return ADDED; }
> +"deleted"		{ return DELETED; }

I think Patrick asked to use "new" instead of "added" and "destroy"
instead of "deleted" IIRC.

>  
>  "accept"		{ return ACCEPT; }
>  "drop"			{ return DROP; }
> @@ -256,6 +260,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
>  "flush"			{ return FLUSH; }
>  "rename"		{ return RENAME; }
>  "export"		{ return EXPORT; }
> +"monitor"		{ return MONITOR; }
>  
>  "position"		{ return POSITION; }
>  "comment"		{ return COMMENT; }
> 
--
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