static int nft_netdev_register_hooks(struct net *net,
                                     struct list_head *hook_list)
 {
+       struct nf_hook_ops *ops;
        struct nft_hook *hook;
        int err, j;
 
        j = 0;
        list_for_each_entry(hook, hook_list, list) {
-               err = nf_register_net_hook(net, &hook->ops);
-               if (err < 0)
-                       goto err_register;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       err = nf_register_net_hook(net, ops);
+                       if (err < 0)
+                               goto err_register;
 
-               j++;
+                       j++;
+               }
        }
        return 0;
 
 err_register:
        list_for_each_entry(hook, hook_list, list) {
-               if (j-- <= 0)
-                       break;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       if (j-- <= 0)
+                               break;
 
-               nf_unregister_net_hook(net, &hook->ops);
+                       nf_unregister_net_hook(net, ops);
+               }
        }
        return err;
 }
 
+static void nft_netdev_hook_free_ops(struct nft_hook *hook)
+{
+       struct nf_hook_ops *ops, *next;
+
+       list_for_each_entry_safe(ops, next, &hook->ops_list, list) {
+               list_del(&ops->list);
+               kfree(ops);
+       }
+}
+
 static void nft_netdev_hook_free(struct nft_hook *hook)
 {
+       nft_netdev_hook_free_ops(hook);
        kfree(hook);
 }
 
