We want to be able to enable/disable IP packet defrag from core
bpf/netfilter code. In other words, execute code from core that could
possibly be built as a module.
To help avoid symbol resolution errors, use glue hooks that the modules
will register callbacks with during module init.
Signed-off-by: Daniel Xu <dxu@dxuuu.xyz>
Reviewed-by: Florian Westphal <fw@strlen.de>
Link: https://lore.kernel.org/r/f6a8824052441b72afe5285acedbd634bd3384c1.1689970773.git.dxu@dxuuu.xyz
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <linux/static_key.h>
+#include <linux/module.h>
 #include <linux/netfilter_defs.h>
 #include <linux/netdevice.h>
 #include <linux/sockptr.h>
 };
 extern const struct nfnl_ct_hook __rcu *nfnl_ct_hook;
 
+struct nf_defrag_hook {
+       struct module *owner;
+       int (*enable)(struct net *net);
+       void (*disable)(struct net *net);
+};
+
+extern const struct nf_defrag_hook __rcu *nf_defrag_v4_hook;
+extern const struct nf_defrag_hook __rcu *nf_defrag_v6_hook;
+
 /*
  * nf_skb_duplicated - TEE target has sent a packet
  *
 
 #include <linux/ip.h>
 #include <linux/netfilter.h>
 #include <linux/module.h>
+#include <linux/rcupdate.h>
 #include <linux/skbuff.h>
 #include <net/netns/generic.h>
 #include <net/route.h>
        }
 }
 
+static const struct nf_defrag_hook defrag_hook = {
+       .owner = THIS_MODULE,
+       .enable = nf_defrag_ipv4_enable,
+       .disable = nf_defrag_ipv4_disable,
+};
+
 static struct pernet_operations defrag4_net_ops = {
        .exit = defrag4_net_exit,
 };
 
 static int __init nf_defrag_init(void)
 {
-       return register_pernet_subsys(&defrag4_net_ops);
+       int err;
+
+       err = register_pernet_subsys(&defrag4_net_ops);
+       if (err)
+               return err;
+
+       rcu_assign_pointer(nf_defrag_v4_hook, &defrag_hook);
+       return err;
 }
 
 static void __exit nf_defrag_fini(void)
 {
+       rcu_assign_pointer(nf_defrag_v4_hook, NULL);
        unregister_pernet_subsys(&defrag4_net_ops);
 }
 
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/icmp.h>
+#include <linux/rcupdate.h>
 #include <linux/sysctl.h>
 #include <net/ipv6_frag.h>
 
        }
 }
 
+static const struct nf_defrag_hook defrag_hook = {
+       .owner = THIS_MODULE,
+       .enable = nf_defrag_ipv6_enable,
+       .disable = nf_defrag_ipv6_disable,
+};
+
 static struct pernet_operations defrag6_net_ops = {
        .exit = defrag6_net_exit,
 };
                pr_err("nf_defrag_ipv6: can't register pernet ops\n");
                goto cleanup_frag6;
        }
+
+       rcu_assign_pointer(nf_defrag_v6_hook, &defrag_hook);
+
        return ret;
 
 cleanup_frag6:
 
 static void __exit nf_defrag_fini(void)
 {
+       rcu_assign_pointer(nf_defrag_v6_hook, NULL);
        unregister_pernet_subsys(&defrag6_net_ops);
        nf_ct_frag6_cleanup();
 }
 
 const struct nf_ct_hook __rcu *nf_ct_hook __read_mostly;
 EXPORT_SYMBOL_GPL(nf_ct_hook);
 
+const struct nf_defrag_hook __rcu *nf_defrag_v4_hook __read_mostly;
+EXPORT_SYMBOL_GPL(nf_defrag_v4_hook);
+
+const struct nf_defrag_hook __rcu *nf_defrag_v6_hook __read_mostly;
+EXPORT_SYMBOL_GPL(nf_defrag_v6_hook);
+
 #if IS_ENABLED(CONFIG_NF_CONNTRACK)
 u8 nf_ctnetlink_has_listener;
 EXPORT_SYMBOL_GPL(nf_ctnetlink_has_listener);