dpif: New function dpif_create_and_open().
[sliver-openvswitch.git] / lib / dpif.c
index d2ef845..793eaa1 100644 (file)
 #include "ofpbuf.h"
 #include "packets.h"
 #include "poll-loop.h"
+#include "svec.h"
 #include "util.h"
 #include "valgrind.h"
 
 #include "vlog.h"
 #define THIS_MODULE VLM_dpif
 
-static struct dpif_class *dpif_classes[] = {
+static const struct dpif_class *dpif_classes[] = {
     &dpif_linux_class,
+    &dpif_netdev_class,
 };
 enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) };
 
@@ -63,8 +65,8 @@ static void check_rw_odp_flow(struct odp_flow *);
 
 /* Performs periodic work needed by all the various kinds of dpifs.
  *
- * If your program opens any dpifs, it must call this function within its main
- * poll loop. */
+ * If your program opens any dpifs, it must call both this function and
+ * netdev_run() within its main poll loop. */
 void
 dp_run(void)
 {
@@ -79,8 +81,8 @@ dp_run(void)
 
 /* Arranges for poll_block() to wake up when dp_run() needs to be called.
  *
- * If your program opens any dpifs, it must call this function within its main
- * poll loop. */
+ * If your program opens any dpifs, it must call both this function and
+ * netdev_wait() within its main poll loop. */
 void
 dp_wait(void)
 {
@@ -93,6 +95,34 @@ dp_wait(void)
     }
 }
 
+/* Clears 'all_dps' and enumerates the names of all known created datapaths, 
+ * where possible, into it.  The caller must first initialize 'all_dps'.
+ * Returns 0 if successful, otherwise a positive errno value.
+ *
+ * Some kinds of datapaths might not be practically enumerable.  This is not
+ * considered an error. */
+int
+dp_enumerate(struct svec *all_dps)
+{
+    int error;
+    int i;
+
+    svec_clear(all_dps);
+    error = 0;
+    for (i = 0; i < N_DPIF_CLASSES; i++) {
+        const struct dpif_class *class = dpif_classes[i];
+        int retval = class->enumerate ? class->enumerate(all_dps) : 0;
+        if (retval) {
+            VLOG_WARN("failed to enumerate %s datapaths: %s",
+                      class->name, strerror(retval));
+            if (!error) {
+                error = retval;
+            }
+        }
+    }
+    return error;
+}
+
 static int
 do_open(const char *name_, bool create, struct dpif **dpifp)
 {
@@ -139,13 +169,35 @@ dpif_open(const char *name, struct dpif **dpifp)
 /* Tries to create and open a new datapath with the given 'name'.  Will fail if
  * a datapath named 'name' already exists.  Returns 0 if successful, otherwise
  * a positive errno value.  On success stores a pointer to the datapath in
- * '*dpifp', otherwise a null pointer.*/
+ * '*dpifp', otherwise a null pointer. */
 int
 dpif_create(const char *name, struct dpif **dpifp)
 {
     return do_open(name, true, dpifp);
 }
 
+/* Tries to open a datapath with the given 'name', creating it if it does not
+ * exist.  Returns 0 if successful, otherwise a positive errno value.  On
+ * success stores a pointer to the datapath in '*dpifp', otherwise a null
+ * pointer. */
+int
+dpif_create_and_open(const char *name, struct dpif **dpifp)
+{
+    int error;
+
+    error = dpif_create(name, dpifp);
+    if (error == EEXIST || error == EBUSY) {
+        error = dpif_open(name, dpifp);
+        if (error) {
+            VLOG_WARN("datapath %s already exists but cannot be opened: %s",
+                      name, strerror(error));
+        }
+    } else if (error) {
+        VLOG_WARN("failed to create datapath %s: %s", name, strerror(error));
+    }
+    return error;
+}
+
 /* Closes and frees the connection to 'dpif'.  Does not destroy the datapath
  * itself; call dpif_delete() first, instead, if that is desirable. */
 void
@@ -165,6 +217,32 @@ dpif_name(const struct dpif *dpif)
     return dpif->name;
 }
 
+/* Enumerates all names that may be used to open 'dpif' into 'all_names'.  The
+ * Linux datapath, for example, supports opening a datapath both by number,
+ * e.g. "dp0", and by the name of the datapath's local port.  For some
+ * datapaths, this might be an infinite set (e.g. in a file name, slashes may
+ * be duplicated any number of times), in which case only the names most likely
+ * to be used will be enumerated.
+ *
+ * The caller must already have initialized 'all_names'.  Any existing names in
+ * 'all_names' will not be disturbed. */
+int
+dpif_get_all_names(const struct dpif *dpif, struct svec *all_names)
+{
+    if (dpif->class->get_all_names) {
+        int error = dpif->class->get_all_names(dpif, all_names);
+        if (error) {
+            VLOG_WARN_RL(&error_rl,
+                         "failed to retrieve names for datpath %s: %s",
+                         dpif_name(dpif), strerror(error));
+        }
+        return error;
+    } else {
+        svec_add(all_names, dpif_name(dpif));
+        return 0;
+    }
+}
+
 /* Destroys the datapath that 'dpif' is connected to, first removing all of its
  * ports.  After calling this function, it does not make sense to pass 'dpif'
  * to any functions other than dpif_name() or dpif_close(). */
@@ -341,7 +419,7 @@ dpif_port_list(const struct dpif *dpif,
                struct odp_port **portsp, size_t *n_portsp)
 {
     struct odp_port *ports;
-    size_t n_ports;
+    size_t n_ports = 0;
     int error;
 
     for (;;) {