*
* Virtual Server: Network Support
*
- * Copyright (C) 2003-2005 Herbert Pötzl
+ * Copyright (C) 2003-2006 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
*
*/
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/vserver/network_cmd.h>
#include <linux/rcupdate.h>
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);
+ spin_lock(&nx_info_hash_lock);
/* context must be hashed */
BUG_ON(!nx_info_state(nxi, NXS_HASHED));
nxi->nx_state &= ~NXS_HASHED;
hlist_del(&nxi->nx_hlist);
+ spin_unlock(&nx_info_hash_lock);
}
/* __create_nx_info()
* create the requested context
- * get() and hash it */
+ * get(), claim() and hash it */
static struct nx_info * __create_nx_info(int id)
{
/* new context */
vxdprintk(VXD_CBIT(nid, 0),
"create_nx_info(%d) = %p (new)", id, new);
+ claim_nx_info(new, NULL);
__hash_nx_info(get_nx_info(new));
nxi = new, new = NULL;
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
#endif
-/* locate_nx_info()
+/* lookup_nx_info()
* search for a nx_info and get() it
* negative id means current */
-struct nx_info *locate_nx_info(int id)
+struct nx_info *lookup_nx_info(int id)
{
struct nx_info *nxi = NULL;
if (old_nxi)
release_nx_info(old_nxi, p);
+ ret = 0;
out:
put_nx_info(old_nxi);
return ret;
}
+#ifdef CONFIG_INET
+
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
-
int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi)
{
if (!nxi)
return 1;
if (!ifa)
return 0;
- return addr_in_nx_info(nxi, ifa->ifa_address);
+ return addr_in_nx_info(nxi, ifa->ifa_local);
}
int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi)
{
- struct in_device *in_dev = __in_dev_get(dev);
- struct in_ifaddr **ifap = NULL;
- struct in_ifaddr *ifa = NULL;
+ struct in_device *in_dev;
+ struct in_ifaddr **ifap;
+ struct in_ifaddr *ifa;
+ int ret = 0;
if (!nxi)
return 1;
+
+ in_dev = in_dev_get(dev);
if (!in_dev)
- return 0;
+ goto out;
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
- if (addr_in_nx_info(nxi, ifa->ifa_address))
- return 1;
+ if (addr_in_nx_info(nxi, ifa->ifa_local)) {
+ ret = 1;
+ break;
+ }
}
- return 0;
+ in_dev_put(in_dev);
+out:
+ return ret;
}
/*
static inline int __addr_in_socket(struct sock *sk, uint32_t addr)
{
struct nx_info *nxi = sk->sk_nx_info;
- uint32_t saddr = tcp_v4_rcv_saddr(sk);
+ uint32_t saddr = inet_rcv_saddr(sk);
vxdprintk(VXD_CBIT(net, 5),
"__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx",
}
}
+#endif /* CONFIG_INET */
+
+void nx_set_persistent(struct nx_info *nxi)
+{
+ vxdprintk(VXD_CBIT(nid, 6),
+ "nx_set_persistent(%p[#%d])", nxi, nxi->nx_id);
+
+ get_nx_info(nxi);
+ claim_nx_info(nxi, NULL);
+}
+
+void nx_clear_persistent(struct nx_info *nxi)
+{
+ vxdprintk(VXD_CBIT(nid, 6),
+ "nx_clear_persistent(%p[#%d])", nxi, nxi->nx_id);
+
+ release_nx_info(nxi, NULL);
+ put_nx_info(nxi);
+}
+
+void nx_update_persistent(struct nx_info *nxi)
+{
+ if (nx_info_flags(nxi, NXF_PERSISTENT, 0))
+ nx_set_persistent(nxi);
+ else
+ nx_clear_persistent(nxi);
+}
/* vserver syscall commands below here */
read_unlock(&tasklist_lock);
}
else
- nid = current->nid;
+ nid = nx_current_nid();
return nid;
}
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RESOURCE))
return -EPERM;
- nxi = locate_nx_info(id);
+ nxi = lookup_nx_info(id);
if (!nxi)
return -ESRCH;
/* initial flags */
new_nxi->nx_flags = vc_data.flagword;
- vs_net_change(new_nxi, VSC_NETUP);
+ ret = -ENOEXEC;
+ if (vs_net_change(new_nxi, VSC_NETUP))
+ goto out;
+
+ ret = nx_migrate_task(current, new_nxi);
+ if (ret)
+ goto out;
+
+ /* return context id on success */
ret = new_nxi->nx_id;
- nx_migrate_task(current, new_nxi);
- /* if this fails, we might end up with a hashed nx_info */
+
+ /* get a reference for persistent contexts */
+ if ((vc_data.flagword & NXF_PERSISTENT))
+ nx_set_persistent(new_nxi);
+out:
+ release_nx_info(new_nxi, NULL);
put_nx_info(new_nxi);
return ret;
}
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- nxi = locate_nx_info(id);
+ nxi = lookup_nx_info(id);
if (!nxi)
return -ESRCH;
nx_migrate_task(current, nxi);
return 0;
}
+int vc_net_add(uint32_t nid, 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;
+
+ switch (vc_data.type) {
+ case NXA_TYPE_IPV4:
+ if ((vc_data.count < 1) || (vc_data.count > 4))
+ return -EINVAL;
+ break;
+
+ default:
+ break;
+ }
+
+ nxi = lookup_nx_info(nid);
+ if (!nxi)
+ return -ESRCH;
+
+ switch (vc_data.type) {
+ case NXA_TYPE_IPV4:
+ index = 0;
+ while ((index < vc_data.count) &&
+ ((pos = nxi->nbipv4) < NB_IPV4ROOT)) {
+ nxi->ipv4[pos] = vc_data.ip[index];
+ nxi->mask[pos] = vc_data.mask[index];
+ index++;
+ nxi->nbipv4++;
+ }
+ ret = index;
+ break;
+
+ case NXA_TYPE_IPV4|NXA_MOD_BCAST:
+ nxi->v4_bcast = vc_data.ip[0];
+ ret = 1;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ put_nx_info(nxi);
+ return ret;
+}
+
+int vc_net_remove(uint32_t nid, 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;
+ }
+
+ put_nx_info(nxi);
+ return ret;
+}
int vc_get_nflags(uint32_t id, void __user *data)
{
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- nxi = locate_nx_info(id);
+ 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, IPF_ONE_TIME);
+ vc_data.mask = vx_mask_flags(~0UL, nxi->nx_flags, NXF_ONE_TIME);
put_nx_info(nxi);
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- nxi = locate_nx_info(id);
+ nxi = lookup_nx_info(id);
if (!nxi)
return -ESRCH;
/* special STATE flag handling */
- mask = vx_mask_mask(vc_data.mask, nxi->nx_flags, IPF_ONE_TIME);
+ mask = vx_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,
vc_data.flagword, mask);
+ if (trigger & NXF_PERSISTENT)
+ nx_update_persistent(nxi);
+
put_nx_info(nxi);
return 0;
}
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- nxi = locate_nx_info(id);
+ nxi = lookup_nx_info(id);
if (!nxi)
return -ESRCH;
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
- nxi = locate_nx_info(id);
+ nxi = lookup_nx_info(id);
if (!nxi)
return -ESRCH;