#include <net/sch_generic.h>
 #include <net/pkt_sched.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
 
 struct tcf_common {
        struct hlist_node               tcfc_head;
        __u32                   type; /* for backward compat(TCA_OLD_COMPAT) */
        __u32                   order;
        struct list_head        list;
+       struct tcf_hashinfo     *hinfo;
 };
 
 struct tc_action_ops {
        struct list_head head;
-       struct tcf_hashinfo *hinfo;
        char    kind[IFNAMSIZ];
        __u32   type; /* TBD to match kind */
        struct module           *owner;
        int     (*act)(struct sk_buff *, const struct tc_action *, struct tcf_result *);
        int     (*dump)(struct sk_buff *, struct tc_action *, int, int);
        void    (*cleanup)(struct tc_action *, int bind);
-       int     (*lookup)(struct tc_action *, u32);
+       int     (*lookup)(struct net *, struct tc_action *, u32);
        int     (*init)(struct net *net, struct nlattr *nla,
                        struct nlattr *est, struct tc_action *act, int ovr,
                        int bind);
-       int     (*walk)(struct sk_buff *, struct netlink_callback *, int, struct tc_action *);
+       int     (*walk)(struct net *, struct sk_buff *,
+                       struct netlink_callback *, int, struct tc_action *);
+};
+
+struct tc_action_net {
+       struct tcf_hashinfo *hinfo;
+       const struct tc_action_ops *ops;
 };
 
-int tcf_hash_search(struct tc_action *a, u32 index);
-u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo);
-int tcf_hash_check(u32 index, struct tc_action *a, int bind);
-int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
-                   int size, int bind, bool cpustats);
+static inline
+int tc_action_net_init(struct tc_action_net *tn, const struct tc_action_ops *ops,
+                      unsigned int mask)
+{
+       int err = 0;
+
+       tn->hinfo = kmalloc(sizeof(*tn->hinfo), GFP_KERNEL);
+       if (!tn->hinfo)
+               return -ENOMEM;
+       tn->ops = ops;
+       err = tcf_hashinfo_init(tn->hinfo, mask);
+       if (err)
+               kfree(tn->hinfo);
+       return err;
+}
+
+void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
+                         struct tcf_hashinfo *hinfo);
+
+static inline void tc_action_net_exit(struct tc_action_net *tn)
+{
+       tcf_hashinfo_destroy(tn->ops, tn->hinfo);
+}
+
+int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
+                      struct netlink_callback *cb, int type,
+                      struct tc_action *a);
+int tcf_hash_search(struct tc_action_net *tn, struct tc_action *a, u32 index);
+u32 tcf_hash_new_index(struct tc_action_net *tn);
+int tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a,
+                  int bind);
+int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
+                   struct tc_action *a, int size, int bind, bool cpustats);
 void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est);
-void tcf_hash_insert(struct tc_action *a);
+void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a);
 
 int __tcf_hash_release(struct tc_action *a, bool bind, bool strict);
 
        return __tcf_hash_release(a, bind, false);
 }
 
-int tcf_register_action(struct tc_action_ops *a, unsigned int mask);
-int tcf_unregister_action(struct tc_action_ops *a);
+int tcf_register_action(struct tc_action_ops *a, struct pernet_operations *ops);
+int tcf_unregister_action(struct tc_action_ops *a, struct pernet_operations *ops);
 int tcf_action_destroy(struct list_head *actions, int bind);
 int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
                    struct tcf_result *res);
 
        kfree(p);
 }
 
-static void tcf_hash_destroy(struct tc_action *a)
+static void tcf_hash_destroy(struct tcf_hashinfo *hinfo, struct tc_action *a)
 {
        struct tcf_common *p = a->priv;
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
 
        spin_lock_bh(&hinfo->lock);
        hlist_del(&p->tcfc_head);
                if (p->tcfc_bindcnt <= 0 && p->tcfc_refcnt <= 0) {
                        if (a->ops->cleanup)
                                a->ops->cleanup(a, bind);
-                       tcf_hash_destroy(a);
+                       tcf_hash_destroy(a->hinfo, a);
                        ret = ACT_P_DELETED;
                }
        }
 }
 EXPORT_SYMBOL(__tcf_hash_release);
 
-static int tcf_dump_walker(struct sk_buff *skb, struct netlink_callback *cb,
-                          struct tc_action *a)
+static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
+                          struct netlink_callback *cb, struct tc_action *a)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct hlist_head *head;
        struct tcf_common *p;
        int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
        goto done;
 }
 
-static int tcf_del_walker(struct sk_buff *skb, struct tc_action *a)
+static int tcf_del_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb,
+                         struct tc_action *a)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct hlist_head *head;
        struct hlist_node *n;
        struct tcf_common *p;
        return ret;
 }
 
