diff options
Diffstat (limited to 'src/mnl.c')
-rw-r--r-- | src/mnl.c | 82 |
1 files changed, 46 insertions, 36 deletions
@@ -82,8 +82,6 @@ nft_mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len, */ #define BATCH_PAGE_SIZE getpagesize() * 32 -static struct mnl_nlmsg_batch *batch; - static struct mnl_nlmsg_batch *mnl_batch_alloc(void) { static char *buf; @@ -93,11 +91,6 @@ static struct mnl_nlmsg_batch *mnl_batch_alloc(void) return mnl_nlmsg_batch_start(buf, BATCH_PAGE_SIZE); } -void mnl_batch_init(void) -{ - batch = mnl_batch_alloc(); -} - static LIST_HEAD(batch_page_list); static int batch_num_pages; @@ -106,35 +99,53 @@ struct batch_page { struct mnl_nlmsg_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(batch); + return mnl_nlmsg_batch_current(nft_batch_page_current()->batch); } -static void mnl_batch_page_add(void) +static void nft_batch_page_add(void) { - struct batch_page *batch_page; struct nlmsghdr *last_nlh; /* Get the last message not fitting in the batch */ last_nlh = nft_nlmsg_batch_current(); - - batch_page = xmalloc(sizeof(struct batch_page)); - batch_page->batch = batch; - list_add_tail(&batch_page->head, &batch_page_list); - batch_num_pages++; - batch = mnl_batch_alloc(); - + /* 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(batch); + 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--; } static void nft_batch_continue(void) { - if (!mnl_nlmsg_batch_next(batch)) - mnl_batch_page_add(); + if (!mnl_nlmsg_batch_next(nft_batch_page_current()->batch)) + nft_batch_page_add(); } static uint32_t mnl_batch_put(int type) @@ -171,12 +182,16 @@ 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(batch) != (NLMSG_HDRLEN+sizeof(struct nfgenmsg)) * 2; + return mnl_nlmsg_batch_size(nft_batch_page_current()->batch) != + (NLMSG_HDRLEN+sizeof(struct nfgenmsg)) * 2; } void mnl_batch_reset(void) { - mnl_nlmsg_batch_reset(batch); + struct batch_page *batch_page, *next; + + list_for_each_entry_safe(batch_page, next, &batch_page_list, head) + nft_batch_page_release(batch_page); } static void mnl_err_list_node_add(struct list_head *err_list, int error, @@ -226,12 +241,12 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) .msg_iov = iov, .msg_iovlen = batch_num_pages, }; - struct batch_page *batch_page, *next; + struct batch_page *batch_page; int i = 0; mnl_set_sndbuffer(nl); - list_for_each_entry_safe(batch_page, next, &batch_page_list, head) { + 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++; @@ -243,10 +258,6 @@ static ssize_t mnl_nft_socket_sendmsg(const struct mnl_socket *nl) sizeof(struct nfgenmsg)); } #endif - list_del(&batch_page->head); - xfree(batch_page->batch); - xfree(batch_page); - batch_num_pages--; } return sendmsg(mnl_socket_get_fd(nl), &msg, 0); @@ -262,12 +273,13 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) .tv_usec = 0 }; - if (!mnl_nlmsg_batch_is_empty(batch)) - mnl_batch_page_add(); + /* 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) - goto err; + return -1; FD_ZERO(&readfds); FD_SET(fd, &readfds); @@ -275,14 +287,14 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) /* receive and digest all the acknowledgments from the kernel. */ ret = select(fd+1, &readfds, NULL, NULL, &tv); if (ret == -1) - goto err; + return -1; while (ret > 0 && FD_ISSET(fd, &readfds)) { struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf; ret = mnl_socket_recvfrom(nl, rcv_buf, sizeof(rcv_buf)); if (ret == -1) - goto err; + return -1; ret = mnl_cb_run(rcv_buf, ret, 0, portid, NULL, NULL); /* Continue on error, make sure we get all acknowledgments */ @@ -291,13 +303,11 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) ret = select(fd+1, &readfds, NULL, NULL, &tv); if (ret == -1) - goto err; + return -1; FD_ZERO(&readfds); FD_SET(fd, &readfds); } -err: - mnl_nlmsg_batch_reset(batch); return ret; } |