aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2015-03-25 10:08:47 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2015-03-26 06:09:34 -0400
commit61edafbb47e9f46fb850035b1f8f062564445704 (patch)
tree9adc749e66e69c6cd5b1d82434ab00bf1c406670
parentfe2811ebeb97a7a76de0b2b35f13600169508393 (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.h2
-rw-r--r--net/netfilter/nf_tables_api.c34
-rw-r--r--net/netfilter/nft_hash.c18
-rw-r--r--net/netfilter/nft_rbtree.c14
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
426void 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
3158void 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}
3168EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
3169
3158static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, 3170static 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
99static 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
108static void nft_hash_remove(const struct nft_set *set, 99static 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
118static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) 107static 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, &params); 197 return rhashtable_init(&priv->ht, &params);
209} 198}
210 199
211static void nft_free_element(void *ptr, void *arg) 200static 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
216static void nft_hash_destroy(const struct nft_set *set) 205static 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
223static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, 213static 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
75static 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
86static int __nft_rbtree_insert(const struct nft_set *set, 75static 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
139static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) 127static 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