summaryrefslogtreecommitdiffstats
path: root/net/netfilter/nft_hash.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2015-03-25 14:08:50 +0000
committerPablo Neira Ayuso <pablo@netfilter.org>2015-03-26 11:09:35 +0100
commitcc02e457bb86f7b6ffee3651bab22d104b60effb (patch)
tree49f656039fee513e2ae6eeba06e141993c15ab9f /net/netfilter/nft_hash.c
parentea4bd995b0f2fc5677ff8085e92a5d2544b9937c (diff)
downloadlinux-cc02e457bb86f7b6ffee3651bab22d104b60effb.tar.bz2
netfilter: nf_tables: implement set transaction support
Set elements are the last object type not supporting transaction support. Implement similar to the existing rule transactions: The global transaction counter keeps track of two generations, current and next. Each element contains a bitmask specifying in which generations it is inactive. New elements start out as inactive in the current generation and active in the next. On commit, the previous next generation becomes the current generation and the element becomes active. The bitmask is then cleared to indicate that the element is active in all future generations. If the transaction is aborted, the element is removed from the set before it becomes active. When removing an element, it gets marked as inactive in the next generation. On commit the next generation becomes active and the therefor the element inactive. It is then taken out of then set and released. On abort, the element is marked as active for the next generation again. Lookups ignore elements not active in the current generation. The current set types (hash/rbtree) both use a field in the extension area to store the generation mask. This (currently) does not require any additional memory since we have some free space in there. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter/nft_hash.c')
-rw-r--r--net/netfilter/nft_hash.c38
1 files changed, 28 insertions, 10 deletions
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 {
struct nft_hash_cmp_arg {
const struct nft_set *set;
const struct nft_data *key;
+ u8 genmask;
};
static const struct rhashtable_params nft_hash_params;
@@ -61,6 +62,8 @@ static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg,
if (nft_data_cmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
return 1;
+ if (!nft_set_elem_active(&he->ext, x->genmask))
+ return 1;
return 0;
}
@@ -71,6 +74,7 @@ static bool nft_hash_lookup(const struct nft_set *set,
struct nft_hash *priv = nft_set_priv(set);
const struct nft_hash_elem *he;
struct nft_hash_cmp_arg arg = {
+ .genmask = nft_genmask_cur(read_pnet(&set->pnet)),
.set = set,
.key = key,
};
@@ -88,6 +92,7 @@ static int nft_hash_insert(const struct nft_set *set,
struct nft_hash *priv = nft_set_priv(set);
struct nft_hash_elem *he = elem->priv;
struct nft_hash_cmp_arg arg = {
+ .genmask = nft_genmask_next(read_pnet(&set->pnet)),
.set = set,
.key = &elem->key,
};
@@ -96,30 +101,39 @@ static int nft_hash_insert(const struct nft_set *set,
nft_hash_params);
}
-static void nft_hash_remove(const struct nft_set *set,
- const struct nft_set_elem *elem)
+static void nft_hash_activate(const struct nft_set *set,
+ const struct nft_set_elem *elem)
{
- struct nft_hash *priv = nft_set_priv(set);
+ struct nft_hash_elem *he = elem->priv;
- rhashtable_remove_fast(&priv->ht, elem->cookie, nft_hash_params);
+ nft_set_elem_change_active(set, &he->ext);
}
-static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem)
+static void *nft_hash_deactivate(const struct nft_set *set,
+ const struct nft_set_elem *elem)
{
struct nft_hash *priv = nft_set_priv(set);
struct nft_hash_elem *he;
struct nft_hash_cmp_arg arg = {
+ .genmask = nft_genmask_next(read_pnet(&set->pnet)),
.set = set,
.key = &elem->key,
};
he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params);
- if (!he)
- return -ENOENT;
+ if (he != NULL)
+ nft_set_elem_change_active(set, &he->ext);
- elem->priv = he;
+ return he;
+}
- return 0;
+static void nft_hash_remove(const struct nft_set *set,
+ const struct nft_set_elem *elem)
+{
+ struct nft_hash *priv = nft_set_priv(set);
+ struct nft_hash_elem *he = elem->priv;
+
+ rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params);
}
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,
struct nft_hash_elem *he;
struct rhashtable_iter hti;
struct nft_set_elem elem;
+ u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
int err;
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,
if (iter->count < iter->skip)
goto cont;
+ if (!nft_set_elem_active(&he->ext, genmask))
+ goto cont;
elem.priv = he;
@@ -241,8 +258,9 @@ static struct nft_set_ops nft_hash_ops __read_mostly = {
.estimate = nft_hash_estimate,
.init = nft_hash_init,
.destroy = nft_hash_destroy,
- .get = nft_hash_get,
.insert = nft_hash_insert,
+ .activate = nft_hash_activate,
+ .deactivate = nft_hash_deactivate,
.remove = nft_hash_remove,
.lookup = nft_hash_lookup,
.walk = nft_hash_walk,