-static int tcf_generic_walker(struct sk_buff *skb, struct netlink_callback *cb,
-                             int type, struct tc_action *a)
+int tcf_generic_walker(struct tc_action_net *tn, struct sk_buff *skb,
+                      struct netlink_callback *cb, int type,
+                      struct tc_action *a)
 {
+       struct tcf_hashinfo *hinfo = tn->hinfo;
+
+       a->hinfo = hinfo;
+
        if (type == RTM_DELACTION) {
-               return tcf_del_walker(skb, a);
+               return tcf_del_walker(hinfo, skb, a);
        } else if (type == RTM_GETACTION) {
-               return tcf_dump_walker(skb, cb, a);
+               return tcf_dump_walker(hinfo, skb, cb, a);
        } else {
                WARN(1, "tcf_generic_walker: unknown action %d\n", type);
                return -EINVAL;
        }
 }
+EXPORT_SYMBOL(tcf_generic_walker);
 
 static struct tcf_common *tcf_hash_lookup(u32 index, struct tcf_hashinfo *hinfo)
 {
        return p;
 }
 
-u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo)
+u32 tcf_hash_new_index(struct tc_action_net *tn)
 {
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        u32 val = hinfo->index;
 
        do {
 }
 EXPORT_SYMBOL(tcf_hash_new_index);
 
-int tcf_hash_search(struct tc_action *a, u32 index)
+int tcf_hash_search(struct tc_action_net *tn, struct tc_action *a, u32 index)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        struct tcf_common *p = tcf_hash_lookup(index, hinfo);
 
        if (p) {
                a->priv = p;
+               a->hinfo = hinfo;
                return 1;
        }
        return 0;
 }
 EXPORT_SYMBOL(tcf_hash_search);
 
-int tcf_hash_check(u32 index, struct tc_action *a, int bind)
+int tcf_hash_check(struct tc_action_net *tn, u32 index, struct tc_action *a,
+                  int bind)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        struct tcf_common *p = NULL;
        if (index && (p = tcf_hash_lookup(index, hinfo)) != NULL) {
                if (bind)
                        p->tcfc_bindcnt++;
                p->tcfc_refcnt++;
                a->priv = p;
+               a->hinfo = hinfo;
                return 1;
        }
        return 0;
 }
 EXPORT_SYMBOL(tcf_hash_cleanup);
 
-int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a,
-                   int size, int bind, bool cpustats)
+int tcf_hash_create(struct tc_action_net *tn, u32 index, struct nlattr *est,
+                   struct tc_action *a, int size, int bind, bool cpustats)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
        struct tcf_common *p = kzalloc(size, GFP_KERNEL);
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        int err = -ENOMEM;
 
        if (unlikely(!p))
        }
        spin_lock_init(&p->tcfc_lock);
        INIT_HLIST_NODE(&p->tcfc_head);
-       p->tcfc_index = index ? index : tcf_hash_new_index(hinfo);
+       p->tcfc_index = index ? index : tcf_hash_new_index(tn);
        p->tcfc_tm.install = jiffies;
        p->tcfc_tm.lastuse = jiffies;
        if (est) {
        }
 
        a->priv = (void *) p;
+       a->hinfo = hinfo;
        return 0;
 }
 EXPORT_SYMBOL(tcf_hash_create);
 
-void tcf_hash_insert(struct tc_action *a)
+void tcf_hash_insert(struct tc_action_net *tn, struct tc_action *a)
 {
        struct tcf_common *p = a->priv;
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        unsigned int h = tcf_hash(p->tcfc_index, hinfo->hmask);
 
        spin_lock_bh(&hinfo->lock);
 }
 EXPORT_SYMBOL(tcf_hash_insert);
 
-static void tcf_hashinfo_destroy(const struct tc_action_ops *ops)
+void tcf_hashinfo_destroy(const struct tc_action_ops *ops,
+                         struct tcf_hashinfo *hinfo)
 {
-       struct tcf_hashinfo *hinfo = ops->hinfo;
        struct tc_action a = {
                .ops = ops,
+               .hinfo = hinfo,
        };
        int i;
 
        }
        kfree(hinfo->htab);
 }
+EXPORT_SYMBOL(tcf_hashinfo_destroy);
 
 static LIST_HEAD(act_base);
 static DEFINE_RWLOCK(act_mod_lock);
 
-int tcf_register_action(struct tc_action_ops *act, unsigned int mask)
+int tcf_register_action(struct tc_action_ops *act,
+                       struct pernet_operations *ops)
 {
        struct tc_action_ops *a;
-       int err;
+       int ret;
 
-       /* Must supply act, dump and init */
-       if (!act->act || !act->dump || !act->init)
+       if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup)
                return -EINVAL;
 
-       /* Supply defaults */
-       if (!act->lookup)
-               act->lookup = tcf_hash_search;
-       if (!act->walk)
-               act->walk = tcf_generic_walker;
-
-       act->hinfo = kmalloc(sizeof(struct tcf_hashinfo), GFP_KERNEL);
-       if (!act->hinfo)
-               return -ENOMEM;
-       err = tcf_hashinfo_init(act->hinfo, mask);
-       if (err) {
-               kfree(act->hinfo);
-               return err;
-       }
-
        write_lock(&act_mod_lock);
        list_for_each_entry(a, &act_base, head) {
                if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {
                        write_unlock(&act_mod_lock);
-                       tcf_hashinfo_destroy(act);
-                       kfree(act->hinfo);
                        return -EEXIST;
                }
        }
        list_add_tail(&act->head, &act_base);
        write_unlock(&act_mod_lock);
