From: Pablo Neira Ayuso <[email protected]>

Similar to ("netfilter: nf_tables: add generation mask to tables").

Signed-off-by: Pablo Neira Ayuso <[email protected]>
(cherry picked from commit 37a9cc52552579f22e18cca401cfc4351b6cbc72)

https://bugs.openvz.org/browse/OVZ-7223
Signed-off-by: Vasily Averin <[email protected]>
---
 include/net/netfilter/nf_tables.h |  8 +++--
 net/netfilter/nf_tables_api.c     | 68 +++++++++++++++++++++++----------------
 net/netfilter/nft_dynset.c        |  7 ++--
 net/netfilter/nft_lookup.c        |  6 ++--
 4 files changed, 54 insertions(+), 35 deletions(-)

diff --git a/include/net/netfilter/nf_tables.h 
b/include/net/netfilter/nf_tables.h
index b16862e..eab0bd3 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -349,6 +349,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
  *     @ops: set ops
  *     @pnet: network namespace
  *     @flags: set flags
+ *     @genmask: generation mask
  *     @klen: key length
  *     @dlen: data length
  *     @data: private set data
@@ -370,7 +371,8 @@ struct nft_set {
        /* runtime data below here */
        const struct nft_set_ops        *ops ____cacheline_aligned;
        possible_net_t                  pnet;
-       u16                             flags;
+       u16                             flags:14,
+                                       genmask:2;
        u8                              klen;
        u8                              dlen;
        unsigned char                   data[]
@@ -388,9 +390,9 @@ static inline struct nft_set *nft_set_container_of(const 
void *priv)
 }
 
 struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
-                                    const struct nlattr *nla);
+                                    const struct nlattr *nla, u8 genmask);
 struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
-                                         const struct nlattr *nla);
+                                         const struct nlattr *nla, u8 genmask);
 
 static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
 {
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 04921ce..1cea127 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -288,9 +288,6 @@ static int nft_delrule_by_chain(struct nft_ctx *ctx)
        return 0;
 }
 
-/* Internal set flag */
-#define NFT_SET_INACTIVE       (1 << 15)
-
 static int nft_trans_set_add(struct nft_ctx *ctx, int msg_type,
                             struct nft_set *set)
 {
@@ -303,7 +300,7 @@ static int nft_trans_set_add(struct nft_ctx *ctx, int 
msg_type,
        if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
                nft_trans_set_id(trans) =
                        ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
-               set->flags |= NFT_SET_INACTIVE;
+               nft_activate_next(ctx->net, set);
        }
        nft_trans_set(trans) = set;
        list_add_tail(&trans->list, &ctx->net->nft.commit_list);
@@ -319,7 +316,7 @@ static int nft_delset(struct nft_ctx *ctx, struct nft_set 
*set)
        if (err < 0)
                return err;
 
-       list_del_rcu(&set->list);
+       nft_deactivate_next(ctx->net, set);
        ctx->table->use--;
 
        return err;
@@ -739,6 +736,9 @@ static int nft_flush_table(struct nft_ctx *ctx)
        }
 
        list_for_each_entry_safe(set, ns, &ctx->table->sets, list) {
+               if (!nft_is_active_next(ctx->net, set))
+                       continue;
+
                if (set->flags & NFT_SET_ANONYMOUS &&
                    !list_empty(&set->bindings))
                        continue;
@@ -2436,7 +2436,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, 
struct net *net,
 }
 
 struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
-                                    const struct nlattr *nla)
+                                    const struct nlattr *nla, u8 genmask)
 {
        struct nft_set *set;
 
@@ -2444,22 +2444,27 @@ struct nft_set *nf_tables_set_lookup(const struct 
nft_table *table,
                return ERR_PTR(-EINVAL);
 
        list_for_each_entry(set, &table->sets, list) {
-               if (!nla_strcmp(nla, set->name))
+               if (!nla_strcmp(nla, set->name) &&
+                   nft_active_genmask(set, genmask))
                        return set;
        }
        return ERR_PTR(-ENOENT);
 }
 
 struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
-                                         const struct nlattr *nla)
+                                         const struct nlattr *nla,
+                                         u8 genmask)
 {
        struct nft_trans *trans;
        u32 id = ntohl(nla_get_be32(nla));
 
        list_for_each_entry(trans, &net->nft.commit_list, list) {
+               struct nft_set *set = nft_trans_set(trans);
+
                if (trans->msg_type == NFT_MSG_NEWSET &&
-                   id == nft_trans_set_id(trans))
-                       return nft_trans_set(trans);
+                   id == nft_trans_set_id(trans) &&
+                   nft_active_genmask(set, genmask))
+                       return set;
        }
        return ERR_PTR(-ENOENT);
 }
