1. 程式人生 > >第十三章 網路名稱空間(核心原始碼實現)--基於Linux3.10

第十三章 網路名稱空間(核心原始碼實現)--基於Linux3.10

圖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目錄的介面。