+
+       ret = register_pernet_subsys(ops);
+       if (ret) {
+               tcf_unregister_action(act, ops);
+               return ret;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(tcf_register_action);
 
-int tcf_unregister_action(struct tc_action_ops *act)
+int tcf_unregister_action(struct tc_action_ops *act,
+                         struct pernet_operations *ops)
 {
        struct tc_action_ops *a;
        int err = -ENOENT;
 
+       unregister_pernet_subsys(ops);
+
        write_lock(&act_mod_lock);
        list_for_each_entry(a, &act_base, head) {
                if (a == act) {
                        list_del(&act->head);
-                       tcf_hashinfo_destroy(act);
-                       kfree(act->hinfo);
                        err = 0;
                        break;
                }
        return act;
 }
 
-static struct tc_action *
-tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
+static struct tc_action *tcf_action_get_1(struct net *net, struct nlattr *nla,
+                                         struct nlmsghdr *n, u32 portid)
 {
        struct nlattr *tb[TCA_ACT_MAX + 1];
        struct tc_action *a;
        if (a->ops == NULL) /* could happen in batch of actions */
                goto err_free;
        err = -ENOENT;
-       if (a->ops->lookup(a, index) == 0)
+       if (a->ops->lookup(net, a, index) == 0)
                goto err_mod;
 
        module_put(a->ops->owner);
        if (nest == NULL)
                goto out_module_put;
 
-       err = a.ops->walk(skb, &dcb, RTM_DELACTION, &a);
+       err = a.ops->walk(net, skb, &dcb, RTM_DELACTION, &a);
        if (err < 0)
                goto out_module_put;
        if (err == 0)
        }
 
        for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
-               act = tcf_action_get_1(tb[i], n, portid);
+               act = tcf_action_get_1(net, tb[i], n, portid);
                if (IS_ERR(act)) {
                        ret = PTR_ERR(act);
                        goto err;
 static int
 tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
 {
+       struct net *net = sock_net(skb->sk);
        struct nlmsghdr *nlh;
        unsigned char *b = skb_tail_pointer(skb);
        struct nlattr *nest;
        if (nest == NULL)
                goto out_module_put;
 
-       ret = a_o->walk(skb, cb, RTM_GETACTION, &a);
+       ret = a_o->walk(net, skb, cb, RTM_GETACTION, &a);
        if (ret < 0)
                goto out_module_put;
 
 
        bool is_ebpf;
 };
 
+static int bpf_net_id;
+
 static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act,
                   struct tcf_result *res)
 {
                        struct nlattr *est, struct tc_action *act,
                        int replace, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
        struct nlattr *tb[TCA_ACT_BPF_MAX + 1];
        struct tcf_bpf_cfg cfg, old;
        struct tc_act_bpf *parm;
 
        parm = nla_data(tb[TCA_ACT_BPF_PARMS]);
 
-       if (!tcf_hash_check(parm->index, act, bind)) {
-               ret = tcf_hash_create(parm->index, est, act,
+       if (!tcf_hash_check(tn, parm->index, act, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, act,
                                      sizeof(*prog), bind, true);
                if (ret < 0)
                        return ret;
        rcu_assign_pointer(prog->filter, cfg.filter);
 
        if (res == ACT_P_CREATED) {
-               tcf_hash_insert(act);
+               tcf_hash_insert(tn, act);
        } else {
                /* make sure the program being replaced is no longer executing */
                synchronize_rcu();
        tcf_bpf_cfg_cleanup(&tmp);
 }
 
+static int tcf_bpf_walker(struct net *net, struct sk_buff *skb,
+                         struct netlink_callback *cb, int type,
+                         struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_bpf_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_bpf_ops __read_mostly = {
        .kind           =       "bpf",
        .type           =       TCA_ACT_BPF,
        .dump           =       tcf_bpf_dump,
        .cleanup        =       tcf_bpf_cleanup,
        .init           =       tcf_bpf_init,
+       .walk           =       tcf_bpf_walker,
+       .lookup         =       tcf_bpf_search,
+};
+
+static __net_init int bpf_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       return tc_action_net_init(tn, &act_bpf_ops, BPF_TAB_MASK);
+}
+
+static void __net_exit bpf_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, bpf_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations bpf_net_ops = {
+       .init = bpf_init_net,
+       .exit = bpf_exit_net,
+       .id   = &bpf_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init bpf_init_module(void)
 {
-       return tcf_register_action(&act_bpf_ops, BPF_TAB_MASK);
+       return tcf_register_action(&act_bpf_ops, &bpf_net_ops);
 }
 
 static void __exit bpf_cleanup_module(void)
 {
-       tcf_unregister_action(&act_bpf_ops);
+       tcf_unregister_action(&act_bpf_ops, &bpf_net_ops);
 }
 
 module_init(bpf_init_module);
 
 
 #define CONNMARK_TAB_MASK     3
 
+static int connmark_net_id;
+
 static int tcf_connmark(struct sk_buff *skb, const struct tc_action *a,
                        struct tcf_result *res)
 {
                             struct nlattr *est, struct tc_action *a,
                             int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
        struct nlattr *tb[TCA_CONNMARK_MAX + 1];
        struct tcf_connmark_info *ci;
        struct tc_connmark *parm;
 
        parm = nla_data(tb[TCA_CONNMARK_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*ci),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*ci), bind, false);
                if (ret)
                        return ret;
 
                ci->net = net;
                ci->zone = parm->zone;
 
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
                ret = ACT_P_CREATED;
        } else {
                ci = to_connmark(a);
        return -1;
 }
 
+static int tcf_connmark_walker(struct net *net, struct sk_buff *skb,
+                              struct netlink_callback *cb, int type,
+                              struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_connmark_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_connmark_ops = {
        .kind           =       "connmark",
        .type           =       TCA_ACT_CONNMARK,
        .act            =       tcf_connmark,
        .dump           =       tcf_connmark_dump,
        .init           =       tcf_connmark_init,
+       .walk           =       tcf_connmark_walker,
+       .lookup         =       tcf_connmark_search,
+};
+
+static __net_init int connmark_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       return tc_action_net_init(tn, &act_connmark_ops, CONNMARK_TAB_MASK);
+}
+
+static void __net_exit connmark_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, connmark_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations connmark_net_ops = {
+       .init = connmark_init_net,
+       .exit = connmark_exit_net,
+       .id   = &connmark_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init connmark_init_module(void)
 {
-       return tcf_register_action(&act_connmark_ops, CONNMARK_TAB_MASK);
+       return tcf_register_action(&act_connmark_ops, &connmark_net_ops);
 }
 
 static void __exit connmark_cleanup_module(void)
 {
-       tcf_unregister_action(&act_connmark_ops);
+       tcf_unregister_action(&act_connmark_ops, &connmark_net_ops);
 }
 
 module_init(connmark_init_module);
 
        [TCA_CSUM_PARMS] = { .len = sizeof(struct tc_csum), },
 };
 
-static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est,
-                        struct tc_action *a, int ovr, int bind)
+static int csum_net_id;
+
+static int tcf_csum_init(struct net *net, struct nlattr *nla,
+                        struct nlattr *est, struct tc_action *a, int ovr,
+                        int bind)
 {
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
        struct nlattr *tb[TCA_CSUM_MAX + 1];
        struct tc_csum *parm;
        struct tcf_csum *p;
                return -EINVAL;
        parm = nla_data(tb[TCA_CSUM_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*p), bind, false);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
        spin_unlock_bh(&p->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
 
        return ret;
 }
        return -1;
 }
 
+static int tcf_csum_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_csum_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_csum_ops = {
        .kind           = "csum",
        .type           = TCA_ACT_CSUM,
        .act            = tcf_csum,
        .dump           = tcf_csum_dump,
        .init           = tcf_csum_init,
+       .walk           = tcf_csum_walker,
+       .lookup         = tcf_csum_search,
+};
+
+static __net_init int csum_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       return tc_action_net_init(tn, &act_csum_ops, CSUM_TAB_MASK);
+}
+
+static void __net_exit csum_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, csum_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations csum_net_ops = {
+       .init = csum_init_net,
+       .exit = csum_exit_net,
+       .id   = &csum_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_DESCRIPTION("Checksum updating actions");
 
 static int __init csum_init_module(void)
 {
-       return tcf_register_action(&act_csum_ops, CSUM_TAB_MASK);
+       return tcf_register_action(&act_csum_ops, &csum_net_ops);
 }
 
 static void __exit csum_cleanup_module(void)
 {
-       tcf_unregister_action(&act_csum_ops);
+       tcf_unregister_action(&act_csum_ops, &csum_net_ops);
 }
 
 module_init(csum_init_module);
 
 
 #define GACT_TAB_MASK  15
 
+static int gact_net_id;
+
 #ifdef CONFIG_GACT_PROB
 static int gact_net_rand(struct tcf_gact *gact)
 {
                         struct nlattr *est, struct tc_action *a,
                         int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
        struct nlattr *tb[TCA_GACT_MAX + 1];
        struct tc_gact *parm;
        struct tcf_gact *gact;
        }
 #endif
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*gact),
-                                     bind, true);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*gact), bind, true);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
        }
 #endif
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
        return -1;
 }
 
