第十三章 網路名稱空間(核心原始碼實現)--基於Linux3.10
阿新 • • 發佈:2018-12-30
圖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目錄的介面。