[RFC libnftnl PATCH 1/2] src: add mnlio API functions

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

 



These functions are likely to be used by all userspace programs to interact
with the nftables kernel subsystem.

Lets put in the library, so: its easy to maintain, we can save lots of LOCs,
programmers can easily learn how to work with nftables, etc..

This patch will require several iterations: batch_pages are left behind.

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx>
---
 include/libnftnl/Makefile.am |    3 
 include/libnftnl/mnlio.h     |   92 ++++
 src/Makefile.am              |    1 
 src/libnftnl.map             |   37 ++
 src/mnlio.c                  |  957 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1089 insertions(+), 1 deletion(-)
 create mode 100644 include/libnftnl/mnlio.h
 create mode 100644 src/mnlio.c

diff --git a/include/libnftnl/Makefile.am b/include/libnftnl/Makefile.am
index a0841d2..cf703bb 100644
--- a/include/libnftnl/Makefile.am
+++ b/include/libnftnl/Makefile.am
@@ -4,4 +4,5 @@ pkginclude_HEADERS = table.h		\
 		     expr.h		\
 		     set.h		\
 		     ruleset.h		\
-		     common.h
+		     common.h		\
+		     mnlio.h
diff --git a/include/libnftnl/mnlio.h b/include/libnftnl/mnlio.h
new file mode 100644
index 0000000..e517d70
--- /dev/null
+++ b/include/libnftnl/mnlio.h
@@ -0,0 +1,92 @@
+#ifndef _LIBNFTNL_MNLIO_H_
+#define _LIBNFTNL_MNLIO_H_
+
+#include <libnftnl/ruleset.h>
+#include <libnftnl/table.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/set.h>
+#include <libnftnl/rule.h>
+
+int
+nft_mnlio_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
+	       int (*cb)(const struct nlmsghdr *nlh, void *data),
+	       void *cb_data);
+void nft_mnlio_batch_put(struct mnl_nlmsg_batch *batch, int type,
+			 uint32_t seq);
+int nft_mnlio_batch_talk(struct mnl_socket *nl, struct mnl_nlmsg_batch *b);
+void nft_mnlio_batch_begin(struct mnl_nlmsg_batch *batch);
+void nft_mnlio_batch_end(struct mnl_nlmsg_batch *batch);
+struct mnl_nlmsg_batch *nft_mnlio_batch_alloc(void);
+bool nft_mnlio_batch_ready(struct mnl_nlmsg_batch *batch);
+void nft_mnlio_batch_reset(struct mnl_nlmsg_batch *batch);
+
+int nft_mnlio_rule_add(struct nft_rule *nlr, unsigned int flags,
+		       struct mnl_nlmsg_batch *batch);
+int nft_mnlio_rule_list_add(struct nft_rule_list *nlrl, unsigned int flags,
+			    struct mnl_nlmsg_batch *batch);
+int nft_mnlio_rule_del(struct nft_rule *nlr, unsigned int flags,
+		       struct mnl_nlmsg_batch *batch);
+struct nft_rule_list *
+nft_mnlio_rule_dump(struct mnl_socket *nf_sock, int family);
+
+int nft_mnlio_chain_add(struct mnl_socket *nf_sock, struct nft_chain *nlc,
+			unsigned int flags);
+int nft_mnlio_chain_list_add(struct mnl_socket *nf_sock,
+			     struct nft_chain_list *nlcl,
+			     unsigned int flags);
+int nft_mnlio_chain_delete(struct mnl_socket *nf_sock, struct nft_chain *nlc,
+			   unsigned int flags);
+int nft_mnlio_chain_list_delete(struct mnl_socket *nfsock,
+				struct nft_chain_list *nlcl,
+				unsigned int flags);
+struct nft_chain_list *
+nft_mnlio_chain_dump(struct mnl_socket *nf_sock, int family);
+int nft_mnlio_chain_get(struct mnl_socket *nf_sock, struct nft_chain *nlc,
+			unsigned int flags);
+
+int nft_mnlio_table_add(struct mnl_socket *nf_sock, struct nft_table *nlt,
+			unsigned int flags);
+int nft_mnlio_table_list_add(struct mnl_socket *nf_sock,
+			     struct nft_table_list *nltl,
+			     unsigned int flags);
+int nft_mnlio_table_delete(struct mnl_socket *nf_sock, struct nft_table *nlt,
+			   unsigned int flags);
+int nft_mnlio_table_list_delete(struct mnl_socket *nfsock,
+				struct nft_table_list *nltl,
+				unsigned int flags);
+struct nft_table_list *
+nft_mnlio_table_dump(struct mnl_socket *nf_sock, int family);
+int nft_mnlio_table_get(struct mnl_socket *nf_sock, struct nft_table *nlt,
+			unsigned int flags);
+
+int nft_mnlio_set_add(struct mnl_socket *nf_sock, struct nft_set *nls,
+		      unsigned int flags);
+int nft_mnlio_set_list_add(struct mnl_socket *nf_sock,
+			   struct nft_set_list *nlsl,
+			   unsigned int flags);
+int nft_mnlio_set_delete(struct mnl_socket *nf_sock, struct nft_set *nls,
+			 unsigned int flags);
+int nft_mnlio_set_list_delete(struct mnl_socket *nfsock,
+			      struct nft_set_list *nlsl, unsigned int flags);
+struct nft_set_list *
+nft_mnlio_set_dump(struct mnl_socket *nf_sock, int family, const char *table);
+int nft_mnlio_set_get(struct mnl_socket *nf_sock, struct nft_set *nls);
+
+int nft_mnlio_setelem_add(struct mnl_socket *nf_sock, struct nft_set *nls,
+			  unsigned int flags);
+
+int nft_mnlio_setelem_list_add(struct mnl_socket *nf_sock,
+			       struct nft_set_list *nlsl,
+			       unsigned int flags);
+int nft_mnlio_setelem_delete(struct mnl_socket *nf_sock, struct nft_set *nls,
+			     unsigned int flags);
+int nft_mnlio_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls);
+
+struct nft_ruleset *
+nft_mnlio_ruleset_dump(struct mnl_socket *nf_sock, uint32_t family);
+int nft_mnlio_ruleset_add(struct mnl_socket *nf_sock, struct nft_ruleset *rs,
+			  unsigned int tflags, unsigned int cflags,
+			  unsigned int rflags, unsigned int sflags,
+			  unsigned int seflags, struct mnl_nlmsg_batch *batch);
+
+#endif /* _LIBNFTNL_MNLIO_H_ */
diff --git a/src/Makefile.am b/src/Makefile.am
index 450279f..ba1eb49 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,6 +35,7 @@ libnftnl_la_SOURCES = utils.c		\
 		      expr/reject.c	\
 		      expr/target.c	\
 		      expr/data_reg.h	\