@@ -2484,6 +2489,8 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, 
struct nft_set *set,
                list_for_each_entry(i, &ctx->table->sets, list) {
                        int tmp;
 
+                       if (!nft_is_active_next(ctx->net, set))
+                               continue;
                        if (!sscanf(i->name, name, &tmp))
                                continue;
                        if (tmp < min || tmp >= min + BITS_PER_BYTE * PAGE_SIZE)
@@ -2503,6 +2510,8 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, 
struct nft_set *set,
 
        snprintf(set->name, sizeof(set->name), name, min + n);
        list_for_each_entry(i, &ctx->table->sets, list) {
+               if (!nft_is_active_next(ctx->net, i))
+                       continue;
                if (!strcmp(set->name, i->name))
                        return -ENFILE;
        }
@@ -2652,6 +2661,8 @@ static int nf_tables_dump_sets(struct sk_buff *skb, 
struct netlink_callback *cb)
                        list_for_each_entry_rcu(set, &table->sets, list) {
                                if (idx < s_idx)
                                        goto cont;
+                               if (!nft_is_active(net, set))
+                                       goto cont;
 
                                ctx_set = *ctx;
                                ctx_set.table = table;
@@ -2724,11 +2735,9 @@ static int nf_tables_getset(struct sock *nlsk, struct 
sk_buff *skb,
        if (!nla[NFTA_SET_TABLE])
                return -EINVAL;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
+       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
        if (IS_ERR(set))
                return PTR_ERR(set);
-       if (set->flags & NFT_SET_INACTIVE)
-               return -ENOENT;
 
        skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
        if (skb2 == NULL)
@@ -2872,7 +2881,7 @@ static int nf_tables_newset(struct net *net, struct sock 
*nlsk,
 
        nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
 
-       set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
+       set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME], genmask);
        if (IS_ERR(set)) {
                if (PTR_ERR(set) != -ENOENT)
                        return PTR_ERR(set);
@@ -2987,7 +2996,7 @@ static int nf_tables_delset(struct net *net, struct sock 
*nlsk,
        if (err < 0)
                return err;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
+       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
        if (IS_ERR(set))
                return PTR_ERR(set);
        if (!list_empty(&set->bindings))
@@ -3056,7 +3065,7 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, 
struct nft_set *set,
        list_del_rcu(&binding->list);
 
        if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS &&
-           !(set->flags & NFT_SET_INACTIVE))
+           nft_is_active(ctx->net, set))
                nf_tables_set_destroy(ctx, set);
 }
 
@@ -3244,11 +3253,10 @@ static int nf_tables_dump_set(struct sk_buff *skb, 
struct netlink_callback *cb)
        if (err < 0)
                return err;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+                                  genmask);
        if (IS_ERR(set))
                return PTR_ERR(set);
-       if (set->flags & NFT_SET_INACTIVE)
-               return -ENOENT;
 
        event  = NFT_MSG_NEWSETELEM;
        event |= NFNL_SUBSYS_NFTABLES << 8;
@@ -3311,11 +3319,10 @@ static int nf_tables_getsetelem(struct sock *nlsk, 
struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+                                  genmask);
        if (IS_ERR(set))
                return PTR_ERR(set);
