From mboxrd@z Thu Jan 1 00:00:00 1970 From: Benjamin Thery Subject: Re: [RFC][patch 1/3] network container subsystem Date: Wed, 05 Sep 2007 13:50:13 +0200 Message-ID: <46DE97F5.3090609@bull.net> References: <20070904170022.964253374@dyn-9-101-17-26.toulouse-stg.fr.ibm.com> <20070904171525.771956554@dyn-9-101-17-26.toulouse-stg.fr.ibm.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <20070904171525.771956554-lUQnSZrVijcklpeYT4thRqpRWpusSO0yQ3R/GR7Q8HurIzol8Bc5pA@public.gmane.org> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org Errors-To: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org To: dlezcano-NmTC/0ZBporQT0dZR+AlfA@public.gmane.org Cc: Linux Containers List-Id: containers.vger.kernel.org dlezcano-NmTC/0ZBporQT0dZR+AlfA@public.gmane.org wrote: > From: Daniel Lezcano > > This patch creates the network container subsystem. > It consists for the moment on a single file "network.ipv4". > > The interface is pretty simple: > > To add an IP address to the container: > > echo add AB12FFFF > network.ipv4 > > To remove this IP address: > -------------------------- > > echo del AB12FFFF > network.ipv4 > > To list the addresses: > ---------------------- > > cat network.ipv4 > > The parameter is an IPV4 address in the hexa format. The parsing of a dotted-decimal > parameter is totally painful. If this format hurts someone, I can change it to a dotted > format at the risk of having something buggy. I think passing ipv4 addresses in hexa form is painful :) Why not use something like this: __be32 addr; unsigned int a, b, c, d; if (sscanf (buffer, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) { if (a < 256 && b < 256 && c < 256 && d < 256) { addr = htonl (a<<24 | b<<16 | c<<8 | d); return 0; } } return -EINVAL; > > This patch by itself does nothing more than adding/removing elements from a list. > > Signed-off-by: Daniel Lezcano > > --- > include/linux/container_subsys.h | 4 > init/Kconfig | 8 + > kernel/Makefile | 1 > kernel/container_network.c | 285 +++++++++++++++++++++++++++++++++++++++ > 4 files changed, 298 insertions(+) > > Index: 2.6-mm/include/linux/container_subsys.h > =================================================================== > --- 2.6-mm.orig/include/linux/container_subsys.h > +++ 2.6-mm/include/linux/container_subsys.h > @@ -30,3 +30,7 @@ > #endif > > /* */ > + > +#ifdef CONFIG_CONTAINER_NETWORK > +SUBSYS(network) > +#endif > Index: 2.6-mm/init/Kconfig > =================================================================== > --- 2.6-mm.orig/init/Kconfig > +++ 2.6-mm/init/Kconfig > @@ -326,6 +326,14 @@ > Provides a simple Resource Controller for monitoring the > total CPU consumed by the tasks in a container > > +config CONTAINER_NETWORK > + bool "Network container subsystem" > + depends on CONTAINERS && SECURITY_NETWORK > + help > + Provides a network controller to isolate network traffic > + > + Say N if unsure > + > config CPUSETS > bool "Cpuset support" > depends on SMP && CONTAINERS > Index: 2.6-mm/kernel/Makefile > =================================================================== > --- 2.6-mm.orig/kernel/Makefile > +++ 2.6-mm/kernel/Makefile > @@ -43,6 +43,7 @@ > obj-$(CONFIG_CPUSETS) += cpuset.o > obj-$(CONFIG_CONTAINER_CPUACCT) += cpu_acct.o > obj-$(CONFIG_CONTAINER_NS) += ns_container.o > +obj-$(CONFIG_CONTAINER_NETWORK) += container_network.o > obj-$(CONFIG_IKCONFIG) += configs.o > obj-$(CONFIG_STOP_MACHINE) += stop_machine.o > obj-$(CONFIG_AUDIT) += audit.o auditfilter.o > Index: 2.6-mm/kernel/container_network.c > =================================================================== > --- /dev/null > +++ 2.6-mm/kernel/container_network.c > @@ -0,0 +1,285 @@ > +/* > + * container_network.c - container network subsystem > + * > + * Copyright 2006, 2007 IBM Corp > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +struct network { > + struct container_subsys_state css; > + struct list_head ipv4_list; /* store the IPV4 addresses */ > + rwlock_t ipv4_list_lock; > +}; > + > +struct ipv4_list { > + __be32 address; > + struct list_head list; > +}; Can we use "struct in_addr" instead of __be32? (may be you don't want to include in.h?) > + > +static struct network top_network = { > + .ipv4_list = LIST_HEAD_INIT(top_network.ipv4_list), > + .ipv4_list_lock = __RW_LOCK_UNLOCKED(top_network.ipv4_list_lock), > +}; > + > +struct container_subsys network_subsys; > + > +enum container_filetype { > + FILE_IPV4, > +}; > + > +static inline struct network *container_network(struct container *container) > +{ > + return container_of( > + container_subsys_state(container, network_subsys_id), > + struct network, css); > +} > + > +static struct container_subsys_state *network_create(struct container_subsys *ss, > + struct container *container) > +{ > + struct network *network; > + > + /* Don't let anybody do that */ > + if (!capable(CAP_NET_ADMIN)) > + return ERR_PTR(-EPERM); > + > + /* The current container is the initial container */ > + if (!container->parent) > + return &top_network.css; > + > + network = kzalloc(sizeof(*network), GFP_KERNEL); > + if (!network) > + return ERR_PTR(-ENOMEM); > + > + INIT_LIST_HEAD(&network->ipv4_list); > + network->ipv4_list_lock = __RW_LOCK_UNLOCKED(network->ipv4_list_lock); > + > + return &network->css; > +} > + > +static void network_destroy(struct container_subsys *ss, > + struct container *container) > +{ > + struct network *network; > + struct ipv4_list *entry, *next; > + struct list_head *l; > + rwlock_t *lock; > + > + network = container_network(container); > + l = &network->ipv4_list; > + lock = &network->ipv4_list_lock; > + > + /* flush the ipv4 list */ > + write_lock(lock); > + list_for_each_entry_safe(entry, next, l, list) { > + list_del(&entry->list); > + kfree(entry); > + } > + write_unlock(lock); > + > + kfree(network); > +} > + > +static int network_add_ipv4_address(struct container *container, __be32 address) > +{ > + struct ipv4_list *entry; > + struct network *network; > + > + entry = kmalloc(sizeof(*entry), GFP_KERNEL); > + if (!entry) > + return -ENOMEM; > + entry->address = address; > + > + network = container_network(container); > + write_lock(&network->ipv4_list_lock); > + list_add(&entry->list, &network->ipv4_list); > + write_unlock(&network->ipv4_list_lock); > + > + return 0; > +} > + > +static int network_del_ipv4_address(struct container *container, __be32 address) > +{ > + struct ipv4_list *entry; > + struct network *network; > + int ret = 0; > + > + network = container_network(container); > + write_lock(&network->ipv4_list_lock); > + list_for_each_entry(entry, &network->ipv4_list, list) { > + if (entry->address != address) > + continue; > + > + list_del(&entry->list); > + goto out_free; > + } > + ret = -EINVAL; > +out: > + write_unlock(&network->ipv4_list_lock); > + return ret; > + > +out_free: > + kfree(entry); > + goto out; > +} > + > +static int network_parse_ipv4_address(struct container *container, char *buffer) > +{ > + int len = strlen(buffer); > + char *addr; > + __be32 address; > + > + /* remove trailing left space */ May be "leading space" is better than "trailing left space" :) > + while(isspace(*buffer)) > + buffer++; > + > + /* remove trailing right space */ > + while(isspace(buffer[len - 1])) > + buffer[(len--) - 1] = 0; > + > + len = strlen(buffer); > + addr = memchr(buffer, ' ', len); > + if (!addr) > + return -EINVAL; > + *addr++ = 0; > + > + /* remove trailing left space again */ > + while(isspace(*addr)) > + addr++; > + > + /* Shall I check if the address is setup on the host ? */ > + sscanf(addr, "%X", &address); > + > + if (!strcmp(buffer, "add")) > + return network_add_ipv4_address(container, address); > + else if (!strcmp(buffer, "del")) > + return network_del_ipv4_address(container, address); > + > + return -EINVAL; > +} > + > +static int network_fill_ipv4_address(struct container *container, char *buffer) > +{ > + struct network *network; > + struct ipv4_list *entry; > + char *s = buffer; > + network = container_network(container); > + > + read_lock(&network->ipv4_list_lock); > + list_for_each_entry(entry, &network->ipv4_list, list) > + s += sprintf(s, "%X\n", entry->address); Pretty print: s+= sprintf(s, NIPQUAD_FMT "\n", NIPQUAD(entry->address)); > + read_unlock(&network->ipv4_list_lock); > + > + return strlen(buffer); > +} > + > +static ssize_t network_write(struct container *container, > + struct cftype *cft, > + struct file *file, > + const char __user *userbuf, > + size_t nbytes, loff_t *unused_ppos) > +{ > + enum container_filetype type = cft->private; > + char *buffer; > + int retval = 0; > + > + if (!capable(CAP_NET_ADMIN)) > + return -EPERM; > + > + if (nbytes >= PATH_MAX) > + return -E2BIG; > + > + buffer = kmalloc(nbytes + 1, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + if (copy_from_user(buffer, userbuf, nbytes)) { > + retval = -EFAULT; > + goto out_free; > + } > + buffer[nbytes] = 0; > + > + container_lock(); > + switch(type) { > + > + case FILE_IPV4: > + retval = network_parse_ipv4_address(container, buffer); > + break; > + > + default: > + retval = -EINVAL; > + break; > + }; > + container_unlock(); > + > +out_free: > + if (!retval) > + retval = nbytes; > + > + kfree(buffer); > + return retval; > +} > + > +static ssize_t network_read(struct container *container, > + struct cftype *cft, > + struct file *file, > + char __user *userbuf, > + size_t nbytes, loff_t *ppos) > +{ > + enum container_filetype type = cft->private; > + char *page; > + int retval; > + > + page = (char *)__get_free_page(GFP_TEMPORARY); > + if (!page) > + return -ENOMEM; > + > + container_lock(); > + switch(type) { > + case FILE_IPV4: > + retval = network_fill_ipv4_address(container, page); > + break; > + > + default: > + retval = -EINVAL; > + }; > + container_unlock(); > + > + retval = simple_read_from_buffer(userbuf, nbytes, ppos, page, retval); > + > + free_page((unsigned long)page); > + return retval; > +} > + > +static struct cftype files[] = { > + { > + .name = "ipv4", > + .read = network_read, > + .write = network_write, > + .private = FILE_IPV4, > + }, > +}; > + > +static int network_populate(struct container_subsys *ss, struct container *cont) > +{ > + return container_add_files(cont, ss, files, ARRAY_SIZE(files)); > +} > + > +struct container_subsys network_subsys = { > + .name = "network", > + .create = network_create, > + .destroy = network_destroy, > + .populate = network_populate, > + .subsys_id = network_subsys_id, > + .can_attach = NULL, > + .attach = NULL, > + .fork = NULL, > + .exit = NULL, > +}; > > -- _______________________________________________ Containers mailing list Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org https://lists.linux-foundation.org/mailman/listinfo/containers -- B e n j a m i n T h e r y - BULL/DT/Open Software R&D http://www.bull.com