All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3 libnftnl] common: add batching interfaces
@ 2014-08-13 16:54 Pablo Neira Ayuso
  2014-08-13 16:54 ` [PATCH 2/3 libnftnl] examples: nft-chain-add: add chain_add_parse() Pablo Neira Ayuso
  2014-08-13 16:54 ` [PATCH 3/3 libnftnl] examples: nft-chain-add: support new batching interface Pablo Neira Ayuso
  0 siblings, 2 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2014-08-13 16:54 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, Arturo Borrero Gonzalez

This patch adds the following new interfaces:

 int nft_batch_is_supported(void);
 void nft_batch_begin(char *buf, uint32_t seq);
 void nft_batch_end(char *buf, uint32_t seq);

Quite likely this is going to be reused by third party applications
requiring to put things in the batch. We already have potential clients
for this code in nft and iptables-compat.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/libnftnl/common.h |    7 ++++
 src/common.c              |   89 +++++++++++++++++++++++++++++++++++++++++++++
 src/libnftnl.map          |    3 ++
 3 files changed, 99 insertions(+)

diff --git a/include/libnftnl/common.h b/include/libnftnl/common.h
index 04d2906..2b498d4 100644
--- a/include/libnftnl/common.h
+++ b/include/libnftnl/common.h
@@ -36,4 +36,11 @@ struct nlmsghdr *nft_nlmsg_build_hdr(char *buf, uint16_t cmd, uint16_t family,
 struct nft_parse_err *nft_parse_err_alloc(void);
 void nft_parse_err_free(struct nft_parse_err *);
 int nft_parse_perror(const char *str, struct nft_parse_err *err);
+
+struct mnl_socket;
+
+int nft_batch_is_supported(void);
+void nft_batch_begin(char *buf, uint32_t seq);
+void nft_batch_end(char *buf, uint32_t seq);
+
 #endif
diff --git a/src/common.c b/src/common.c
index 1b600f1..a571fe7 100644
--- a/src/common.c
+++ b/src/common.c
@@ -9,12 +9,15 @@
 
 #include <stdlib.h>
 #include <sys/socket.h>
+#include <time.h>
 #include <linux/netlink.h>
 #include <linux/netfilter/nfnetlink.h>
 
 #include <libmnl/libmnl.h>
 #include <libnftnl/common.h>
+#include <libnftnl/set.h>
 
+#include <errno.h>
 #include "internal.h"
 
 struct nlmsghdr *nft_nlmsg_build_hdr(char *buf, uint16_t cmd, uint16_t family,
@@ -137,6 +140,34 @@ int nft_event_footer_snprintf(char *buf, size_t size, uint32_t type,
 	}
 }
 
+static void nft_batch_build_hdr(char *buf, uint16_t type, uint32_t seq)
+{
+	struct nlmsghdr *nlh;
+	struct nfgenmsg *nfg;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type = type;
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+	nlh->nlmsg_seq = seq;
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_UNSPEC;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = NFNL_SUBSYS_NFTABLES;
+}
+
+void nft_batch_begin(char *buf, uint32_t seq)
+{
+	nft_batch_build_hdr(buf, NFNL_MSG_BATCH_BEGIN, seq);
+}
+EXPORT_SYMBOL(nft_batch_begin);
+
+void nft_batch_end(char *buf, uint32_t seq)
+{
+	nft_batch_build_hdr(buf, NFNL_MSG_BATCH_END, seq);
+}
+EXPORT_SYMBOL(nft_batch_end);
+
 int nft_event_footer_fprintf(FILE *fp, uint32_t type, uint32_t flags)
 {
 	char buf[32]; /* enough for the maximum string length above */
@@ -146,3 +177,61 @@ int nft_event_footer_fprintf(FILE *fp, uint32_t type, uint32_t flags)
 
 	return fprintf(fp, "%s", buf);
 }
+
+int nft_batch_is_supported(void)
+{
+	struct mnl_socket *nl;
+	struct mnl_nlmsg_batch *b;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	uint32_t seq = time(NULL);
+	int ret;
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL)
+		return -1;
+
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
+		return -1;
+
+	b = mnl_nlmsg_batch_start(buf, sizeof(buf));
+
+	nft_batch_begin(mnl_nlmsg_batch_current(b), seq++);
+	mnl_nlmsg_batch_next(b);
+
+	nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(b),
+				NFT_MSG_NEWSET, AF_INET,
+				NLM_F_ACK, seq++);
+	mnl_nlmsg_batch_next(b);
+
+	nft_batch_end(mnl_nlmsg_batch_current(b), seq++);
+	mnl_nlmsg_batch_next(b);
+
+	ret = mnl_socket_sendto(nl, mnl_nlmsg_batch_head(b),
+				mnl_nlmsg_batch_size(b));
+	if (ret < 0)
+		goto err;
+
+	mnl_nlmsg_batch_stop(b);
+
+	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	while (ret > 0) {
+		ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(nl),
+				 NULL, NULL);
+		if (ret <= 0)
+			break;
+
+		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	}
+	mnl_socket_close(nl);
+
+	/* We're sending an incomplete message to see if the kernel supports
+	 * set messages in batches. EINVAL means that we sent an incomplete
+	 * message with missing attributes. The kernel just ignores messages
+	 * that we cannot include in the batch.
+	 */
+	return (ret == -1 && errno == EINVAL) ? 1 : 0;
+err:
+	mnl_nlmsg_batch_stop(b);
+	return -1;
+}
+EXPORT_SYMBOL(nft_batch_is_supported);
diff --git a/src/libnftnl.map b/src/libnftnl.map
index e8c634f..d8dcf8e 100644
--- a/src/libnftnl.map
+++ b/src/libnftnl.map
@@ -209,4 +209,7 @@ LIBNFTNL_1.1 {
 
 LIBNFTNL_1.2 {
   nft_set_elems_nlmsg_build_payload_iter;
+  nft_batch_is_supported;
+  nft_batch_begin;
+  nft_batch_end;
 } LIBNFTNL_1.1;
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/3 libnftnl] examples: nft-chain-add: add chain_add_parse()
  2014-08-13 16:54 [PATCH 1/3 libnftnl] common: add batching interfaces Pablo Neira Ayuso
