]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/netfilter/nf_tables_api.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
[mirror_ubuntu-artful-kernel.git] / net / netfilter / nf_tables_api.c
index 1b913760f205be79e1809c983cb3140c284a00cc..5592250297402fe6e272f3213efa7e02ab230485 100644 (file)
@@ -144,7 +144,7 @@ static int nf_tables_register_hooks(struct net *net,
                                    unsigned int hook_nops)
 {
        if (table->flags & NFT_TABLE_F_DORMANT ||
-           !(chain->flags & NFT_BASE_CHAIN))
+           !nft_is_base_chain(chain))
                return 0;
 
        return nf_register_net_hooks(net, nft_base_chain(chain)->ops,
@@ -157,7 +157,7 @@ static void nf_tables_unregister_hooks(struct net *net,
                                       unsigned int hook_nops)
 {
        if (table->flags & NFT_TABLE_F_DORMANT ||
-           !(chain->flags & NFT_BASE_CHAIN))
+           !nft_is_base_chain(chain))
                return;
 
        nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, hook_nops);
@@ -240,6 +240,10 @@ static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type,
        if (trans == NULL)
                return NULL;
 
+       if (msg_type == NFT_MSG_NEWRULE && ctx->nla[NFTA_RULE_ID] != NULL) {
+               nft_trans_rule_id(trans) =
+                       ntohl(nla_get_be32(ctx->nla[NFTA_RULE_ID]));
+       }
        nft_trans_rule(trans) = rule;
        list_add_tail(&trans->list, &ctx->net->nft.commit_list);
 
@@ -434,7 +438,7 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
 
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
@@ -457,16 +461,15 @@ nla_put_failure:
        return -1;
 }
 
-static int nf_tables_table_notify(const struct nft_ctx *ctx, int event)
+static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
 {
        struct sk_buff *skb;
        int err;
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
-               return 0;
+               return;
 
-       err = -ENOBUFS;
        skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (skb == NULL)
                goto err;
@@ -478,14 +481,11 @@ static int nf_tables_table_notify(const struct nft_ctx *ctx, int event)
                goto err;
        }
 
-       err = nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                            ctx->report, GFP_KERNEL);
+       nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
+                      ctx->report, GFP_KERNEL);
+       return;
 err:
-       if (err < 0) {
-               nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                                 err);
-       }
-       return err;
+       nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 
 static int nf_tables_dump_tables(struct sk_buff *skb,
@@ -576,6 +576,28 @@ err:
        return err;
 }
 
+static void _nf_tables_table_disable(struct net *net,
+                                    const struct nft_af_info *afi,
+                                    struct nft_table *table,
+                                    u32 cnt)
+{
+       struct nft_chain *chain;
+       u32 i = 0;
+
+       list_for_each_entry(chain, &table->chains, list) {
+               if (!nft_is_active_next(net, chain))
+                       continue;
+               if (!nft_is_base_chain(chain))
+                       continue;
+
+               if (cnt && i++ == cnt)
+                       break;
+
+               nf_unregister_net_hooks(net, nft_base_chain(chain)->ops,
+                                       afi->nops);
+       }
+}
+
 static int nf_tables_table_enable(struct net *net,
                                  const struct nft_af_info *afi,
                                  struct nft_table *table)