-       if (set->flags & NFT_SET_INACTIVE)
-               return -ENOENT;
 
        if (nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
@@ -3638,11 +3645,13 @@ static int nf_tables_newsetelem(struct net *net, struct 
sock *nlsk,
        if (err < 0)
                return err;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+                                  genmask);
        if (IS_ERR(set)) {
                if (nla[NFTA_SET_ELEM_LIST_SET_ID]) {
                        set = nf_tables_set_lookup_byid(net,
-                                       nla[NFTA_SET_ELEM_LIST_SET_ID]);
+                                       nla[NFTA_SET_ELEM_LIST_SET_ID],
+                                       genmask);
                }
                if (IS_ERR(set))
                        return PTR_ERR(set);
@@ -3759,7 +3768,8 @@ static int nf_tables_delsetelem(struct net *net, struct 
sock *nlsk,
        if (err < 0)
                return err;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
+       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET],
+                                  genmask);
        if (IS_ERR(set))
                return PTR_ERR(set);
        if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
@@ -4085,7 +4095,7 @@ static int nf_tables_commit(struct sk_buff *skb)
                                              NFT_MSG_DELRULE);
                        break;
                case NFT_MSG_NEWSET:
-                       nft_trans_set(trans)->flags &= ~NFT_SET_INACTIVE;
+                       nft_clear(net, nft_trans_set(trans));
                        /* This avoids hitting -EBUSY when deleting the table
                         * from the transaction.
                         */
@@ -4098,6 +4108,7 @@ static int nf_tables_commit(struct sk_buff *skb)
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSET:
+                       list_del_rcu(&nft_trans_set(trans)->list);
                        nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
                                             NFT_MSG_DELSET, GFP_KERNEL);
                        break;
@@ -4216,8 +4227,7 @@ static int __nf_tables_abort(struct net *net)
                        break;
                case NFT_MSG_DELSET:
                        trans->ctx.table->use++;
-                       list_add_tail_rcu(&nft_trans_set(trans)->list,
-                                         &trans->ctx.table->sets);
+                       nft_clear(trans->ctx.net, nft_trans_set(trans));
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_NEWSETELEM:
@@ -4372,6 +4382,8 @@ static int nf_tables_check_loops(const struct nft_ctx 
*ctx,
        }
 
        list_for_each_entry(set, &ctx->table->sets, list) {
+               if (!nft_is_active_next(ctx->net, set))
+                       continue;
                if (!(set->flags & NFT_SET_MAP) ||
                    set->dtype != NFT_DATA_VERDICT)
                        continue;
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 3f9f8e8..6212273 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -106,6 +106,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_dynset *priv = nft_expr_priv(expr);
+       u8 genmask = nft_genmask_next(ctx->net);
        struct nft_set *set;
        u64 timeout;
        int err;
@@ -115,11 +116,13 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
            tb[NFTA_DYNSET_SREG_KEY] == NULL)
                return -EINVAL;
 
-       set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME]);
+       set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME],
+                                  genmask);
        if (IS_ERR(set)) {
                if (tb[NFTA_DYNSET_SET_ID])
                        set = nf_tables_set_lookup_byid(ctx->net,
-                                                       tb[NFTA_DYNSET_SET_ID]);
+                                                       tb[NFTA_DYNSET_SET_ID],
+                                                       genmask);
                if (IS_ERR(set))
                        return PTR_ERR(set);
        }
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
index c9ce7d6..6c0b285 100644
--- a/net/netfilter/nft_lookup.c
+++ b/net/netfilter/nft_lookup.c
@@ -62,6 +62,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_lookup *priv = nft_expr_priv(expr);
+       u8 genmask = nft_genmask_next(ctx->net);
        struct nft_set *set;
        u32 flags;
        int err;
@@ -70,11 +71,12 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
            tb[NFTA_LOOKUP_SREG] == NULL)
                return -EINVAL;
 
-       set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET]);
+       set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET], genmask);
        if (IS_ERR(set)) {
                if (tb[NFTA_LOOKUP_SET_ID]) {
                        set = nf_tables_set_lookup_byid(ctx->net,
-                                                       tb[NFTA_LOOKUP_SET_ID]);
+                                                       tb[NFTA_LOOKUP_SET_ID],
+                                                       genmask);
                }
                if (IS_ERR(set))
                        return PTR_ERR(set);
-- 
1.8.3.1

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to