第十三章 网络命名空间(内核源码实现)--基于Linux3.10

下载地址《http://download.csdn.net/detail/shichaog/8620701》

有两篇翻译博文《Lxc之二—网络设置》和《linuxnamespace-之使用》;LXC文章中关于网络的设置是从用户空间配置的,从该文章可以知道网络命名空间的一些基本概念和其提供的功能。而《linuxnamespace-之使用》包括了网络命名空间管理、配置以及使用,这比LXC译文更接近网络命名空间的实现,但是都是基于用户空间的,这章是关于Linux网络命名空间内核源码。在Linux中,每一个网络空间都使用struct net表示。

13.1 命名空间创建

在当前Linux下,对进程而言一个命名空间包括五个具体的命名空间,mnt、uts、ipc、pid以及net,在os启动时,其会初始化一个称为init的初始命名空间,并将该命名空间给创建的进程,在后续创建进程时,将根据创建的flag确定是否创建新的命名空间。在图13.1.1中,进程1、2都指向了init命名空间,在创建进程3时,明确指定了复制网络命名空间,其它的命名空间依然会继承(copy)。


图13.1.1 命名空间和进程的组合

创建命名空间的系统调用如下,nstype是创建进程时指定的创建命名空间的标志。

kernel/nsproxy.c

239 SYSCALL_DEFINE2(setns, int, fd, int, nstype)
240 {
241     const struct proc_ns_operations *ops;
242     struct task_struct *tsk = current; 获得当前进程描述结构体
243     struct nsproxy *new_nsproxy;
// 创建一个新的命名空间的调用
258     new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs);
//proc目录下信息注册
264     err = ops->install(new_nsproxy, ei->ns);
//将新创建的命名空间new_nsproxy赋值给当前进程,即替换掉以前的命名空间。
269     switch_task_namespaces(tsk, new_nsproxy);
273 }

258调用的函数依然在nsproxy.c文件,该函数定义见59行。

59 static struct nsproxy *create_new_namespaces(unsigned long flags,
 60     struct task_struct *tsk, struct user_namespace *user_ns,
 61     struct fs_struct *new_fs)
 62 {
 63     struct nsproxy *new_nsp;
 64     int err;
//从nsproxy_cachep中申请一个nsproxy缓存,并将引用计数置1,
 66     new_nsp = create_nsproxy();
/mnt命名空间
70     new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);
//uts命名空间
 76     new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);
//ipc命名空间
 82     new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);
//ns命名空间
 88     new_nsp->pid_ns = copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns);
//网络命名空间
94     new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
117 }

类似图13.1.1中进程3那样需要部分复制命名空间时(clone系统调用),copy_namespaces()将被调用。

123 int copy_namespaces(unsigned long flags, struct task_struct *tsk)
124 {
125     struct nsproxy *old_ns = tsk->nsproxy; //当前进程命名空间
126     struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);
127     struct nsproxy *new_ns;
128     int err = 0;
129 
130     if (!old_ns)
131         return 0;
//引用计数原子加1
133     get_nsproxy(old_ns);
//复制标志
135     if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
136                 CLONE_NEWPID | CLONE_NEWNET)))
137         return 0;
//权能
139     if (!ns_capable(user_ns, CAP_SYS_ADMIN)) {
140         err = -EPERM;
141         goto out;
142     }
143 
//在复制ipc空间时,存在不同命名空间信号量的问题,切换到新的命名空间意味着原来的信号量将不可达,undolist(未处理
//信号的链表必须和新的ipc空间分离),如果标志设置有CLONE_SYSVSEM,意味着要求信号量共享,那就意味着不能创
//建新的ipc空间了。
151     if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) {
152         err = -EINVAL;
153         goto out;
154     }
//创建命名空间
156     new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
157     if (IS_ERR(new_ns)) {
158         err = PTR_ERR(new_ns);
159         goto out;
160     }
//将进程的命名空间空间指针指向新的命名空间
162     tsk->nsproxy = new_ns;
163 
164 out:
165     put_nsproxy(old_ns);
166     return err;
167 }

13.2 网络命名空间管理

网络命名空间操作主要在net/core/net_namespace.c,接13.1节的copy_net_ns()函数。该函数返回值是一个网络空间。创建网络命名空间时以创建网络命名空间进程的nsproxy-> net_ns为网络命名空间的原型,这是因为不同的网络命名空间很多的基础设施是一样的,比如对loopback回环接口的支持、TCP的支持、UDP支持、IP支持等等。

238 struct net *copy_net_ns(unsigned long flags,
239             struct user_namespace *user_ns, struct net *old_net)
240 {
241     struct net *net;
242     int rv;
//如果flag中CLONE_NEWNET没有设置,说明不需要创建新的网络命名空间,直接返回原来的命名空间。否则创建新的网
//络命名空间
244     if (!(flags & CLONE_NEWNET))
245         return get_net(old_net);
//从net_cachep为新的网络命名空间申请内存。
247     net = net_alloc();
//增加user命名空间的引用计数 
251     get_user_ns(user_ns);
252 
253     mutex_lock(&net_mutex);
//调用pernet_list上注册的服务函数,对这个新的网络命名空间执行init。
254     rv = setup_net(net, user_ns);
255     if (rv == 0) {
256         rtnl_lock();
257         list_add_tail_rcu(&net->list, &net_namespace_list); // net_namespace_list为所有命名空间串接的链表。
258         rtnl_unlock();
259     }
260     mutex_unlock(&net_mutex);
261     if (rv < 0) { //出错处理
//user命名空间计数值减一
262         put_user_ns(user_ns);
//释放net命名空间。
263         net_drop_ns(net);
264         return ERR_PTR(rv);
265     }
266     return net;
267 }

254行的setup_net()如下, 其主要工作就是遍历pernet_list获得对应的structpernet_operations结构体,然后将struct pernet_operations结构对应的实例的init成员函数作用于新创建的命名空间。

150 static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
151 {
166     list_for_each_entry(ops, &pernet_list, list) {
167         error = ops_init(ops, net);
168         if (error < 0)
169             goto out_undo;
170     }
189 }

structpernet_operations的实例还是很多的,以下截图展示了其中的一部分,对于arp.c文件,其arp_net_ops的arp_net_init()实例会在167行被调用,以初始化新网络命名空间arp协议在proc目录的接口。


图13.2.1 structpernet_operations实例

其它网络命名空间的函数如下:

get_net_ns_by_fd()根据文件描述获得网络命名空间

get_net_ns_by_pid()根据进程ID获得网络命名空间。

net_ns_init()网络命名空间初始化,pure_initcall声明,在系统启动时会被调用初始化网络命名空间。

register_pernet_subsys()注册图13.2.1中的各种操作集,调用register_pernet_operations(),完成,实质工作在__register_pernet_operations()函数中完成真正的注册。

unregister_pernet_subsys注销


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shichaog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值