@@ -586,7 +608,7 @@ static int nf_tables_table_enable(struct net *net,
        list_for_each_entry(chain, &table->chains, list) {
                if (!nft_is_active_next(net, chain))
                        continue;
-               if (!(chain->flags & NFT_BASE_CHAIN))
+               if (!nft_is_base_chain(chain))
                        continue;
 
                err = nf_register_net_hooks(net, nft_base_chain(chain)->ops,
@@ -598,18 +620,8 @@ static int nf_tables_table_enable(struct net *net,
        }
        return 0;
 err:
-       list_for_each_entry(chain, &table->chains, list) {
-               if (!nft_is_active_next(net, chain))
-                       continue;
-               if (!(chain->flags & NFT_BASE_CHAIN))
-                       continue;
-
-               if (i-- <= 0)
-                       break;
-
-               nf_unregister_net_hooks(net, nft_base_chain(chain)->ops,
-                                       afi->nops);
-       }
+       if (i)
+               _nf_tables_table_disable(net, afi, table, i);
        return err;
 }
 
@@ -617,17 +629,7 @@ static void nf_tables_table_disable(struct net *net,
                                    const struct nft_af_info *afi,
                                    struct nft_table *table)
 {
-       struct nft_chain *chain;
-
-       list_for_each_entry(chain, &table->chains, list) {
-               if (!nft_is_active_next(net, chain))
-                       continue;
-               if (!(chain->flags & NFT_BASE_CHAIN))
-                       continue;
-
-               nf_unregister_net_hooks(net, nft_base_chain(chain)->ops,
-                                       afi->nops);
-       }
+       _nf_tables_table_disable(net, afi, table, 0);
 }
 
 static int nf_tables_updtable(struct nft_ctx *ctx)
@@ -696,10 +698,7 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
        if (IS_ERR(table)) {
                if (PTR_ERR(table) != -ENOENT)
                        return PTR_ERR(table);
-               table = NULL;
-       }
-
-       if (table != NULL) {
+       } else {
                if (nlh->nlmsg_flags & NLM_F_EXCL)
                        return -EEXIST;
                if (nlh->nlmsg_flags & NLM_F_REPLACE)
@@ -990,7 +989,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
 
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
@@ -1008,7 +1007,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
        if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
                goto nla_put_failure;
 
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                const struct nft_base_chain *basechain = nft_base_chain(chain);
                const struct nf_hook_ops *ops = &basechain->ops[0];
                struct nlattr *nest;
@@ -1047,16 +1046,15 @@ nla_put_failure:
        return -1;
 }
 
-static int nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
+static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
 {
        struct sk_buff *skb;
        int err;
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
-               return 0;
+               return;
 
-       err = -ENOBUFS;
        skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (skb == NULL)
                goto err;
@@ -1069,14 +1067,11 @@ static int nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
                goto err;
        }
 
-       err = nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                            ctx->report, GFP_KERNEL);
+       nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
+                      ctx->report, GFP_KERNEL);
+       return;
 err:
-       if (err < 0) {
-               nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                                 err);
-       }
-       return err;
+       nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 
 static int nf_tables_dump_chains(struct sk_buff *skb,
@@ -1187,7 +1182,8 @@ static struct nft_stats __percpu *nft_stats_alloc(const struct nlattr *attr)
        struct nft_stats *stats;
        int err;
 
-       err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
+       err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy,
+                              NULL);
        if (err < 0)
                return ERR_PTR(err);
 
@@ -1231,7 +1227,7 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
 {
        BUG_ON(chain->use > 0);
 
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                struct nft_base_chain *basechain = nft_base_chain(chain);
 
                module_put(basechain->type->owner);
@@ -1262,7 +1258,7 @@ static int nft_chain_parse_hook(struct net *net,
        int err;
 
        err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
-                              nft_hook_policy);
+                              nft_hook_policy, NULL);
        if (err < 0)
                return err;
 
@@ -1369,8 +1365,8 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
        }
 
        if (nla[NFTA_CHAIN_POLICY]) {
-               if ((chain != NULL &&
-                   !(chain->flags & NFT_BASE_CHAIN)))
+               if (chain != NULL &&
+                   !nft_is_base_chain(chain))
                        return -EOPNOTSUPP;
 
                if (chain == NULL &&
@@ -1401,7 +1397,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
                        struct nft_chain_hook hook;
                        struct nf_hook_ops *ops;
 
-                       if (!(chain->flags & NFT_BASE_CHAIN))
+                       if (!nft_is_base_chain(chain))
                                return -EBUSY;
 
                        err = nft_chain_parse_hook(net, nla, afi, &hook,
@@ -1438,7 +1434,7 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
                }
 
                if (nla[NFTA_CHAIN_COUNTERS]) {
-                       if (!(chain->flags & NFT_BASE_CHAIN))
+                       if (!nft_is_base_chain(chain))
                                return -EOPNOTSUPP;
 
                        stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
@@ -1729,7 +1725,7 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
        struct nlattr *tb[NFTA_EXPR_MAX + 1];
        int err;
 
-       err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
+       err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy, NULL);
        if (err < 0)
                return err;
 
@@ -1739,7 +1735,7 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
 
        if (tb[NFTA_EXPR_DATA]) {
                err = nla_parse_nested(info->tb, type->maxattr,
-                                      tb[NFTA_EXPR_DATA], type->policy);
+                                      tb[NFTA_EXPR_DATA], type->policy, NULL);
                if (err < 0)
                        goto err1;
        } else
@@ -1777,8 +1773,19 @@ static int nf_tables_newexpr(const struct nft_ctx *ctx,
                        goto err1;
        }
 
+       if (ops->validate) {
+               const struct nft_data *data = NULL;
+
+               err = ops->validate(ctx, expr, &data);
+               if (err < 0)
+                       goto err2;
+       }
+
        return 0;
 
+err2:
+       if (ops->destroy)
+               ops->destroy(ctx, expr);
 err1:
        expr->ops = NULL;
        return err;
@@ -1879,10 +1886,9 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
        const struct nft_expr *expr, *next;
        struct nlattr *list;
        const struct nft_rule *prule;
-       int type = event | NFNL_SUBSYS_NFTABLES << 8;
+       u16 type = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
 
-       nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
-                       flags);
+       nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
 
