diff options
-rw-r--r-- | src/main.c | 26 | ||||
-rw-r--r-- | src/mnl.c | 82 | ||||
-rw-r--r-- | src/netlink.c | 1 |
3 files changed, 60 insertions, 49 deletions
@@ -166,13 +166,15 @@ static const struct input_descriptor indesc_cmdline = { static int nft_netlink(struct parser_state *state, struct list_head *msgs) { struct netlink_ctx ctx; - struct cmd *cmd, *next; + struct cmd *cmd; struct mnl_err *err, *tmp; LIST_HEAD(err_list); uint32_t batch_seqnum; bool batch_supported = netlink_batch_supported(); int ret = 0; + mnl_batch_init(); + batch_seqnum = mnl_batch_begin(); list_for_each_entry(cmd, &state->cmds, list) { memset(&ctx, 0, sizeof(ctx)); @@ -182,16 +184,14 @@ static int nft_netlink(struct parser_state *state, struct list_head *msgs) init_list_head(&ctx.list); ret = do_command(&ctx, cmd); if (ret < 0) - return ret; + goto out; } mnl_batch_end(); - if (mnl_batch_ready()) - ret = netlink_batch_send(&err_list); - else { - mnl_batch_reset(); + if (!mnl_batch_ready()) goto out; - } + + ret = netlink_batch_send(&err_list); list_for_each_entry_safe(err, tmp, &err_list, head) { list_for_each_entry(cmd, &state->cmds, list) { @@ -208,16 +208,13 @@ static int nft_netlink(struct parser_state *state, struct list_head *msgs) } } out: - list_for_each_entry_safe(cmd, next, &state->cmds, list) { - list_del(&cmd->list); - cmd_free(cmd); - } - + mnl_batch_reset(); return ret; } int nft_run(void *scanner, struct parser_state *state, struct list_head *msgs) { + struct cmd *cmd, *next; int ret; ret = nft_parse(scanner, state); @@ -230,6 +227,11 @@ retry: goto retry; } + list_for_each_entry_safe(cmd, next, &state->cmds, list) { + list_del(&cmd->list); + cmd_free(cmd); + } + return ret; } @@ -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; } diff --git a/src/netlink.c b/src/netlink.c index 05fae103..e1492152 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -59,7 +59,6 @@ static void __init netlink_open_sock(void) { nf_sock = nfsock_open(); fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK); - mnl_batch_init(); } static void __exit netlink_close_sock(void) |