业务场景中,需要创建指定的network namespace
, 并且内核模块中的netfilter
逻辑只应生效在该network namespace
中。这就需要我们创建network namespace
之后,将指定的namespace
传递给内核模块。
用户态创建network namespace
可以使用ip
命令指定名称,如:
但实际上在内核中,network namespace
并不具备名称信息,名称信息只存在于用户态。可以参考man ip-netns
:
1 2 3 4 By convention a named network namespace is an object at /var/run/netns/NAME that can be opened. The file descriptor resulting from opening /var/run/netns/NAME refers to the specified network namespace. Holding that file descriptor open keeps the network namespace alive. The file descriptor can be used with the setns(2) system call to change the network namespace associated with a task.
但network namespace
在/proc
文件系统中存在,因而可以使用文件的inode
来标识。inode
信息则可以通过network namespace
中的进程从/proc
获取到namespace
的文件来识别。
下边来实验。 先在上边创建的ns1
中执行一个sleep 3600
:
1 ip netns exec ns1 sleep 3600
通过pid
获取network namespace
的inode
:
1 2 3 4 5 [root@localhost ~]# ps aux |grep sleep root 22371 0.0 0.0 108052 356 pts/2 S+ 17:59 0:00 sleep 3600 root 22620 0.0 0.0 9092 680 pts/3 S+ 18:01 0:00 grep --color=auto sleep [root@localhost ~]# ls -l /proc/22371/ns/net lrwxrwxrwx 1 root root 0 Jan 2 17:59 /proc/22371/ns/net -> net:[4026532631]
在CentOS7
的内核源码中,inode
信息保存在struct net
结构的proc_inum
字段中。后来迁移到了struct ns_common
结构中:
不同版本的内核需要兼容处理一下。这里以CentOS7
为实验环境,编写内核模块源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #define pr_fmt(fmt) "[%s]: " fmt, KBUILD_MODNAME #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/net.h> #include <net/net_namespace.h> #include <linux/proc_ns.h> #include <linux/nsproxy.h> #include <linux/dcache.h> #include <linux/sched.h> static unsigned int inode = 0; module_param(inode, uint, 0400); int __init netns_inode_init(void) { struct net *net; pr_info("netns_inode module init\n"); for_each_net(net) { pr_info("namespace: p: %px, inode: %u%s", net, net->proc_inum, (inode == net->proc_inum) ? " ***\n" : "\n"); } return -1; } void __exit netns_inode_exit(void) { pr_info("netns_inode module exit\n"); return; } module_init(netns_inode_init); module_exit(netns_inode_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("netns inode");
编译后执行内核模块,可以识别到传入的inode
标识:
1 2 3 4 5 6 7 8 [root@localhost netns_inode]# insmod netns_inode.ko inode=4026532631 insmod: ERROR: could not insert module netns_inode.ko: Operation not permitted [root@localhost netns_inode]# dmesg [1216768.454246] [netns_inode]: netns_inode module init [1216768.454250] [netns_inode]: namespace: p: ffffffffa3111640, inode: 4026531956 [1216768.454252] [netns_inode]: namespace: p: ffffa0c93f6b9480, inode: 4026532511 [1216768.454253] [netns_inode]: namespace: p: ffffa0c91c738000, inode: 4026532574 [1216768.454254] [netns_inode]: namespace: p: ffffa0c613f70000, inode: 4026532631 ***