+static int tcf_gact_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_gact_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_gact_ops = {
        .kind           =       "gact",
        .type           =       TCA_ACT_GACT,
        .act            =       tcf_gact,
        .dump           =       tcf_gact_dump,
        .init           =       tcf_gact_init,
+       .walk           =       tcf_gact_walker,
+       .lookup         =       tcf_gact_search,
+};
+
+static __net_init int gact_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       return tc_action_net_init(tn, &act_gact_ops, GACT_TAB_MASK);
+}
+
+static void __net_exit gact_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, gact_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations gact_net_ops = {
+       .init = gact_init_net,
+       .exit = gact_exit_net,
+       .id   = &gact_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
 #else
        pr_info("GACT probability NOT on\n");
 #endif
-       return tcf_register_action(&act_gact_ops, GACT_TAB_MASK);
+
+       return tcf_register_action(&act_gact_ops, &gact_net_ops);
 }
 
 static void __exit gact_cleanup_module(void)
 {
-       tcf_unregister_action(&act_gact_ops);
+       tcf_unregister_action(&act_gact_ops, &gact_net_ops);
 }
 
 module_init(gact_init_module);
 
 
 #define IPT_TAB_MASK     15
 
+static int ipt_net_id;
+
+static int xt_net_id;
+
 static int ipt_init_target(struct xt_entry_target *t, char *table, unsigned int hook)
 {
        struct xt_tgchk_param par;
        [TCA_IPT_TARG]  = { .len = sizeof(struct xt_entry_target) },
 };
 
