aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2017-03-10 12:32:31 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2017-03-13 08:34:21 -0400
commite920dde5160887d07b738f5a7f593b1fa9b1e32e (patch)
tree947962b3ad71db1c28300ac83660820fe64c94c8
parent170a1fb9c01bc40b7e8fd57a32ac9a0e131ec5b6 (diff)
netfilter: nft_set_bitmap: keep a list of dummy elements
Element comments may come without any prior set flag, so we have to keep a list of dummy struct nft_set_ext to keep this information around. This is only useful for set dumps to userspace. From the packet path, this set type relies on the bitmap representation. This patch simplifies the logic since we don't need to allocate the dummy nft_set_ext structure anymore on the fly at the cost of increasing memory consumption because of the list of dummy struct nft_set_ext. Fixes: 665153ff5752 ("netfilter: nf_tables: add bitmap set type") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--net/netfilter/nft_set_bitmap.c146
1 files changed, 66 insertions, 80 deletions
diff --git a/net/netfilter/nft_set_bitmap.c b/net/netfilter/nft_set_bitmap.c
index 9b024e22717b..8ebbc2940f4c 100644
--- a/net/netfilter/nft_set_bitmap.c
+++ b/net/netfilter/nft_set_bitmap.c
@@ -15,6 +15,11 @@
15#include <linux/netfilter/nf_tables.h> 15#include <linux/netfilter/nf_tables.h>
16#include <net/netfilter/nf_tables.h> 16#include <net/netfilter/nf_tables.h>
17 17
18struct nft_bitmap_elem {
19 struct list_head head;
20 struct nft_set_ext ext;
21};
22
18/* This bitmap uses two bits to represent one element. These two bits determine 23/* This bitmap uses two bits to represent one element. These two bits determine
19 * the element state in the current and the future generation. 24 * the element state in the current and the future generation.
20 * 25 *
@@ -41,8 +46,9 @@
41 * restore its previous state. 46 * restore its previous state.
42 */ 47 */
43struct nft_bitmap { 48struct nft_bitmap {
44 u16 bitmap_size; 49 struct list_head list;
45 u8 bitmap[]; 50 u16 bitmap_size;
51 u8 bitmap[];
46}; 52};
47 53
48static inline void nft_bitmap_location(const struct nft_set *set, 54static inline void nft_bitmap_location(const struct nft_set *set,
@@ -82,21 +88,43 @@ static bool nft_bitmap_lookup(const struct net *net, const struct nft_set *set,
82 return nft_bitmap_active(priv->bitmap, idx, off, genmask); 88 return nft_bitmap_active(priv->bitmap, idx, off, genmask);
83} 89}
84 90
91static struct nft_bitmap_elem *
92nft_bitmap_elem_find(const struct nft_set *set, struct nft_bitmap_elem *this,
93 u8 genmask)
94{
95 const struct nft_bitmap *priv = nft_set_priv(set);
96 struct nft_bitmap_elem *be;
97
98 list_for_each_entry_rcu(be, &priv->list, head) {
99 if (memcmp(nft_set_ext_key(&be->ext),
100 nft_set_ext_key(&this->ext), set->klen) ||
101 !nft_set_elem_active(&be->ext, genmask))
102 continue;
103
104 return be;
105 }
106 return NULL;
107}
108
85static int nft_bitmap_insert(const struct net *net, const struct nft_set *set, 109static int nft_bitmap_insert(const struct net *net, const struct nft_set *set,
86 const struct nft_set_elem *elem, 110 const struct nft_set_elem *elem,
87 struct nft_set_ext **_ext) 111 struct nft_set_ext **ext)
88{ 112{
89 struct nft_bitmap *priv = nft_set_priv(set); 113 struct nft_bitmap *priv = nft_set_priv(set);
90 struct nft_set_ext *ext = elem->priv; 114 struct nft_bitmap_elem *new = elem->priv, *be;
91 u8 genmask = nft_genmask_next(net); 115 u8 genmask = nft_genmask_next(net);
92 u32 idx, off; 116 u32 idx, off;
93 117
94 nft_bitmap_location(set, nft_set_ext_key(ext), &idx, &off); 118 be = nft_bitmap_elem_find(set, new, genmask);
95 if (nft_bitmap_active(priv->bitmap, idx, off, genmask)) 119 if (be) {
120 *ext = &be->ext;
96 return -EEXIST; 121 return -EEXIST;
122 }
97 123
124 nft_bitmap_location(set, nft_set_ext_key(&new->ext), &idx, &off);
98 /* Enter 01 state. */ 125 /* Enter 01 state. */
99 priv->bitmap[idx] |= (genmask << off); 126 priv->bitmap[idx] |= (genmask << off);
127 list_add_tail_rcu(&new->head, &priv->list);
100 128
101 return 0; 129 return 0;
102} 130}
@@ -106,13 +134,14 @@ static void nft_bitmap_remove(const struct net *net,
106 const struct nft_set_elem *elem) 134 const struct nft_set_elem *elem)
107{ 135{
108 struct nft_bitmap *priv = nft_set_priv(set); 136 struct nft_bitmap *priv = nft_set_priv(set);
109 struct nft_set_ext *ext = elem->priv; 137 struct nft_bitmap_elem *be = elem->priv;
110 u8 genmask = nft_genmask_next(net); 138 u8 genmask = nft_genmask_next(net);
111 u32 idx, off; 139 u32 idx, off;
112 140
113 nft_bitmap_location(set, nft_set_ext_key(ext), &idx, &off); 141 nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
114 /* Enter 00 state. */ 142 /* Enter 00 state. */
115 priv->bitmap[idx] &= ~(genmask << off); 143 priv->bitmap[idx] &= ~(genmask << off);
144 list_del_rcu(&be->head);
116} 145}
117 146
118static void nft_bitmap_activate(const struct net *net, 147static void nft_bitmap_activate(const struct net *net,
@@ -120,73 +149,52 @@ static void nft_bitmap_activate(const struct net *net,
120 const struct nft_set_elem *elem) 149 const struct nft_set_elem *elem)
121{ 150{
122 struct nft_bitmap *priv = nft_set_priv(set); 151 struct nft_bitmap *priv = nft_set_priv(set);
123 struct nft_set_ext *ext = elem->priv; 152 struct nft_bitmap_elem *be = elem->priv;
124 u8 genmask = nft_genmask_next(net); 153 u8 genmask = nft_genmask_next(net);
125 u32 idx, off; 154 u32 idx, off;
126 155
127 nft_bitmap_location(set, nft_set_ext_key(ext), &idx, &off); 156 nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
128 /* Enter 11 state. */ 157 /* Enter 11 state. */
129 priv->bitmap[idx] |= (genmask << off); 158 priv->bitmap[idx] |= (genmask << off);
159 nft_set_elem_change_active(net, set, &be->ext);
130} 160}
131 161
132static bool nft_bitmap_flush(const struct net *net, 162static bool nft_bitmap_flush(const struct net *net,
133 const struct nft_set *set, void *ext) 163 const struct nft_set *set, void *_be)
134{ 164{
135 struct nft_bitmap *priv = nft_set_priv(set); 165 struct nft_bitmap *priv = nft_set_priv(set);
136 u8 genmask = nft_genmask_next(net); 166 u8 genmask = nft_genmask_next(net);
167 struct nft_bitmap_elem *be = _be;
137 u32 idx, off; 168 u32 idx, off;
138 169
139 nft_bitmap_location(set, nft_set_ext_key(ext), &idx, &off); 170 nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
140 /* Enter 10 state, similar to deactivation. */ 171 /* Enter 10 state, similar to deactivation. */
141 priv->bitmap[idx] &= ~(genmask << off); 172 priv->bitmap[idx] &= ~(genmask << off);
173 nft_set_elem_change_active(net, set, &be->ext);
142 174
143 return true; 175 return true;
144} 176}
145 177
146static struct nft_set_ext *nft_bitmap_ext_alloc(const struct nft_set *set,
147 const struct nft_set_elem *elem)
148{
149 struct nft_set_ext_tmpl tmpl;
150 struct nft_set_ext *ext;
151
152 nft_set_ext_prepare(&tmpl);
153 nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
154
155 ext = kzalloc(tmpl.len, GFP_KERNEL);
156 if (!ext)
157 return NULL;
158
159 nft_set_ext_init(ext, &tmpl);
160 memcpy(nft_set_ext_key(ext), elem->key.val.data, set->klen);
161
162 return ext;
163}
164
165static void *nft_bitmap_deactivate(const struct net *net, 178static void *nft_bitmap_deactivate(const struct net *net,
166 const struct nft_set *set, 179 const struct nft_set *set,
167 const struct nft_set_elem *elem) 180 const struct nft_set_elem *elem)
168{ 181{
169 struct nft_bitmap *priv = nft_set_priv(set); 182 struct nft_bitmap *priv = nft_set_priv(set);
183 struct nft_bitmap_elem *this = elem->priv, *be;
170 u8 genmask = nft_genmask_next(net); 184 u8 genmask = nft_genmask_next(net);
171 struct nft_set_ext *ext;
172 u32 idx, off; 185 u32 idx, off;
173 186
174 nft_bitmap_location(set, elem->key.val.data, &idx, &off); 187 nft_bitmap_location(set, elem->key.val.data, &idx, &off);
175 188
176 if (!nft_bitmap_active(priv->bitmap, idx, off, genmask)) 189 be = nft_bitmap_elem_find(set, this, genmask);
177 return NULL; 190 if (!be)
178
179 /* We have no real set extension since this is a bitmap, allocate this
180 * dummy object that is released from the commit/abort path.
181 */
182 ext = nft_bitmap_ext_alloc(set, elem);
183 if (!ext)
184 return NULL; 191 return NULL;
185 192
186 /* Enter 10 state. */ 193 /* Enter 10 state. */
187 priv->bitmap[idx] &= ~(genmask << off); 194 priv->bitmap[idx] &= ~(genmask << off);
195 nft_set_elem_change_active(net, set, &be->ext);
188 196
189 return ext; 197 return be;
190} 198}
191 199
192static void nft_bitmap_walk(const struct nft_ctx *ctx, 200static void nft_bitmap_walk(const struct nft_ctx *ctx,
@@ -194,47 +202,23 @@ static void nft_bitmap_walk(const struct nft_ctx *ctx,
194 struct nft_set_iter *iter) 202 struct nft_set_iter *iter)
195{ 203{
196 const struct nft_bitmap *priv = nft_set_priv(set); 204 const struct nft_bitmap *priv = nft_set_priv(set);
197 struct nft_set_ext_tmpl tmpl; 205 struct nft_bitmap_elem *be;
198 struct nft_set_elem elem; 206 struct nft_set_elem elem;
199 struct nft_set_ext *ext; 207
200 int idx, off; 208 list_for_each_entry_rcu(be, &priv->list, head) {
201 u16 key; 209 if (iter->count < iter->skip)
202 210 goto cont;
203 nft_set_ext_prepare(&tmpl); 211 if (!nft_set_elem_active(&be->ext, iter->genmask))
204 nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen); 212 goto cont;
205 213
206 for (idx = 0; idx < priv->bitmap_size; idx++) { 214 elem.priv = be;
207 for (off = 0; off < BITS_PER_BYTE; off += 2) { 215
208 if (iter->count < iter->skip) 216 iter->err = iter->fn(ctx, set, iter, &elem);
209 goto cont; 217
210 218 if (iter->err < 0)
211 if (!nft_bitmap_active(priv->bitmap, idx, off, 219 return;
212 iter->genmask))
213 goto cont;
214
215 ext = kzalloc(tmpl.len, GFP_KERNEL);
216 if (!ext) {
217 iter->err = -ENOMEM;
218 return;
219 }
220 nft_set_ext_init(ext, &tmpl);
221 key = ((idx * BITS_PER_BYTE) + off) >> 1;
222 memcpy(nft_set_ext_key(ext), &key, set->klen);
223
224 elem.priv = ext;
225 iter->err = iter->fn(ctx, set, iter, &elem);
226
227 /* On set flush, this dummy extension object is released
228 * from the commit/abort path.
229 */
230 if (!iter->flush)
231 kfree(ext);
232
233 if (iter->err < 0)
234 return;
235cont: 220cont:
236 iter->count++; 221 iter->count++;
237 }
238 } 222 }
239} 223}
240 224
@@ -265,6 +249,7 @@ static int nft_bitmap_init(const struct nft_set *set,
265{ 249{
266 struct nft_bitmap *priv = nft_set_priv(set); 250 struct nft_bitmap *priv = nft_set_priv(set);
267 251
252 INIT_LIST_HEAD(&priv->list);
268 priv->bitmap_size = nft_bitmap_size(set->klen); 253 priv->bitmap_size = nft_bitmap_size(set->klen);
269 254
270 return 0; 255 return 0;
@@ -290,6 +275,7 @@ static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,
290 275
291static struct nft_set_ops nft_bitmap_ops __read_mostly = { 276static struct nft_set_ops nft_bitmap_ops __read_mostly = {
292 .privsize = nft_bitmap_privsize, 277 .privsize = nft_bitmap_privsize,
278 .elemsize = offsetof(struct nft_bitmap_elem, ext),
293 .estimate = nft_bitmap_estimate, 279 .estimate = nft_bitmap_estimate,
294 .init = nft_bitmap_init, 280 .init = nft_bitmap_init,
295 .destroy = nft_bitmap_destroy, 281 .destroy = nft_bitmap_destroy,