+		      mnlio.c		\
 		      libnftnl.map	\
 		      expr_ops.h	\
 		      internal.h
diff --git a/src/libnftnl.map b/src/libnftnl.map
index 43378ed..acc7201 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -194,5 +194,42 @@ global:
   nft_parse_err_free;
   nft_parse_perror;
 
+  nft_mnlio_talk;
+  nft_mnlio_batch_put;
+  nft_mnlio_batch_talk;
+  nft_mnlio_batch_begin;
+  nft_mnlio_batch_end;
+  nft_mnlio_batch_alloc;
+  nft_mnlio_batch_ready;
+  nft_mnlio_batch_reset;
+  nft_mnlio_rule_add;
+  nft_mnlio_rule_list_add;
+  nft_mnlio_rule_del;
+  nft_mnlio_rule_dump;
+  nft_mnlio_chain_add;
+  nft_mnlio_chain_list_add;
+  nft_mnlio_chain_delete;
+  nft_mnlio_chain_list_delete;
+  nft_mnlio_chain_dump;
+  nft_mnlio_chain_get;
+  nft_mnlio_table_add;
+  nft_mnlio_table_list_add;
+  nft_mnlio_table_delete;
+  nft_mnlio_table_list_delete;
+  nft_mnlio_table_dump;
+  nft_mnlio_table_get;
+  nft_mnlio_set_add;
+  nft_mnlio_set_list_add;
+  nft_mnlio_set_delete;
+  nft_mnlio_set_list_delete;
+  nft_mnlio_set_dump;
+  nft_mnlio_set_get;
+  nft_mnlio_setelem_add;
+  nft_mnlio_setelem_list_add;
+  nft_mnlio_setelem_delete;
+  nft_mnlio_setelem_get;
+  nft_mnlio_ruleset_dump;
+  nft_mnlio_ruleset_add;
+
 local: *;
 };
