- 这个结构没什么特别之处 :
文章插图
?
- 内核pernet_operations结构将被链接到pernet_list这个双向链表上, 定义:
static LIST_HEAD(pernet_list);static struct list_head *first_device = &pernet_list;DEFINE_MUTEX(net_mutex);
- 辅助函数register_pernet_subsys和unregister_pernet_subsys分别向该链表添加和删除数据元素. 每当创建一个新的网络命名空间时, 内核将遍历pernet_operations的链表, 用表示新命名空间的net实例作为参数来调用初始化函数 。在删除网络命名空间时,清理工作的处理是类似的
- 每个network namespace包换许多元件, 所以当一个新的network namespace被创建, 这些元件必须被初始化. 同样, 当它被删除时,需要做必要的清理工作.
- Kernel引入了如下结构pernet_operations来维护所有需要做的 initialization/cleanup工作
- 当一个新的network namespace被创建, kernel遍历pernet_operations 的list, 即遍历pernet_list, 并调用其init函数.
- 在linux内核中默认情况下, 会有一个"默认的网络命名空间", 其名为init_net, 并也将其导出, 作为全局变量.
- kernel2.4、2.6:通过copy_net_ns和net_create函数向内核中添加一个网络命名空间, 其中copy_net_ns函数
//http://lxr.free-electrons.com/source/net/core/net_namespace.c?v=2.6.32#L120//这个函数用于向内核中添加一个网络命名空间// struct net *net_create(void);// 这个函数主要做了三件事 :// 1.通过struct net*net_alloc(void)函数分配了一个structnet结构体// 2.通过setup_net(struct net*ns)函数对分配的struct net结构体进行了相应的设置;// 3.将分配的struct net结构体加入到 net_namespace_list的双链表尾部//http://lxr.free-electrons.com/source/net/core/net_namespace.c?v=2.6.32#L143struct net *copy_net_ns(unsigned long flags, struct net *old_net){if (!(flags & CLONE_NEWNET))return get_net(old_net);return net_create();}// 1. 如果设置了CLONE_NEWNET, 就通过net_create创建一个新的net网络命令空间// 2. 否则的话, 返回旧的网络命令空间
- kernel 3.10之后删除了 net_create 函数, 而通过copy_net_ns函数添加一个网络命名空间 。
- 内核可以通过net_free和net_drop_ns函数来释放掉指定的网络命名空间.
- 定义:
static void net_free(struct net *net){kfree(rcu_access_pointer(net->gen));kmem_cache_free(net_cachep, net);}void net_drop_ns(void *p){struct net *ns = p;if (ns && atomic_dec_and_test(&ns->passive))net_free(ns);}
2.3 总结- 记住下列事实就足够了
- 网络子系统实现的所有全局函数,都需要一个网络命名空间作为参数,而网络子系统的所有全局属性,只能通过所述命名空间迂回访问.
- linux系统包括默认的命名空间 : init_net和用户自定义的net namespace一般是默认的命名空间:init_net, 也就是所有的"网络通信协议"+"网络设备"都是属于默认的命名空间.
- 网络命名空间定义了2个链表, pernet_list和net_namespace_list init_net会被链接到net_namespace_list这个双向链表上 pernet_operations结构将被链接到first_device = pernet_list这个双向链表上
- 如果没自定义网络命名空间的话,所有想用网络命名空间时都将利用默认的init_net
- 就是网络设备. 通过register_pernet_device注册:就是"注册一个网络设备"到"所有的网络命名空间net", 网络设备包括两类:虚拟的网络设备和物理网络设备 :
- 虚拟网络设备的协议根据自身设计特点对skb数据进行处理, 并通过全局变量xx_net_id和各个协议私有的特殊数据结构xx_net, 寻找到该数据包对应的应用层socket插口, 并将其放在该socket插口的接收队列中; 最后应用层在某个时刻会通过read系统调用读取该数据
文章插图
?
3.2 物理网络设备
- 比如网卡驱动、无线网卡驱动
- 上述的socket索引方法有个绕弯的地方:就是每个协议私有的xx_net结构可以直接由协议模块本身分配,索引起来也方便,不要用到全局的net_generic 。而目前内核所用的方法,其实是为了另外的目的,那就是命名空间namespace 。也就是虚拟多用户的一套机制,具体的也没细看,好像目前内核整个namespace还没有全部完成 。
推荐阅读
- Linux运维三剑客 grep、awk、sed实用笔记
- CVE-2021-4034 关于 Linux Polkit 权限提升漏洞的修复方法
- 2022 年保护 Linux 服务器的 10 种流行开源工具
- 全宇宙最全的Linux运维bash脚本常见用法总结
- 从linux内核看io_uring的实现
- 一文了解在 Python 中如何使用列表推导
- Linux系统中 tar.xz文件解压
- C语言进行Linux网络编程
- linux系统下安装mysql 8.0.26配置文件my.cnf详细注解
- Linux运维常用工具