-static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est,
-                       struct tc_action *a, int ovr, int bind)
+static int __tcf_ipt_init(struct tc_action_net *tn, struct nlattr *nla,
+                         struct nlattr *est, struct tc_action *a, int ovr,
+                         int bind)
 {
        struct nlattr *tb[TCA_IPT_MAX + 1];
        struct tcf_ipt *ipt;
        if (tb[TCA_IPT_INDEX] != NULL)
                index = nla_get_u32(tb[TCA_IPT_INDEX]);
 
-       if (!tcf_hash_check(index, a, bind) ) {
-               ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind, false);
+       if (!tcf_hash_check(tn, index, a, bind)) {
+               ret = tcf_hash_create(tn, index, est, a, sizeof(*ipt), bind,
+                                     false);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
        ipt->tcfi_hook  = hook;
        spin_unlock_bh(&ipt->tcf_lock);
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 
 err3:
        return err;
 }
 
+static int tcf_ipt_init(struct net *net, struct nlattr *nla,
+                       struct nlattr *est, struct tc_action *a, int ovr,
+                       int bind)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return __tcf_ipt_init(tn, nla, est, a, ovr, bind);
+}
+
+static int tcf_xt_init(struct net *net, struct nlattr *nla,
+                      struct nlattr *est, struct tc_action *a, int ovr,
+                      int bind)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return __tcf_ipt_init(tn, nla, est, a, ovr, bind);
+}
+
 static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a,
                   struct tcf_result *res)
 {
        return -1;
 }
 
+static int tcf_ipt_walker(struct net *net, struct sk_buff *skb,
+                         struct netlink_callback *cb, int type,
+                         struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_ipt_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_ipt_ops = {
        .kind           =       "ipt",
        .type           =       TCA_ACT_IPT,
        .dump           =       tcf_ipt_dump,
        .cleanup        =       tcf_ipt_release,
        .init           =       tcf_ipt_init,
+       .walk           =       tcf_ipt_walker,
+       .lookup         =       tcf_ipt_search,
+};
+
+static __net_init int ipt_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       return tc_action_net_init(tn, &act_ipt_ops, IPT_TAB_MASK);
+}
+
+static void __net_exit ipt_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, ipt_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations ipt_net_ops = {
+       .init = ipt_init_net,
+       .exit = ipt_exit_net,
+       .id   = &ipt_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
+static int tcf_xt_walker(struct net *net, struct sk_buff *skb,
+                        struct netlink_callback *cb, int type,
+                        struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_xt_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_xt_ops = {
        .kind           =       "xt",
        .type           =       TCA_ACT_XT,
        .act            =       tcf_ipt,
        .dump           =       tcf_ipt_dump,
        .cleanup        =       tcf_ipt_release,
-       .init           =       tcf_ipt_init,
+       .init           =       tcf_xt_init,
+       .walk           =       tcf_xt_walker,
+       .lookup         =       tcf_xt_search,
+};
+
+static __net_init int xt_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       return tc_action_net_init(tn, &act_xt_ops, IPT_TAB_MASK);
+}
+
+static void __net_exit xt_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, xt_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations xt_net_ops = {
+       .init = xt_init_net,
+       .exit = xt_exit_net,
+       .id   = &xt_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002-13)");
 {
        int ret1, ret2;
 
-       ret1 = tcf_register_action(&act_xt_ops, IPT_TAB_MASK);
+       ret1 = tcf_register_action(&act_xt_ops, &xt_net_ops);
        if (ret1 < 0)
-               printk("Failed to load xt action\n");
-       ret2 = tcf_register_action(&act_ipt_ops, IPT_TAB_MASK);
+               pr_err("Failed to load xt action\n");
+
+       ret2 = tcf_register_action(&act_ipt_ops, &ipt_net_ops);
        if (ret2 < 0)
-               printk("Failed to load ipt action\n");
+               pr_err("Failed to load ipt action\n");
 
        if (ret1 < 0 && ret2 < 0) {
                return ret1;
 
 static void __exit ipt_cleanup_module(void)
 {
-       tcf_unregister_action(&act_xt_ops);
-       tcf_unregister_action(&act_ipt_ops);
+       tcf_unregister_action(&act_ipt_ops, &ipt_net_ops);
+       tcf_unregister_action(&act_xt_ops, &xt_net_ops);
 }
 
 module_init(ipt_init_module);
 
        [TCA_MIRRED_PARMS]      = { .len = sizeof(struct tc_mirred) },
 };
 
+static int mirred_net_id;
+
 static int tcf_mirred_init(struct net *net, struct nlattr *nla,
                           struct nlattr *est, struct tc_action *a, int ovr,
                           int bind)
 {
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
        struct nlattr *tb[TCA_MIRRED_MAX + 1];
        struct tc_mirred *parm;
        struct tcf_mirred *m;
                dev = NULL;
        }
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
                if (dev == NULL)
                        return -EINVAL;
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*m),
-                                     bind, true);
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*m), bind, true);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
                spin_lock_bh(&mirred_list_lock);
                list_add(&m->tcfm_list, &mirred_list);
                spin_unlock_bh(&mirred_list_lock);
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        }
 
        return ret;
        return -1;
 }
 