diff --git a/src/mnlio.c b/src/mnlio.c
new file mode 100644
index 0000000..8e558dd
--- /dev/null
+++ b/src/mnlio.c
@@ -0,0 +1,957 @@
+/*
+ * Copyright (c) 2013 Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include "internal.h"
+
+#include <libmnl/libmnl.h>
+#include <libnftnl/common.h>
+#include <libnftnl/ruleset.h>
+#include <libnftnl/table.h>
+#include <libnftnl/chain.h>
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+#include <libnftnl/set.h>
+#include <libnftnl/mnlio.h>
+
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include <errno.h>
+
+static uint32_t seq;
+
+static uint32_t nft_mnlio_seqnum_alloc(void)
+{
+	return seq++;
+}
+
+int
+nft_mnlio_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len,
+	       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;
+
+	if (mnl_socket_sendto(nf_sock, data, len) < 0)
+		return -1;
+
+	ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
+	while (ret > 0) {
+		ret = mnl_cb_run(buf, ret, seq, portid, cb, cb_data);
+		if (ret <= 0)
+			goto out;
+
+		ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf));
+	}
+out:
+	if (ret < 0 && errno == EAGAIN)
+		return 0;
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_talk);
+
+/*
+ * Batching
+ */
+
+/* selected batch page is 256 Kbytes long to load ruleset of
+ * half a million rules without hitting -EMSGSIZE due to large
+ * iovec.
+ */
+#define BATCH_PAGE_SIZE (getpagesize() * 32)
+
+struct mnl_nlmsg_batch *nft_mnlio_batch_alloc(void)
+{
+	static char *buf;
+
+	/* libmnl needs higher buffer to handle batch overflows */
+	buf = malloc(BATCH_PAGE_SIZE + getpagesize());
+	if (buf == NULL)
+		return NULL;
+
+	return mnl_nlmsg_batch_start(buf, BATCH_PAGE_SIZE);
+}
+EXPORT_SYMBOL(nft_mnlio_batch_alloc);
+
+bool nft_mnlio_batch_ready(struct mnl_nlmsg_batch *batch)
+{
+	/* Check if the batch only contains the initial and trailing batch
+	 * messages. In that case, the batch is empty.
+	 */
+	return mnl_nlmsg_batch_size(batch) != (NLMSG_HDRLEN+sizeof(struct nfgenmsg)) * 2;
+}
+EXPORT_SYMBOL(nft_mnlio_batch_ready);
+
+void nft_mnlio_batch_reset(struct mnl_nlmsg_batch *batch)
+{
+	mnl_nlmsg_batch_reset(batch);
+}
+EXPORT_SYMBOL(nft_mnlio_batch_reset);
+
+void nft_mnlio_batch_put(struct mnl_nlmsg_batch *batch, int type,
+			 uint32_t seqnum)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+
+	nlh = mnl_nlmsg_put_header(mnl_nlmsg_batch_current(batch));
+	nlh->nlmsg_type = type;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+	nlh->nlmsg_seq = seqnum;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = NFNL_SUBSYS_NFTABLES;
+
+	mnl_nlmsg_batch_next(batch);
+}
+EXPORT_SYMBOL(nft_mnlio_batch_put);
+
+void nft_mnlio_batch_begin(struct mnl_nlmsg_batch *b)
+{
+	nft_mnlio_batch_put(b, NFNL_MSG_BATCH_BEGIN,
+			    nft_mnlio_seqnum_alloc());
+}
+EXPORT_SYMBOL(nft_mnlio_batch_begin);
+
+void nft_mnlio_batch_end(struct mnl_nlmsg_batch *b)
+{
+	nft_mnlio_batch_put(b, NFNL_MSG_BATCH_END,
+			    nft_mnlio_seqnum_alloc());
+}
+EXPORT_SYMBOL(nft_mnlio_batch_end);
+
+int nft_mnlio_batch_talk(struct mnl_socket *nl, struct mnl_nlmsg_batch *b)
+{
+	int ret, fd = mnl_socket_get_fd(nl);
+	char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
+	fd_set readfds;
+	struct timeval tv = {
+		.tv_sec		= 0,
+		.tv_usec	= 0
+	};
+
+	ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b),
+				mnl_nlmsg_batch_size(b));
+	if (ret == -1)
+		goto err;
+
+	FD_ZERO(&readfds);
+	FD_SET(fd, &readfds);
+
+	/* receive and digest all the acknowledgments from the kernel. */
+	ret = select(fd+1, &readfds, NULL, NULL, &tv);
+	if (ret == -1)
+		goto err;
+
+	while (ret > 0 && FD_ISSET(fd, &readfds)) {
+		ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf));
+		if (ret == -1)
+			goto err;
+
+		ret = mnl_cb_run(rcv_buf, ret, 0, mnl_socket_get_portid(nl),
+				 NULL, NULL);
+		if (ret < 0)
+			goto err;
+
+		ret = select(fd+1, &readfds, NULL, NULL, &tv);
+		if (ret == -1)
+			goto err;
+
+		FD_ZERO(&readfds);
+		FD_SET(fd, &readfds);
+	}
+err:
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_batch_talk);
+
+/*
+ * Rule
+ */
+int nft_mnlio_rule_add(struct nft_rule *nlr, unsigned int flags,
+		       struct mnl_nlmsg_batch *batch)
+{
+	struct nlmsghdr *nlh;
+
+	nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+			NFT_MSG_NEWRULE,
+			nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY),
+			NLM_F_CREATE | flags, nft_mnlio_seqnum_alloc());
+
+	nft_rule_nlmsg_build_payload(nlh, nlr);
+
+	return 0;
+}
+EXPORT_SYMBOL(nft_mnlio_rule_add);
+
+int nft_mnlio_rule_list_add(struct nft_rule_list *nlrl, unsigned int flags,
+			    struct mnl_nlmsg_batch *batch)
+{
+	int ret = 0;
+	struct nft_rule_list_iter *i;
+	struct nft_rule *r;
+
+	i = nft_rule_list_iter_create(nlrl);
+	if (i == NULL)
+		return -1;
+
+	r = nft_rule_list_iter_next(i);
+	while (r != NULL) {
+		ret = nft_mnlio_rule_add(r, flags, batch);
+		if (ret != 0)
+			return ret;
+
+		r = nft_rule_list_iter_next(i);
+	}
+	nft_rule_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_rule_list_add);
+
+int nft_mnlio_rule_del(struct nft_rule *nlr, unsigned int flags,
+		       struct mnl_nlmsg_batch *batch)
+{
+	struct nlmsghdr *nlh;
+
+	nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+			NFT_MSG_DELRULE,
+			nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY),
+			0, nft_mnlio_seqnum_alloc());
+
+	nft_rule_nlmsg_build_payload(nlh, nlr);
+
+	return 0;
+}
+EXPORT_SYMBOL(nft_mnlio_rule_del);
+
+static int rule_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nft_rule_list *nlr_list = data;
+	struct nft_rule *r;
+
+	r = nft_rule_alloc();
+	if (r == NULL)
+		return -1;
+
+	if (nft_rule_nlmsg_parse(nlh, r) < 0)
+		goto err_free;
+
+	nft_rule_list_add_tail(r, nlr_list);
+	return MNL_CB_OK;
+
+err_free:
+	nft_rule_free(r);
+	return MNL_CB_OK;
+}
+
+struct nft_rule_list *
+nft_mnlio_rule_dump(struct mnl_socket *nf_sock, int family)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	struct nft_rule_list *nlr_list;
+	int ret;
+
+	nlr_list = nft_rule_list_alloc();
+	if (nlr_list == NULL)
+		return NULL;
+
+	nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family,
+				       NLM_F_DUMP, seq);
+
+	ret = nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, rule_cb, nlr_list);
+	if (ret < 0)
+		goto err;
+
+	return nlr_list;
+err:
+	nft_rule_list_free(nlr_list);
+	return NULL;
+}
+EXPORT_SYMBOL(nft_mnlio_rule_dump);
+
+/*
+ * Chain
+ */
+int nft_mnlio_chain_add(struct mnl_socket *nf_sock, struct nft_chain *nlc,
+			unsigned int flags)
+
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN,
+			nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY),
+			NLM_F_CREATE | NLM_F_ACK | flags, seq);
+	nft_chain_nlmsg_build_payload(nlh, nlc);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
+}
+EXPORT_SYMBOL(nft_mnlio_chain_add);
+
+
+int nft_mnlio_chain_list_add(struct mnl_socket *nf_sock,
+			     struct nft_chain_list *nlcl,
+			     unsigned int flags)
+{
+	int ret = 0;
+	struct nft_chain_list_iter *i;
+	struct nft_chain *c;
+
+	i = nft_chain_list_iter_create(nlcl);
+	if (i == NULL)
+		return -1;
+
+	c = nft_chain_list_iter_next(i);
+	while (c != NULL) {
+		ret = nft_mnlio_chain_add(nf_sock, c, flags);
+
+		if (ret != 0)
+			break;
+
+		c = nft_chain_list_iter_next(i);
+	}
+	nft_chain_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_chain_list_add);
+
+int nft_mnlio_chain_delete(struct mnl_socket *nf_sock, struct nft_chain *nlc,
+			   unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_DELCHAIN,
+			nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY),
+			NLM_F_ACK, seq);
+	nft_chain_nlmsg_build_payload(nlh, nlc);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
+}
+EXPORT_SYMBOL(nft_mnlio_chain_delete);
+
+int nft_mnlio_chain_list_delete(struct mnl_socket *nfsock,
+				struct nft_chain_list *nlcl,
+				unsigned int flags)
+{
+	struct nft_chain_list_iter *i;
+	struct nft_chain *c;
+	int ret = 0;
+
+	i = nft_chain_list_iter_create(nlcl);
+	if (i == NULL)
+		return -1;
+
+	c = nft_chain_list_iter_next(i);
+	while (c != NULL) {
+		ret = nft_mnlio_chain_delete(nfsock, c, flags);
+
+		if (ret < 0)
+			break;
+
+		c = nft_chain_list_iter_next(i);
+	}
+	nft_chain_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_chain_list_delete);
+
+static int chain_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nft_chain_list *nlc_list = data;
+	struct nft_chain *c;
+
+	c = nft_chain_alloc();
+	if (c == NULL)
+		return -1;
+
+	if (nft_chain_nlmsg_parse(nlh, c) < 0)
+		goto err_free;
+
+	nft_chain_list_add_tail(c, nlc_list);
+	return MNL_CB_OK;
+
+err_free:
+	nft_chain_free(c);
+	return MNL_CB_OK;
+}
+
+struct nft_chain_list *
+nft_mnlio_chain_dump(struct mnl_socket *nf_sock, int family)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	struct nft_chain_list *nlc_list;
+	int ret;
+
+	nlc_list = nft_chain_list_alloc();
+	if (nlc_list == NULL)
+		return NULL;
+
+	nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family,
+					NLM_F_DUMP, seq);
+
+	ret = nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, chain_cb, nlc_list);
+	if (ret < 0)
+		goto err;
+
+	return nlc_list;
+err:
+	nft_chain_list_free(nlc_list);
+	return NULL;
+}
+EXPORT_SYMBOL(nft_mnlio_chain_dump);
+
+static int chain_get_cb(const struct nlmsghdr *nlh, void *data)
+{
+	nft_chain_nlmsg_parse(nlh, data);
+	return MNL_CB_OK;
+}
+
+int nft_mnlio_chain_get(struct mnl_socket *nf_sock, struct nft_chain *nlc,
+			unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN,
+			nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY),
+			NLM_F_ACK | flags, seq);
+	nft_chain_nlmsg_build_payload(nlh, nlc);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, chain_get_cb, nlc);
+}
+EXPORT_SYMBOL(nft_mnlio_chain_get);
+
+/*
+ * Table
+ */
+int nft_mnlio_table_add(struct mnl_socket *nf_sock, struct nft_table *nlt,
+			unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE,
+			nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY),
+			NLM_F_ACK | flags, seq);
+	nft_table_nlmsg_build_payload(nlh, nlt);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
+}
+EXPORT_SYMBOL(nft_mnlio_table_add);
+
+int nft_mnlio_table_list_add(struct mnl_socket *nf_sock,
+			     struct nft_table_list *nltl,
+			     unsigned int flags)
+{
+	int ret = 0;
+	struct nft_table_list_iter *i;
+	struct nft_table *t;
+
+	i = nft_table_list_iter_create(nltl);
+	if (i == NULL)
+		return -1;
+
+	t = nft_table_list_iter_next(i);
+	while (t != NULL) {
+		ret = nft_mnlio_table_add(nf_sock, t, flags);
+
+		if (ret != 0)
+			break;
+
+		t = nft_table_list_iter_next(i);
+	}
+	nft_table_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_table_list_add);
+
+int nft_mnlio_table_delete(struct mnl_socket *nf_sock, struct nft_table *nlt,
+			   unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_DELTABLE,
+			nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY),
+			NLM_F_ACK, seq);
+	nft_table_nlmsg_build_payload(nlh, nlt);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
+}
+EXPORT_SYMBOL(nft_mnlio_table_delete);
+
+int nft_mnlio_table_list_delete(struct mnl_socket *nfsock,
+				struct nft_table_list *nltl,
+				unsigned int flags)
+{
+	struct nft_table_list_iter *i;
+	struct nft_table *t;
+	int ret = 0;
+
+	i = nft_table_list_iter_create(nltl);
+	if (i == NULL)
+		return -1;
+
+	t = nft_table_list_iter_next(i);
+	while (t != NULL) {
+		ret = nft_mnlio_table_delete(nfsock, t, flags);
+
+		if (ret < 0)
+			break;
+
+		t = nft_table_list_iter_next(i);
+	}
+	nft_table_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_table_list_delete);
+
+static int table_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nft_table_list *nlt_list = data;
+	struct nft_table *t;
+
+	t = nft_table_alloc();
+	if (t == NULL)
+		return -1;
+
+	if (nft_table_nlmsg_parse(nlh, t) < 0)
+		goto err_free;
+
+	nft_table_list_add_tail(t, nlt_list);
+	return MNL_CB_OK;
+
+err_free:
+	nft_table_free(t);
+	return MNL_CB_OK;
+}
+
+struct nft_table_list *
+nft_mnlio_table_dump(struct mnl_socket *nf_sock, int family)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	struct nft_table_list *nlt_list;
+	int ret;
+
+	nlt_list = nft_table_list_alloc();
+	if (nlt_list == NULL)
+		return NULL;
+
+	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family,
+					NLM_F_DUMP, seq);
+
+	ret = nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, table_cb, nlt_list);
+	if (ret < 0)
+		goto err;
+
+	return nlt_list;
+err:
+	nft_table_list_free(nlt_list);
+	return NULL;
+}
+EXPORT_SYMBOL(nft_mnlio_table_dump);
+
+static int table_get_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nft_table *t = data;
+
+	nft_table_nlmsg_parse(nlh, t);
+	return MNL_CB_OK;
+}
+
+int nft_mnlio_table_get(struct mnl_socket *nf_sock, struct nft_table *nlt,
+			unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	uint32_t family;
+
+	family = nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY);
+	nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family,
+					NLM_F_ACK, seq);
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, table_get_cb, nlt);
+}
+EXPORT_SYMBOL(nft_mnlio_table_get);
+
+
+/*
+ * Set
+ */
+static int set_add_cb(const struct nlmsghdr *nlh, void *data)
+{
+	nft_set_nlmsg_parse(nlh, data);
+	return MNL_CB_OK;
+}
+
+int nft_mnlio_set_add(struct mnl_socket *nf_sock, struct nft_set *nls,
+		      unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_NEWSET,
+			nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+			NLM_F_CREATE | NLM_F_ACK | flags, seq);
+	nft_set_nlmsg_build_payload(nlh, nls);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, set_add_cb, nls);
+}
+EXPORT_SYMBOL(nft_mnlio_set_add);
+
+int nft_mnlio_set_list_add(struct mnl_socket *nf_sock,
+			   struct nft_set_list *nlsl,
+			   unsigned int flags)
+{
+	int ret = 0;
+	struct nft_set_list_iter *i;
+	struct nft_set *s;
+
+	i = nft_set_list_iter_create(nlsl);
+	if (i == NULL)
+		return -1;
+
+	s = nft_set_list_iter_next(i);
+	while (s != NULL) {
+		ret = nft_mnlio_set_add(nf_sock, s, flags);
+
+		if (ret != 0)
+			break;
+
+		s = nft_set_list_iter_next(i);
+	}
+	nft_set_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_set_list_add);
+
+int nft_mnlio_set_delete(struct mnl_socket *nf_sock, struct nft_set *nls,
+			 unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_DELSET,
+			nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+			flags|NLM_F_ACK, seq);
+	nft_set_nlmsg_build_payload(nlh, nls);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
+}
+EXPORT_SYMBOL(nft_mnlio_set_delete);
+
+int nft_mnlio_set_list_delete(struct mnl_socket *nfsock,
+			      struct nft_set_list *nlsl, unsigned int flags)
+{
+	struct nft_set_list_iter *i;
+	struct nft_set *s;
+	int ret = 0;
+
+	i = nft_set_list_iter_create(nlsl);
+	if (i == NULL)
+		return -1;
+
+	s = nft_set_list_iter_next(i);
+	while (s != NULL) {
+		ret = nft_mnlio_set_delete(nfsock, s, flags);
+
+		if (ret < 0)
+			break;
+
+		s = nft_set_list_iter_next(i);
+	}
+	nft_set_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_set_list_delete);
+
+static int set_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nft_set_list *nls_list = data;
+	struct nft_set *s;
+
+	s = nft_set_alloc();
+	if (s == NULL)
+		return -1;
+
+	if (nft_set_nlmsg_parse(nlh, s) < 0)
+		goto err_free;
+
+	nft_set_list_add_tail(s, nls_list);
+	return MNL_CB_OK;
+
+err_free:
+	nft_set_free(s);
+	return MNL_CB_OK;
+}
+
+struct nft_set_list *
+nft_mnlio_set_dump(struct mnl_socket *nf_sock, int family, const char *table)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	struct nft_set *s;
+	struct nft_set_list *nls_list;
+	int ret;
+
+	s = nft_set_alloc();
+	if (s == NULL)
+		return NULL;
+
+	nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
+				      NLM_F_DUMP|NLM_F_ACK, seq);
+	if (table != NULL)
+		nft_set_attr_set(s, NFT_SET_ATTR_TABLE, table);
+	nft_set_nlmsg_build_payload(nlh, s);
+	nft_set_free(s);
+
+	nls_list = nft_set_list_alloc();
+	if (nls_list == NULL)
+		return NULL;
+
+	ret = nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, set_cb, nls_list);
+	if (ret < 0)
+		goto err;
+
+	return nls_list;
+err:
+	nft_set_list_free(nls_list);
+	return NULL;
+}
+EXPORT_SYMBOL(nft_mnlio_set_dump);
+
+static int set_get_cb(const struct nlmsghdr *nlh, void *data)
+{
+	struct nft_set *s = data;
+
+	nft_set_nlmsg_parse(nlh, s);
+	return MNL_CB_OK;
+}
+
+int nft_mnlio_set_get(struct mnl_socket *nf_sock, struct nft_set *nls)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET,
+			nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+			NLM_F_ACK, seq);
+	nft_set_nlmsg_build_payload(nlh, nls);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, set_get_cb, nls);
+}
+EXPORT_SYMBOL(nft_mnlio_set_get);
+
+/*
+ * Set elements
+ */
+int nft_mnlio_setelem_add(struct mnl_socket *nf_sock, struct nft_set *nls,
+			  unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_set_elem_nlmsg_build_hdr(buf, NFT_MSG_NEWSETELEM,
+			nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+			NLM_F_CREATE | NLM_F_ACK | flags, seq);
+	nft_set_elems_nlmsg_build_payload(nlh, nls);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
+}
+EXPORT_SYMBOL(nft_mnlio_setelem_add);
+
+int nft_mnlio_setelem_list_add(struct mnl_socket *nf_sock,
+			       struct nft_set_list *nlsl,
+			       unsigned int flags)
+{
+	int ret = 0;
+	struct nft_set_list_iter *i;
+	struct nft_set *s;
+
+	i = nft_set_list_iter_create(nlsl);
+	if (i == NULL)
+		return -1;
+
+	s = nft_set_list_iter_next(i);
+	while (s != NULL) {
+		ret = nft_mnlio_setelem_add(nf_sock, s, flags);
+
+		if (ret != 0)
+			break;
+
+		s = nft_set_list_iter_next(i);
+	}
+	nft_set_list_iter_destroy(i);
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_setelem_list_add);
+
+int nft_mnlio_setelem_delete(struct mnl_socket *nf_sock, struct nft_set *nls,
+			     unsigned int flags)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_set_elem_nlmsg_build_hdr(buf, NFT_MSG_DELSETELEM,
+			nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+			NLM_F_ACK, seq);
+	nft_set_elems_nlmsg_build_payload(nlh, nls);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL);
+}
+EXPORT_SYMBOL(nft_mnlio_setelem_delete);
+
+static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
+{
+	nft_set_elems_nlmsg_parse(nlh, data);
+	return MNL_CB_OK;
+}
+
+int nft_mnlio_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls)
+{
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+
+	nlh = nft_set_elem_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM,
+			nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY),
+			NLM_F_DUMP|NLM_F_ACK, seq);
+	nft_set_nlmsg_build_payload(nlh, nls);
+
+	return nft_mnlio_talk(nf_sock, nlh, nlh->nlmsg_len, set_elem_cb, nls);
+}
+EXPORT_SYMBOL(nft_mnlio_setelem_get);
+
+/*
+ * ruleset
+ */
+struct nft_ruleset *
+nft_mnlio_ruleset_dump(struct mnl_socket *nf_sock, uint32_t family)
+{
+	struct nft_ruleset *rs;
+	struct nft_table_list *t;
+	struct nft_chain_list *c;
+	struct nft_set_list *sl;
+	struct nft_set_list_iter *i;
+	struct nft_set *s;
+	struct nft_rule_list *r;
+	int ret = 0;
+
+	rs = nft_ruleset_alloc();
+	if (rs == NULL)
+		return NULL;
+
+	t = nft_mnlio_table_dump(nf_sock, family);
+	if (t != NULL)
+		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_TABLELIST, t);
+
+	c = nft_mnlio_chain_dump(nf_sock, family);
+	if (c != NULL)
+		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_CHAINLIST, c);
+
+	sl = nft_mnlio_set_dump(nf_sock, family, NULL);
+	if (sl != NULL) {
+		i = nft_set_list_iter_create(sl);
+		s = nft_set_list_iter_next(i);
+		while (s != NULL) {
+			ret = nft_mnlio_setelem_get(nf_sock, s);
+			if (ret != 0)
+				goto out;
+
+			s = nft_set_list_iter_next(i);
+		}
+		nft_set_list_iter_destroy(i);
+
+		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_SETLIST, sl);
+	}
+
+	r = nft_mnlio_rule_dump(nf_sock, family);
+	if (r != NULL)
+		nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, r);
+
+	if (!(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_TABLELIST)) &&
+	    !(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_CHAINLIST)) &&
+	    !(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_SETLIST)) &&
+	    !(nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_RULELIST)))
+		goto out;
+
+	return rs;
+out:
+	nft_ruleset_free(rs);
+	return NULL;
+}
+EXPORT_SYMBOL(nft_mnlio_ruleset_dump);
+
+int nft_mnlio_ruleset_add(struct mnl_socket *nf_sock, struct nft_ruleset *rs,
+			  unsigned int tflags, unsigned int cflags,
+			  unsigned int rflags, unsigned int sflags,
+			  unsigned int seflags, struct mnl_nlmsg_batch *batch)
+{
+	int ret = 0;
+	struct nft_table_list *t;
+	struct nft_chain_list *c;
+	struct nft_set_list *s;
+	struct nft_rule_list *r;
+
+	if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_TABLELIST)) {
+		t = (struct nft_table_list *)
+		     nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_TABLELIST);
+		ret = nft_mnlio_table_list_add(nf_sock, t, tflags);
+		if (ret != 0)
+			return ret;
+	}
+
+	if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_CHAINLIST)) {
+		c = (struct nft_chain_list *)
+		     nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_CHAINLIST);
+		ret = nft_mnlio_chain_list_add(nf_sock, c, cflags);
+		if (ret != 0)
+			return ret;
+	}
+
+	if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_SETLIST)) {
+		s = (struct nft_set_list *)
+		     nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_SETLIST);
+		ret = nft_mnlio_set_list_add(nf_sock, s, sflags);
+		if (ret != 0)
+			return ret;
+
+		ret = nft_mnlio_setelem_list_add(nf_sock, s, seflags);
+		if (ret != 0)
+			return ret;
+
+	}
+
+	if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_RULELIST)) {
+		r = (struct nft_rule_list *)
+		     nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_RULELIST);
+		ret = nft_mnlio_rule_list_add(r, rflags, batch);
+		if (ret != 0)
+			return ret;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(nft_mnlio_ruleset_add);

--
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