#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/idr.h>
#include <linux/jhash.h>
#include <linux/rculist.h>
#include <linux/rhashtable.h>
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
#include <net/tc_act/tc_pedit.h>
#include <net/tc_act/tc_mirred.h>
#include <net/tc_act/tc_vlan.h>
#include <net/tc_act/tc_tunnel_key.h>
#include <net/tc_act/tc_csum.h>
#include <net/tc_act/tc_gact.h>
#include <net/tc_act/tc_police.h>
#include <net/tc_act/tc_sample.h>
#include <net/tc_act/tc_skbedit.h>
#include <net/tc_act/tc_ct.h>
#include <net/tc_act/tc_mpls.h>
#include <net/tc_act/tc_gate.h>
#include <net/flow_offload.h>
#include <net/tc_wrapper.h>
static LIST_HEAD(tcf_proto_base);
static DEFINE_RWLOCK(cls_mod_lock);
static struct xarray tcf_exts_miss_cookies_xa;
struct tcf_exts_miss_cookie_node { … };
tcf_exts_miss_cookie;
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
static int
tcf_exts_miss_cookie_base_alloc(struct tcf_exts *exts, struct tcf_proto *tp,
u32 handle)
{ … }
static void tcf_exts_miss_cookie_base_destroy(struct tcf_exts *exts)
{ … }
static struct tcf_exts_miss_cookie_node *
tcf_exts_miss_cookie_lookup(u64 miss_cookie, int *act_index)
{ … }
#else
static int
tcf_exts_miss_cookie_base_alloc(struct tcf_exts *exts, struct tcf_proto *tp,
u32 handle)
{
return 0;
}
static void tcf_exts_miss_cookie_base_destroy(struct tcf_exts *exts)
{
}
#endif
static u64 tcf_exts_miss_cookie_get(u32 miss_cookie_base, int act_index)
{ … }
#ifdef CONFIG_NET_CLS_ACT
DEFINE_STATIC_KEY_FALSE(tc_skb_ext_tc);
EXPORT_SYMBOL(…);
void tc_skb_ext_tc_enable(void)
{ … }
EXPORT_SYMBOL(…);
void tc_skb_ext_tc_disable(void)
{ … }
EXPORT_SYMBOL(…);
#endif
static u32 destroy_obj_hashfn(const struct tcf_proto *tp)
{ … }
static void tcf_proto_signal_destroying(struct tcf_chain *chain,
struct tcf_proto *tp)
{ … }
static bool tcf_proto_cmp(const struct tcf_proto *tp1,
const struct tcf_proto *tp2)
{ … }
static bool tcf_proto_exists_destroying(struct tcf_chain *chain,
struct tcf_proto *tp)
{ … }
static void
tcf_proto_signal_destroyed(struct tcf_chain *chain, struct tcf_proto *tp)
{ … }
static const struct tcf_proto_ops *__tcf_proto_lookup_ops(const char *kind)
{ … }
static const struct tcf_proto_ops *
tcf_proto_lookup_ops(const char *kind, bool rtnl_held,
struct netlink_ext_ack *extack)
{ … }
int register_tcf_proto_ops(struct tcf_proto_ops *ops)
{ … }
EXPORT_SYMBOL(…);
static struct workqueue_struct *tc_filter_wq;
void unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
{ … }
EXPORT_SYMBOL(…);
bool tcf_queue_work(struct rcu_work *rwork, work_func_t func)
{ … }
EXPORT_SYMBOL(…);
static inline u32 tcf_auto_prio(struct tcf_proto *tp)
{ … }
static bool tcf_proto_check_kind(struct nlattr *kind, char *name)
{ … }
static bool tcf_proto_is_unlocked(const char *kind)
{ … }
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
u32 prio, struct tcf_chain *chain,
bool rtnl_held,
struct netlink_ext_ack *extack)
{ … }
static void tcf_proto_get(struct tcf_proto *tp)
{ … }
static void tcf_maintain_bypass(struct tcf_block *block)
{ … }
static void tcf_block_filter_cnt_update(struct tcf_block *block, bool *counted, bool add)
{ … }
static void tcf_chain_put(struct tcf_chain *chain);
static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,
bool sig_destroy, struct netlink_ext_ack *extack)
{ … }
static void tcf_proto_put(struct tcf_proto *tp, bool rtnl_held,
struct netlink_ext_ack *extack)
{ … }
static bool tcf_proto_check_delete(struct tcf_proto *tp)
{ … }
static void tcf_proto_mark_delete(struct tcf_proto *tp)
{ … }
static bool tcf_proto_is_deleting(struct tcf_proto *tp)
{ … }
#define ASSERT_BLOCK_LOCKED(block) …
struct tcf_filter_chain_list_item { … };
static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
u32 chain_index)
{ … }
static void tcf_chain_head_change_item(struct tcf_filter_chain_list_item *item,
struct tcf_proto *tp_head)
{ … }
static void tcf_chain0_head_change(struct tcf_chain *chain,
struct tcf_proto *tp_head)
{ … }
static bool tcf_chain_detach(struct tcf_chain *chain)
{ … }
static void tcf_block_destroy(struct tcf_block *block)
{ … }
static void tcf_chain_destroy(struct tcf_chain *chain, bool free_block)
{ … }
static void tcf_chain_hold(struct tcf_chain *chain)
{ … }
static bool tcf_chain_held_by_acts_only(struct tcf_chain *chain)
{ … }
static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block,
u32 chain_index)
{ … }
#if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
static struct tcf_chain *tcf_chain_lookup_rcu(const struct tcf_block *block,
u32 chain_index)
{ … }
#endif
static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
u32 seq, u16 flags, int event, bool unicast,
struct netlink_ext_ack *extack);
static struct tcf_chain *__tcf_chain_get(struct tcf_block *block,
u32 chain_index, bool create,
bool by_act)
{ … }
static struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
bool create)
{ … }
struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index)
{ … }
EXPORT_SYMBOL(…);
static void tc_chain_tmplt_del(const struct tcf_proto_ops *tmplt_ops,
void *tmplt_priv);
static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
void *tmplt_priv, u32 chain_index,
struct tcf_block *block, struct sk_buff *oskb,
u32 seq, u16 flags);
static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
bool explicitly_created)
{ … }
static void tcf_chain_put(struct tcf_chain *chain)
{ … }
void tcf_chain_put_by_act(struct tcf_chain *chain)
{ … }
EXPORT_SYMBOL(…);
static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
{ … }
static void tcf_chain_flush(struct tcf_chain *chain, bool rtnl_held)
{ … }
static int tcf_block_setup(struct tcf_block *block,
struct flow_block_offload *bo);
static void tcf_block_offload_init(struct flow_block_offload *bo,
struct net_device *dev, struct Qdisc *sch,
enum flow_block_command command,
enum flow_block_binder_type binder_type,
struct flow_block *flow_block,
bool shared, struct netlink_ext_ack *extack)
{ … }
static void tcf_block_unbind(struct tcf_block *block,
struct flow_block_offload *bo);
static void tc_block_indr_cleanup(struct flow_block_cb *block_cb)
{ … }
static bool tcf_block_offload_in_use(struct tcf_block *block)
{ … }
static int tcf_block_offload_cmd(struct tcf_block *block,
struct net_device *dev, struct Qdisc *sch,
struct tcf_block_ext_info *ei,
enum flow_block_command command,
struct netlink_ext_ack *extack)
{ … }
static int tcf_block_offload_bind(struct tcf_block *block, struct Qdisc *q,
struct tcf_block_ext_info *ei,
struct netlink_ext_ack *extack)
{ … }
static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q,
struct tcf_block_ext_info *ei)
{ … }
static int
tcf_chain0_head_change_cb_add(struct tcf_block *block,
struct tcf_block_ext_info *ei,
struct netlink_ext_ack *extack)
{ … }
static void
tcf_chain0_head_change_cb_del(struct tcf_block *block,
struct tcf_block_ext_info *ei)
{ … }
struct tcf_net { … };
static unsigned int tcf_net_id;
static int tcf_block_insert(struct tcf_block *block, struct net *net,
struct netlink_ext_ack *extack)
{ … }
static void tcf_block_remove(struct tcf_block *block, struct net *net)
{ … }
static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
u32 block_index,
struct netlink_ext_ack *extack)
{ … }
struct tcf_block *tcf_block_lookup(struct net *net, u32 block_index)
{ … }
EXPORT_SYMBOL(…);
static struct tcf_block *tcf_block_refcnt_get(struct net *net, u32 block_index)
{ … }
static struct tcf_chain *
__tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
{ … }
struct tcf_chain *
tcf_get_next_chain(struct tcf_block *block, struct tcf_chain *chain)
{ … }
EXPORT_SYMBOL(…);
static struct tcf_proto *
__tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
{ … }
struct tcf_proto *
tcf_get_next_proto(struct tcf_chain *chain, struct tcf_proto *tp)
{ … }
EXPORT_SYMBOL(…);
static void tcf_block_flush_all_chains(struct tcf_block *block, bool rtnl_held)
{ … }
static int __tcf_qdisc_find(struct net *net, struct Qdisc **q,
u32 *parent, int ifindex, bool rtnl_held,
struct netlink_ext_ack *extack)
{ … }
static int __tcf_qdisc_cl_find(struct Qdisc *q, u32 parent, unsigned long *cl,
int ifindex, struct netlink_ext_ack *extack)
{ … }
static struct tcf_block *__tcf_block_find(struct net *net, struct Qdisc *q,
unsigned long cl, int ifindex,
u32 block_index,
struct netlink_ext_ack *extack)
{ … }
static void __tcf_block_put(struct tcf_block *block, struct Qdisc *q,
struct tcf_block_ext_info *ei, bool rtnl_held)
{ … }
static void tcf_block_refcnt_put(struct tcf_block *block, bool rtnl_held)
{ … }
static struct tcf_block *tcf_block_find(struct net *net, struct Qdisc **q,
u32 *parent, unsigned long *cl,
int ifindex, u32 block_index,
struct netlink_ext_ack *extack)
{ … }
static void tcf_block_release(struct Qdisc *q, struct tcf_block *block,
bool rtnl_held)
{ … }
struct tcf_block_owner_item { … };
static void
tcf_block_owner_netif_keep_dst(struct tcf_block *block,
struct Qdisc *q,
enum flow_block_binder_type binder_type)
{ … }
void tcf_block_netif_keep_dst(struct tcf_block *block)
{ … }
EXPORT_SYMBOL(…);
static int tcf_block_owner_add(struct tcf_block *block,
struct Qdisc *q,
enum flow_block_binder_type binder_type)
{ … }
static void tcf_block_owner_del(struct tcf_block *block,
struct Qdisc *q,
enum flow_block_binder_type binder_type)
{ … }
static bool tcf_block_tracks_dev(struct tcf_block *block,
struct tcf_block_ext_info *ei)
{ … }
int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
struct tcf_block_ext_info *ei,
struct netlink_ext_ack *extack)
{ … }
EXPORT_SYMBOL(…);
static void tcf_chain_head_change_dflt(struct tcf_proto *tp_head, void *priv)
{ … }
int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
struct netlink_ext_ack *extack)
{ … }
EXPORT_SYMBOL(…);
void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
struct tcf_block_ext_info *ei)
{ … }
EXPORT_SYMBOL(…);
void tcf_block_put(struct tcf_block *block)
{ … }
EXPORT_SYMBOL(…);
static int
tcf_block_playback_offloads(struct tcf_block *block, flow_setup_cb_t *cb,
void *cb_priv, bool add, bool offload_in_use,
struct netlink_ext_ack *extack)
{ … }
static int tcf_block_bind(struct tcf_block *block,
struct flow_block_offload *bo)
{ … }
static void tcf_block_unbind(struct tcf_block *block,
struct flow_block_offload *bo)
{ … }
static int tcf_block_setup(struct tcf_block *block,
struct flow_block_offload *bo)
{ … }
static inline int __tcf_classify(struct sk_buff *skb,
const struct tcf_proto *tp,
const struct tcf_proto *orig_tp,
struct tcf_result *res,
bool compat_mode,
struct tcf_exts_miss_cookie_node *n,
int act_index,
u32 *last_executed_chain)
{ … }
int tcf_classify(struct sk_buff *skb,
const struct tcf_block *block,
const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode)
{ … }
EXPORT_SYMBOL(…);
struct tcf_chain_info { … };
static struct tcf_proto *tcf_chain_tp_prev(struct tcf_chain *chain,
struct tcf_chain_info *chain_info)
{ … }
static int tcf_chain_tp_insert(struct tcf_chain *chain,
struct tcf_chain_info *chain_info,
struct tcf_proto *tp)
{ … }
static void tcf_chain_tp_remove(struct tcf_chain *chain,
struct tcf_chain_info *chain_info,
struct tcf_proto *tp)
{ … }
static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
struct tcf_chain_info *chain_info,
u32 protocol, u32 prio,
bool prio_allocate);
static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
struct tcf_proto *tp_new,
u32 protocol, u32 prio,
bool rtnl_held)
{ … }
static void tcf_chain_tp_delete_empty(struct tcf_chain *chain,
struct tcf_proto *tp, bool rtnl_held,
struct netlink_ext_ack *extack)
{ … }
static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
struct tcf_chain_info *chain_info,
u32 protocol, u32 prio,
bool prio_allocate)
{ … }
static int tcf_fill_node(struct net *net, struct sk_buff *skb,
struct tcf_proto *tp, struct tcf_block *block,
struct Qdisc *q, u32 parent, void *fh,
u32 portid, u32 seq, u16 flags, int event,
bool terse_dump, bool rtnl_held,
struct netlink_ext_ack *extack)
{ … }
static int tfilter_notify(struct net *net, struct sk_buff *oskb,
struct nlmsghdr *n, struct tcf_proto *tp,
struct tcf_block *block, struct Qdisc *q,
u32 parent, void *fh, int event, bool unicast,
bool rtnl_held, struct netlink_ext_ack *extack)
{ … }
static int tfilter_del_notify(struct net *net, struct sk_buff *oskb,
struct nlmsghdr *n, struct tcf_proto *tp,
struct tcf_block *block, struct Qdisc *q,
u32 parent, void *fh, bool *last, bool rtnl_held,
struct netlink_ext_ack *extack)
{ … }
static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
struct tcf_block *block, struct Qdisc *q,
u32 parent, struct nlmsghdr *n,
struct tcf_chain *chain, int event,
struct netlink_ext_ack *extack)
{ … }
static void tfilter_put(struct tcf_proto *tp, void *fh)
{ … }
static bool is_qdisc_ingress(__u32 classid)
{ … }
static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
struct netlink_ext_ack *extack)
{ … }
static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
struct netlink_ext_ack *extack)
{ … }
static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
struct netlink_ext_ack *extack)
{ … }
struct tcf_dump_args { … };
static int tcf_node_dump(struct tcf_proto *tp, void *n, struct tcf_walker *arg)
{ … }
static bool tcf_chain_dump(struct tcf_chain *chain, struct Qdisc *q, u32 parent,
struct sk_buff *skb, struct netlink_callback *cb,
long index_start, long *p_index, bool terse)
{ … }
static const struct nla_policy tcf_tfilter_dump_policy[TCA_MAX + 1] = …;
static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
{ … }
static int tc_chain_fill_node(const struct tcf_proto_ops *tmplt_ops,
void *tmplt_priv, u32 chain_index,
struct net *net, struct sk_buff *skb,
struct tcf_block *block,
u32 portid, u32 seq, u16 flags, int event,
struct netlink_ext_ack *extack)
{ … }
static int tc_chain_notify(struct tcf_chain *chain, struct sk_buff *oskb,
u32 seq, u16 flags, int event, bool unicast,
struct netlink_ext_ack *extack)
{ … }
static int tc_chain_notify_delete(const struct tcf_proto_ops *tmplt_ops,
void *tmplt_priv, u32 chain_index,
struct tcf_block *block, struct sk_buff *oskb,
u32 seq, u16 flags)
{ … }
static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net,
struct nlattr **tca,
struct netlink_ext_ack *extack)
{ … }
static void tc_chain_tmplt_del(const struct tcf_proto_ops *tmplt_ops,
void *tmplt_priv)
{ … }
static int tc_ctl_chain(struct sk_buff *skb, struct nlmsghdr *n,
struct netlink_ext_ack *extack)
{ … }
static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
{ … }
int tcf_exts_init_ex(struct tcf_exts *exts, struct net *net, int action,
int police, struct tcf_proto *tp, u32 handle,
bool use_action_miss)
{ … }
EXPORT_SYMBOL(…);
void tcf_exts_destroy(struct tcf_exts *exts)
{ … }
EXPORT_SYMBOL(…);
int tcf_exts_validate_ex(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
struct nlattr *rate_tlv, struct tcf_exts *exts,
u32 flags, u32 fl_flags, struct netlink_ext_ack *extack)
{ … }
EXPORT_SYMBOL(…);
int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
struct nlattr *rate_tlv, struct tcf_exts *exts,
u32 flags, struct netlink_ext_ack *extack)
{ … }
EXPORT_SYMBOL(…);
void tcf_exts_change(struct tcf_exts *dst, struct tcf_exts *src)
{ … }
EXPORT_SYMBOL(…);
#ifdef CONFIG_NET_CLS_ACT
static struct tc_action *tcf_exts_first_act(struct tcf_exts *exts)
{ … }
#endif
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts)
{ … }
EXPORT_SYMBOL(…);
int tcf_exts_terse_dump(struct sk_buff *skb, struct tcf_exts *exts)
{ … }
EXPORT_SYMBOL(…);
int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts)
{ … }
EXPORT_SYMBOL(…);
static void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)
{ … }
static void tcf_block_offload_dec(struct tcf_block *block, u32 *flags)
{ … }
static void tc_cls_offload_cnt_update(struct tcf_block *block,
struct tcf_proto *tp, u32 *cnt,
u32 *flags, u32 diff, bool add)
{ … }
static void
tc_cls_offload_cnt_reset(struct tcf_block *block, struct tcf_proto *tp,
u32 *cnt, u32 *flags)
{ … }
static int
__tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
void *type_data, bool err_stop)
{ … }
int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type,
void *type_data, bool err_stop, bool rtnl_held)
{ … }
EXPORT_SYMBOL(…);
int tc_setup_cb_add(struct tcf_block *block, struct tcf_proto *tp,
enum tc_setup_type type, void *type_data, bool err_stop,
u32 *flags, unsigned int *in_hw_count, bool rtnl_held)
{ … }
EXPORT_SYMBOL(…);
int tc_setup_cb_replace(struct tcf_block *block, struct tcf_proto *tp,
enum tc_setup_type type, void *type_data, bool err_stop,
u32 *old_flags, unsigned int *old_in_hw_count,
u32 *new_flags, unsigned int *new_in_hw_count,
bool rtnl_held)
{ … }
EXPORT_SYMBOL(…);
int tc_setup_cb_destroy(struct tcf_block *block, struct tcf_proto *tp,
enum tc_setup_type type, void *type_data, bool err_stop,
u32 *flags, unsigned int *in_hw_count, bool rtnl_held)
{ … }
EXPORT_SYMBOL(…);
int tc_setup_cb_reoffload(struct tcf_block *block, struct tcf_proto *tp,
bool add, flow_setup_cb_t *cb,
enum tc_setup_type type, void *type_data,
void *cb_priv, u32 *flags, unsigned int *in_hw_count)
{ … }
EXPORT_SYMBOL(…);
static int tcf_act_get_user_cookie(struct flow_action_entry *entry,
const struct tc_action *act)
{ … }
static void tcf_act_put_user_cookie(struct flow_action_entry *entry)
{ … }
void tc_cleanup_offload_action(struct flow_action *flow_action)
{ … }
EXPORT_SYMBOL(…);
static int tc_setup_offload_act(struct tc_action *act,
struct flow_action_entry *entry,
u32 *index_inc,
struct netlink_ext_ack *extack)
{ … }
int tc_setup_action(struct flow_action *flow_action,
struct tc_action *actions[],
u32 miss_cookie_base,
struct netlink_ext_ack *extack)
{ … }
int tc_setup_offload_action(struct flow_action *flow_action,
const struct tcf_exts *exts,
struct netlink_ext_ack *extack)
{ … }
EXPORT_SYMBOL(…);
unsigned int tcf_exts_num_actions(struct tcf_exts *exts)
{ … }
EXPORT_SYMBOL(…);
#ifdef CONFIG_NET_CLS_ACT
static int tcf_qevent_parse_block_index(struct nlattr *block_index_attr,
u32 *p_block_index,
struct netlink_ext_ack *extack)
{ … }
int tcf_qevent_init(struct tcf_qevent *qe, struct Qdisc *sch,
enum flow_block_binder_type binder_type,
struct nlattr *block_index_attr,
struct netlink_ext_ack *extack)
{ … }
EXPORT_SYMBOL(…);
void tcf_qevent_destroy(struct tcf_qevent *qe, struct Qdisc *sch)
{ … }
EXPORT_SYMBOL(…);
int tcf_qevent_validate_change(struct tcf_qevent *qe, struct nlattr *block_index_attr,
struct netlink_ext_ack *extack)
{ … }
EXPORT_SYMBOL(…);
struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, struct sk_buff *skb,
struct sk_buff **to_free, int *ret)
{ … }
EXPORT_SYMBOL(…);
int tcf_qevent_dump(struct sk_buff *skb, int attr_name, struct tcf_qevent *qe)
{ … }
EXPORT_SYMBOL(…);
#endif
static __net_init int tcf_net_init(struct net *net)
{ … }
static void __net_exit tcf_net_exit(struct net *net)
{ … }
static struct pernet_operations tcf_net_ops = …;
static int __init tc_filter_init(void)
{ … }
subsys_initcall(tc_filter_init);