如何在每个网络名称空间中编写作为新实例的 Linux 内核模块?

How to write Linux kernel module that is a new instance in each network namespace?

使用 struct pernet_operationsregister_pernet_subsys(..) 是在 Linux 内核模块中为每个网络命名空间设置状态的正确方法吗?

或者有没有办法只标记一个内核模块,它在每个网络命名空间中都有一个独立的状态?

Linux 内核模块只有一种状态。网络名称空间需要在内核模块中明确处理。

要使用的关键方法是 register_pernet_subsysunregister_pernet_subsysnet_generic

这是一个示例内核模块:

#include <net/sock.h>
#include <net/netns/generic.h>
#include <net/net_namespace.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/pid_namespace.h>

/*
 * Per network namespace data
 */
struct ns_data {
  struct sock *sk;
};

/*
 * Index to store custom data for each network namespace.
 */
static unsigned int net_id;

/*
 * Called for every existing and added network namespaces
 */
static int __net_init ns_test_init(struct net *net)
{
  // create (if not present) and access data item in network namespace (net) using the id (net_id) 
  struct ns_data *data = net_generic(net, net_id);
  data->sk = -1; // initialize or example socket

  // ...

  return 0;
}

static void __net_exit ns_test_exit(struct net *net)
{
  // called when the network namespace is removed
  struct ns_data *data = net_generic(net, net_id);

  // close socket
  netlink_kernel_release(data->sk);
}

// callback to make the module network namespace aware
static struct pernet_operations net_ops __net_initdata = {
  .init = ns_test_init,
  .exit = ns_test_exit,
  .id = &net_id,
  .size = sizeof(struct ns_data),
};

static int __init netlink_test_init(void)
{
  printk(KERN_INFO "netlink_test: Init module\n");

  register_pernet_subsys(&net_ops);

  return 0;
}

static void __exit netlink_test_exit(void)
{
  printk(KERN_INFO "netlink_test: Exit module\n");

  unregister_pernet_subsys(&net_ops);
}

module_init(netlink_test_init);
module_exit(netlink_test_exit);

MODULE_LICENSE("GPL");