@@ -1900,7 +1906,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
                goto nla_put_failure;
 
        if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
-               prule = list_entry(rule->list.prev, struct nft_rule, list);
+               prule = list_prev_entry(rule, list);
                if (nla_put_be64(skb, NFTA_RULE_POSITION,
                                 cpu_to_be64(prule->handle),
                                 NFTA_RULE_PAD))
@@ -1931,18 +1937,16 @@ nla_put_failure:
        return -1;
 }
 
-static int nf_tables_rule_notify(const struct nft_ctx *ctx,
-                                const struct nft_rule *rule,
-                                int event)
+static void nf_tables_rule_notify(const struct nft_ctx *ctx,
+                                 const struct nft_rule *rule, int event)
 {
        struct sk_buff *skb;
        int err;
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
-               return 0;
+               return;
 
-       err = -ENOBUFS;
        skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (skb == NULL)
                goto err;
@@ -1955,14 +1959,11 @@ static int nf_tables_rule_notify(const struct nft_ctx *ctx,
                goto err;
        }
 
-       err = nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                            ctx->report, GFP_KERNEL);
+       nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES,
+                      ctx->report, GFP_KERNEL);
+       return;
 err:
-       if (err < 0) {
-               nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES,
-                                 err);
-       }
-       return err;
+       nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 
 struct nft_rule_dump_ctx {
@@ -2294,6 +2295,22 @@ err1:
        return err;
 }
 
+static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
+                                            const struct nlattr *nla)
+{
+       u32 id = ntohl(nla_get_be32(nla));
+       struct nft_trans *trans;
+
+       list_for_each_entry(trans, &net->nft.commit_list, list) {
+               struct nft_rule *rule = nft_trans_rule(trans);
+
+               if (trans->msg_type == NFT_MSG_NEWRULE &&
+                   id == nft_trans_rule_id(trans))
+                       return rule;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 static int nf_tables_delrule(struct net *net, struct sock *nlsk,
                             struct sk_buff *skb, const struct nlmsghdr *nlh,
                             const struct nlattr * const nla[])
@@ -2331,6 +2348,12 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
                        if (IS_ERR(rule))
                                return PTR_ERR(rule);
 
+                       err = nft_delrule(&ctx, rule);
+               } else if (nla[NFTA_RULE_ID]) {
+                       rule = nft_rule_lookup_byid(net, nla[NFTA_RULE_ID]);
+                       if (IS_ERR(rule))
+                               return PTR_ERR(rule);
+
                        err = nft_delrule(&ctx, rule);
                } else {
                        err = nft_delrule_by_chain(&ctx);
@@ -2399,12 +2422,14 @@ nft_select_set_ops(const struct nlattr * const nla[],
        features = 0;
        if (nla[NFTA_SET_FLAGS] != NULL) {
                features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
-               features &= NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_TIMEOUT;
+               features &= NFT_SET_INTERVAL | NFT_SET_MAP | NFT_SET_TIMEOUT |
+                           NFT_SET_OBJECT;
        }
 
-       bops       = NULL;
-       best.size  = ~0;
-       best.class = ~0;
+       bops        = NULL;
+       best.size   = ~0;
+       best.lookup = ~0;
+       best.space  = ~0;
 
        list_for_each_entry(ops, &nf_tables_set_ops, list) {
                if ((ops->features & features) != features)
@@ -2414,16 +2439,27 @@ nft_select_set_ops(const struct nlattr * const nla[],
 
                switch (policy) {
                case NFT_SET_POL_PERFORMANCE:
-                       if (est.class < best.class)
-                               break;
-                       if (est.class == best.class && est.size < best.size)
+                       if (est.lookup < best.lookup)
                                break;
+                       if (est.lookup == best.lookup) {
+                               if (!desc->size) {
+                                       if (est.space < best.space)
+                                               break;
+                               } else if (est.size < best.size) {
+                                       break;
+                               }
+                       }
                        continue;
                case NFT_SET_POL_MEMORY:
-                       if (est.size < best.size)
-                               break;
-                       if (est.size == best.size && est.class < best.class)
+                       if (!desc->size) {
+                               if (est.space < best.space)
+                                       break;
+                               if (est.space == best.space &&
+                                   est.lookup < best.lookup)
+                                       break;
+                       } else if (est.size < best.size) {
                                break;
+                       }
                        continue;
                default:
                        break;
@@ -2498,8 +2534,8 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
        return 0;
 }
 
-struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
-                                    const struct nlattr *nla, u8 genmask)
+static struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
+                                           const struct nlattr *nla, u8 genmask)
 {
        struct nft_set *set;
 
@@ -2513,11 +2549,10 @@ struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
        }
        return ERR_PTR(-ENOENT);
 }
-EXPORT_SYMBOL_GPL(nf_tables_set_lookup);
 
-struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
-                                         const struct nlattr *nla,
-                                         u8 genmask)
+static struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
+                                                const struct nlattr *nla,
+                                                u8 genmask)
 {
        struct nft_trans *trans;
        u32 id = ntohl(nla_get_be32(nla));
@@ -2532,7 +2567,25 @@ struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
        }
        return ERR_PTR(-ENOENT);
 }
