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 
11 struct nftnl_batch {
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 
24 static 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;
42 err2:
43  free(buf);
44 err1:
45  free(page);
46  return NULL;
47 }
48 
49 static 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 
57 EXPORT_SYMBOL(nftnl_batch_alloc);
58 struct 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;
77 err1:
78  free(batch);
79  return NULL;
80 }
81 
82 EXPORT_SYMBOL(nftnl_batch_free);
83 void 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 
96 EXPORT_SYMBOL(nftnl_batch_update);
97 int 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;
117 err1:
118  return -1;
119 }
120 
121 EXPORT_SYMBOL(nftnl_batch_buffer);
122 void *nftnl_batch_buffer(struct nftnl_batch *batch)
123 {
124  return mnl_nlmsg_batch_current(batch->current_page->batch);
125 }
126 
127 EXPORT_SYMBOL(nftnl_batch_buffer_len);
128 uint32_t nftnl_batch_buffer_len(struct nftnl_batch *batch)
129 {
130  return mnl_nlmsg_batch_size(batch->current_page->batch);
131 }
132 
133 EXPORT_SYMBOL(nftnl_batch_iovec_len);
134 int 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 
145 EXPORT_SYMBOL(nftnl_batch_iovec);
146 void 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 }