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