@ 2014-08-13 16:54 ` Pablo Neira Ayuso
  2014-08-13 16:54 ` [PATCH 3/3 libnftnl] examples: nft-chain-add: support new batching interface Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2014-08-13 16:54 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, Arturo Borrero Gonzalez

This function parses the command line options and it creates the
nft_chain object.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 examples/nft-chain-add.c |   73 +++++++++++++++++++++++++++-------------------
 1 file changed, 43 insertions(+), 30 deletions(-)

diff --git a/examples/nft-chain-add.c b/examples/nft-chain-add.c
index 3edff86..4d32ddd 100644
--- a/examples/nft-chain-add.c
+++ b/examples/nft-chain-add.c
@@ -20,14 +20,52 @@
 #include <libmnl/libmnl.h>
 #include <libnftnl/chain.h>
 
+static struct nft_chain *chain_add_parse(int argc, char *argv[])
+{
+	struct nft_chain *t;
+	int hooknum = 0;
+
+	if (argc == 6) {
+		/* This is a base chain, set the hook number */
+		if (strcmp(argv[4], "NF_INET_LOCAL_IN") == 0)
+			hooknum = NF_INET_LOCAL_IN;
+		else if (strcmp(argv[4], "NF_INET_LOCAL_OUT") == 0)
+			hooknum = NF_INET_LOCAL_OUT;
+		else if (strcmp(argv[4], "NF_INET_PRE_ROUTING") == 0)
+			hooknum = NF_INET_PRE_ROUTING;
+		else if (strcmp(argv[4], "NF_INET_POST_ROUTING") == 0)
+			hooknum = NF_INET_POST_ROUTING;
+		else if (strcmp(argv[4], "NF_INET_FORWARD") == 0)
+			hooknum = NF_INET_FORWARD;
+		else {
+			fprintf(stderr, "Unknown hook: %s\n", argv[4]);
+			return NULL;
+		}
+	}
+
+	t = nft_chain_alloc();
+	if (t == NULL) {
+		perror("OOM");
+		return NULL;
+	}
+	nft_chain_attr_set(t, NFT_CHAIN_ATTR_TABLE, argv[2]);
+	nft_chain_attr_set(t, NFT_CHAIN_ATTR_NAME, argv[3]);
+	if (argc == 6) {
+		nft_chain_attr_set_u32(t, NFT_CHAIN_ATTR_HOOKNUM, hooknum);
+		nft_chain_attr_set_u32(t, NFT_CHAIN_ATTR_PRIO, atoi(argv[5]));
+	}
+
+	return t;
+}
+
 int main(int argc, char *argv[])
 {
 	struct mnl_socket *nl;
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nlmsghdr *nlh;
 	uint32_t portid, seq;
-	struct nft_chain *t = NULL;
-	int ret, family, hooknum = 0;
+	int ret, family;
+	struct nft_chain *t;
 
 	if (argc != 4 && argc != 6) {
 		fprintf(stderr, "Usage: %s <family> <table> <chain> "
@@ -49,38 +87,13 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	if (argc == 6) {
-		/* This is a base chain, set the hook number */
-		if (strcmp(argv[4], "NF_INET_LOCAL_IN") == 0)
-			hooknum = NF_INET_LOCAL_IN;
-		else if (strcmp(argv[4], "NF_INET_LOCAL_OUT") == 0)
-			hooknum = NF_INET_LOCAL_OUT;
-		else if (strcmp(argv[4], "NF_INET_PRE_ROUTING") == 0)
-			hooknum = NF_INET_PRE_ROUTING;
-		else if (strcmp(argv[4], "NF_INET_POST_ROUTING") == 0)
-			hooknum = NF_INET_POST_ROUTING;
-		else if (strcmp(argv[4], "NF_INET_FORWARD") == 0)
-			hooknum = NF_INET_FORWARD;
-		else {
-			fprintf(stderr, "Unknown hook: %s\n", argv[4]);
-			exit(EXIT_FAILURE);
-		}
-	}
-
-	t = nft_chain_alloc();
-	if (t == NULL) {
-		perror("OOM");
+	t = chain_add_parse(argc, argv);
+	if (t == NULL)
 		exit(EXIT_FAILURE);
-	}
+
 	seq = time(NULL);
 	nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, family,
 					NLM_F_EXCL|NLM_F_ACK, seq);
-	nft_chain_attr_set(t, NFT_CHAIN_ATTR_TABLE, argv[2]);
-	nft_chain_attr_set(t, NFT_CHAIN_ATTR_NAME, argv[3]);
-	if (argc == 6) {
-		nft_chain_attr_set_u32(t, NFT_CHAIN_ATTR_HOOKNUM, hooknum);
-		nft_chain_attr_set_u32(t, NFT_CHAIN_ATTR_PRIO, atoi(argv[5]));
-	}
 	nft_chain_nlmsg_build_payload(nlh, t);
 	nft_chain_free(t);
 
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 3/3 libnftnl] examples: nft-chain-add: support new batching interface
  2014-08-13 16:54 [PATCH 1/3 libnftnl] common: add batching interfaces Pablo Neira Ayuso
  2014-08-13 16:54 ` [PATCH 2/3 libnftnl] examples: nft-chain-add: add chain_add_parse() Pablo Neira Ayuso
@ 2014-08-13 16:54 ` Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2014-08-13 16:54 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, Arturo Borrero Gonzalez

Chains are included in the batch since 3.16. Add support for adding
the chains dependending on the available interface.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 examples/nft-chain-add.c |   34 +++++++++++++++++++++++++++++-----
 1 file changed, 29 insertions(+), 5 deletions(-)

diff --git a/examples/nft-chain-add.c b/examples/nft-chain-add.c
index 4d32ddd..f7f640a 100644
--- a/examples/nft-chain-add.c
+++ b/examples/nft-chain-add.c
@@ -63,9 +63,11 @@ int main(int argc, char *argv[])
 	struct mnl_socket *nl;
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nlmsghdr *nlh;
-	uint32_t portid, seq;
+	uint32_t portid, seq, chain_seq;
 	int ret, family;
 	struct nft_chain *t;
+	struct mnl_nlmsg_batch *batch;
+	int batching;
 
 	if (argc != 4 && argc != 6) {
 		fprintf(stderr, "Usage: %s <family> <table> <chain> "
@@ -91,11 +93,32 @@ int main(int argc, char *argv[])
 	if (t == NULL)
 		exit(EXIT_FAILURE);
 
+	batching = nft_batch_is_supported();
+	if (batching < 0) {
+		perror("cannot talk to nfnetlink");
+		exit(EXIT_FAILURE);
+	}
+
 	seq = time(NULL);
-	nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, family,
-					NLM_F_EXCL|NLM_F_ACK, seq);
+	batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
+
+	if (batching) {
+		nft_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
+		mnl_nlmsg_batch_next(batch);
+	}
+
+	chain_seq = seq;
+	nlh = nft_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
+					NFT_MSG_NEWCHAIN, family,
+					NLM_F_ACK, seq++);
 	nft_chain_nlmsg_build_payload(nlh, t);
 	nft_chain_free(t);
+	mnl_nlmsg_batch_next(batch);
+
+	if (batching) {
+		nft_batch_end(mnl_nlmsg_batch_current(batch), seq++);
+		mnl_nlmsg_batch_next(batch);
+	}
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
@@ -109,14 +132,15 @@ int main(int argc, char *argv[])
 	}
 	portid = mnl_socket_get_portid(nl);
 
-	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+	if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
+			      mnl_nlmsg_batch_size(batch)) < 0) {
 		perror("mnl_socket_send");
 		exit(EXIT_FAILURE);
 	}
 
 	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
 	while (ret > 0) {
-		ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
+		ret = mnl_cb_run(buf, ret, chain_seq, portid, NULL, NULL);
 		if (ret <= 0)
 			break;
 		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2014-08-13 16:54 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-13 16:54 [PATCH 1/3 libnftnl] common: add batching interfaces Pablo Neira Ayuso
2014-08-13 16:54 ` [PATCH 2/3 libnftnl] examples: nft-chain-add: add chain_add_parse() Pablo Neira Ayuso
2014-08-13 16:54 ` [PATCH 3/3 libnftnl] examples: nft-chain-add: support new batching interface Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.