[ovs-dev] [PATCH 1/2] netdev: Allow providers to be managed at runtime.

Jesse Gross jesse at nicira.com
Fri Jan 29 20:39:46 UTC 2010


The list of netdev providers was previously staticly defined at
compile time.  This allows new providers to be added and removed
at runtime.
---
 lib/netdev-provider.h |    8 ++--
 lib/netdev.c          |  124 +++++++++++++++++++++++++++++++++++++-----------
 lib/netdev.h          |    6 ++-
 3 files changed, 104 insertions(+), 34 deletions(-)

diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index a6c0fd8..43a330c 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -107,12 +107,12 @@ struct netdev_class {
      * the system. */
     const char *type;
 
-    /* Called only once, at program startup.  Returning an error from this
-     * function will prevent any network device in this class from being
-     * opened.
+    /* Called when the netdev provider is registered, typically at program
+     * startup.  Returning an error from this function will prevent any network
+     * device in this class from being opened.
      *
      * This function may be set to null if a network device class needs no
-     * initialization at program startup. */
+     * initialization at registration time. */
     int (*init)(void);
 
     /* Performs periodic work needed by netdevs of this class.  May be null if
diff --git a/lib/netdev.c b/lib/netdev.c
index 84efc6b..f0512d5 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -40,12 +40,15 @@
 #define THIS_MODULE VLM_netdev
 #include "vlog.h"
 
-static const struct netdev_class *netdev_classes[] = {
+static const struct netdev_class *base_netdev_classes[] = {
     &netdev_linux_class,
     &netdev_tap_class,
     &netdev_gre_class,
 };
-static int n_netdev_classes = ARRAY_SIZE(netdev_classes);
+
+static const struct netdev_class **netdev_classes;
+static size_t n_netdev_classes;
+static size_t allocated_netdev_classes;
 
 /* All created network devices. */
 static struct shash netdev_dev_shash = SHASH_INITIALIZER(&netdev_dev_shash);
@@ -61,43 +64,21 @@ static void close_all_netdevs(void *aux UNUSED);
 static int restore_flags(struct netdev *netdev);
 void update_device_args(struct netdev_dev *, const struct shash *args);
 
-/* Attempts to initialize the netdev module.  Returns 0 if successful,
- * otherwise a positive errno value.
- *
- * Calling this function is optional.  If not called explicitly, it will
- * automatically be called upon the first attempt to open or create a 
- * network device. */
-int
+static void
 netdev_initialize(void)
 {
     static int status = -1;
 
     if (status < 0) {
-        int i, j;
+        int i;
 
         fatal_signal_add_hook(close_all_netdevs, NULL, NULL, true);
 
         status = 0;
-        for (i = j = 0; i < n_netdev_classes; i++) {
-            const struct netdev_class *class = netdev_classes[i];
-            if (class->init) {
-                int retval = class->init();
-                if (!retval) {
-                    netdev_classes[j++] = class;
-                } else {
-                    VLOG_ERR("failed to initialize %s network device "
-                             "class: %s", class->type, strerror(retval));
-                    if (!status) {
-                        status = retval;
-                    }
-                }
-            } else {
-                netdev_classes[j++] = class;
-            }
+        for (i = 0; i < ARRAY_SIZE(base_netdev_classes); i++) {
+            netdev_register_provider(base_netdev_classes[i]);
         }
-        n_netdev_classes = j;
     }
-    return status;
 }
 
 /* Performs periodic work needed by all the various kinds of netdevs.
@@ -132,6 +113,91 @@ netdev_wait(void)
     }
 }
 
+/* Initializes and registers a new netdev provider.  After successful
+ * registration, new netdevs of that type can be opened using netdev_open(). */
+int
+netdev_register_provider(const struct netdev_class *new_class)
+{
+    int i;
+
+    for (i = 0; i < n_netdev_classes; i++) {
+        if (!strcmp(netdev_classes[i]->type, new_class->type)) {
+            VLOG_WARN("attempted to register duplicate netdev provider: "
+                      "%s", new_class->type);
+            return EEXIST;
+        }
+    }
+
+    if (new_class->init) {
+        int error = new_class->init();
+        if (error) {
+            VLOG_ERR("failed to initialize %s network device "
+                     "class: %s", new_class->type, strerror(error));
+            return error;
+        }
+    }
+
+    if (n_netdev_classes >= allocated_netdev_classes) {
+        netdev_classes = x2nrealloc(netdev_classes,
+                                    &allocated_netdev_classes,
+                                    sizeof *netdev_classes);
+    }
+    netdev_classes[n_netdev_classes++] = new_class;
+
+    return 0;
+}
+
+/* Unregisters a netdev provider.  'del_class' must have been previously
+ * registered and not currently be in use by any netdevs.  After unregistration
+ * new netdevs of that type cannot be opened using netdev_open(). */
+int
+netdev_unregister_provider(const struct netdev_class *del_class)
+{
+    int i;
+
+    for (i = 0; i < n_netdev_classes; i++) {
+
+        if (netdev_classes[i] == del_class) {
+            struct shash_node *node;
+
+            SHASH_FOR_EACH(node, &netdev_dev_shash) {
+                struct netdev_dev *netdev_dev = node->data;
+                if (netdev_dev->class == del_class) {
+                    VLOG_WARN("attempted to unregister in use netdev provider: "
+                              "%s", del_class->type);
+                    return EBUSY;
+                }
+            }
+
+            if (i != n_netdev_classes - 1) {
+                memmove(netdev_classes + i, netdev_classes + i + 1,
+                        (n_netdev_classes - (i + 1)) * sizeof *netdev_classes);
+            }
+            n_netdev_classes--;
+
+            return 0;
+        }
+    }
+
+    VLOG_WARN("attempted to unregister a netdev provider that is not "
+              "registered: %s", del_class->type);
+    return EAFNOSUPPORT;
+}
+
+/* Clears 'types' and enumerates the types of all currently registered netdev
+ * providers into it.  The caller must first initialize the svec. */
+void
+netdev_enumerate_types(struct svec *types)
+{
+    int i;
+
+    svec_clear(types);
+
+    for (i = 0; i < n_netdev_classes; i++) {
+        svec_add(types, netdev_classes[i]->type);
+    }
+}
+
 /* Compares 'args' to those used to those used by 'dev'.  Returns true
  * if the arguments are the same, false otherwise.  Does not update the
  * values stored in 'dev'. */
@@ -228,7 +294,7 @@ create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
 
     VLOG_WARN("could not create netdev %s of unknown type %s", options->name,
                                                                 options->type);
-    return EINVAL;
+    return EAFNOSUPPORT;
 }
 
 /* Opens the network device named 'name' (e.g. "eth0") and returns zero if
diff --git a/lib/netdev.h b/lib/netdev.h
index 3f6d5ea..0cc22b6 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -86,11 +86,15 @@ struct netdev_options {
 };
 
 struct netdev;
+struct netdev_class;
 
-int netdev_initialize(void);
 void netdev_run(void);
 void netdev_wait(void);
 
+int netdev_register_provider(const struct netdev_class *);
+int netdev_unregister_provider(const struct netdev_class *);
+void netdev_enumerate_types(struct svec *types);
+
 int netdev_open(struct netdev_options *, struct netdev **);
 int netdev_open_default(const char *name, struct netdev **);
 int netdev_reconfigure(struct netdev *, const struct shash *args);
-- 
1.6.3.3





More information about the dev mailing list