+static int tcf_mirred_walker(struct net *net, struct sk_buff *skb,
+                            struct netlink_callback *cb, int type,
+                            struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_mirred_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static int mirred_device_event(struct notifier_block *unused,
                               unsigned long event, void *ptr)
 {
        .dump           =       tcf_mirred_dump,
        .cleanup        =       tcf_mirred_release,
        .init           =       tcf_mirred_init,
+       .walk           =       tcf_mirred_walker,
+       .lookup         =       tcf_mirred_search,
+};
+
+static __net_init int mirred_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       return tc_action_net_init(tn, &act_mirred_ops, MIRRED_TAB_MASK);
+}
+
+static void __net_exit mirred_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, mirred_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations mirred_net_ops = {
+       .init = mirred_init_net,
+       .exit = mirred_exit_net,
+       .id   = &mirred_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002)");
                return err;
 
        pr_info("Mirror/redirect action on\n");
-       return tcf_register_action(&act_mirred_ops, MIRRED_TAB_MASK);
+       return tcf_register_action(&act_mirred_ops, &mirred_net_ops);
 }
 
 static void __exit mirred_cleanup_module(void)
 {
-       tcf_unregister_action(&act_mirred_ops);
+       tcf_unregister_action(&act_mirred_ops, &mirred_net_ops);
        unregister_netdevice_notifier(&mirred_device_notifier);
 }
 
 
 
 #define NAT_TAB_MASK   15
 
+static int nat_net_id;
+
 static const struct nla_policy nat_policy[TCA_NAT_MAX + 1] = {
        [TCA_NAT_PARMS] = { .len = sizeof(struct tc_nat) },
 };
 static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est,
                        struct tc_action *a, int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
        struct nlattr *tb[TCA_NAT_MAX + 1];
        struct tc_nat *parm;
        int ret = 0, err;
                return -EINVAL;
        parm = nla_data(tb[TCA_NAT_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*p), bind, false);
                if (ret)
                        return ret;
                ret = ACT_P_CREATED;
        spin_unlock_bh(&p->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
 
        return ret;
 }
        return -1;
 }
 
+static int tcf_nat_walker(struct net *net, struct sk_buff *skb,
+                         struct netlink_callback *cb, int type,
+                         struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_nat_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_nat_ops = {
        .kind           =       "nat",
        .type           =       TCA_ACT_NAT,
        .act            =       tcf_nat,
        .dump           =       tcf_nat_dump,
        .init           =       tcf_nat_init,
+       .walk           =       tcf_nat_walker,
+       .lookup         =       tcf_nat_search,
+};
+
+static __net_init int nat_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       return tc_action_net_init(tn, &act_nat_ops, NAT_TAB_MASK);
+}
+
+static void __net_exit nat_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, nat_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations nat_net_ops = {
+       .init = nat_init_net,
+       .exit = nat_exit_net,
+       .id   = &nat_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_DESCRIPTION("Stateless NAT actions");
 
 static int __init nat_init_module(void)
 {
-       return tcf_register_action(&act_nat_ops, NAT_TAB_MASK);
+       return tcf_register_action(&act_nat_ops, &nat_net_ops);
 }
 
 static void __exit nat_cleanup_module(void)
 {
-       tcf_unregister_action(&act_nat_ops);
+       tcf_unregister_action(&act_nat_ops, &nat_net_ops);
 }
 
 module_init(nat_init_module);
 
 
 #define PEDIT_TAB_MASK 15
 
+static int pedit_net_id;
+
 static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = {
        [TCA_PEDIT_PARMS]       = { .len = sizeof(struct tc_pedit) },
 };
                          struct nlattr *est, struct tc_action *a,
                          int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
        struct nlattr *tb[TCA_PEDIT_MAX + 1];
        struct tc_pedit *parm;
        int ret = 0, err;
        if (nla_len(tb[TCA_PEDIT_PARMS]) < sizeof(*parm) + ksize)
                return -EINVAL;
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
                if (!parm->nkeys)
                        return -EINVAL;
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*p),
-                                     bind, false);
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*p), bind, false);
                if (ret)
                        return ret;
                p = to_pedit(a);
        memcpy(p->tcfp_keys, parm->keys, ksize);
        spin_unlock_bh(&p->tcf_lock);
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
        return -1;
 }
 
