2 * linux/kernel/vserver/network.c
4 * Virtual Server: Network Support
6 * Copyright (C) 2003-2004 Herbert Pƶtzl
8 * V0.01 broken out from vcontext V0.05
9 * V0.02 cleaned up implementation
10 * V0.03 added equiv nx commands
14 #include <linux/config.h>
15 #include <linux/slab.h>
16 #include <linux/vserver/network.h>
17 #include <linux/ninline.h>
19 #include <asm/errno.h>
24 spinlock_t nxlist_lock
25 __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
29 * struct nx_info allocation and deallocation
32 static struct nx_info *alloc_nx_info(void)
34 struct nx_info *new = NULL;
36 nxdprintk("alloc_nx_info()\n");
37 /* would this benefit from a slab cache? */
38 new = kmalloc(sizeof(struct nx_info), GFP_KERNEL);
42 memset (new, 0, sizeof(struct nx_info));
43 /* rest of init goes here */
45 nxdprintk("alloc_nx_info() = %p\n", new);
49 void free_nx_info(struct nx_info *nxi)
51 nxdprintk("free_nx_info(%p)\n", nxi);
55 struct nx_info *create_nx_info(void)
60 nxdprintk("create_nx_info()\n");
61 if (!(new = alloc_nx_info()))
64 spin_lock(&nxlist_lock);
67 atomic_set(&new->nx_refcount, 1);
69 list_add(&new->nx_list, &nx_infos);
71 spin_unlock(&nxlist_lock);
77 * struct nx_info search by id
78 * assumes nxlist_lock is held
81 static __inline__ struct nx_info *__find_nx_info(int id)
85 list_for_each_entry(nxi, &nx_infos, nx_list)
93 * struct nx_info ref stuff
96 struct nx_info *find_nx_info(int id)
101 nxi = current->nx_info;
104 spin_lock(&nxlist_lock);
105 if ((nxi = __find_nx_info(id)))
107 spin_unlock(&nxlist_lock);
113 * verify that id is a valid nid
116 int nx_info_id_valid(int id)
120 spin_lock(&nxlist_lock);
121 valid = (__find_nx_info(id) != NULL);
122 spin_unlock(&nxlist_lock);
128 * dynamic context id ...
131 static __inline__ nid_t __nx_dynamic_id(void)
133 static nid_t seq = MAX_N_CONTEXT;
137 if (++seq > MAX_N_CONTEXT)
139 if (!__find_nx_info(seq))
141 } while (barrier != seq);
145 static struct nx_info * __foc_nx_info(int id, int *err)
147 struct nx_info *new, *nxi = NULL;
149 nxdprintk("foc_nx_info(%d)\n", id);
150 // if (!(new = alloc_nx_info(id))) {
151 if (!(new = alloc_nx_info())) {
156 spin_lock(&nxlist_lock);
158 /* dynamic context requested */
159 if (id == IP_DYNAMIC_ID) {
160 id = __nx_dynamic_id();
162 printk(KERN_ERR "no dynamic context available.\n");
167 /* existing context requested */
168 else if ((nxi = __find_nx_info(id))) {
169 /* context in setup is not available */
170 if (nxi->nx_flags & VXF_STATE_SETUP) {
171 nxdprintk("foc_nx_info(%d) = %p (not available)\n", id, nxi);
175 nxdprintk("foc_nx_info(%d) = %p (found)\n", id, nxi);
182 /* new context requested */
183 nxdprintk("foc_nx_info(%d) = %p (new)\n", id, new);
184 atomic_set(&new->nx_refcount, 1);
185 list_add(&new->nx_list, &nx_infos);
186 nxi = new, new = NULL;
190 spin_unlock(&nxlist_lock);
197 struct nx_info *find_or_create_nx_info(int id)
201 return __foc_nx_info(id, &err);
205 * migrate task to new network
208 int nx_migrate_task(struct task_struct *p, struct nx_info *nxi)
210 struct nx_info *old_nxi = task_get_nx_info(p);
216 nxdprintk("nx_migrate_task(%p,%p[#%d.%d)\n", p, nxi,
217 nxi->nx_id, atomic_read(&nxi->nx_refcount));
222 set_nx_info(&p->nx_info, nxi);
226 put_nx_info(old_nxi);
228 put_nx_info(old_nxi);
233 #include <linux/netdevice.h>
234 #include <linux/inetdevice.h>
236 static inline int __addr_in_nx_info(u32 addr, struct nx_info *nxi)
241 for (i=0; i<nbip; i++)
242 if (nxi->ipv4[i] == addr)
247 int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi)
252 return __addr_in_nx_info(ifa->ifa_address, nxi);
255 int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi)
257 struct in_device *in_dev = __in_dev_get(dev);
258 struct in_ifaddr **ifap = NULL;
259 struct in_ifaddr *ifa = NULL;
266 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
267 ifap = &ifa->ifa_next) {
268 if (__addr_in_nx_info(ifa->ifa_address, nxi))
277 /* vserver syscall commands below here */
279 /* taks nid and nx_info functions */
281 #include <asm/uaccess.h>
284 int vc_task_nid(uint32_t id, void __user *data)
289 struct task_struct *tsk;
291 if (!vx_check(0, VX_ADMIN|VX_WATCH))
294 read_lock(&tasklist_lock);
295 tsk = find_task_by_pid(id);
296 nid = (tsk) ? tsk->nid : -ESRCH;
297 read_unlock(&tasklist_lock);
305 int vc_nx_info(uint32_t id, void __user *data)
308 struct vcmd_nx_info_v0 vc_data;
310 if (!vx_check(0, VX_ADMIN))
312 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
315 nxi = find_nx_info(id);
319 vc_data.nid = nxi->nx_id;
322 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
328 /* network functions */
330 int vc_net_create(uint32_t nid, void __user *data)
332 // int ret = -ENOMEM;
333 struct nx_info *new_nxi;
336 if (!capable(CAP_SYS_ADMIN))
339 if ((nid >= MIN_D_CONTEXT) && (nid != VX_DYNAMIC_ID))
345 new_nxi = __foc_nx_info(nid, &ret);
348 if (!(new_nxi->nx_flags & VXF_STATE_SETUP)) {
353 ret = new_nxi->nx_id;
354 nx_migrate_task(current, new_nxi);
356 put_nx_info(new_nxi);
361 int vc_net_migrate(uint32_t id, void __user *data)
365 if (!capable(CAP_SYS_ADMIN))
368 nxi = find_nx_info(id);
371 nx_migrate_task(current, nxi);
376 int vc_net_add(uint32_t id, void __user *data)
379 struct vcmd_net_nx_v0 vc_data;
381 if (!capable(CAP_SYS_ADMIN))
383 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
386 nxi = find_nx_info(id);
390 // add ip to net context here
395 int vc_net_remove(uint32_t id, void __user *data)
398 struct vcmd_net_nx_v0 vc_data;
400 if (!capable(CAP_SYS_ADMIN))
402 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
405 nxi = find_nx_info(id);
409 // rem ip from net context here
416 int vc_get_nflags(uint32_t id, void __user *data)
419 struct vcmd_net_flags_v0 vc_data;
421 if (!capable(CAP_SYS_ADMIN))
424 nxi = find_nx_info(id);
428 vc_data.flagword = nxi->nx_flags;
430 // vc_data.mask = ~0UL;
431 /* special STATE flag handling */
432 vc_data.mask = vx_mask_flags(~0UL, nxi->nx_flags, IPF_ONE_TIME);
436 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
441 int vc_set_nflags(uint32_t id, void __user *data)
444 struct vcmd_net_flags_v0 vc_data;
445 uint64_t mask, trigger;
447 if (!capable(CAP_SYS_ADMIN))
449 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
452 nxi = find_nx_info(id);
456 /* special STATE flag handling */
457 mask = vx_mask_mask(vc_data.mask, nxi->nx_flags, IPF_ONE_TIME);
458 trigger = (mask & nxi->nx_flags) ^ (mask & vc_data.flagword);
459 // if (trigger & IPF_STATE_SETUP)
461 nxi->nx_flags = vx_mask_flags(nxi->nx_flags,
462 vc_data.flagword, mask);
467 int vc_get_ncaps(uint32_t id, void __user *data)
470 struct vcmd_net_caps_v0 vc_data;
472 if (!capable(CAP_SYS_ADMIN))
475 nxi = find_nx_info(id);
479 vc_data.ncaps = nxi->nx_ncaps;
480 vc_data.cmask = ~0UL;
483 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
488 int vc_set_ncaps(uint32_t id, void __user *data)
491 struct vcmd_net_caps_v0 vc_data;
493 if (!capable(CAP_SYS_ADMIN))
495 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
498 nxi = find_nx_info(id);
502 nxi->nx_ncaps = vx_mask_flags(nxi->nx_ncaps,
503 vc_data.ncaps, vc_data.cmask);
509 #include <linux/module.h>
511 EXPORT_SYMBOL_GPL(free_nx_info);
512 EXPORT_SYMBOL_GPL(nxlist_lock);