*
* Virtual Server: Network Support
*
- * Copyright (C) 2003-2006 Herbert Pötzl
+ * Copyright (C) 2003-2007 Herbert Pötzl
*
* V0.01 broken out from vcontext V0.05
* V0.02 cleaned up implementation
* V0.03 added equiv nx commands
* V0.04 switch to RCU based hash
* V0.05 and back to locking again
- * V0.06 have __create claim() the nxi
+ * V0.06 changed vcmds to nxi arg
+ * V0.07 have __create claim() the nxi
*
*/
#include <linux/slab.h>
-#include <linux/vserver/network_cmd.h>
#include <linux/rcupdate.h>
#include <net/tcp.h>
#include <asm/errno.h>
+#include <linux/vserver/base.h>
+#include <linux/vserver/network_cmd.h>
+
+
+atomic_t nx_global_ctotal = ATOMIC_INIT(0);
+atomic_t nx_global_cactive = ATOMIC_INIT(0);
/* __alloc_nx_info()
vxdprintk(VXD_CBIT(nid, 0),
"alloc_nx_info(%d) = %p", nid, new);
+ atomic_inc(&nx_global_ctotal);
return new;
}
nxi->nx_state |= NXS_RELEASED;
kfree(nxi);
+ atomic_dec(&nx_global_ctotal);
}
static void __shutdown_nx_info(struct nx_info *nxi)
nxi->nx_state |= NXS_HASHED;
head = &nx_info_hash[__hashval(nxi->nx_id)];
hlist_add_head(&nxi->nx_hlist, head);
+ atomic_inc(&nx_global_cactive);
}
/* __unhash_nx_info()
static inline void __unhash_nx_info(struct nx_info *nxi)
{
+ vxd_assert_lock(&nx_info_hash_lock);
vxdprintk(VXD_CBIT(nid, 4),
- "__unhash_nx_info: %p[#%d]", nxi, nxi->nx_id);
+ "__unhash_nx_info: %p[#%d.%d.%d]", nxi, nxi->nx_id,
+ atomic_read(&nxi->nx_usecnt), atomic_read(&nxi->nx_tasks));
- spin_lock(&nx_info_hash_lock);
/* context must be hashed */
BUG_ON(!nx_info_state(nxi, NXS_HASHED));
+ /* but without tasks */
+ BUG_ON(atomic_read(&nxi->nx_tasks));
nxi->nx_state &= ~NXS_HASHED;
hlist_del(&nxi->nx_hlist);
- spin_unlock(&nx_info_hash_lock);
+ atomic_dec(&nx_global_cactive);
}
/* dynamic context requested */
if (id == NX_DYNAMIC_ID) {
+#ifdef CONFIG_VSERVER_DYNAMIC_IDS
id = __nx_dynamic_id();
if (!id) {
printk(KERN_ERR "no dynamic context available.\n");
goto out_unlock;
}
new->nx_id = id;
+#else
+ printk(KERN_ERR "dynamic contexts disabled.\n");
+ nxi = ERR_PTR(-EINVAL);
+ goto out_unlock;
+#endif
}
/* static context requested */
else if ((nxi = __lookup_nx_info(id))) {
void unhash_nx_info(struct nx_info *nxi)
{
__shutdown_nx_info(nxi);
+ spin_lock(&nx_info_hash_lock);
__unhash_nx_info(nxi);
+ spin_unlock(&nx_info_hash_lock);
}
#ifdef CONFIG_VSERVER_LEGACYNET
#ifdef CONFIG_PROC_FS
+/* get_nid_list()
+
+ * get a subset of hashed nids for proc
+ * assumes size is at least one */
+
int get_nid_list(int index, unsigned int *nids, int size)
{
int hindex, nr_nids = 0;
+ /* only show current and children */
+ if (!nx_check(0, VS_ADMIN|VS_WATCH)) {
+ if (index > 0)
+ return 0;
+ nids[nr_nids] = nx_current_nid();
+ return 1;
+ }
+
for (hindex = 0; hindex < NX_HASH_SIZE; hindex++) {
struct hlist_head *head = &nx_info_hash[hindex];
struct hlist_node *pos;
atomic_read(&nxi->nx_usecnt),
atomic_read(&nxi->nx_tasks));
+ if (nx_info_flags(nxi, NXF_INFO_PRIVATE, 0) &&
+ !nx_info_flags(nxi, NXF_STATE_SETUP, 0))
+ return -EACCES;
+
+ if (nx_info_state(nxi, NXS_SHUTDOWN))
+ return -EFAULT;
+
/* maybe disallow this completely? */
old_nxi = task_get_nx_info(p);
if (old_nxi == nxi)
if (!nxi)
return 1;
+ if (!dev)
+ goto out;
in_dev = in_dev_get(dev);
if (!in_dev)
goto out;
* sk: the socket to check against
* addr: the address in question (must be != 0)
*/
-static inline int __addr_in_socket(struct sock *sk, uint32_t addr)
+static inline int __addr_in_socket(const struct sock *sk, uint32_t addr)
{
struct nx_info *nxi = sk->sk_nx_info;
uint32_t saddr = inet_rcv_saddr(sk);
}
-int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, struct sock *sk)
+int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, const struct sock *sk)
{
vxdprintk(VXD_CBIT(net, 2),
"nx_addr_conflict(%p,%p) %d.%d,%d.%d",
if (id) {
struct task_struct *tsk;
- if (!vx_check(0, VX_ADMIN|VX_WATCH))
+ if (!nx_check(0, VS_ADMIN|VS_WATCH))
return -EPERM;
read_lock(&tasklist_lock);
}
-int vc_nx_info(uint32_t id, void __user *data)
+int vc_nx_info(struct nx_info *nxi, void __user *data)
{
- struct nx_info *nxi;
struct vcmd_nx_info_v0 vc_data;
- if (!vx_check(0, VX_ADMIN))
- return -ENOSYS;
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
- return -EPERM;
-
- nxi = lookup_nx_info(id);
- if (!nxi)
- return -ESRCH;
-
vc_data.nid = nxi->nx_id;
- put_nx_info(nxi);
if (copy_to_user (data, &vc_data, sizeof(vc_data)))
return -EFAULT;
struct nx_info *new_nxi;
int ret;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
if (data && copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- if ((nid > MAX_S_CONTEXT) && (nid != VX_DYNAMIC_ID))
+ if ((nid > MAX_S_CONTEXT) && (nid != NX_DYNAMIC_ID))
return -EINVAL;
if (nid < 2)
return -EINVAL;
}
-int vc_net_migrate(uint32_t id, void __user *data)
+int vc_net_migrate(struct nx_info *nxi, void __user *data)
{
- struct nx_info *nxi;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- nxi = lookup_nx_info(id);
- if (!nxi)
- return -ESRCH;
- nx_migrate_task(current, nxi);
- put_nx_info(nxi);
- return 0;
+ return nx_migrate_task(current, nxi);
}
-int vc_net_add(uint32_t nid, void __user *data)
+int vc_net_add(struct nx_info *nxi, void __user *data)
{
struct vcmd_net_addr_v0 vc_data;
- struct nx_info *nxi;
int index, pos, ret = 0;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
if (data && copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
break;
}
- nxi = lookup_nx_info(nid);
- if (!nxi)
- return -ESRCH;
-
switch (vc_data.type) {
case NXA_TYPE_IPV4:
index = 0;
ret = -EINVAL;
break;
}
-
- put_nx_info(nxi);
return ret;
}
-int vc_net_remove(uint32_t nid, void __user *data)
+int vc_net_remove(struct nx_info * nxi, void __user *data)
{
struct vcmd_net_addr_v0 vc_data;
- struct nx_info *nxi;
- int ret = 0;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
if (data && copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- nxi = lookup_nx_info(nid);
- if (!nxi)
- return -ESRCH;
-
switch (vc_data.type) {
case NXA_TYPE_ANY:
nxi->nbipv4 = 0;
break;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-
- put_nx_info(nxi);
- return ret;
+ return 0;
}
-int vc_get_nflags(uint32_t id, void __user *data)
+int vc_get_nflags(struct nx_info *nxi, void __user *data)
{
- struct nx_info *nxi;
struct vcmd_net_flags_v0 vc_data;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- nxi = lookup_nx_info(id);
- if (!nxi)
- return -ESRCH;
-
vc_data.flagword = nxi->nx_flags;
/* special STATE flag handling */
- vc_data.mask = vx_mask_flags(~0UL, nxi->nx_flags, NXF_ONE_TIME);
-
- put_nx_info(nxi);
+ vc_data.mask = vs_mask_flags(~0UL, nxi->nx_flags, NXF_ONE_TIME);
if (copy_to_user (data, &vc_data, sizeof(vc_data)))
return -EFAULT;
return 0;
}
-int vc_set_nflags(uint32_t id, void __user *data)
+int vc_set_nflags(struct nx_info *nxi, void __user *data)
{
- struct nx_info *nxi;
struct vcmd_net_flags_v0 vc_data;
uint64_t mask, trigger;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- nxi = lookup_nx_info(id);
- if (!nxi)
- return -ESRCH;
-
/* special STATE flag handling */
- mask = vx_mask_mask(vc_data.mask, nxi->nx_flags, NXF_ONE_TIME);
+ mask = vs_mask_mask(vc_data.mask, nxi->nx_flags, NXF_ONE_TIME);
trigger = (mask & nxi->nx_flags) ^ (mask & vc_data.flagword);
- nxi->nx_flags = vx_mask_flags(nxi->nx_flags,
+ nxi->nx_flags = vs_mask_flags(nxi->nx_flags,
vc_data.flagword, mask);
if (trigger & NXF_PERSISTENT)
nx_update_persistent(nxi);
- put_nx_info(nxi);
return 0;
}
-int vc_get_ncaps(uint32_t id, void __user *data)
+int vc_get_ncaps(struct nx_info *nxi, void __user *data)
{
- struct nx_info *nxi;
struct vcmd_net_caps_v0 vc_data;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- nxi = lookup_nx_info(id);
- if (!nxi)
- return -ESRCH;
-
vc_data.ncaps = nxi->nx_ncaps;
vc_data.cmask = ~0UL;
- put_nx_info(nxi);
if (copy_to_user (data, &vc_data, sizeof(vc_data)))
return -EFAULT;
return 0;
}
-int vc_set_ncaps(uint32_t id, void __user *data)
+int vc_set_ncaps(struct nx_info *nxi, void __user *data)
{
- struct nx_info *nxi;
struct vcmd_net_caps_v0 vc_data;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- nxi = lookup_nx_info(id);
- if (!nxi)
- return -ESRCH;
-
- nxi->nx_ncaps = vx_mask_flags(nxi->nx_ncaps,
+ nxi->nx_ncaps = vs_mask_flags(nxi->nx_ncaps,
vc_data.ncaps, vc_data.cmask);
- put_nx_info(nxi);
return 0;
}