libnftnl 1.2.9
batch.c
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright (c) 2013-2015 Pablo Neira Ayuso <pablo@netfilter.org>
4 */
5
6#include "internal.h"
7#include <errno.h>
8#include <libmnl/libmnl.h>
9#include <libnftnl/batch.h>
10
12 uint32_t num_pages;
13 struct nftnl_batch_page *current_page;
14 uint32_t page_size;
15 uint32_t page_overrun_size;
16 struct list_head page_list;
17};
18
20 struct list_head head;
21 struct mnl_nlmsg_batch *batch;
22};
23
24static struct nftnl_batch_page *nftnl_batch_page_alloc(struct nftnl_batch *batch)
25{
26 struct nftnl_batch_page *page;
27 char *buf;
28
29 page = malloc(sizeof(struct nftnl_batch_page));
30 if (page == NULL)
31 return NULL;
32
33 buf = malloc(batch->page_size + batch->page_overrun_size);
34 if (buf == NULL)
35 goto err1;
36
37 page->batch = mnl_nlmsg_batch_start(buf, batch->page_size);
38 if (page->batch == NULL)
39 goto err2;
40
41 return page;
42err2:
43 free(buf);
44err1:
45 free(page);
46 return NULL;
47}
48
49static void nftnl_batch_add_page(struct nftnl_batch_page *page,
50 struct nftnl_batch *batch)
51{
52 batch->current_page = page;
53 batch->num_pages++;
54 list_add_tail(&page->head, &batch->page_list);
55}
56
57EXPORT_SYMBOL(nftnl_batch_alloc);
58struct nftnl_batch *nftnl_batch_alloc(uint32_t pg_size, uint32_t pg_overrun_size)
59{
60 struct nftnl_batch *batch;
61 struct nftnl_batch_page *page;
62
63 batch = calloc(1, sizeof(struct nftnl_batch));
64 if (batch == NULL)
65 return NULL;
66
67 batch->page_size = pg_size;
68 batch->page_overrun_size = pg_overrun_size;
69 INIT_LIST_HEAD(&batch->page_list);
70
71 page = nftnl_batch_page_alloc(batch);
72 if (page == NULL)
73 goto err1;
74
75 nftnl_batch_add_page(page, batch);
76 return batch;
77err1:
78 free(batch);
79 return NULL;
80}
81
82EXPORT_SYMBOL(nftnl_batch_free);
83void nftnl_batch_free(struct nftnl_batch *batch)
84{
85 struct nftnl_batch_page *page, *next;
86
87 list_for_each_entry_safe(page, next, &batch->page_list, head) {
88 free(mnl_nlmsg_batch_head(page->batch));
89 mnl_nlmsg_batch_stop(page->batch);
90 free(page);
91 }
92
93 free(batch);
94}
95
96EXPORT_SYMBOL(nftnl_batch_update);
97int nftnl_batch_update(struct nftnl_batch *batch)
98{
99 struct nftnl_batch_page *page;
100 struct nlmsghdr *last_nlh;
101
102 if (mnl_nlmsg_batch_next(batch->current_page->batch))
103 return 0;
104
105 last_nlh = nftnl_batch_buffer(batch);
106
107 page = nftnl_batch_page_alloc(batch);
108 if (page == NULL)
109 goto err1;
110
111 nftnl_batch_add_page(page, batch);
112
113 memcpy(nftnl_batch_buffer(batch), last_nlh, last_nlh->nlmsg_len);
114 mnl_nlmsg_batch_next(batch->current_page->batch);
115
116 return 0;
117err1:
118 return -1;
119}
120
121EXPORT_SYMBOL(nftnl_batch_buffer);
122void *nftnl_batch_buffer(struct nftnl_batch *batch)
123{
124 return mnl_nlmsg_batch_current(batch->current_page->batch);
125}
126
127EXPORT_SYMBOL(nftnl_batch_buffer_len);
128uint32_t nftnl_batch_buffer_len(struct nftnl_batch *batch)
129{
130 return mnl_nlmsg_batch_size(batch->current_page->batch);
131}
132
133EXPORT_SYMBOL(nftnl_batch_iovec_len);
134int nftnl_batch_iovec_len(struct nftnl_batch *batch)
135{
136 int num_pages = batch->num_pages;
137
138 /* Skip last page if it's empty */
139 if (mnl_nlmsg_batch_is_empty(batch->current_page->batch))
140 num_pages--;
141
142 return num_pages;
143}
144
145EXPORT_SYMBOL(nftnl_batch_iovec);
146void nftnl_batch_iovec(struct nftnl_batch *batch, struct iovec *iov,
147 uint32_t iovlen)
148{
149 struct nftnl_batch_page *page;
150 int i = 0;
151
152 list_for_each_entry(page, &batch->page_list, head) {
153 if (i >= iovlen)
154 break;
155
156 iov[i].iov_base = mnl_nlmsg_batch_head(page->batch);
157 iov[i].iov_len = mnl_nlmsg_batch_size(page->batch);
158 i++;
159 }
160}