static LIST_HEAD(nf_tables_expressions);
 static LIST_HEAD(nf_tables_objects);
 static LIST_HEAD(nf_tables_flowtables);
+static u64 table_handle;
 
 static void nft_ctx_init(struct nft_ctx *ctx,
                         struct net *net,
        return NULL;
 }
 
+static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
+                                                  const struct nlattr *nla,
+                                                  u8 genmask)
+{
+       struct nft_table *table;
+
+       list_for_each_entry(table, &net->nft.tables, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
+                   nft_active_genmask(table, genmask))
+                       return table;
+       }
+       return NULL;
+}
+
 static struct nft_table *nf_tables_table_lookup(const struct net *net,
                                                const struct nlattr *nla,
                                                u8 family, u8 genmask)
        return ERR_PTR(-ENOENT);
 }
 
+static struct nft_table *nf_tables_table_lookup_byhandle(const struct net *net,
+                                                        const struct nlattr *nla,
+                                                        u8 genmask)
+{
+       struct nft_table *table;
+
+       if (nla == NULL)
+               return ERR_PTR(-EINVAL);
+
+       table = nft_table_lookup_byhandle(net, nla, genmask);
+       if (table != NULL)
+               return table;
+
+       return ERR_PTR(-ENOENT);
+}
+
 static inline u64 nf_tables_alloc_handle(struct nft_table *table)
 {
        return ++table->hgenerator;
        [NFTA_TABLE_NAME]       = { .type = NLA_STRING,
                                    .len = NFT_TABLE_MAXNAMELEN - 1 },
        [NFTA_TABLE_FLAGS]      = { .type = NLA_U32 },
+       [NFTA_TABLE_HANDLE]     = { .type = NLA_U64 },
 };
 
 static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
 
        if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
            nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
-           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
+           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
+           nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
+                        NFTA_TABLE_PAD))
                goto nla_put_failure;
 
        nlmsg_end(skb, nlh);
        INIT_LIST_HEAD(&table->flowtables);
        table->family = family;
        table->flags = flags;
+       table->handle = ++table_handle;
 
        nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
        err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
        struct nft_ctx ctx;
 
        nft_ctx_init(&ctx, net, skb, nlh, 0, NULL, NULL, nla);
-       if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
+       if (family == AF_UNSPEC ||
+           (!nla[NFTA_TABLE_NAME] && !nla[NFTA_TABLE_HANDLE]))
                return nft_flush(&ctx, family);
 
-       table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME], family,
-                                      genmask);
+       if (nla[NFTA_TABLE_HANDLE])
+               table = nf_tables_table_lookup_byhandle(net,
+                                                       nla[NFTA_TABLE_HANDLE],
+                                                       genmask);
+       else
+               table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME],
+                                              family, genmask);
+
        if (IS_ERR(table))
                return PTR_ERR(table);
 
        struct nft_rule *rule;
        int family = nfmsg->nfgen_family;
        struct nft_ctx ctx;
+       u64 handle;
        u32 use;
        int err;
 
        if (IS_ERR(table))
                return PTR_ERR(table);
 
-       chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
+       if (nla[NFTA_CHAIN_HANDLE]) {
+               handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
+               chain = nf_tables_chain_lookup_byhandle(table, handle, genmask);
+       } else {
+               chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
+       }
        if (IS_ERR(chain))
                return PTR_ERR(chain);
 
        [NFTA_SET_USERDATA]             = { .type = NLA_BINARY,
                                            .len  = NFT_USERDATA_MAXLEN },
        [NFTA_SET_OBJ_TYPE]             = { .type = NLA_U32 },
+       [NFTA_SET_HANDLE]               = { .type = NLA_U64 },
 };
 
 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
        return ERR_PTR(-ENOENT);
 }
 
+static struct nft_set *nf_tables_set_lookup_byhandle(const struct nft_table *table,
+                                                    const struct nlattr *nla, u8 genmask)
+{
+       struct nft_set *set;
+
+       if (nla == NULL)
+               return ERR_PTR(-EINVAL);
+
+       list_for_each_entry(set, &table->sets, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == set->handle &&
+                   nft_active_genmask(set, genmask))
+                       return set;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 static struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
                                                 const struct nlattr *nla,
                                                 u8 genmask)
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_SET_NAME, set->name))
                goto nla_put_failure;
+       if (nla_put_be64(skb, NFTA_SET_HANDLE, cpu_to_be64(set->handle),
+                        NFTA_SET_PAD))
+               goto nla_put_failure;
        if (set->flags != 0)
                if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
                        goto nla_put_failure;
        set->udata  = udata;
        set->timeout = timeout;
        set->gc_int = gc_int;
