Each batch page has a size of 320 Kbytes, and the limit has been set to 256 KBytes, so the overrun area is 64 KBytes long to accomodate the largest netlink message (sets). Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- src/mnl.c | 124 ++++++++++++++++--------------------------------------------- 1 file changed, 33 insertions(+), 91 deletions(-) diff --git a/src/mnl.c b/src/mnl.c index 89c2bb5..76a9714 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -16,6 +16,7 @@ #include <libnftnl/rule.h> #include <libnftnl/expr.h> #include <libnftnl/set.h> +#include <libnftnl/batch.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nf_tables.h> @@ -126,77 +127,26 @@ static int check_genid(const struct nlmsghdr *nlh) */ #define BATCH_PAGE_SIZE getpagesize() * 32 -static struct mnl_nlmsg_batch *mnl_batch_alloc(void) -{ - static char *buf; - - /* libmnl needs higher buffer to handle batch overflows. */ - buf = xmalloc(BATCH_PAGE_SIZE + NFT_NLMSG_MAXSIZE); - return mnl_nlmsg_batch_start(buf, BATCH_PAGE_SIZE); -} - -static LIST_HEAD(batch_page_list); -static int batch_num_pages; - -struct batch_page { - struct list_head head; - struct mnl_nlmsg_batch *batch; -}; +static struct nft_batch *batch; void mnl_batch_init(void) { - struct batch_page *batch_page; - - batch_page = xmalloc(sizeof(struct batch_page)); - batch_page->batch = mnl_batch_alloc(); - batch_num_pages++; - list_add_tail(&batch_page->head, &batch_page_list); -} - -static struct batch_page *nft_batch_page_current(void) -{ - return list_entry(batch_page_list.prev, struct batch_page, head); -} - -static void *nft_nlmsg_batch_current(void) -{ - return mnl_nlmsg_batch_current(nft_batch_page_current()->batch); -} - -static void nft_batch_page_add(void) -{ - struct nlmsghdr *last_nlh; - - /* Get the last message not fitting in the batch */ - last_nlh = nft_nlmsg_batch_current(); - /* Add new batch page */ - mnl_batch_init(); - /* Copy the last message not fitting to the new batch page */ - memcpy(nft_nlmsg_batch_current(), last_nlh, last_nlh->nlmsg_len); - /* No overflow may happen as this is a new empty batch page */ - mnl_nlmsg_batch_next(nft_batch_page_current()->batch); -} - -static void nft_batch_page_release(struct batch_page *batch_page) -{ - list_del(&batch_page->head); - xfree(mnl_nlmsg_batch_head(batch_page->batch)); - mnl_nlmsg_batch_stop(batch_page->batch); - xfree(batch_page); - batch_num_pages--; + batch = nft_batch_alloc(BATCH_PAGE_SIZE, NFT_NLMSG_MAXSIZE); + if (batch == NULL) + memory_allocation_error(); } static void nft_batch_continue(void) { - if (!mnl_nlmsg_batch_next(nft_batch_page_current()->batch)) - nft_batch_page_add(); + if (nft_batch_update(batch) < 0) + memory_allocation_error(); } uint32_t mnl_batch_begin(void) { uint32_t seq = mnl_seqnum_alloc(); - nft_batch_begin(nft_nlmsg_batch_current(), seq); + nft_batch_begin(nft_batch_buffer(batch), seq); nft_batch_continue(); return seq; @@ -204,7 +154,7 @@ uint32_t mnl_batch_begin(void) void mnl_batch_end(void) { - nft_batch_end(nft_nlmsg_batch_current(), mnl_seqnum_alloc()); + nft_batch_end(nft_batch_buffer(batch), mnl_seqnum_alloc()); nft_batch_continue(); } @@ -213,16 +163,13 @@ bool mnl_batch_ready(void) /* Check if the batch only contains the initial and trailing batch * messages. In that case, the batch is empty. */ - return mnl_nlmsg_batch_size(nft_batch_page_current()->batch) != - (NLMSG_HDRLEN+sizeof(struct nfgenmsg)) * 2; + return nft_batch_buffer_len(batch) != + (NLMSG_HDRLEN + sizeof(struct nfgenmsg)) * 2; } void mnl_batch_reset(void) { - struct batch_page *batch_page, *next; - - list_for_each_entry_safe(batch_page, next, &batch_page_list, head) - nft_batch_page_release(batch_page); + nft_batch_free(batch); } static void mnl_err_list_node_add(struct list_head *err_list, int error, @@ -247,10 +194,10 @@ static void mnl_set_sndbuffer(const struct mnl_socket *nl) { int newbuffsiz; - if (batch_num_pages * BATCH_PAGE_SIZE <= nlbuffsiz) + if (nft_batch_iovec_len(batch) * BATCH_PAGE_SIZE <= nlbuffsiz) return; - newbuffsiz = batch_num_pages * BATCH_PAGE_SIZE; + newbuffsiz = nft_batch_iovec_len(batch) * BATCH_PAGE_SIZE; /* Rise sender buffer length to avoid hitting -EMSGSIZE */ if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE, @@ -265,27 +212,26 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK }; - struct iovec iov[batch_num_pages]; + uint32_t iov_len = nft_batch_iovec_len(batch); + struct iovec iov[iov_len]; struct msghdr msg = { .msg_name = (struct sockaddr *) &snl, .msg_namelen = sizeof(snl), .msg_iov = iov, - .msg_iovlen = batch_num_pages, + .msg_iovlen = iov_len, }; - struct batch_page *batch_page; - int i = 0; +#ifdef DEBUG + uint32_t i; +#endif mnl_set_sndbuffer(nl); + nft_batch_iovec(batch, iov, iov_len); - list_for_each_entry(batch_page, &batch_page_list, head) { - iov[i].iov_base = mnl_nlmsg_batch_head(batch_page->batch); - iov[i].iov_len = mnl_nlmsg_batch_size(batch_page->batch); - i++; #ifdef DEBUG + for (i = 0; i < iov_len; i++) { if (debug_level & DEBUG_MNL) { mnl_nlmsg_fprintf(stdout, - mnl_nlmsg_batch_head(batch_page->batch), - mnl_nlmsg_batch_size(batch_page->batch), + iov[i].iov_base, iov[i].iov_len, sizeof(struct nfgenmsg)); } #endif @@ -304,10 +250,6 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) .tv_usec = 0 }; - /* Remove last page from the batch if it's empty */ - if (mnl_nlmsg_batch_is_empty(nft_batch_page_current()->batch)) - nft_batch_page_release(nft_batch_page_current()); - ret = mnl_nft_socket_sendmsg(nl); if (ret == -1) return -1; @@ -347,7 +289,7 @@ int mnl_nft_rule_batch_add(struct nft_rule *nlr, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_rule_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_rule_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_NEWRULE, nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY), NLM_F_CREATE | flags, seqnum); @@ -363,7 +305,7 @@ int mnl_nft_rule_batch_del(struct nft_rule *nlr, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_rule_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_rule_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_DELRULE, nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY), 0, seqnum); @@ -476,7 +418,7 @@ int mnl_nft_chain_batch_add(struct nft_chain *nlc, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_chain_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_chain_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_NEWCHAIN, nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY), NLM_F_CREATE | flags, seqnum); @@ -505,7 +447,7 @@ int mnl_nft_chain_batch_del(struct nft_chain *nlc, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_chain_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_chain_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_DELCHAIN, nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY), NLM_F_ACK, seqnum); @@ -604,7 +546,7 @@ int mnl_nft_table_batch_add(struct nft_table *nlt, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_table_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_table_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_NEWTABLE, nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY), flags, seqnum); @@ -633,7 +575,7 @@ int mnl_nft_table_batch_del(struct nft_table *nlt, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_table_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_table_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_DELTABLE, nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY), NLM_F_ACK, seqnum); @@ -754,7 +696,7 @@ int mnl_nft_set_batch_add(struct nft_set *nls, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_set_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_set_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_NEWSET, nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), NLM_F_CREATE | flags, seqnum); @@ -769,7 +711,7 @@ int mnl_nft_set_batch_del(struct nft_set *nls, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_set_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_set_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_DELSET, nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), flags, seqnum); @@ -920,7 +862,7 @@ int mnl_nft_setelem_batch_add(struct nft_set *nls, unsigned int flags, memory_allocation_error(); do { - nlh = nft_set_elem_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_set_elem_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_NEWSETELEM, nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), NLM_F_CREATE | flags, seqnum); @@ -938,7 +880,7 @@ int mnl_nft_setelem_batch_del(struct nft_set *nls, unsigned int flags, { struct nlmsghdr *nlh; - nlh = nft_set_elem_nlmsg_build_hdr(nft_nlmsg_batch_current(), + nlh = nft_set_elem_nlmsg_build_hdr(nft_batch_buffer(batch), NFT_MSG_DELSETELEM, nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), 0, seqnum); -- 1.7.10.4 -- 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