+static int tcf_pedit_walker(struct net *net, struct sk_buff *skb,
+                           struct netlink_callback *cb, int type,
+                           struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_pedit_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_pedit_ops = {
        .kind           =       "pedit",
        .type           =       TCA_ACT_PEDIT,
        .dump           =       tcf_pedit_dump,
        .cleanup        =       tcf_pedit_cleanup,
        .init           =       tcf_pedit_init,
+       .walk           =       tcf_pedit_walker,
+       .lookup         =       tcf_pedit_search,
+};
+
+static __net_init int pedit_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       return tc_action_net_init(tn, &act_pedit_ops, PEDIT_TAB_MASK);
+}
+
+static void __net_exit pedit_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, pedit_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations pedit_net_ops = {
+       .init = pedit_init_net,
+       .exit = pedit_exit_net,
+       .id   = &pedit_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
 
 static int __init pedit_init_module(void)
 {
-       return tcf_register_action(&act_pedit_ops, PEDIT_TAB_MASK);
+       return tcf_register_action(&act_pedit_ops, &pedit_net_ops);
 }
 
 static void __exit pedit_cleanup_module(void)
 {
-       tcf_unregister_action(&act_pedit_ops);
+       tcf_unregister_action(&act_pedit_ops, &pedit_net_ops);
 }
 
 module_init(pedit_init_module);
 
 
 /* Each policer is serialized by its individual spinlock */
 
-static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
-                             int type, struct tc_action *a)
+static int police_net_id;
+
+static int tcf_act_police_walker(struct net *net, struct sk_buff *skb,
+                                struct netlink_callback *cb, int type,
+                                struct tc_action *a)
 {
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        struct hlist_head *head;
        struct tcf_common *p;
        int err = 0, index = -1, i = 0, s_i = 0, n_i = 0;
        struct tc_police *parm;
        struct tcf_police *police;
        struct qdisc_rate_table *R_tab = NULL, *P_tab = NULL;
-       struct tcf_hashinfo *hinfo = a->ops->hinfo;
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+       struct tcf_hashinfo *hinfo = tn->hinfo;
        int size;
 
        if (nla == NULL)
        parm = nla_data(tb[TCA_POLICE_TBF]);
 
        if (parm->index) {
-               if (tcf_hash_search(a, parm->index)) {
+               if (tcf_hash_search(tn, a, parm->index)) {
                        police = to_police(a->priv);
                        if (bind) {
                                police->tcf_bindcnt += 1;
 
        police->tcfp_t_c = ktime_get_ns();
        police->tcf_index = parm->index ? parm->index :
-               tcf_hash_new_index(hinfo);
+               tcf_hash_new_index(tn);
        h = tcf_hash(police->tcf_index, POL_TAB_MASK);
        spin_lock_bh(&hinfo->lock);
        hlist_add_head(&police->tcf_head, &hinfo->htab[h]);
        return -1;
 }
 
+static int tcf_police_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 MODULE_AUTHOR("Alexey Kuznetsov");
 MODULE_DESCRIPTION("Policing actions");
 MODULE_LICENSE("GPL");
        .act            =       tcf_act_police,
        .dump           =       tcf_act_police_dump,
        .init           =       tcf_act_police_locate,
-       .walk           =       tcf_act_police_walker
+       .walk           =       tcf_act_police_walker,
+       .lookup         =       tcf_police_search,
+};
+
+static __net_init int police_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+
+       return tc_action_net_init(tn, &act_police_ops, POL_TAB_MASK);
+}
+
+static void __net_exit police_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, police_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations police_net_ops = {
+       .init = police_init_net,
+       .exit = police_exit_net,
+       .id   = &police_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init
 police_init_module(void)
 {
-       return tcf_register_action(&act_police_ops, POL_TAB_MASK);
+       return tcf_register_action(&act_police_ops, &police_net_ops);
 }
 
 static void __exit
 police_cleanup_module(void)
 {
-       tcf_unregister_action(&act_police_ops);
+       tcf_unregister_action(&act_police_ops, &police_net_ops);
 }
 
 module_init(police_init_module);
 
 
 #define SIMP_TAB_MASK     7
 
+static int simp_net_id;
+
 #define SIMP_MAX_DATA  32
 static int tcf_simp(struct sk_buff *skb, const struct tc_action *a,
                    struct tcf_result *res)
                         struct nlattr *est, struct tc_action *a,
                         int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
        struct nlattr *tb[TCA_DEF_MAX + 1];
        struct tc_defact *parm;
        struct tcf_defact *d;
        parm = nla_data(tb[TCA_DEF_PARMS]);
        defdata = nla_data(tb[TCA_DEF_DATA]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*d),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*d), bind, false);
                if (ret)
                        return ret;
 
        }
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
        return -1;
 }
 
+static int tcf_simp_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_simp_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_simp_ops = {
        .kind           =       "simple",
        .type           =       TCA_ACT_SIMP,
        .dump           =       tcf_simp_dump,
        .cleanup        =       tcf_simp_release,
        .init           =       tcf_simp_init,
+       .walk           =       tcf_simp_walker,
+       .lookup         =       tcf_simp_search,
+};
+
+static __net_init int simp_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       return tc_action_net_init(tn, &act_simp_ops, SIMP_TAB_MASK);
+}
+
+static void __net_exit simp_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, simp_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations simp_net_ops = {
+       .init = simp_init_net,
+       .exit = simp_exit_net,
+       .id   = &simp_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Jamal Hadi Salim(2005)");
 
 static int __init simp_init_module(void)
 {
-       int ret;
-       ret = tcf_register_action(&act_simp_ops, SIMP_TAB_MASK);
+       int ret = tcf_register_action(&act_simp_ops, &simp_net_ops);
        if (!ret)
                pr_info("Simple TC action Loaded\n");
        return ret;
 
 static void __exit simp_cleanup_module(void)
 {
-       tcf_unregister_action(&act_simp_ops);
+       tcf_unregister_action(&act_simp_ops, &simp_net_ops);
 }
 
 module_init(simp_init_module);
 
 
 #define SKBEDIT_TAB_MASK     15
 
+static int skbedit_net_id;
+
 static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
                       struct tcf_result *res)
 {
                            struct nlattr *est, struct tc_action *a,
                            int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
        struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
        struct tc_skbedit *parm;
        struct tcf_skbedit *d;
 
        parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*d),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*d), bind, false);
                if (ret)
                        return ret;
 
        spin_unlock_bh(&d->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
        return -1;
 }
 
