int                             (*insert)(const struct net *net,
                                                  const struct nft_set *set,
-                                                 const struct nft_set_elem *elem);
+                                                 const struct nft_set_elem *elem,
+                                                 struct nft_set_ext **ext);
        void                            (*activate)(const struct net *net,
                                                    const struct nft_set *set,
                                                    const struct nft_set_elem *elem);
 
 }
 
 static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
-                           const struct nlattr *attr)
+                           const struct nlattr *attr, u32 nlmsg_flags)
 {
        struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
        struct nft_data_desc d1, d2;
        struct nft_set_ext_tmpl tmpl;
-       struct nft_set_ext *ext;
+       struct nft_set_ext *ext, *ext2;
        struct nft_set_elem elem;
        struct nft_set_binding *binding;
        struct nft_userdata *udata;
                goto err4;
 
        ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
-       err = set->ops->insert(ctx->net, set, &elem);
-       if (err < 0)
+       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) &&
+                           memcmp(nft_set_ext_data(ext),
+                                  nft_set_ext_data(ext2), set->dlen) != 0)
+                               err = -EBUSY;
+                       else if (!(nlmsg_flags & NLM_F_EXCL))
+                               err = 0;
+               }
                goto err5;
+       }
 
        nft_trans_elem(trans) = elem;
        list_add_tail(&trans->list, &ctx->net->nft.commit_list);
                    !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact))
                        return -ENFILE;
 
-               err = nft_add_set_elem(&ctx, set, attr);
+               err = nft_add_set_elem(&ctx, set, attr, nlh->nlmsg_flags);
                if (err < 0) {
                        atomic_dec(&set->nelems);
                        break;
 
 }
 
 static int nft_hash_insert(const struct net *net, const struct nft_set *set,
-                          const struct nft_set_elem *elem)
+                          const struct nft_set_elem *elem,
+                          struct nft_set_ext **ext)
 {
        struct nft_hash *priv = nft_set_priv(set);
        struct nft_hash_elem *he = elem->priv;
                .set     = set,
                .key     = elem->key.val.data,
        };
-
-       return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
-                                           nft_hash_params);
+       struct nft_hash_elem *prev;
+
+       prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
+                                              nft_hash_params);
+       if (IS_ERR(prev))
+               return PTR_ERR(prev);
+       if (prev) {
+               *ext = &prev->ext;
+               return -EEXIST;
+       }
+       return 0;
 }
 
 static void nft_hash_activate(const struct net *net, const struct nft_set *set,
 
 }
 
 static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
-                              struct nft_rbtree_elem *new)
+                              struct nft_rbtree_elem *new,
+                              struct nft_set_ext **ext)
 {
        struct nft_rbtree *priv = nft_set_priv(set);
        u8 genmask = nft_genmask_next(net);
                                else if (!nft_rbtree_interval_end(rbe) &&
                                         nft_rbtree_interval_end(new))
                                        p = &parent->rb_right;
-                               else
+                               else {
+                                       *ext = &rbe->ext;
                                        return -EEXIST;
+                               }
                        }
                }
        }
 }
 
 static int nft_rbtree_insert(const struct net *net, const struct nft_set *set,
-                            const struct nft_set_elem *elem)
+                            const struct nft_set_elem *elem,
+                            struct nft_set_ext **ext)
 {
        struct nft_rbtree_elem *rbe = elem->priv;
        int err;
 
        spin_lock_bh(&nft_rbtree_lock);
-       err = __nft_rbtree_insert(net, set, rbe);
+       err = __nft_rbtree_insert(net, set, rbe, ext);
        spin_unlock_bh(&nft_rbtree_lock);
 
        return err;