+       set->handle = nf_tables_alloc_handle(table);
 
        err = ops->init(set, &desc, nla);
        if (err < 0)
        if (err < 0)
                return err;
 
-       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
+       if (nla[NFTA_SET_HANDLE])
+               set = nf_tables_set_lookup_byhandle(ctx.table, nla[NFTA_SET_HANDLE], genmask);
+       else
+               set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
        if (IS_ERR(set))
                return PTR_ERR(set);
 
 }
 EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
 
+struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table,
+                                                const struct nlattr *nla,
+                                                u32 objtype, u8 genmask)
+{
+       struct nft_object *obj;
+
+       list_for_each_entry(obj, &table->objects, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == obj->handle &&
+                   objtype == obj->ops->type->type &&
+                   nft_active_genmask(obj, genmask))
+                       return obj;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
        [NFTA_OBJ_TABLE]        = { .type = NLA_STRING,
                                    .len = NFT_TABLE_MAXNAMELEN - 1 },
                                    .len = NFT_OBJ_MAXNAMELEN - 1 },
        [NFTA_OBJ_TYPE]         = { .type = NLA_U32 },
        [NFTA_OBJ_DATA]         = { .type = NLA_NESTED },
+       [NFTA_OBJ_HANDLE]       = { .type = NLA_U64},
 };
 
 static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
                goto err1;
        }
        obj->table = table;
+       obj->handle = nf_tables_alloc_handle(table);
+
        obj->name = nla_strdup(nla[NFTA_OBJ_NAME], GFP_KERNEL);
        if (!obj->name) {
                err = -ENOMEM;
            nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
            nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
            nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
-           nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
+           nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset) ||
+           nla_put_be64(skb, NFTA_OBJ_HANDLE, cpu_to_be64(obj->handle),
+                        NFTA_OBJ_PAD))
                goto nla_put_failure;
 
        nlmsg_end(skb, nlh);
        u32 objtype;
 
        if (!nla[NFTA_OBJ_TYPE] ||
-           !nla[NFTA_OBJ_NAME])
+           (!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE]))
                return -EINVAL;
 
        table = nf_tables_table_lookup(net, nla[NFTA_OBJ_TABLE], family,
                return PTR_ERR(table);
 
        objtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
-       obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME], objtype, genmask);
+       if (nla[NFTA_OBJ_HANDLE])
+               obj = nf_tables_obj_lookup_byhandle(table, nla[NFTA_OBJ_HANDLE],
+                                                   objtype, genmask);
+       else
+               obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME],
+                                          objtype, genmask);
        if (IS_ERR(obj))
                return PTR_ERR(obj);
        if (obj->use > 0)
        [NFTA_FLOWTABLE_NAME]           = { .type = NLA_STRING,
                                            .len = NFT_NAME_MAXLEN - 1 },
        [NFTA_FLOWTABLE_HOOK]           = { .type = NLA_NESTED },
+       [NFTA_FLOWTABLE_HANDLE]         = { .type = NLA_U64 },
 };
 
 struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
 }
 EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup);
 
+struct nft_flowtable *
+nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
+                                   const struct nlattr *nla, u8 genmask)
+{
+       struct nft_flowtable *flowtable;
+
+       list_for_each_entry(flowtable, &table->flowtables, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == flowtable->handle &&
+                   nft_active_genmask(flowtable, genmask))
+                       return flowtable;
+       }
+       return ERR_PTR(-ENOENT);
+}
+
 #define NFT_FLOWTABLE_DEVICE_MAX       8
 
 static int nf_tables_parse_devices(const struct nft_ctx *ctx,
                return -ENOMEM;
 
        flowtable->table = table;
+       flowtable->handle = nf_tables_alloc_handle(table);
+
        flowtable->name = nla_strdup(nla[NFTA_FLOWTABLE_NAME], GFP_KERNEL);
        if (!flowtable->name) {
                err = -ENOMEM;
        if (IS_ERR(table))
                return PTR_ERR(table);
 
-       flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
-                                              genmask);
+       if (nla[NFTA_FLOWTABLE_HANDLE])
+               flowtable = nf_tables_flowtable_lookup_byhandle(table,
+                                                               nla[NFTA_FLOWTABLE_HANDLE],
+                                                               genmask);
+       else
+               flowtable = nf_tables_flowtable_lookup(table,
+                                                      nla[NFTA_FLOWTABLE_NAME],
+                                                      genmask);
        if (IS_ERR(flowtable))
                 return PTR_ERR(flowtable);
        if (flowtable->use > 0)
 
        if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
            nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
-           nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)))
+           nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
+           nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
+                        NFTA_FLOWTABLE_PAD))
                goto nla_put_failure;
 
        nest = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK);