diff options
author | Patrick McHardy <kaber@trash.net> | 2015-03-25 10:08:47 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2015-03-26 06:09:34 -0400 |
commit | 61edafbb47e9f46fb850035b1f8f062564445704 (patch) | |
tree | 9adc749e66e69c6cd5b1d82434ab00bf1c406670 | |
parent | fe2811ebeb97a7a76de0b2b35f13600169508393 (diff) |
netfilter: nf_tables: consolide set element destruction
With the conversion to set extensions, it is now possible to consolidate
the different set element destruction functions.
The set implementations' ->remove() functions are changed to only take
the element out of their internal data structures. Elements will be freed
in a batched fashion after the global transaction's completion RCU grace
period.
This reduces the amount of grace periods required for nft_hash from N
to zero additional ones, additionally this guarantees that the set
elements' extensions of all implementations can be used under RCU
protection.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | include/net/netfilter/nf_tables.h | 2 | ||||
-rw-r--r-- | net/netfilter/nf_tables_api.c | 34 | ||||
-rw-r--r-- | net/netfilter/nft_hash.c | 18 | ||||
-rw-r--r-- | net/netfilter/nft_rbtree.c | 14 |
4 files changed, 27 insertions, 41 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index ef3457c1cb62..6ac63323afd2 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -423,6 +423,8 @@ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set, | |||
423 | return elem + set->ops->elemsize; | 423 | return elem + set->ops->elemsize; |
424 | } | 424 | } |
425 | 425 | ||
426 | void nft_set_elem_destroy(const struct nft_set *set, void *elem); | ||
427 | |||
426 | /** | 428 | /** |
427 | * struct nft_expr_type - nf_tables expression type | 429 | * struct nft_expr_type - nf_tables expression type |
428 | * | 430 | * |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 99cb884b985f..b35512f1934c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -3155,6 +3155,18 @@ static void *nft_set_elem_init(const struct nft_set *set, | |||
3155 | return elem; | 3155 | return elem; |
3156 | } | 3156 | } |
3157 | 3157 | ||
3158 | void nft_set_elem_destroy(const struct nft_set *set, void *elem) | ||
3159 | { | ||
3160 | struct nft_set_ext *ext = nft_set_elem_ext(set, elem); | ||
3161 | |||
3162 | nft_data_uninit(nft_set_ext_key(ext), NFT_DATA_VALUE); | ||
3163 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) | ||
3164 | nft_data_uninit(nft_set_ext_data(ext), set->dtype); | ||
3165 | |||
3166 | kfree(elem); | ||
3167 | } | ||
3168 | EXPORT_SYMBOL_GPL(nft_set_elem_destroy); | ||
3169 | |||
3158 | static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, | 3170 | static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, |
3159 | const struct nlattr *attr) | 3171 | const struct nlattr *attr) |
3160 | { | 3172 | { |
@@ -3596,6 +3608,10 @@ static void nf_tables_commit_release(struct nft_trans *trans) | |||
3596 | case NFT_MSG_DELSET: | 3608 | case NFT_MSG_DELSET: |
3597 | nft_set_destroy(nft_trans_set(trans)); | 3609 | nft_set_destroy(nft_trans_set(trans)); |
3598 | break; | 3610 | break; |
3611 | case NFT_MSG_DELSETELEM: | ||
3612 | nft_set_elem_destroy(nft_trans_elem_set(trans), | ||
3613 | nft_trans_elem(trans).priv); | ||
3614 | break; | ||
3599 | } | 3615 | } |
3600 | kfree(trans); | 3616 | kfree(trans); |
3601 | } | 3617 | } |
@@ -3605,7 +3621,6 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3605 | struct net *net = sock_net(skb->sk); | 3621 | struct net *net = sock_net(skb->sk); |
3606 | struct nft_trans *trans, *next; | 3622 | struct nft_trans *trans, *next; |
3607 | struct nft_trans_elem *te; | 3623 | struct nft_trans_elem *te; |
3608 | struct nft_set_ext *ext; | ||
3609 | 3624 | ||
3610 | /* Bump generation counter, invalidate any dump in progress */ | 3625 | /* Bump generation counter, invalidate any dump in progress */ |
3611 | while (++net->nft.base_seq == 0); | 3626 | while (++net->nft.base_seq == 0); |
@@ -3690,18 +3705,12 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3690 | break; | 3705 | break; |
3691 | case NFT_MSG_DELSETELEM: | 3706 | case NFT_MSG_DELSETELEM: |
3692 | te = (struct nft_trans_elem *)trans->data; | 3707 | te = (struct nft_trans_elem *)trans->data; |
3693 | ext = nft_set_elem_ext(te->set, te->elem.priv); | ||
3694 | 3708 | ||
3695 | nf_tables_setelem_notify(&trans->ctx, te->set, | 3709 | nf_tables_setelem_notify(&trans->ctx, te->set, |
3696 | &te->elem, | 3710 | &te->elem, |
3697 | NFT_MSG_DELSETELEM, 0); | 3711 | NFT_MSG_DELSETELEM, 0); |
3698 | te->set->ops->get(te->set, &te->elem); | 3712 | te->set->ops->get(te->set, &te->elem); |
3699 | nft_data_uninit(&te->elem.key, NFT_DATA_VALUE); | ||
3700 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) | ||
3701 | nft_data_uninit(nft_set_ext_data(ext), | ||
3702 | te->set->dtype); | ||
3703 | te->set->ops->remove(te->set, &te->elem); | 3713 | te->set->ops->remove(te->set, &te->elem); |
3704 | nft_trans_destroy(trans); | ||
3705 | break; | 3714 | break; |
3706 | } | 3715 | } |
3707 | } | 3716 | } |
@@ -3733,6 +3742,10 @@ static void nf_tables_abort_release(struct nft_trans *trans) | |||
3733 | case NFT_MSG_NEWSET: | 3742 | case NFT_MSG_NEWSET: |
3734 | nft_set_destroy(nft_trans_set(trans)); | 3743 | nft_set_destroy(nft_trans_set(trans)); |
3735 | break; | 3744 | break; |
3745 | case NFT_MSG_NEWSETELEM: | ||
3746 | nft_set_elem_destroy(nft_trans_elem_set(trans), | ||
3747 | nft_trans_elem(trans).priv); | ||
3748 | break; | ||
3736 | } | 3749 | } |
3737 | kfree(trans); | 3750 | kfree(trans); |
3738 | } | 3751 | } |
@@ -3742,7 +3755,6 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
3742 | struct net *net = sock_net(skb->sk); | 3755 | struct net *net = sock_net(skb->sk); |
3743 | struct nft_trans *trans, *next; | 3756 | struct nft_trans *trans, *next; |
3744 | struct nft_trans_elem *te; | 3757 | struct nft_trans_elem *te; |
3745 | struct nft_set_ext *ext; | ||
3746 | 3758 | ||
3747 | list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { | 3759 | list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { |
3748 | switch (trans->msg_type) { | 3760 | switch (trans->msg_type) { |
@@ -3804,15 +3816,9 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
3804 | case NFT_MSG_NEWSETELEM: | 3816 | case NFT_MSG_NEWSETELEM: |
3805 | nft_trans_elem_set(trans)->nelems--; | 3817 | nft_trans_elem_set(trans)->nelems--; |
3806 | te = (struct nft_trans_elem *)trans->data; | 3818 | te = (struct nft_trans_elem *)trans->data; |
3807 | ext = nft_set_elem_ext(te->set, te->elem.priv); | ||
3808 | 3819 | ||
3809 | te->set->ops->get(te->set, &te->elem); | 3820 | te->set->ops->get(te->set, &te->elem); |
3810 | nft_data_uninit(&te->elem.key, NFT_DATA_VALUE); | ||
3811 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) | ||
3812 | nft_data_uninit(nft_set_ext_data(ext), | ||
3813 | te->set->dtype); | ||
3814 | te->set->ops->remove(te->set, &te->elem); | 3821 | te->set->ops->remove(te->set, &te->elem); |
3815 | nft_trans_destroy(trans); | ||
3816 | break; | 3822 | break; |
3817 | case NFT_MSG_DELSETELEM: | 3823 | case NFT_MSG_DELSETELEM: |
3818 | nft_trans_elem_set(trans)->nelems++; | 3824 | nft_trans_elem_set(trans)->nelems++; |
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c index 15951a823d1d..94bf25def37f 100644 --- a/net/netfilter/nft_hash.c +++ b/net/netfilter/nft_hash.c | |||
@@ -96,23 +96,12 @@ static int nft_hash_insert(const struct nft_set *set, | |||
96 | nft_hash_params); | 96 | nft_hash_params); |
97 | } | 97 | } |
98 | 98 | ||
99 | static void nft_hash_elem_destroy(const struct nft_set *set, | ||
100 | struct nft_hash_elem *he) | ||
101 | { | ||
102 | nft_data_uninit(nft_set_ext_key(&he->ext), NFT_DATA_VALUE); | ||
103 | if (set->flags & NFT_SET_MAP) | ||
104 | nft_data_uninit(nft_set_ext_data(&he->ext), set->dtype); | ||
105 | kfree(he); | ||
106 | } | ||
107 | |||
108 | static void nft_hash_remove(const struct nft_set *set, | 99 | static void nft_hash_remove(const struct nft_set *set, |
109 | const struct nft_set_elem *elem) | 100 | const struct nft_set_elem *elem) |
110 | { | 101 | { |
111 | struct nft_hash *priv = nft_set_priv(set); | 102 | struct nft_hash *priv = nft_set_priv(set); |
112 | 103 | ||
113 | rhashtable_remove_fast(&priv->ht, elem->cookie, nft_hash_params); | 104 | rhashtable_remove_fast(&priv->ht, elem->cookie, nft_hash_params); |
114 | synchronize_rcu(); | ||
115 | kfree(elem->cookie); | ||
116 | } | 105 | } |
117 | 106 | ||
118 | static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) | 107 | static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) |
@@ -208,16 +197,17 @@ static int nft_hash_init(const struct nft_set *set, | |||
208 | return rhashtable_init(&priv->ht, ¶ms); | 197 | return rhashtable_init(&priv->ht, ¶ms); |
209 | } | 198 | } |
210 | 199 | ||
211 | static void nft_free_element(void *ptr, void *arg) | 200 | static void nft_hash_elem_destroy(void *ptr, void *arg) |
212 | { | 201 | { |
213 | nft_hash_elem_destroy((const struct nft_set *)arg, ptr); | 202 | nft_set_elem_destroy((const struct nft_set *)arg, ptr); |
214 | } | 203 | } |
215 | 204 | ||
216 | static void nft_hash_destroy(const struct nft_set *set) | 205 | static void nft_hash_destroy(const struct nft_set *set) |
217 | { | 206 | { |
218 | struct nft_hash *priv = nft_set_priv(set); | 207 | struct nft_hash *priv = nft_set_priv(set); |
219 | 208 | ||
220 | rhashtable_free_and_destroy(&priv->ht, nft_free_element, (void *)set); | 209 | rhashtable_free_and_destroy(&priv->ht, nft_hash_elem_destroy, |
210 | (void *)set); | ||
221 | } | 211 | } |
222 | 212 | ||
223 | static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, | 213 | static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, |
diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c index ebf6e60df41c..332c6afc77e9 100644 --- a/net/netfilter/nft_rbtree.c +++ b/net/netfilter/nft_rbtree.c | |||
@@ -72,17 +72,6 @@ out: | |||
72 | return false; | 72 | return false; |
73 | } | 73 | } |
74 | 74 | ||
75 | static void nft_rbtree_elem_destroy(const struct nft_set *set, | ||
76 | struct nft_rbtree_elem *rbe) | ||
77 | { | ||
78 | nft_data_uninit(nft_set_ext_key(&rbe->ext), NFT_DATA_VALUE); | ||
79 | if (set->flags & NFT_SET_MAP && | ||
80 | nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_DATA)) | ||
81 | nft_data_uninit(nft_set_ext_data(&rbe->ext), set->dtype); | ||
82 | |||
83 | kfree(rbe); | ||
84 | } | ||
85 | |||
86 | static int __nft_rbtree_insert(const struct nft_set *set, | 75 | static int __nft_rbtree_insert(const struct nft_set *set, |
87 | struct nft_rbtree_elem *new) | 76 | struct nft_rbtree_elem *new) |
88 | { | 77 | { |
@@ -133,7 +122,6 @@ static void nft_rbtree_remove(const struct nft_set *set, | |||
133 | spin_lock_bh(&nft_rbtree_lock); | 122 | spin_lock_bh(&nft_rbtree_lock); |
134 | rb_erase(&rbe->node, &priv->root); | 123 | rb_erase(&rbe->node, &priv->root); |
135 | spin_unlock_bh(&nft_rbtree_lock); | 124 | spin_unlock_bh(&nft_rbtree_lock); |
136 | kfree(rbe); | ||
137 | } | 125 | } |
138 | 126 | ||
139 | static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) | 127 | static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) |
@@ -213,7 +201,7 @@ static void nft_rbtree_destroy(const struct nft_set *set) | |||
213 | while ((node = priv->root.rb_node) != NULL) { | 201 | while ((node = priv->root.rb_node) != NULL) { |
214 | rb_erase(node, &priv->root); | 202 | rb_erase(node, &priv->root); |
215 | rbe = rb_entry(node, struct nft_rbtree_elem, node); | 203 | rbe = rb_entry(node, struct nft_rbtree_elem, node); |
216 | nft_rbtree_elem_destroy(set, rbe); | 204 | nft_set_elem_destroy(set, rbe); |
217 | } | 205 | } |
218 | } | 206 | } |
219 | 207 | ||