Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/linux-2.6-nsfd

* git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/linux-2.6-nsfd:
net: fix get_net_ns_by_fd for !CONFIG_NET_NS
ns proc: Return -ENOENT for a nonexistent /proc/self/ns/ entry.
ns: Declare sys_setns in syscalls.h
net: Allow setting the network namespace by fd
ns proc: Add support for the ipc namespace
ns proc: Add support for the uts namespace
ns proc: Add support for the network namespace.
ns: Introduce the setns syscall
ns: proc files for namespace naming policy.

+444 -12
+1
fs/proc/Makefile
··· 20 20 proc-y += uptime.o 21 21 proc-y += version.o 22 22 proc-y += softirqs.o 23 + proc-y += namespaces.o 23 24 proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o 24 25 proc-$(CONFIG_NET) += proc_net.o 25 26 proc-$(CONFIG_PROC_KCORE) += kcore.o
+9 -11
fs/proc/base.c
··· 600 600 return allowed; 601 601 } 602 602 603 - static int proc_setattr(struct dentry *dentry, struct iattr *attr) 603 + int proc_setattr(struct dentry *dentry, struct iattr *attr) 604 604 { 605 605 int error; 606 606 struct inode *inode = dentry->d_inode; ··· 1736 1736 return 0; 1737 1737 } 1738 1738 1739 - 1740 - static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task) 1739 + struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task) 1741 1740 { 1742 1741 struct inode * inode; 1743 1742 struct proc_inode *ei; ··· 1778 1779 return NULL; 1779 1780 } 1780 1781 1781 - static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 1782 + int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 1782 1783 { 1783 1784 struct inode *inode = dentry->d_inode; 1784 1785 struct task_struct *task; ··· 1819 1820 * made this apply to all per process world readable and executable 1820 1821 * directories. 1821 1822 */ 1822 - static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) 1823 + int pid_revalidate(struct dentry *dentry, struct nameidata *nd) 1823 1824 { 1824 1825 struct inode *inode; 1825 1826 struct task_struct *task; ··· 1861 1862 return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first; 1862 1863 } 1863 1864 1864 - static const struct dentry_operations pid_dentry_operations = 1865 + const struct dentry_operations pid_dentry_operations = 1865 1866 { 1866 1867 .d_revalidate = pid_revalidate, 1867 1868 .d_delete = pid_delete_dentry, 1868 1869 }; 1869 1870 1870 1871 /* Lookups */ 1871 - 1872 - typedef struct dentry *instantiate_t(struct inode *, struct dentry *, 1873 - struct task_struct *, const void *); 1874 1872 1875 1873 /* 1876 1874 * Fill a directory entry. ··· 1881 1885 * reported by readdir in sync with the inode numbers reported 1882 1886 * by stat. 1883 1887 */ 1884 - static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 1885 - char *name, int len, 1888 + int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 1889 + const char *name, int len, 1886 1890 instantiate_t instantiate, struct task_struct *task, const void *ptr) 1887 1891 { 1888 1892 struct dentry *child, *dir = filp->f_path.dentry; ··· 2816 2820 DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), 2817 2821 DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), 2818 2822 DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), 2823 + DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), 2819 2824 #ifdef CONFIG_NET 2820 2825 DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), 2821 2826 #endif ··· 3165 3168 static const struct pid_entry tid_base_stuff[] = { 3166 3169 DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), 3167 3170 DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), 3171 + DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), 3168 3172 REG("environ", S_IRUSR, proc_environ_operations), 3169 3173 INF("auxv", S_IRUSR, proc_pid_auxv), 3170 3174 ONE("status", S_IRUGO, proc_pid_status),
+7
fs/proc/inode.c
··· 28 28 { 29 29 struct proc_dir_entry *de; 30 30 struct ctl_table_header *head; 31 + const struct proc_ns_operations *ns_ops; 31 32 32 33 truncate_inode_pages(&inode->i_data, 0); 33 34 end_writeback(inode); ··· 45 44 rcu_assign_pointer(PROC_I(inode)->sysctl, NULL); 46 45 sysctl_head_put(head); 47 46 } 47 + /* Release any associated namespace */ 48 + ns_ops = PROC_I(inode)->ns_ops; 49 + if (ns_ops && ns_ops->put) 50 + ns_ops->put(PROC_I(inode)->ns); 48 51 } 49 52 50 53 static struct kmem_cache * proc_inode_cachep; ··· 67 62 ei->pde = NULL; 68 63 ei->sysctl = NULL; 69 64 ei->sysctl_entry = NULL; 65 + ei->ns = NULL; 66 + ei->ns_ops = NULL; 70 67 inode = &ei->vfs_inode; 71 68 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; 72 69 return inode;
+18
fs/proc/internal.h
··· 127 127 */ 128 128 int proc_readdir(struct file *, void *, filldir_t); 129 129 struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *); 130 + 131 + 132 + 133 + /* Lookups */ 134 + typedef struct dentry *instantiate_t(struct inode *, struct dentry *, 135 + struct task_struct *, const void *); 136 + int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 137 + const char *name, int len, 138 + instantiate_t instantiate, struct task_struct *task, const void *ptr); 139 + int pid_revalidate(struct dentry *dentry, struct nameidata *nd); 140 + struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task); 141 + extern const struct dentry_operations pid_dentry_operations; 142 + int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); 143 + int proc_setattr(struct dentry *dentry, struct iattr *attr); 144 + 145 + extern const struct inode_operations proc_ns_dir_inode_operations; 146 + extern const struct file_operations proc_ns_dir_operations; 147 +
+198
fs/proc/namespaces.c
··· 1 + #include <linux/proc_fs.h> 2 + #include <linux/nsproxy.h> 3 + #include <linux/sched.h> 4 + #include <linux/ptrace.h> 5 + #include <linux/fs_struct.h> 6 + #include <linux/mount.h> 7 + #include <linux/path.h> 8 + #include <linux/namei.h> 9 + #include <linux/file.h> 10 + #include <linux/utsname.h> 11 + #include <net/net_namespace.h> 12 + #include <linux/mnt_namespace.h> 13 + #include <linux/ipc_namespace.h> 14 + #include <linux/pid_namespace.h> 15 + #include "internal.h" 16 + 17 + 18 + static const struct proc_ns_operations *ns_entries[] = { 19 + #ifdef CONFIG_NET_NS 20 + &netns_operations, 21 + #endif 22 + #ifdef CONFIG_UTS_NS 23 + &utsns_operations, 24 + #endif 25 + #ifdef CONFIG_IPC_NS 26 + &ipcns_operations, 27 + #endif 28 + }; 29 + 30 + static const struct file_operations ns_file_operations = { 31 + .llseek = no_llseek, 32 + }; 33 + 34 + static struct dentry *proc_ns_instantiate(struct inode *dir, 35 + struct dentry *dentry, struct task_struct *task, const void *ptr) 36 + { 37 + const struct proc_ns_operations *ns_ops = ptr; 38 + struct inode *inode; 39 + struct proc_inode *ei; 40 + struct dentry *error = ERR_PTR(-ENOENT); 41 + 42 + inode = proc_pid_make_inode(dir->i_sb, task); 43 + if (!inode) 44 + goto out; 45 + 46 + ei = PROC_I(inode); 47 + inode->i_mode = S_IFREG|S_IRUSR; 48 + inode->i_fop = &ns_file_operations; 49 + ei->ns_ops = ns_ops; 50 + ei->ns = ns_ops->get(task); 51 + if (!ei->ns) 52 + goto out_iput; 53 + 54 + dentry->d_op = &pid_dentry_operations; 55 + d_add(dentry, inode); 56 + /* Close the race of the process dying before we return the dentry */ 57 + if (pid_revalidate(dentry, NULL)) 58 + error = NULL; 59 + out: 60 + return error; 61 + out_iput: 62 + iput(inode); 63 + goto out; 64 + } 65 + 66 + static int proc_ns_fill_cache(struct file *filp, void *dirent, 67 + filldir_t filldir, struct task_struct *task, 68 + const struct proc_ns_operations *ops) 69 + { 70 + return proc_fill_cache(filp, dirent, filldir, 71 + ops->name, strlen(ops->name), 72 + proc_ns_instantiate, task, ops); 73 + } 74 + 75 + static int proc_ns_dir_readdir(struct file *filp, void *dirent, 76 + filldir_t filldir) 77 + { 78 + int i; 79 + struct dentry *dentry = filp->f_path.dentry; 80 + struct inode *inode = dentry->d_inode; 81 + struct task_struct *task = get_proc_task(inode); 82 + const struct proc_ns_operations **entry, **last; 83 + ino_t ino; 84 + int ret; 85 + 86 + ret = -ENOENT; 87 + if (!task) 88 + goto out_no_task; 89 + 90 + ret = -EPERM; 91 + if (!ptrace_may_access(task, PTRACE_MODE_READ)) 92 + goto out; 93 + 94 + ret = 0; 95 + i = filp->f_pos; 96 + switch (i) { 97 + case 0: 98 + ino = inode->i_ino; 99 + if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) 100 + goto out; 101 + i++; 102 + filp->f_pos++; 103 + /* fall through */ 104 + case 1: 105 + ino = parent_ino(dentry); 106 + if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) 107 + goto out; 108 + i++; 109 + filp->f_pos++; 110 + /* fall through */ 111 + default: 112 + i -= 2; 113 + if (i >= ARRAY_SIZE(ns_entries)) { 114 + ret = 1; 115 + goto out; 116 + } 117 + entry = ns_entries + i; 118 + last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; 119 + while (entry <= last) { 120 + if (proc_ns_fill_cache(filp, dirent, filldir, 121 + task, *entry) < 0) 122 + goto out; 123 + filp->f_pos++; 124 + entry++; 125 + } 126 + } 127 + 128 + ret = 1; 129 + out: 130 + put_task_struct(task); 131 + out_no_task: 132 + return ret; 133 + } 134 + 135 + const struct file_operations proc_ns_dir_operations = { 136 + .read = generic_read_dir, 137 + .readdir = proc_ns_dir_readdir, 138 + }; 139 + 140 + static struct dentry *proc_ns_dir_lookup(struct inode *dir, 141 + struct dentry *dentry, struct nameidata *nd) 142 + { 143 + struct dentry *error; 144 + struct task_struct *task = get_proc_task(dir); 145 + const struct proc_ns_operations **entry, **last; 146 + unsigned int len = dentry->d_name.len; 147 + 148 + error = ERR_PTR(-ENOENT); 149 + 150 + if (!task) 151 + goto out_no_task; 152 + 153 + error = ERR_PTR(-EPERM); 154 + if (!ptrace_may_access(task, PTRACE_MODE_READ)) 155 + goto out; 156 + 157 + last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; 158 + for (entry = ns_entries; entry <= last; entry++) { 159 + if (strlen((*entry)->name) != len) 160 + continue; 161 + if (!memcmp(dentry->d_name.name, (*entry)->name, len)) 162 + break; 163 + } 164 + error = ERR_PTR(-ENOENT); 165 + if (entry > last) 166 + goto out; 167 + 168 + error = proc_ns_instantiate(dir, dentry, task, *entry); 169 + out: 170 + put_task_struct(task); 171 + out_no_task: 172 + return error; 173 + } 174 + 175 + const struct inode_operations proc_ns_dir_inode_operations = { 176 + .lookup = proc_ns_dir_lookup, 177 + .getattr = pid_getattr, 178 + .setattr = proc_setattr, 179 + }; 180 + 181 + struct file *proc_ns_fget(int fd) 182 + { 183 + struct file *file; 184 + 185 + file = fget(fd); 186 + if (!file) 187 + return ERR_PTR(-EBADF); 188 + 189 + if (file->f_op != &ns_file_operations) 190 + goto out_invalid; 191 + 192 + return file; 193 + 194 + out_invalid: 195 + fput(file); 196 + return ERR_PTR(-EINVAL); 197 + } 198 +
+1
include/linux/if_link.h
··· 136 136 IFLA_PORT_SELF, 137 137 IFLA_AF_SPEC, 138 138 IFLA_GROUP, /* Group the device belongs to */ 139 + IFLA_NET_NS_FD, 139 140 __IFLA_MAX 140 141 }; 141 142
+21
include/linux/proc_fs.h
··· 179 179 extern struct file *get_mm_exe_file(struct mm_struct *mm); 180 180 extern void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm); 181 181 182 + extern struct file *proc_ns_fget(int fd); 183 + 182 184 #else 183 185 184 186 #define proc_net_fops_create(net, name, mode, fops) ({ (void)(mode), NULL; }) ··· 243 241 struct mm_struct *newmm) 244 242 {} 245 243 244 + static inline struct file *proc_ns_fget(int fd) 245 + { 246 + return ERR_PTR(-EINVAL); 247 + } 248 + 246 249 #endif /* CONFIG_PROC_FS */ 247 250 248 251 #if !defined(CONFIG_PROC_KCORE) ··· 258 251 #else 259 252 extern void kclist_add(struct kcore_list *, void *, size_t, int type); 260 253 #endif 254 + 255 + struct nsproxy; 256 + struct proc_ns_operations { 257 + const char *name; 258 + int type; 259 + void *(*get)(struct task_struct *task); 260 + void (*put)(void *ns); 261 + int (*install)(struct nsproxy *nsproxy, void *ns); 262 + }; 263 + extern const struct proc_ns_operations netns_operations; 264 + extern const struct proc_ns_operations utsns_operations; 265 + extern const struct proc_ns_operations ipcns_operations; 261 266 262 267 union proc_op { 263 268 int (*proc_get_link)(struct inode *, struct path *); ··· 289 270 struct proc_dir_entry *pde; 290 271 struct ctl_table_header *sysctl; 291 272 struct ctl_table *sysctl_entry; 273 + void *ns; 274 + const struct proc_ns_operations *ns_ops; 292 275 struct inode vfs_inode; 293 276 }; 294 277
+1
include/linux/syscalls.h
··· 846 846 asmlinkage long sys_open_by_handle_at(int mountdirfd, 847 847 struct file_handle __user *handle, 848 848 int flags); 849 + asmlinkage long sys_setns(int fd, int nstype); 849 850 #endif
+1
include/net/net_namespace.h
··· 119 119 extern struct list_head net_namespace_list; 120 120 121 121 extern struct net *get_net_ns_by_pid(pid_t pid); 122 + extern struct net *get_net_ns_by_fd(int pid); 122 123 123 124 #ifdef CONFIG_NET_NS 124 125 extern void __put_net(struct net *net);
+37
ipc/namespace.c
··· 12 12 #include <linux/fs.h> 13 13 #include <linux/mount.h> 14 14 #include <linux/user_namespace.h> 15 + #include <linux/proc_fs.h> 15 16 16 17 #include "util.h" 17 18 ··· 141 140 free_ipc_ns(ns); 142 141 } 143 142 } 143 + 144 + static void *ipcns_get(struct task_struct *task) 145 + { 146 + struct ipc_namespace *ns = NULL; 147 + struct nsproxy *nsproxy; 148 + 149 + rcu_read_lock(); 150 + nsproxy = task_nsproxy(task); 151 + if (nsproxy) 152 + ns = get_ipc_ns(nsproxy->ipc_ns); 153 + rcu_read_unlock(); 154 + 155 + return ns; 156 + } 157 + 158 + static void ipcns_put(void *ns) 159 + { 160 + return put_ipc_ns(ns); 161 + } 162 + 163 + static int ipcns_install(struct nsproxy *nsproxy, void *ns) 164 + { 165 + /* Ditch state from the old ipc namespace */ 166 + exit_sem(current); 167 + put_ipc_ns(nsproxy->ipc_ns); 168 + nsproxy->ipc_ns = get_ipc_ns(ns); 169 + return 0; 170 + } 171 + 172 + const struct proc_ns_operations ipcns_operations = { 173 + .name = "ipc", 174 + .type = CLONE_NEWIPC, 175 + .get = ipcns_get, 176 + .put = ipcns_put, 177 + .install = ipcns_install, 178 + };
+42
kernel/nsproxy.c
··· 22 22 #include <linux/pid_namespace.h> 23 23 #include <net/net_namespace.h> 24 24 #include <linux/ipc_namespace.h> 25 + #include <linux/proc_fs.h> 26 + #include <linux/file.h> 27 + #include <linux/syscalls.h> 25 28 26 29 static struct kmem_cache *nsproxy_cachep; 27 30 ··· 234 231 void exit_task_namespaces(struct task_struct *p) 235 232 { 236 233 switch_task_namespaces(p, NULL); 234 + } 235 + 236 + SYSCALL_DEFINE2(setns, int, fd, int, nstype) 237 + { 238 + const struct proc_ns_operations *ops; 239 + struct task_struct *tsk = current; 240 + struct nsproxy *new_nsproxy; 241 + struct proc_inode *ei; 242 + struct file *file; 243 + int err; 244 + 245 + if (!capable(CAP_SYS_ADMIN)) 246 + return -EPERM; 247 + 248 + file = proc_ns_fget(fd); 249 + if (IS_ERR(file)) 250 + return PTR_ERR(file); 251 + 252 + err = -EINVAL; 253 + ei = PROC_I(file->f_dentry->d_inode); 254 + ops = ei->ns_ops; 255 + if (nstype && (ops->type != nstype)) 256 + goto out; 257 + 258 + new_nsproxy = create_new_namespaces(0, tsk, tsk->fs); 259 + if (IS_ERR(new_nsproxy)) { 260 + err = PTR_ERR(new_nsproxy); 261 + goto out; 262 + } 263 + 264 + err = ops->install(new_nsproxy, ei->ns); 265 + if (err) { 266 + free_nsproxy(new_nsproxy); 267 + goto out; 268 + } 269 + switch_task_namespaces(tsk, new_nsproxy); 270 + out: 271 + fput(file); 272 + return err; 237 273 } 238 274 239 275 static int __init nsproxy_cache_init(void)
+39
kernel/utsname.c
··· 15 15 #include <linux/err.h> 16 16 #include <linux/slab.h> 17 17 #include <linux/user_namespace.h> 18 + #include <linux/proc_fs.h> 18 19 19 20 static struct uts_namespace *create_uts_ns(void) 20 21 { ··· 80 79 put_user_ns(ns->user_ns); 81 80 kfree(ns); 82 81 } 82 + 83 + static void *utsns_get(struct task_struct *task) 84 + { 85 + struct uts_namespace *ns = NULL; 86 + struct nsproxy *nsproxy; 87 + 88 + rcu_read_lock(); 89 + nsproxy = task_nsproxy(task); 90 + if (nsproxy) { 91 + ns = nsproxy->uts_ns; 92 + get_uts_ns(ns); 93 + } 94 + rcu_read_unlock(); 95 + 96 + return ns; 97 + } 98 + 99 + static void utsns_put(void *ns) 100 + { 101 + put_uts_ns(ns); 102 + } 103 + 104 + static int utsns_install(struct nsproxy *nsproxy, void *ns) 105 + { 106 + get_uts_ns(ns); 107 + put_uts_ns(nsproxy->uts_ns); 108 + nsproxy->uts_ns = ns; 109 + return 0; 110 + } 111 + 112 + const struct proc_ns_operations utsns_operations = { 113 + .name = "uts", 114 + .type = CLONE_NEWUTS, 115 + .get = utsns_get, 116 + .put = utsns_put, 117 + .install = utsns_install, 118 + }; 119 +
+65
net/core/net_namespace.c
··· 8 8 #include <linux/idr.h> 9 9 #include <linux/rculist.h> 10 10 #include <linux/nsproxy.h> 11 + #include <linux/proc_fs.h> 12 + #include <linux/file.h> 11 13 #include <net/net_namespace.h> 12 14 #include <net/netns/generic.h> 13 15 ··· 304 302 } 305 303 EXPORT_SYMBOL_GPL(__put_net); 306 304 305 + struct net *get_net_ns_by_fd(int fd) 306 + { 307 + struct proc_inode *ei; 308 + struct file *file; 309 + struct net *net; 310 + 311 + net = ERR_PTR(-EINVAL); 312 + file = proc_ns_fget(fd); 313 + if (!file) 314 + goto out; 315 + 316 + ei = PROC_I(file->f_dentry->d_inode); 317 + if (ei->ns_ops != &netns_operations) 318 + goto out; 319 + 320 + net = get_net(ei->ns); 321 + out: 322 + if (file) 323 + fput(file); 324 + return net; 325 + } 326 + 307 327 #else 308 328 struct net *copy_net_ns(unsigned long flags, struct net *old_net) 309 329 { 310 330 if (flags & CLONE_NEWNET) 311 331 return ERR_PTR(-EINVAL); 312 332 return old_net; 333 + } 334 + 335 + struct net *get_net_ns_by_fd(int fd) 336 + { 337 + return ERR_PTR(-EINVAL); 313 338 } 314 339 #endif 315 340 ··· 590 561 mutex_unlock(&net_mutex); 591 562 } 592 563 EXPORT_SYMBOL_GPL(unregister_pernet_device); 564 + 565 + #ifdef CONFIG_NET_NS 566 + static void *netns_get(struct task_struct *task) 567 + { 568 + struct net *net = NULL; 569 + struct nsproxy *nsproxy; 570 + 571 + rcu_read_lock(); 572 + nsproxy = task_nsproxy(task); 573 + if (nsproxy) 574 + net = get_net(nsproxy->net_ns); 575 + rcu_read_unlock(); 576 + 577 + return net; 578 + } 579 + 580 + static void netns_put(void *ns) 581 + { 582 + put_net(ns); 583 + } 584 + 585 + static int netns_install(struct nsproxy *nsproxy, void *ns) 586 + { 587 + put_net(nsproxy->net_ns); 588 + nsproxy->net_ns = get_net(ns); 589 + return 0; 590 + } 591 + 592 + const struct proc_ns_operations netns_operations = { 593 + .name = "net", 594 + .type = CLONE_NEWNET, 595 + .get = netns_get, 596 + .put = netns_put, 597 + .install = netns_install, 598 + }; 599 + #endif
+4 -1
net/core/rtnetlink.c
··· 1046 1046 [IFLA_LINKMODE] = { .type = NLA_U8 }, 1047 1047 [IFLA_LINKINFO] = { .type = NLA_NESTED }, 1048 1048 [IFLA_NET_NS_PID] = { .type = NLA_U32 }, 1049 + [IFLA_NET_NS_FD] = { .type = NLA_U32 }, 1049 1050 [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, 1050 1051 [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, 1051 1052 [IFLA_VF_PORTS] = { .type = NLA_NESTED }, ··· 1095 1094 */ 1096 1095 if (tb[IFLA_NET_NS_PID]) 1097 1096 net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); 1097 + else if (tb[IFLA_NET_NS_FD]) 1098 + net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD])); 1098 1099 else 1099 1100 net = get_net(src_net); 1100 1101 return net; ··· 1227 1224 int send_addr_notify = 0; 1228 1225 int err; 1229 1226 1230 - if (tb[IFLA_NET_NS_PID]) { 1227 + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { 1231 1228 struct net *net = rtnl_link_get_net(dev_net(dev), tb); 1232 1229 if (IS_ERR(net)) { 1233 1230 err = PTR_ERR(net);