Adds to the network namespace a device list view. This view is emptied
when the unshare is done. The view is filled/emptied by a set of
function which can be called by an external module.

Replace-Subject: [Network namespace] Network device sharing by view
Signed-off-by: Daniel Lezcano <[EMAIL PROTECTED]> 
--
 include/linux/net_ns.h     |    2 
 include/linux/net_ns_dev.h |   32 +++++++
 init/version.c             |    4 
 net/core/Makefile          |    2 
 net/core/net_ns_dev.c      |  205 +++++++++++++++++++++++++++++++++++++++++++++
 net/net_ns.c               |    6 +
 6 files changed, 250 insertions(+), 1 deletion(-)

Index: 2.6-mm/include/linux/net_ns_dev.h
===================================================================
--- /dev/null
+++ 2.6-mm/include/linux/net_ns_dev.h
@@ -0,0 +1,32 @@
+#ifndef _LINUX_NET_NS_DEV_H
+#define _LINUX_NET_NS_DEV_H
+
+struct net_device;
+
+struct net_ns_dev {
+       struct list_head list;
+       struct net_device *dev;
+};
+
+struct net_ns_dev_list {
+       struct list_head list;
+       rwlock_t lock;
+};
+
+extern int net_ns_dev_unregister(struct net_device *dev,
+                                struct net_ns_dev_list *devlist);
+
+extern int net_ns_dev_register(struct net_device *dev,
+                              struct net_ns_dev_list *devlist);
+
+extern struct net_device *net_ns_dev_find_by_name(const char *devname,
+                                                 struct net_ns_dev_list 
*devlist);
+extern int net_ns_dev_remove(const char *devname,
+                            struct net_ns_dev_list *devlist);
+
+extern int net_ns_dev_add(const char *devname,
+                         struct net_ns_dev_list *devlist);
+
+extern int free_net_ns_dev(struct net_ns_dev_list *devlist);
+
+#endif
Index: 2.6-mm/include/linux/net_ns.h
===================================================================
--- 2.6-mm.orig/include/linux/net_ns.h
+++ 2.6-mm/include/linux/net_ns.h
@@ -4,9 +4,11 @@
 #include <linux/kref.h>
 #include <linux/sched.h>
 #include <linux/nsproxy.h>
+#include <linux/net_ns_dev.h>
 
 struct net_namespace {
        struct kref kref;
+       struct net_ns_dev_list dev_list;
 };
 
 extern struct net_namespace init_net_ns;
