summaryrefslogtreecommitdiffstats
path: root/src/netlink.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2013-09-22 20:41:03 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2013-09-23 20:28:22 +0200
commita72315d2bad47d99a18376290dd62336ca94ed95 (patch)
treef0c194f4ac38b1363b58fc33cd83c2b547b52bcb /src/netlink.c
parente391b72b611403d184bbb26e3d076d543c7ea7c6 (diff)
src: add rule batching support
This patch allows nft to put all rule update messages into one single batch that is sent to the kernel if `-f' option is used. In order to provide fine grain error reporting, I decided to to correlate the netlink message sequence number with the correspoding command sequence number, which is the same. Thus, nft can identify what rules trigger problems inside a batch and report them accordingly. Moreover, to avoid playing buffer size games at batch building stage, ie. guess what is the final size of the batch for this ruleset update will be, this patch collects batch pages that are converted to iovec to ensure linearization when the batch is sent to the kernel. This reduces the amount of unnecessary memory usage that is allocated for the batch. This patch uses the libmnl nlmsg batching infrastructure and it requires the kernel patch entitled (netfilter: nfnetlink: add batch support and use it from nf_tables). Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/netlink.c')
-rw-r--r--src/netlink.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/src/netlink.c b/src/netlink.c
index 9a766cb1..c48e667b 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -37,6 +37,7 @@ static void __init netlink_open_sock(void)
memory_allocation_error();
fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK);
+ mnl_batch_init();
}
static void __exit netlink_close_sock(void)
@@ -44,8 +45,8 @@ static void __exit netlink_close_sock(void)
mnl_socket_close(nf_sock);
}
-static int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc,
- const char *fmt, ...)
+int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc,
+ const char *fmt, ...)
{
struct error_record *erec;
va_list ap;
@@ -305,8 +306,9 @@ struct expr *netlink_alloc_data(const struct location *loc,
}
}
-int netlink_add_rule(struct netlink_ctx *ctx, const struct handle *h,
- const struct rule *rule, uint32_t flags)
+int netlink_add_rule_batch(struct netlink_ctx *ctx,
+ const struct handle *h,
+ const struct rule *rule, uint32_t flags)
{
struct nft_rule *nlr;
int err;
@@ -314,29 +316,44 @@ int netlink_add_rule(struct netlink_ctx *ctx, const struct handle *h,
nlr = alloc_nft_rule(&rule->handle);
err = netlink_linearize_rule(ctx, nlr, rule);
if (err == 0) {
- err = mnl_nft_rule_add(nf_sock, nlr, flags | NLM_F_EXCL);
+ err = mnl_nft_rule_batch_add(nlr, flags | NLM_F_EXCL,
+ ctx->seqnum);
if (err < 0)
netlink_io_error(ctx, &rule->location,
- "Could not add rule: %s",
+ "Could not add rule to batch: %s",
strerror(errno));
}
nft_rule_free(nlr);
return err;
}
-int netlink_delete_rule(struct netlink_ctx *ctx, const struct handle *h,
- const struct location *loc)
+int netlink_add_rule_list(struct netlink_ctx *ctx, const struct handle *h,
+ struct list_head *rule_list)
+{
+ struct rule *rule;
+
+ list_for_each_entry(rule, rule_list, list) {
+ if (netlink_add_rule_batch(ctx, &rule->handle, rule,
+ NLM_F_APPEND) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+int netlink_del_rule_batch(struct netlink_ctx *ctx, const struct handle *h,
+ const struct location *loc)
{
struct nft_rule *nlr;
int err;
nlr = alloc_nft_rule(h);
- err = mnl_nft_rule_delete(nf_sock, nlr, 0);
+ err = mnl_nft_rule_batch_del(nlr, 0, ctx->seqnum);
nft_rule_free(nlr);
if (err < 0)
- netlink_io_error(ctx, loc, "Could not delete rule: %s",
+ netlink_io_error(ctx, loc, "Could not delete rule to batch: %s",
strerror(errno));
+
return err;
}
@@ -408,7 +425,7 @@ static int flush_rule_cb(struct nft_rule *nlr, void *arg)
int err;
netlink_dump_rule(nlr);
- err = mnl_nft_rule_delete(nf_sock, nlr, 0);
+ err = mnl_nft_rule_batch_del(nlr, 0, ctx->seqnum);
if (err < 0) {
netlink_io_error(ctx, NULL, "Could not delete rule: %s",
strerror(errno));
@@ -429,10 +446,12 @@ static int netlink_flush_rules(struct netlink_ctx *ctx, const struct handle *h,
"Could not receive rules from kernel: %s",
strerror(errno));
+ mnl_batch_begin();
nlr = alloc_nft_rule(h);
nft_rule_list_foreach(rule_cache, flush_rule_cb, ctx);
nft_rule_free(nlr);
nft_rule_list_free(rule_cache);
+ mnl_batch_end();
return 0;
}
@@ -1035,3 +1054,8 @@ out:
strerror(errno));
return err;
}
+
+int netlink_batch_send(struct list_head *err_list)
+{
+ return mnl_batch_talk(nf_sock, err_list);
+}