+static void __nft_netdev_hook_free_rcu(struct rcu_head *rcu)
+{
+       struct nft_hook *hook = container_of(rcu, struct nft_hook, rcu);
+
+       nft_netdev_hook_free(hook);
+}
+
 static void nft_netdev_hook_free_rcu(struct nft_hook *hook)
 {
-       kfree_rcu(hook, rcu);
+       call_rcu(&hook->rcu, __nft_netdev_hook_free_rcu);
 }
 
 static void nft_netdev_unregister_hooks(struct net *net,
                                        bool release_netdev)
 {
        struct nft_hook *hook, *next;
+       struct nf_hook_ops *ops;
 
        list_for_each_entry_safe(hook, next, hook_list, list) {
-               nf_unregister_net_hook(net, &hook->ops);
+               list_for_each_entry(ops, &hook->ops_list, list)
+                       nf_unregister_net_hook(net, ops);
                if (release_netdev) {
                        list_del(&hook->list);
                        nft_netdev_hook_free_rcu(hook);
 static struct nft_hook *nft_netdev_hook_alloc(struct net *net,
                                              const struct nlattr *attr)
 {
+       struct nf_hook_ops *ops;
        struct net_device *dev;
        struct nft_hook *hook;
        int err;
                err = -ENOMEM;
                goto err_hook_alloc;
        }
+       INIT_LIST_HEAD(&hook->ops_list);
 
        err = nla_strscpy(hook->ifname, attr, IFNAMSIZ);
        if (err < 0)
                err = -ENOENT;
                goto err_hook_dev;
        }
-       hook->ops.dev = dev;
+
+       ops = kzalloc(sizeof(struct nf_hook_ops), GFP_KERNEL_ACCOUNT);
+       if (!ops) {
+               err = -ENOMEM;
+               goto err_hook_dev;
+       }
+       ops->dev = dev;
+       list_add_tail(&ops->list, &hook->ops_list);
 
        return hook;
 
                              struct nft_chain_hook *hook, u32 flags)
 {
        struct nft_chain *chain;
+       struct nf_hook_ops *ops;
        struct nft_hook *h;
 
        basechain->type = hook->type;
 
        if (nft_base_chain_netdev(family, hook->num)) {
                list_splice_init(&hook->list, &basechain->hook_list);
-               list_for_each_entry(h, &basechain->hook_list, list)
-                       nft_basechain_hook_init(&h->ops, family, hook, chain);
+               list_for_each_entry(h, &basechain->hook_list, list) {
+                       list_for_each_entry(ops, &h->ops_list, list)
+                               nft_basechain_hook_init(ops, family, hook, chain);
+               }
        }
        nft_basechain_hook_init(&basechain->ops, family, hook, chain);
 
 
                if (nft_base_chain_netdev(ctx->family, basechain->ops.hooknum)) {
                        list_for_each_entry_safe(h, next, &hook.list, list) {
-                               h->ops.pf       = basechain->ops.pf;
-                               h->ops.hooknum  = basechain->ops.hooknum;
-                               h->ops.priority = basechain->ops.priority;
-                               h->ops.priv     = basechain->ops.priv;
-                               h->ops.hook     = basechain->ops.hook;
+                               list_for_each_entry(ops, &h->ops_list, list) {
+                                       ops->pf         = basechain->ops.pf;
+                                       ops->hooknum    = basechain->ops.hooknum;
+                                       ops->priority   = basechain->ops.priority;
+                                       ops->priv       = basechain->ops.priv;
+                                       ops->hook       = basechain->ops.hook;
+                               }
 
                                if (nft_hook_list_find(&basechain->hook_list, h)) {
                                        list_del(&h->list);
 err_hooks:
        if (nla[NFTA_CHAIN_HOOK]) {
                list_for_each_entry_safe(h, next, &hook.list, list) {
-                       if (unregister)
-                               nf_unregister_net_hook(ctx->net, &h->ops);
+                       if (unregister) {
+                               list_for_each_entry(ops, &h->ops_list, list)
+                                       nf_unregister_net_hook(ctx->net, ops);
+                       }
                        list_del(&h->list);
                        nft_netdev_hook_free_rcu(h);
                }
                                    struct netlink_ext_ack *extack, bool add)
 {
        struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1];
+       struct nf_hook_ops *ops;
        struct nft_hook *hook;
        int hooknum, priority;
        int err;
        }
 
        list_for_each_entry(hook, &flowtable_hook->list, list) {
-               hook->ops.pf            = NFPROTO_NETDEV;
-               hook->ops.hooknum       = flowtable_hook->num;
-               hook->ops.priority      = flowtable_hook->priority;
-               hook->ops.priv          = &flowtable->data;
-               hook->ops.hook          = flowtable->data.type->hook;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       ops->pf         = NFPROTO_NETDEV;
+                       ops->hooknum    = flowtable_hook->num;
+                       ops->priority   = flowtable_hook->priority;
+                       ops->priv       = &flowtable->data;
+                       ops->hook       = flowtable->data.type->hook;
+               }
        }
 
        return err;
                                                 bool release_netdev)
 {
        struct nft_hook *hook, *next;
+       struct nf_hook_ops *ops;
 
        list_for_each_entry_safe(hook, next, hook_list, list) {
-               nft_unregister_flowtable_ops(net, flowtable, &hook->ops);
+               list_for_each_entry(ops, &hook->ops_list, list)
+                       nft_unregister_flowtable_ops(net, flowtable, ops);
                if (release_netdev) {
                        list_del(&hook->list);
                        nft_netdev_hook_free_rcu(hook);
 {
        struct nft_hook *hook, *next;
        struct nft_flowtable *ft;
+       struct nf_hook_ops *ops;
        int err, i = 0;
 
        list_for_each_entry(hook, hook_list, list) {
                        }
                }
 
-               err = nft_register_flowtable_ops(net, flowtable, &hook->ops);
-               if (err < 0)
-                       goto err_unregister_net_hooks;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       err = nft_register_flowtable_ops(net, flowtable, ops);
+                       if (err < 0)
+                               goto err_unregister_net_hooks;
 
-               i++;
+                       i++;
+               }
        }
 
        return 0;
 
 err_unregister_net_hooks:
        list_for_each_entry_safe(hook, next, hook_list, list) {
-               if (i-- <= 0)
-                       break;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       if (i-- <= 0)
+                               break;
 
-               nft_unregister_flowtable_ops(net, flowtable, &hook->ops);
+                       nft_unregister_flowtable_ops(net, flowtable, ops);
+               }
                list_del_rcu(&hook->list);
                nft_netdev_hook_free_rcu(hook);
        }
        const struct nlattr * const *nla = ctx->nla;
        struct nft_flowtable_hook flowtable_hook;
        struct nft_hook *hook, *next;
+       struct nf_hook_ops *ops;
        struct nft_trans *trans;
        bool unregister = false;
        u32 flags;
 
 err_flowtable_update_hook:
        list_for_each_entry_safe(hook, next, &flowtable_hook.list, list) {
-               if (unregister)
-                       nft_unregister_flowtable_ops(ctx->net, flowtable, &hook->ops);
+               if (unregister) {
+                       list_for_each_entry(ops, &hook->ops_list, list)
+                               nft_unregister_flowtable_ops(ctx->net,
+                                                            flowtable, ops);
+               }
                list_del_rcu(&hook->list);
                nft_netdev_hook_free_rcu(hook);
        }
 struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook,
                                      const struct net_device *dev)
 {
-       if (hook->ops.dev == dev)
-               return (struct nf_hook_ops *)&hook->ops;
+       struct nf_hook_ops *ops;
 
+       list_for_each_entry(ops, &hook->ops_list, list) {
+               if (ops->dev == dev)
+                       return ops;
+       }
        return NULL;
 }
 EXPORT_SYMBOL_GPL(nft_hook_find_ops);
 struct nf_hook_ops *nft_hook_find_ops_rcu(const struct nft_hook *hook,
                                          const struct net_device *dev)
 {
-       return nft_hook_find_ops(hook, dev);
+       struct nf_hook_ops *ops;
+
+       list_for_each_entry_rcu(ops, &hook->ops_list, list) {
+               if (ops->dev == dev)
+                       return ops;
+       }
+       return NULL;
 }
 EXPORT_SYMBOL_GPL(nft_hook_find_ops_rcu);
 
 
                /* flow_offload_netdev_event() cleans up entries for us. */
                nft_unregister_flowtable_ops(dev_net(dev), flowtable, ops);
-               list_del_rcu(&hook->list);
-               kfree_rcu(hook, rcu);
+               list_del_rcu(&ops->list);
+               kfree_rcu(ops, rcu);
                break;
        }
 }
 
 
 bool nft_chain_offload_support(const struct nft_base_chain *basechain)
 {
+       struct nf_hook_ops *ops;
        struct net_device *dev;
        struct nft_hook *hook;
 
                return false;
 
        list_for_each_entry(hook, &basechain->hook_list, list) {
-               if (hook->ops.pf != NFPROTO_NETDEV ||
-                   hook->ops.hooknum != NF_NETDEV_INGRESS)
-                       return false;
-
-               dev = hook->ops.dev;
-               if (!dev->netdev_ops->ndo_setup_tc && !flow_indr_dev_exists())
-                       return false;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       if (ops->pf != NFPROTO_NETDEV ||
+                           ops->hooknum != NF_NETDEV_INGRESS)
+                               return false;
+
+                       dev = ops->dev;
+                       if (!dev->netdev_ops->ndo_setup_tc &&
+                           !flow_indr_dev_exists())
+                               return false;
+               }
        }
 
        return true;
                                const struct net_device *this_dev,
                                enum flow_block_command cmd)
 {
-       struct net_device *dev;
+       struct nf_hook_ops *ops;
        struct nft_hook *hook;
        int err, i = 0;
 
        list_for_each_entry(hook, &basechain->hook_list, list) {
-               dev = hook->ops.dev;
-               if (this_dev && this_dev != dev)
-                       continue;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       if (this_dev && this_dev != ops->dev)
+                               continue;
 
-               err = nft_chain_offload_cmd(basechain, dev, cmd);
-               if (err < 0 && cmd == FLOW_BLOCK_BIND) {
-                       if (!this_dev)
-                               goto err_flow_block;
+                       err = nft_chain_offload_cmd(basechain, ops->dev, cmd);
+                       if (err < 0 && cmd == FLOW_BLOCK_BIND) {
+                               if (!this_dev)
+                                       goto err_flow_block;
 
-                       return err;
+                               return err;
+                       }
+                       i++;
                }
-               i++;
        }
 
        return 0;
 
 err_flow_block:
        list_for_each_entry(hook, &basechain->hook_list, list) {
-               if (i-- <= 0)
-                       break;
+               list_for_each_entry(ops, &hook->ops_list, list) {
+                       if (i-- <= 0)
+                               break;
 
-               dev = hook->ops.dev;
-               nft_chain_offload_cmd(basechain, dev, FLOW_BLOCK_UNBIND);
+                       nft_chain_offload_cmd(basechain, ops->dev,
+                                             FLOW_BLOCK_UNBIND);
+               }
        }
        return err;
 }