-EXPORT_SYMBOL_GPL(nf_tables_set_lookup_byid);
+
+struct nft_set *nft_set_lookup(const struct net *net,
+                              const struct nft_table *table,
+                              const struct nlattr *nla_set_name,
+                              const struct nlattr *nla_set_id,
+                              u8 genmask)
+{
+       struct nft_set *set;
+
+       set = nf_tables_set_lookup(table, nla_set_name, genmask);
+       if (IS_ERR(set)) {
+               if (!nla_set_id)
+                       return set;
+
+               set = nf_tables_set_lookup_byid(net, nla_set_id, genmask);
+       }
+       return set;
+}
+EXPORT_SYMBOL_GPL(nft_set_lookup);
 
 static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
                                    const char *name)
@@ -2592,7 +2645,7 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
        u32 portid = ctx->portid;
        u32 seq = ctx->seq;
 
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
                        flags);
        if (nlh == NULL)
@@ -2658,9 +2711,9 @@ nla_put_failure:
        return -1;
 }
 
-static int nf_tables_set_notify(const struct nft_ctx *ctx,
-                               const struct nft_set *set,
-                               int event, gfp_t gfp_flags)
+static void nf_tables_set_notify(const struct nft_ctx *ctx,
+                                const struct nft_set *set, int event,
+                                gfp_t gfp_flags)
 {
        struct sk_buff *skb;
        u32 portid = ctx->portid;
@@ -2668,9 +2721,8 @@ static int nf_tables_set_notify(const struct nft_ctx *ctx,
 
        if (!ctx->report &&
            !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
-               return 0;
+               return;
 
-       err = -ENOBUFS;
        skb = nlmsg_new(NLMSG_GOODSIZE, gfp_flags);
        if (skb == NULL)
                goto err;
@@ -2681,12 +2733,11 @@ static int nf_tables_set_notify(const struct nft_ctx *ctx,
                goto err;
        }
 
-       err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES,
-                            ctx->report, gfp_flags);
+       nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, ctx->report,
+                      gfp_flags);
+       return;
 err:
-       if (err < 0)
-               nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
-       return err;
+       nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 
 static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
@@ -2828,7 +2879,8 @@ static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
        struct nlattr *da[NFTA_SET_DESC_MAX + 1];
        int err;
 
-       err = nla_parse_nested(da, NFTA_SET_DESC_MAX, nla, nft_set_desc_policy);
+       err = nla_parse_nested(da, NFTA_SET_DESC_MAX, nla,
+                              nft_set_desc_policy, NULL);
        if (err < 0)
                return err;
 
@@ -2966,10 +3018,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
        if (IS_ERR(set)) {
                if (PTR_ERR(set) != -ENOENT)
                        return PTR_ERR(set);
-               set = NULL;
-       }
-
-       if (set != NULL) {
+       } else {
                if (nlh->nlmsg_flags & NLM_F_EXCL)
                        return -EEXIST;
                if (nlh->nlmsg_flags & NLM_F_REPLACE)
@@ -3333,7 +3382,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        int event, err;
 
        err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla,
-                         NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy);
+                         NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy,
+                         NULL);
        if (err < 0)
                return err;
 
@@ -3347,8 +3397,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        if (IS_ERR(set))
                return PTR_ERR(set);
 
-       event  = NFT_MSG_NEWSETELEM;
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event  = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSETELEM);
        portid = NETLINK_CB(cb->skb).portid;
        seq    = cb->nlh->nlmsg_seq;
 
@@ -3433,7 +3482,7 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb,
        struct nlattr *nest;
        int err;
 
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
                        flags);
        if (nlh == NULL)
@@ -3467,10 +3516,10 @@ nla_put_failure:
        return -1;
 }
 
-static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
-                                   const struct nft_set *set,
-                                   const struct nft_set_elem *elem,
-                                   int event, u16 flags)
+static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
+                                    const struct nft_set *set,
+                                    const struct nft_set_elem *elem,
+                                    int event, u16 flags)
 {
        struct net *net = ctx->net;
        u32 portid = ctx->portid;
@@ -3478,9 +3527,8 @@ static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
        int err;
 
        if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
-               return 0;
+               return;
 
-       err = -ENOBUFS;
        skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (skb == NULL)
                goto err;
@@ -3492,12 +3540,11 @@ static int nf_tables_setelem_notify(const struct nft_ctx *ctx,
                goto err;
        }
 
-       err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, ctx->report,
-                            GFP_KERNEL);
+       nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, ctx->report,
+                      GFP_KERNEL);
+       return;
 err:
-       if (err < 0)
-               nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
-       return err;
+       nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 
 static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
@@ -3594,7 +3641,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        int err;
 
        err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
-                              nft_set_elem_policy);
+                              nft_set_elem_policy, NULL);
        if (err < 0)
                return err;
 
@@ -3731,6 +3778,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        err = set->ops->insert(ctx->net, set, &elem, &ext2);
        if (err) {
                if (err == -EEXIST) {
+                       if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^
+                           nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) ||
+                           nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^
+                           nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF))
+                               return -EBUSY;
                        if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
                             nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
                             memcmp(nft_set_ext_data(ext),
@@ -3756,7 +3808,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        return 0;
 
 err6:
-       set->ops->remove(set, &elem);
+       set->ops->remove(ctx->net, set, &elem);
 err5:
        kfree(trans);
 err4:
@@ -3824,7 +3876,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
        int err;
 
        err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
-                              nft_set_elem_policy);
+                              nft_set_elem_policy, NULL);
        if (err < 0)
                goto err1;
 
@@ -3902,7 +3954,7 @@ static int nft_flush_set(const struct nft_ctx *ctx,
        if (!trans)
                return -ENOMEM;
 
-       if (!set->ops->deactivate_one(ctx->net, set, elem->priv)) {
+       if (!set->ops->flush(ctx->net, set, elem->priv)) {
                err = -ENOENT;
                goto err1;
        }
@@ -3940,15 +3992,13 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
                return -EBUSY;
 
        if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) {
-               struct nft_set_dump_args args = {
-                       .iter   = {
-                               .genmask        = genmask,
-                               .fn             = nft_flush_set,
-                       },
+               struct nft_set_iter iter = {
+                       .genmask        = genmask,
+                       .fn             = nft_flush_set,
                };
-               set->ops->walk(&ctx, set, &args.iter);
+               set->ops->walk(&ctx, set, &iter);
 
-               return args.iter.err;
+               return iter.err;
        }
 
        nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
@@ -4048,7 +4098,8 @@ static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
        [NFTA_OBJ_DATA]         = { .type = NLA_NESTED },
 };
 
-static struct nft_object *nft_obj_init(const struct nft_object_type *type,
+static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
+                                      const struct nft_object_type *type,
                                       const struct nlattr *attr)
 {
        struct nlattr *tb[type->maxattr + 1];
@@ -4056,7 +4107,8 @@ static struct nft_object *nft_obj_init(const struct nft_object_type *type,
        int err;
 
        if (attr) {
-               err = nla_parse_nested(tb, type->maxattr, attr, type->policy);
+               err = nla_parse_nested(tb, type->maxattr, attr, type->policy,
+                                      NULL);
                if (err < 0)
                        goto err1;
        } else {
@@ -4068,7 +4120,7 @@ static struct nft_object *nft_obj_init(const struct nft_object_type *type,
        if (obj == NULL)
                goto err1;
 
-       err = type->init((const struct nlattr * const *)tb, obj);
+       err = type->init(ctx, (const struct nlattr * const *)tb, obj);
        if (err < 0)
                goto err2;
 
@@ -4163,10 +4215,7 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
                if (err != -ENOENT)
                        return err;
 
-               obj = NULL;
-       }
-
-       if (obj != NULL) {
+       } else {
                if (nlh->nlmsg_flags & NLM_F_EXCL)
                        return -EEXIST;
 
@@ -4179,7 +4228,7 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
        if (IS_ERR(type))
                return PTR_ERR(type);
 
-       obj = nft_obj_init(type, nla[NFTA_OBJ_DATA]);
+       obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
        if (IS_ERR(obj)) {
                err = PTR_ERR(obj);
                goto err1;
@@ -4211,7 +4260,7 @@ static int nf_tables_fill_obj_info(struct sk_buff *skb, struct net *net,
        struct nfgenmsg *nfmsg;
        struct nlmsghdr *nlh;
 
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
@@ -4393,8 +4442,6 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
 err:
        kfree_skb(skb2);
        return err;
-
-       return 0;
 }
 
 static void nft_obj_destroy(struct nft_object *obj)
@@ -4443,18 +4490,17 @@ static int nf_tables_delobj(struct net *net, struct sock *nlsk,
        return nft_delobj(&ctx, obj);
 }
 
-int nft_obj_notify(struct net *net, struct nft_table *table,
-                  struct nft_object *obj, u32 portid, u32 seq, int event,
-                  int family, int report, gfp_t gfp)
+void nft_obj_notify(struct net *net, struct nft_table *table,
+                   struct nft_object *obj, u32 portid, u32 seq, int event,
+                   int family, int report, gfp_t gfp)
 {
        struct sk_buff *skb;
        int err;
 
        if (!report &&
            !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
-               return 0;
+               return;
 
-       err = -ENOBUFS;
        skb = nlmsg_new(NLMSG_GOODSIZE, gfp);
        if (skb == NULL)
                goto err;
@@ -4466,21 +4512,18 @@ int nft_obj_notify(struct net *net, struct nft_table *table,
                goto err;
        }
 
-       err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report, gfp);
+       nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report, gfp);
+       return;
 err:
-       if (err < 0) {
-               nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
-       }
-       return err;
+       nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 EXPORT_SYMBOL_GPL(nft_obj_notify);
 
-static int nf_tables_obj_notify(const struct nft_ctx *ctx,
-                               struct nft_object *obj, int event)
+static void nf_tables_obj_notify(const struct nft_ctx *ctx,
+                                struct nft_object *obj, int event)
 {
-       return nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid,
-                             ctx->seq, event, ctx->afi->family, ctx->report,
-                             GFP_KERNEL);
+       nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, ctx->seq, event,
+                      ctx->afi->family, ctx->report, GFP_KERNEL);
 }
 
 static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
@@ -4488,7 +4531,7 @@ static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
 {
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
-       int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWGEN;
+       int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
 
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), 0);
        if (nlh == NULL)
@@ -4510,7 +4553,8 @@ nla_put_failure:
        return -EMSGSIZE;
 }
 
-static int nf_tables_gen_notify(struct net *net, struct sk_buff *skb, int event)
+static void nf_tables_gen_notify(struct net *net, struct sk_buff *skb,
+                                int event)
 {
        struct nlmsghdr *nlh = nlmsg_hdr(skb);
        struct sk_buff *skb2;
@@ -4518,9 +4562,8 @@ static int nf_tables_gen_notify(struct net *net, struct sk_buff *skb, int event)
 
        if (nlmsg_report(nlh) &&
            !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
-               return 0;
+               return;
 
-       err = -ENOBUFS;
        skb2 = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if (skb2 == NULL)
                goto err;
@@ -4532,14 +4575,12 @@ static int nf_tables_gen_notify(struct net *net, struct sk_buff *skb, int event)
                goto err;
        }
 
-       err = nfnetlink_send(skb2, net, NETLINK_CB(skb).portid,
-                            NFNLGRP_NFTABLES, nlmsg_report(nlh), GFP_KERNEL);
+       nfnetlink_send(skb2, net, NETLINK_CB(skb).portid, NFNLGRP_NFTABLES,
+                      nlmsg_report(nlh), GFP_KERNEL);
+       return;
 err:
-       if (err < 0) {
-               nfnetlink_set_err(net, NETLINK_CB(skb).portid, NFNLGRP_NFTABLES,
-                                 err);
-       }
-       return err;
+       nfnetlink_set_err(net, NETLINK_CB(skb).portid, NFNLGRP_NFTABLES,
+                         -ENOBUFS);
 }
 
 static int nf_tables_getgen(struct net *net, struct sock *nlsk,
@@ -4672,7 +4713,7 @@ static void nft_chain_commit_update(struct nft_trans *trans)
        if (nft_trans_chain_name(trans)[0])
                strcpy(trans->ctx.chain->name, nft_trans_chain_name(trans));
 
-       if (!(trans->ctx.chain->flags & NFT_BASE_CHAIN))
+       if (!nft_is_base_chain(trans->ctx.chain))
                return;
 
        basechain = nft_base_chain(trans->ctx.chain);
@@ -4811,7 +4852,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                        nf_tables_setelem_notify(&trans->ctx, te->set,
                                                 &te->elem,
                                                 NFT_MSG_DELSETELEM, 0);
-                       te->set->ops->remove(te->set, &te->elem);
+                       te->set->ops->remove(net, te->set, &te->elem);
                        atomic_dec(&te->set->nelems);
                        te->set->ndeact--;
                        break;
@@ -4932,7 +4973,7 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
                case NFT_MSG_NEWSETELEM:
                        te = (struct nft_trans_elem *)trans->data;
 
-                       te->set->ops->remove(te->set, &te->elem);
+                       te->set->ops->remove(net, te->set, &te->elem);
                        atomic_dec(&te->set->nelems);
                        break;
                case NFT_MSG_DELSETELEM:
@@ -4966,6 +5007,11 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
        return 0;
 }
 
+static bool nf_tables_valid_genid(struct net *net, u32 genid)
+{
+       return net->nft.base_seq == genid;
+}
+
 static const struct nfnetlink_subsystem nf_tables_subsys = {
        .name           = "nf_tables",
        .subsys_id      = NFNL_SUBSYS_NFTABLES,
@@ -4973,6 +5019,7 @@ static const struct nfnetlink_subsystem nf_tables_subsys = {
        .cb             = nf_tables_cb,
        .commit         = nf_tables_commit,
        .abort          = nf_tables_abort,
+       .valid_genid    = nf_tables_valid_genid,
 };
 
 int nft_chain_validate_dependency(const struct nft_chain *chain,
@@ -4980,7 +5027,7 @@ int nft_chain_validate_dependency(const struct nft_chain *chain,
 {
        const struct nft_base_chain *basechain;
 
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                basechain = nft_base_chain(chain);
                if (basechain->type->type != type)
                        return -EOPNOTSUPP;
@@ -4994,7 +5041,7 @@ int nft_chain_validate_hooks(const struct nft_chain *chain,
 {
        struct nft_base_chain *basechain;
 
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                basechain = nft_base_chain(chain);
 
                if ((1 << basechain->ops[0].hooknum) & hook_flags)
@@ -5272,7 +5319,8 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
        struct nft_chain *chain;
        int err;
 
-       err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
+       err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy,
+                              NULL);
        if (err < 0)
                return err;
 
@@ -5303,7 +5351,7 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
                                               tb[NFTA_VERDICT_CHAIN], genmask);
                if (IS_ERR(chain))
                        return PTR_ERR(chain);
-               if (chain->flags & NFT_BASE_CHAIN)
+               if (nft_is_base_chain(chain))
                        return -EOPNOTSUPP;
 
                chain->use++;
@@ -5402,7 +5450,7 @@ int nft_data_init(const struct nft_ctx *ctx,
        struct nlattr *tb[NFTA_DATA_MAX + 1];
        int err;
 
-       err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
+       err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy, NULL);
        if (err < 0)
                return err;
 
@@ -5476,7 +5524,7 @@ int __nft_release_basechain(struct nft_ctx *ctx)
 {
        struct nft_rule *rule, *nr;
 
-       BUG_ON(!(ctx->chain->flags & NFT_BASE_CHAIN));
+       BUG_ON(!nft_is_base_chain(ctx->chain));
 
        nf_tables_unregister_hooks(ctx->net, ctx->chain->table, ctx->chain,
                                   ctx->afi->nops);