diff options
-rw-r--r-- | include/net/netfilter/nf_tables.h | 33 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 33 | ||||
-rw-r--r-- | net/netfilter/nft_hash.c | 38 | ||||
-rw-r--r-- | net/netfilter/nft_rbtree.c | 48 |
4 files changed, 112 insertions, 40 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 4c46a325874e..b8cd60dcb4e1 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -138,15 +138,10 @@ struct nft_userdata { | |||
138 | /** | 138 | /** |
139 | * struct nft_set_elem - generic representation of set elements | 139 | * struct nft_set_elem - generic representation of set elements |
140 | * | 140 | * |
141 | * @cookie: implementation specific element cookie | ||
142 | * @key: element key | 141 | * @key: element key |
143 | * @priv: element private data and extensions | 142 | * @priv: element private data and extensions |
144 | * | ||
145 | * The cookie can be used to store a handle to the element for subsequent | ||
146 | * removal. | ||
147 | */ | 143 | */ |
148 | struct nft_set_elem { | 144 | struct nft_set_elem { |
149 | void *cookie; | ||
150 | struct nft_data key; | 145 | struct nft_data key; |
151 | void *priv; | 146 | void *priv; |
152 | }; | 147 | }; |
@@ -207,6 +202,8 @@ struct nft_set_ext; | |||
207 | * | 202 | * |
208 | * @lookup: look up an element within the set | 203 | * @lookup: look up an element within the set |
209 | * @insert: insert new element into set | 204 | * @insert: insert new element into set |
205 | * @activate: activate new element in the next generation | ||
206 | * @deactivate: deactivate element in the next generation | ||
210 | * @remove: remove element from set | 207 | * @remove: remove element from set |
211 | * @walk: iterate over all set elemeennts | 208 | * @walk: iterate over all set elemeennts |
212 | * @privsize: function to return size of set private data | 209 | * @privsize: function to return size of set private data |
@@ -221,10 +218,12 @@ struct nft_set_ops { | |||
221 | bool (*lookup)(const struct nft_set *set, | 218 | bool (*lookup)(const struct nft_set *set, |
222 | const struct nft_data *key, | 219 | const struct nft_data *key, |
223 | const struct nft_set_ext **ext); | 220 | const struct nft_set_ext **ext); |
224 | int (*get)(const struct nft_set *set, | ||
225 | struct nft_set_elem *elem); | ||
226 | int (*insert)(const struct nft_set *set, | 221 | int (*insert)(const struct nft_set *set, |
227 | const struct nft_set_elem *elem); | 222 | const struct nft_set_elem *elem); |
223 | void (*activate)(const struct nft_set *set, | ||
224 | const struct nft_set_elem *elem); | ||
225 | void * (*deactivate)(const struct nft_set *set, | ||
226 | const struct nft_set_elem *elem); | ||
228 | void (*remove)(const struct nft_set *set, | 227 | void (*remove)(const struct nft_set *set, |
229 | const struct nft_set_elem *elem); | 228 | const struct nft_set_elem *elem); |
230 | void (*walk)(const struct nft_ctx *ctx, | 229 | void (*walk)(const struct nft_ctx *ctx, |
@@ -261,6 +260,7 @@ void nft_unregister_set(struct nft_set_ops *ops); | |||
261 | * @nelems: number of elements | 260 | * @nelems: number of elements |
262 | * @policy: set parameterization (see enum nft_set_policies) | 261 | * @policy: set parameterization (see enum nft_set_policies) |
263 | * @ops: set ops | 262 | * @ops: set ops |
263 | * @pnet: network namespace | ||
264 | * @flags: set flags | 264 | * @flags: set flags |
265 | * @klen: key length | 265 | * @klen: key length |
266 | * @dlen: data length | 266 | * @dlen: data length |
@@ -277,6 +277,7 @@ struct nft_set { | |||
277 | u16 policy; | 277 | u16 policy; |
278 | /* runtime data below here */ | 278 | /* runtime data below here */ |
279 | const struct nft_set_ops *ops ____cacheline_aligned; | 279 | const struct nft_set_ops *ops ____cacheline_aligned; |
280 | possible_net_t pnet; | ||
280 | u16 flags; | 281 | u16 flags; |
281 | u8 klen; | 282 | u8 klen; |
282 | u8 dlen; | 283 | u8 dlen; |
@@ -355,10 +356,12 @@ struct nft_set_ext_tmpl { | |||
355 | /** | 356 | /** |
356 | * struct nft_set_ext - set extensions | 357 | * struct nft_set_ext - set extensions |
357 | * | 358 | * |
359 | * @genmask: generation mask | ||
358 | * @offset: offsets of individual extension types | 360 | * @offset: offsets of individual extension types |
359 | * @data: beginning of extension data | 361 | * @data: beginning of extension data |
360 | */ | 362 | */ |
361 | struct nft_set_ext { | 363 | struct nft_set_ext { |
364 | u8 genmask; | ||
362 | u8 offset[NFT_SET_EXT_NUM]; | 365 | u8 offset[NFT_SET_EXT_NUM]; |
363 | char data[0]; | 366 | char data[0]; |
364 | }; | 367 | }; |
@@ -748,6 +751,22 @@ static inline u8 nft_genmask_cur(const struct net *net) | |||
748 | return 1 << ACCESS_ONCE(net->nft.gencursor); | 751 | return 1 << ACCESS_ONCE(net->nft.gencursor); |
749 | } | 752 | } |
750 | 753 | ||
754 | /* | ||
755 | * Set element transaction helpers | ||
756 | */ | ||
757 | |||
758 | static inline bool nft_set_elem_active(const struct nft_set_ext *ext, | ||
759 | u8 genmask) | ||
760 | { | ||
761 | return !(ext->genmask & genmask); | ||
762 | } | ||
763 | |||
764 | static inline void nft_set_elem_change_active(const struct nft_set *set, | ||
765 | struct nft_set_ext *ext) | ||
766 | { | ||
767 | ext->genmask ^= nft_genmask_next(read_pnet(&set->pnet)); | ||
768 | } | ||
769 | |||
751 | /** | 770 | /** |
752 | * struct nft_trans - nf_tables object update in transaction | 771 | * struct nft_trans - nf_tables object update in transaction |
753 | * | 772 | * |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 66fa5e935a55..5604c2df05d1 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -2690,6 +2690,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
2690 | goto err2; | 2690 | goto err2; |
2691 | 2691 | ||
2692 | INIT_LIST_HEAD(&set->bindings); | 2692 | INIT_LIST_HEAD(&set->bindings); |
2693 | write_pnet(&set->pnet, net); | ||
2693 | set->ops = ops; | 2694 | set->ops = ops; |
2694 | set->ktype = ktype; | 2695 | set->ktype = ktype; |
2695 | set->klen = desc.klen; | 2696 | set->klen = desc.klen; |
@@ -3221,10 +3222,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
3221 | if (d1.type != NFT_DATA_VALUE || d1.len != set->klen) | 3222 | if (d1.type != NFT_DATA_VALUE || d1.len != set->klen) |
3222 | goto err2; | 3223 | goto err2; |
3223 | 3224 | ||
3224 | err = -EEXIST; | ||
3225 | if (set->ops->get(set, &elem) == 0) | ||
3226 | goto err2; | ||
3227 | |||
3228 | nft_set_ext_add(&tmpl, NFT_SET_EXT_KEY); | 3225 | nft_set_ext_add(&tmpl, NFT_SET_EXT_KEY); |
3229 | 3226 | ||
3230 | if (nla[NFTA_SET_ELEM_DATA] != NULL) { | 3227 | if (nla[NFTA_SET_ELEM_DATA] != NULL) { |
@@ -3266,6 +3263,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | |||
3266 | if (trans == NULL) | 3263 | if (trans == NULL) |
3267 | goto err4; | 3264 | goto err4; |
3268 | 3265 | ||
3266 | ext->genmask = nft_genmask_cur(ctx->net); | ||
3269 | err = set->ops->insert(set, &elem); | 3267 | err = set->ops->insert(set, &elem); |
3270 | if (err < 0) | 3268 | if (err < 0) |
3271 | goto err5; | 3269 | goto err5; |
@@ -3353,19 +3351,24 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, | |||
3353 | if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) | 3351 | if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) |
3354 | goto err2; | 3352 | goto err2; |
3355 | 3353 | ||
3356 | err = set->ops->get(set, &elem); | ||
3357 | if (err < 0) | ||
3358 | goto err2; | ||
3359 | |||
3360 | trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); | 3354 | trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); |
3361 | if (trans == NULL) { | 3355 | if (trans == NULL) { |
3362 | err = -ENOMEM; | 3356 | err = -ENOMEM; |
3363 | goto err2; | 3357 | goto err2; |
3364 | } | 3358 | } |
3365 | 3359 | ||
3360 | elem.priv = set->ops->deactivate(set, &elem); | ||
3361 | if (elem.priv == NULL) { | ||
3362 | err = -ENOENT; | ||
3363 | goto err3; | ||
3364 | } | ||
3365 | |||
3366 | nft_trans_elem(trans) = elem; | 3366 | nft_trans_elem(trans) = elem; |
3367 | list_add_tail(&trans->list, &ctx->net->nft.commit_list); | 3367 | list_add_tail(&trans->list, &ctx->net->nft.commit_list); |
3368 | return 0; | 3368 | return 0; |
3369 | |||
3370 | err3: | ||
3371 | kfree(trans); | ||
3369 | err2: | 3372 | err2: |
3370 | nft_data_uninit(&elem.key, desc.type); | 3373 | nft_data_uninit(&elem.key, desc.type); |
3371 | err1: | 3374 | err1: |
@@ -3692,9 +3695,11 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3692 | NFT_MSG_DELSET, GFP_KERNEL); | 3695 | NFT_MSG_DELSET, GFP_KERNEL); |
3693 | break; | 3696 | break; |
3694 | case NFT_MSG_NEWSETELEM: | 3697 | case NFT_MSG_NEWSETELEM: |
3695 | nf_tables_setelem_notify(&trans->ctx, | 3698 | te = (struct nft_trans_elem *)trans->data; |
3696 | nft_trans_elem_set(trans), | 3699 | |
3697 | &nft_trans_elem(trans), | 3700 | te->set->ops->activate(te->set, &te->elem); |
3701 | nf_tables_setelem_notify(&trans->ctx, te->set, | ||
3702 | &te->elem, | ||
3698 | NFT_MSG_NEWSETELEM, 0); | 3703 | NFT_MSG_NEWSETELEM, 0); |
3699 | nft_trans_destroy(trans); | 3704 | nft_trans_destroy(trans); |
3700 | break; | 3705 | break; |
@@ -3704,7 +3709,6 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3704 | nf_tables_setelem_notify(&trans->ctx, te->set, | 3709 | nf_tables_setelem_notify(&trans->ctx, te->set, |
3705 | &te->elem, | 3710 | &te->elem, |
3706 | NFT_MSG_DELSETELEM, 0); | 3711 | NFT_MSG_DELSETELEM, 0); |
3707 | te->set->ops->get(te->set, &te->elem); | ||
3708 | te->set->ops->remove(te->set, &te->elem); | 3712 | te->set->ops->remove(te->set, &te->elem); |
3709 | break; | 3713 | break; |
3710 | } | 3714 | } |
@@ -3812,11 +3816,14 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
3812 | nft_trans_elem_set(trans)->nelems--; | 3816 | nft_trans_elem_set(trans)->nelems--; |
3813 | te = (struct nft_trans_elem *)trans->data; | 3817 | te = (struct nft_trans_elem *)trans->data; |
3814 | 3818 | ||
3815 | te->set->ops->get(te->set, &te->elem); | ||
3816 | te->set->ops->remove(te->set, &te->elem); | 3819 | te->set->ops->remove(te->set, &te->elem); |
3817 | break; | 3820 | break; |
3818 | case NFT_MSG_DELSETELEM: | 3821 | case NFT_MSG_DELSETELEM: |
3822 | te = (struct nft_trans_elem *)trans->data; | ||
3823 | |||
3819 | nft_trans_elem_set(trans)->nelems++; | 3824 | nft_trans_elem_set(trans)->nelems++; |
3825 | te->set->ops->activate(te->set, &te->elem); | ||
3826 | |||
3820 | nft_trans_destroy(trans); | 3827 | nft_trans_destroy(trans); |
3821 | break; | 3828 | break; |
3822 | } | 3829 | } |
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 5bee82195ef5..c7e1a9d7d46f 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c | |||
@@ -35,6 +35,7 @@ struct nft_hash_elem { | |||
35 | struct nft_hash_cmp_arg { | 35 | struct nft_hash_cmp_arg { |
36 | const struct nft_set *set; | 36 | const struct nft_set *set; |
37 | const struct nft_data *key; | 37 | const struct nft_data *key; |
38 | u8 genmask; | ||
38 | }; | 39 | }; |
39 | 40 | ||
40 | static const struct rhashtable_params nft_hash_params; | 41 | static const struct rhashtable_params nft_hash_params; |
@@ -61,6 +62,8 @@ static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg, | |||
61 | 62 | ||
62 | if (nft_data_cmp(nft_set_ext_key(&he->ext), x->key, x->set->klen)) | 63 | if (nft_data_cmp(nft_set_ext_key(&he->ext), x->key, x->set->klen)) |
63 | return 1; | 64 | return 1; |
65 | if (!nft_set_elem_active(&he->ext, x->genmask)) | ||
66 | return 1; | ||
64 | return 0; | 67 | return 0; |
65 | } | 68 | } |
66 | 69 | ||
@@ -71,6 +74,7 @@ static bool nft_hash_lookup(const struct nft_set *set, | |||
71 | struct nft_hash *priv = nft_set_priv(set); | 74 | struct nft_hash *priv = nft_set_priv(set); |
72 | const struct nft_hash_elem *he; | 75 | const struct nft_hash_elem *he; |
73 | struct nft_hash_cmp_arg arg = { | 76 | struct nft_hash_cmp_arg arg = { |
77 | .genmask = nft_genmask_cur(read_pnet(&set->pnet)), | ||
74 | .set = set, | 78 | .set = set, |
75 | .key = key, | 79 | .key = key, |
76 | }; | 80 | }; |
@@ -88,6 +92,7 @@ static int nft_hash_insert(const struct nft_set *set, | |||
88 | struct nft_hash *priv = nft_set_priv(set); | 92 | struct nft_hash *priv = nft_set_priv(set); |
89 | struct nft_hash_elem *he = elem->priv; | 93 | struct nft_hash_elem *he = elem->priv; |
90 | struct nft_hash_cmp_arg arg = { | 94 | struct nft_hash_cmp_arg arg = { |
95 | .genmask = nft_genmask_next(read_pnet(&set->pnet)), | ||
91 | .set = set, | 96 | .set = set, |
92 | .key = &elem->key, | 97 | .key = &elem->key, |
93 | }; | 98 | }; |
@@ -96,30 +101,39 @@ static int nft_hash_insert(const struct nft_set *set, | |||
96 | nft_hash_params); | 101 | nft_hash_params); |
97 | } | 102 | } |
98 | 103 | ||
99 | static void nft_hash_remove(const struct nft_set *set, | 104 | static void nft_hash_activate(const struct nft_set *set, |
100 | const struct nft_set_elem *elem) | 105 | const struct nft_set_elem *elem) |
101 | { | 106 | { |
102 | struct nft_hash *priv = nft_set_priv(set); | 107 | struct nft_hash_elem *he = elem->priv; |
103 | 108 | ||
104 | rhashtable_remove_fast(&priv->ht, elem->cookie, nft_hash_params); | 109 | nft_set_elem_change_active(set, &he->ext); |
105 | } | 110 | } |
106 | 111 | ||
107 | static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) | 112 | static void *nft_hash_deactivate(const struct nft_set *set, |
113 | const struct nft_set_elem *elem) | ||
108 | { | 114 | { |
109 | struct nft_hash *priv = nft_set_priv(set); | 115 | struct nft_hash *priv = nft_set_priv(set); |
110 | struct nft_hash_elem *he; | 116 | struct nft_hash_elem *he; |
111 | struct nft_hash_cmp_arg arg = { | 117 | struct nft_hash_cmp_arg arg = { |
118 | .genmask = nft_genmask_next(read_pnet(&set->pnet)), | ||
112 | .set = set, | 119 | .set = set, |
113 | .key = &elem->key, | 120 | .key = &elem->key, |
114 | }; | 121 | }; |
115 | 122 | ||
116 | he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params); | 123 | he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params); |
117 | if (!he) | 124 | if (he != NULL) |
118 | return -ENOENT; | 125 | nft_set_elem_change_active(set, &he->ext); |
119 | 126 | ||
120 | elem->priv = he; | 127 | return he; |
128 | } | ||
121 | 129 | ||
122 | return 0; | 130 | static void nft_hash_remove(const struct nft_set *set, |
131 | const struct nft_set_elem *elem) | ||
132 | { | ||
133 | struct nft_hash *priv = nft_set_priv(set); | ||
134 | struct nft_hash_elem *he = elem->priv; | ||
135 | |||
136 | rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params); | ||
123 | } | 137 | } |
124 | 138 | ||
125 | static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, | 139 | static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, |
@@ -129,6 +143,7 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, | |||
129 | struct nft_hash_elem *he; | 143 | struct nft_hash_elem *he; |
130 | struct rhashtable_iter hti; | 144 | struct rhashtable_iter hti; |
131 | struct nft_set_elem elem; | 145 | struct nft_set_elem elem; |
146 | u8 genmask = nft_genmask_cur(read_pnet(&set->pnet)); | ||
132 | int err; | 147 | int err; |
133 | 148 | ||
134 | err = rhashtable_walk_init(&priv->ht, &hti); | 149 | err = rhashtable_walk_init(&priv->ht, &hti); |
@@ -155,6 +170,8 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, | |||
155 | 170 | ||
156 | if (iter->count < iter->skip) | 171 | if (iter->count < iter->skip) |
157 | goto cont; | 172 | goto cont; |
173 | if (!nft_set_elem_active(&he->ext, genmask)) | ||
174 | goto cont; | ||
158 | 175 | ||
159 | elem.priv = he; | 176 | elem.priv = he; |
160 | 177 | ||
@@ -241,8 +258,9 @@ static struct nft_set_ops nft_hash_ops __read_mostly = { | |||
241 | .estimate = nft_hash_estimate, | 258 | .estimate = nft_hash_estimate, |
242 | .init = nft_hash_init, | 259 | .init = nft_hash_init, |
243 | .destroy = nft_hash_destroy, | 260 | .destroy = nft_hash_destroy, |
244 | .get = nft_hash_get, | ||
245 | .insert = nft_hash_insert, | 261 | .insert = nft_hash_insert, |
262 | .activate = nft_hash_activate, | ||
263 | .deactivate = nft_hash_deactivate, | ||
246 | .remove = nft_hash_remove, | 264 | .remove = nft_hash_remove, |
247 | .lookup = nft_hash_lookup, | 265 | .lookup = nft_hash_lookup, |
248 | .walk = nft_hash_walk, | 266 | .walk = nft_hash_walk, |
diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c index cbba755ebebc..42d0ca45fb9e 100644 --- a/net/netfilter/nft_rbtree.c +++ b/net/netfilter/nft_rbtree.c | |||
@@ -29,6 +29,7 @@ struct nft_rbtree_elem { | |||
29 | struct nft_set_ext ext; | 29 | struct nft_set_ext ext; |
30 | }; | 30 | }; |
31 | 31 | ||
32 | |||
32 | static bool nft_rbtree_lookup(const struct nft_set *set, | 33 | static bool nft_rbtree_lookup(const struct nft_set *set, |
33 | const struct nft_data *key, | 34 | const struct nft_data *key, |
34 | const struct nft_set_ext **ext) | 35 | const struct nft_set_ext **ext) |
@@ -36,6 +37,7 @@ static bool nft_rbtree_lookup(const struct nft_set *set, | |||
36 | const struct nft_rbtree *priv = nft_set_priv(set); | 37 | const struct nft_rbtree *priv = nft_set_priv(set); |
37 | const struct nft_rbtree_elem *rbe, *interval = NULL; | 38 | const struct nft_rbtree_elem *rbe, *interval = NULL; |
38 | const struct rb_node *parent; | 39 | const struct rb_node *parent; |
40 | u8 genmask = nft_genmask_cur(read_pnet(&set->pnet)); | ||
39 | int d; | 41 | int d; |
40 | 42 | ||
41 | spin_lock_bh(&nft_rbtree_lock); | 43 | spin_lock_bh(&nft_rbtree_lock); |
@@ -51,6 +53,10 @@ static bool nft_rbtree_lookup(const struct nft_set *set, | |||
51 | parent = parent->rb_right; | 53 | parent = parent->rb_right; |
52 | else { | 54 | else { |
53 | found: | 55 | found: |
56 | if (!nft_set_elem_active(&rbe->ext, genmask)) { | ||
57 | parent = parent->rb_left; | ||
58 | continue; | ||
59 | } | ||
54 | if (nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) && | 60 | if (nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) && |
55 | *nft_set_ext_flags(&rbe->ext) & | 61 | *nft_set_ext_flags(&rbe->ext) & |
56 | NFT_SET_ELEM_INTERVAL_END) | 62 | NFT_SET_ELEM_INTERVAL_END) |
@@ -77,6 +83,7 @@ static int __nft_rbtree_insert(const struct nft_set *set, | |||
77 | struct nft_rbtree *priv = nft_set_priv(set); | 83 | struct nft_rbtree *priv = nft_set_priv(set); |
78 | struct nft_rbtree_elem *rbe; | 84 | struct nft_rbtree_elem *rbe; |
79 | struct rb_node *parent, **p; | 85 | struct rb_node *parent, **p; |
86 | u8 genmask = nft_genmask_next(read_pnet(&set->pnet)); | ||
80 | int d; | 87 | int d; |
81 | 88 | ||
82 | parent = NULL; | 89 | parent = NULL; |
@@ -91,8 +98,11 @@ static int __nft_rbtree_insert(const struct nft_set *set, | |||
91 | p = &parent->rb_left; | 98 | p = &parent->rb_left; |
92 | else if (d > 0) | 99 | else if (d > 0) |
93 | p = &parent->rb_right; | 100 | p = &parent->rb_right; |
94 | else | 101 | else { |
95 | return -EEXIST; | 102 | if (nft_set_elem_active(&rbe->ext, genmask)) |
103 | return -EEXIST; | ||
104 | p = &parent->rb_left; | ||
105 | } | ||
96 | } | 106 | } |
97 | rb_link_node(&new->node, parent, p); | 107 | rb_link_node(&new->node, parent, p); |
98 | rb_insert_color(&new->node, &priv->root); | 108 | rb_insert_color(&new->node, &priv->root); |
@@ -116,18 +126,28 @@ static void nft_rbtree_remove(const struct nft_set *set, | |||
116 | const struct nft_set_elem *elem) | 126 | const struct nft_set_elem *elem) |
117 | { | 127 | { |
118 | struct nft_rbtree *priv = nft_set_priv(set); | 128 | struct nft_rbtree *priv = nft_set_priv(set); |
119 | struct nft_rbtree_elem *rbe = elem->cookie; | 129 | struct nft_rbtree_elem *rbe = elem->priv; |
120 | 130 | ||
121 | spin_lock_bh(&nft_rbtree_lock); | 131 | spin_lock_bh(&nft_rbtree_lock); |
122 | rb_erase(&rbe->node, &priv->root); | 132 | rb_erase(&rbe->node, &priv->root); |
123 | spin_unlock_bh(&nft_rbtree_lock); | 133 | spin_unlock_bh(&nft_rbtree_lock); |
124 | } | 134 | } |
125 | 135 | ||
126 | static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) | 136 | static void nft_rbtree_activate(const struct nft_set *set, |
137 | const struct nft_set_elem *elem) | ||
138 | { | ||
139 | struct nft_rbtree_elem *rbe = elem->priv; | ||
140 | |||
141 | nft_set_elem_change_active(set, &rbe->ext); | ||
142 | } | ||
143 | |||
144 | static void *nft_rbtree_deactivate(const struct nft_set *set, | ||
145 | const struct nft_set_elem *elem) | ||
127 | { | 146 | { |
128 | const struct nft_rbtree *priv = nft_set_priv(set); | 147 | const struct nft_rbtree *priv = nft_set_priv(set); |
129 | const struct rb_node *parent = priv->root.rb_node; | 148 | const struct rb_node *parent = priv->root.rb_node; |
130 | struct nft_rbtree_elem *rbe; | 149 | struct nft_rbtree_elem *rbe; |
150 | u8 genmask = nft_genmask_cur(read_pnet(&set->pnet)); | ||
131 | int d; | 151 | int d; |
132 | 152 | ||
133 | while (parent != NULL) { | 153 | while (parent != NULL) { |
@@ -140,12 +160,15 @@ static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) | |||
140 | else if (d > 0) | 160 | else if (d > 0) |
141 | parent = parent->rb_right; | 161 | parent = parent->rb_right; |
142 | else { | 162 | else { |
143 | elem->cookie = rbe; | 163 | if (!nft_set_elem_active(&rbe->ext, genmask)) { |
144 | elem->priv = rbe; | 164 | parent = parent->rb_left; |
145 | return 0; | 165 | continue; |
166 | } | ||
167 | nft_set_elem_change_active(set, &rbe->ext); | ||
168 | return rbe; | ||
146 | } | 169 | } |
147 | } | 170 | } |
148 | return -ENOENT; | 171 | return NULL; |
149 | } | 172 | } |
150 | 173 | ||
151 | static void nft_rbtree_walk(const struct nft_ctx *ctx, | 174 | static void nft_rbtree_walk(const struct nft_ctx *ctx, |
@@ -156,13 +179,17 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, | |||
156 | struct nft_rbtree_elem *rbe; | 179 | struct nft_rbtree_elem *rbe; |
157 | struct nft_set_elem elem; | 180 | struct nft_set_elem elem; |
158 | struct rb_node *node; | 181 | struct rb_node *node; |
182 | u8 genmask = nft_genmask_cur(read_pnet(&set->pnet)); | ||
159 | 183 | ||
160 | spin_lock_bh(&nft_rbtree_lock); | 184 | spin_lock_bh(&nft_rbtree_lock); |
161 | for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) { | 185 | for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) { |
186 | rbe = rb_entry(node, struct nft_rbtree_elem, node); | ||
187 | |||
162 | if (iter->count < iter->skip) | 188 | if (iter->count < iter->skip) |
163 | goto cont; | 189 | goto cont; |
190 | if (!nft_set_elem_active(&rbe->ext, genmask)) | ||
191 | goto cont; | ||
164 | 192 | ||
165 | rbe = rb_entry(node, struct nft_rbtree_elem, node); | ||
166 | elem.priv = rbe; | 193 | elem.priv = rbe; |
167 | 194 | ||
168 | iter->err = iter->fn(ctx, set, iter, &elem); | 195 | iter->err = iter->fn(ctx, set, iter, &elem); |
@@ -228,7 +255,8 @@ static struct nft_set_ops nft_rbtree_ops __read_mostly = { | |||
228 | .destroy = nft_rbtree_destroy, | 255 | .destroy = nft_rbtree_destroy, |
229 | .insert = nft_rbtree_insert, | 256 | .insert = nft_rbtree_insert, |
230 | .remove = nft_rbtree_remove, | 257 | .remove = nft_rbtree_remove, |
231 | .get = nft_rbtree_get, | 258 | .deactivate = nft_rbtree_deactivate, |
259 | .activate = nft_rbtree_activate, | ||
232 | .lookup = nft_rbtree_lookup, | 260 | .lookup = nft_rbtree_lookup, |
233 | .walk = nft_rbtree_walk, | 261 | .walk = nft_rbtree_walk, |
234 | .features = NFT_SET_INTERVAL | NFT_SET_MAP, | 262 | .features = NFT_SET_INTERVAL | NFT_SET_MAP, |