Index: 2.6-mm/net/core/net_ns_dev.c
===================================================================
--- /dev/null
+++ 2.6-mm/net/core/net_ns_dev.c
@@ -0,0 +1,205 @@
+/*
+ *  net_ns_dev.c - adds namespace netwok device view
+ *
+ *  Copyright (C) 2006 IBM
+ *
+ *  Author: Daniel Lezcano <[EMAIL PROTECTED]>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation, version 2 of the
+ *     License.
+ */
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/netdevice.h>
+#include <linux/net_ns_dev.h>
+
+int free_net_ns_dev(struct net_ns_dev_list *devlist)
+{
+       struct list_head *l, *next;
+       struct net_ns_dev *db;
+       struct net_device *dev;
+
+       write_lock(&devlist->lock);
+       list_for_each_safe(l, next, &devlist->list) {
+               db = list_entry(l, struct net_ns_dev, list);
+               dev = db->dev;
+               list_del(&db->list);
+               dev_put(dev);
+               kfree(db);
+       }
+       write_unlock(&devlist->lock);
+
+       return 0;
+}
+
+/*
+ * Remove a device to the namespace network devices list
+ * when registered from a namespace
+ * @dev : network device
+ * @dev_list: network namespace devices
+ * Return ENODEV if the device does not exist,
+ */
+int net_ns_dev_unregister(struct net_device *dev,
+                         struct net_ns_dev_list *devlist)
+{
+       struct net_ns_dev *db;
+       struct list_head *l;
+       int ret = -ENODEV;
+
+       write_lock(&devlist->lock);
+       list_for_each(l, &devlist->list) {
+               db = list_entry(l, struct net_ns_dev, list);
+               if (dev != db->dev)
+                       continue;
+
+               list_del(&db->list);
+               dev_put(dev);
+               kfree(db);
+               ret = 0;
+               break;
+       }
+       write_unlock(&devlist->lock);
+       return ret;
+}
+
+EXPORT_SYMBOL_GPL(net_ns_dev_unregister);
+
+/*
+ * Add a device to the namespace network devices list
+ * when registered from a namespace
+ * @dev : network device
+ * @dev_list: network namespace devices
+ * Return ENOMEM if allocation fails, 0 on success
+ */
+int net_ns_dev_register(struct net_device *dev,
+                       struct net_ns_dev_list *devlist)
+{
+       struct net_ns_dev *db;
+
+       db = kmalloc(sizeof(*db), GFP_KERNEL);
+       if (!db)
+               return -ENOMEM;
+
+       write_lock(&devlist->lock);
+       dev_hold(dev);
+       db->dev = dev;
+       list_add_tail(&db->list, &devlist->list);
+       write_unlock(&devlist->lock);
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(net_ns_dev_register);
+
+/*
+ * Add a device to the namespace network devices list
+ * @devname : network device name
+ * @dev_list: network namespace devices
+ * Return ENODEV if the device does not exist,
+ * ENOMEM if allocation fails, 0 on success
+ */
+int net_ns_dev_add(const char *devname,
+                  struct net_ns_dev_list *devlist)
+{
+       struct net_ns_dev *db;
+       struct net_device *dev;
+       int ret = 0;
+
+       read_lock(&dev_base_lock);
+
+       for (dev = dev_base; dev; dev = dev->next)
+               if (!strncmp(dev->name, devname, IFNAMSIZ))
+                       break;
+
+       if (!dev) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       db = kmalloc(sizeof(*db), GFP_KERNEL);
+       if (!db) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       write_lock(&devlist->lock);
+       db->dev = dev;
+       dev_hold(dev);
+       list_add_tail(&db->list, &devlist->list);
+       write_unlock(&devlist->lock);
+
+out:
+       read_unlock(&dev_base_lock);
+
+       return ret;
+}
+
+EXPORT_SYMBOL_GPL(net_ns_dev_add);
+
+/*
+ * Remove a device from the namespace network devices list
+ * @devname : network device name
+ * @dev_list: network namespace devices
+ * Return ENODEV if the device does not exist, 0 on success
+ */
+int net_ns_dev_remove(const char *devname,
+                     struct net_ns_dev_list *devlist)
+{
+       struct net_ns_dev *db;
+       struct net_device *dev;
+       struct list_head *l;
+       int ret = 0;
+
+       write_lock(&devlist->lock);
+       list_for_each(l, &devlist->list) {
+               db = list_entry(l, struct net_ns_dev, list);
+               dev = db->dev;
+
+               if (!strncmp(dev->name, devname, IFNAMSIZ)) {
+                       list_del(&db->list);
+                       dev_put(dev);
+                       kfree(db);
+                       goto out;
+               }
+       }
+       ret = -ENODEV;
+out:
+       write_unlock(&devlist->lock);
+       return ret;
+}
+
+EXPORT_SYMBOL_GPL(net_ns_dev_remove);
+
+/*
+ * Find a namespace network device
+ * @devname : network device name
+ * @dev_list: network namespace devices
+ * Return ENODEV if the device does not exist, 0 on success
+ */
+struct net_device *net_ns_dev_find_by_name(const char *devname,
+                                          struct net_ns_dev_list *devlist)
+{
+       struct net_ns_dev *db;
+       struct net_device *dev;
+       struct list_head *l;
+
+       read_lock(&devlist->lock);
+
+       list_for_each(l, &devlist->list) {
+               db = list_entry(l, struct net_ns_dev, list);
+               dev = db->dev;
+
+               if (!strncmp(dev->name, devname, IFNAMSIZ)) {
+                       dev_hold(dev);
+                       goto out;
+               }
+       }
+       dev = NULL;
+out:
+       read_unlock(&devlist->lock);
+       return dev;
+}
+
+EXPORT_SYMBOL_GPL(net_ns_dev_find_by_name);
Index: 2.6-mm/net/net_ns.c
===================================================================
--- 2.6-mm.orig/net/net_ns.c
+++ 2.6-mm/net/net_ns.c
@@ -23,11 +23,16 @@
 struct net_namespace *clone_net_ns(struct net_namespace *old_ns)
 {
        struct net_namespace *new_ns;
+       struct net_ns_dev_list *new_dev_list;
 
        new_ns = kmalloc(sizeof(*new_ns), GFP_KERNEL);
        if (!new_ns)
                return NULL;
+
        kref_init(&new_ns->kref);
+       new_dev_list = &new_ns->dev_list;
+       INIT_LIST_HEAD(&new_dev_list->list);
+       new_dev_list->lock = RW_LOCK_UNLOCKED;
        return new_ns;
 }
 
@@ -92,5 +97,6 @@ void free_net_ns(struct kref *kref)
        struct net_namespace *ns;
 
        ns = container_of(kref, struct net_namespace, kref);
+       free_net_ns_dev(&ns->dev_list);
        kfree(ns);
 }
Index: 2.6-mm/net/core/Makefile
===================================================================
--- 2.6-mm.orig/net/core/Makefile
+++ 2.6-mm/net/core/Makefile
@@ -7,7 +7,7 @@ obj-y := sock.o request_sock.o skbuff.o 
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
-obj-y               += dev.o ethtool.o dev_mcast.o dst.o \
+obj-y               += dev.o net_ns_dev.o ethtool.o dev_mcast.o dst.o \
                        neighbour.o rtnetlink.o utils.o link_watch.o filter.o
 
 obj-$(CONFIG_XFRM) += flow.o
Index: 2.6-mm/init/version.c
===================================================================
--- 2.6-mm.orig/init/version.c
+++ 2.6-mm/init/version.c
@@ -38,6 +38,10 @@ struct net_namespace init_net_ns = {
        .kref = {
                .refcount       = ATOMIC_INIT(2),
        },
+       .dev_list = {
+                .lock = RW_LOCK_UNLOCKED,
+                .list = LIST_HEAD_INIT(init_net_ns.dev_list.list),
+        },
 };
 EXPORT_SYMBOL_GPL(init_net_ns);
 

--
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to