+static int tcf_skbedit_walker(struct net *net, struct sk_buff *skb,
+                             struct netlink_callback *cb, int type,
+                             struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_skbedit_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_skbedit_ops = {
        .kind           =       "skbedit",
        .type           =       TCA_ACT_SKBEDIT,
        .act            =       tcf_skbedit,
        .dump           =       tcf_skbedit_dump,
        .init           =       tcf_skbedit_init,
+       .walk           =       tcf_skbedit_walker,
+       .lookup         =       tcf_skbedit_search,
+};
+
+static __net_init int skbedit_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       return tc_action_net_init(tn, &act_skbedit_ops, SKBEDIT_TAB_MASK);
+}
+
+static void __net_exit skbedit_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, skbedit_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations skbedit_net_ops = {
+       .init = skbedit_init_net,
+       .exit = skbedit_exit_net,
+       .id   = &skbedit_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
 
 static int __init skbedit_init_module(void)
 {
-       return tcf_register_action(&act_skbedit_ops, SKBEDIT_TAB_MASK);
+       return tcf_register_action(&act_skbedit_ops, &skbedit_net_ops);
 }
 
 static void __exit skbedit_cleanup_module(void)
 {
-       tcf_unregister_action(&act_skbedit_ops);
+       tcf_unregister_action(&act_skbedit_ops, &skbedit_net_ops);
 }
 
 module_init(skbedit_init_module);
 
 
 #define VLAN_TAB_MASK     15
 
+static int vlan_net_id;
+
 static int tcf_vlan(struct sk_buff *skb, const struct tc_action *a,
                    struct tcf_result *res)
 {
                         struct nlattr *est, struct tc_action *a,
                         int ovr, int bind)
 {
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
        struct nlattr *tb[TCA_VLAN_MAX + 1];
        struct tc_vlan *parm;
        struct tcf_vlan *v;
        }
        action = parm->v_action;
 
-       if (!tcf_hash_check(parm->index, a, bind)) {
-               ret = tcf_hash_create(parm->index, est, a, sizeof(*v),
-                                     bind, false);
+       if (!tcf_hash_check(tn, parm->index, a, bind)) {
+               ret = tcf_hash_create(tn, parm->index, est, a,
+                                     sizeof(*v), bind, false);
                if (ret)
                        return ret;
 
        spin_unlock_bh(&v->tcf_lock);
 
        if (ret == ACT_P_CREATED)
-               tcf_hash_insert(a);
+               tcf_hash_insert(tn, a);
        return ret;
 }
 
        return -1;
 }
 
+static int tcf_vlan_walker(struct net *net, struct sk_buff *skb,
+                          struct netlink_callback *cb, int type,
+                          struct tc_action *a)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       return tcf_generic_walker(tn, skb, cb, type, a);
+}
+
+static int tcf_vlan_search(struct net *net, struct tc_action *a, u32 index)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       return tcf_hash_search(tn, a, index);
+}
+
 static struct tc_action_ops act_vlan_ops = {
        .kind           =       "vlan",
        .type           =       TCA_ACT_VLAN,
        .act            =       tcf_vlan,
        .dump           =       tcf_vlan_dump,
        .init           =       tcf_vlan_init,
+       .walk           =       tcf_vlan_walker,
+       .lookup         =       tcf_vlan_search,
+};
+
+static __net_init int vlan_init_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       return tc_action_net_init(tn, &act_vlan_ops, VLAN_TAB_MASK);
+}
+
+static void __net_exit vlan_exit_net(struct net *net)
+{
+       struct tc_action_net *tn = net_generic(net, vlan_net_id);
+
+       tc_action_net_exit(tn);
+}
+
+static struct pernet_operations vlan_net_ops = {
+       .init = vlan_init_net,
+       .exit = vlan_exit_net,
+       .id   = &vlan_net_id,
+       .size = sizeof(struct tc_action_net),
 };
 
 static int __init vlan_init_module(void)
 {
-       return tcf_register_action(&act_vlan_ops, VLAN_TAB_MASK);
+       return tcf_register_action(&act_vlan_ops, &vlan_net_ops);
 }
 
 static void __exit vlan_cleanup_module(void)
 {
-       tcf_unregister_action(&act_vlan_ops);
+       tcf_unregister_action(&act_vlan_ops, &vlan_net_ops);
 }
 
 module_init(vlan_init_module);