+/* Registers a new datapath provider. After successful registration, new
+ * datapaths of that type can be opened using dpif_open(). */
+int
+dp_register_provider(const struct dpif_class *new_class)
+{
+ struct registered_dpif_class *registered_class;
+
+ if (shash_find(&dpif_classes, new_class->type)) {
+ VLOG_WARN("attempted to register duplicate datapath provider: %s",
+ new_class->type);
+ return EEXIST;
+ }
+
+ registered_class = xmalloc(sizeof *registered_class);
+ registered_class->dpif_class = new_class;
+ registered_class->refcount = 0;
+
+ shash_add(&dpif_classes, new_class->type, registered_class);
+
+ return 0;
+}
+
+/* Unregisters a datapath provider. 'type' must have been previously
+ * registered and not currently be in use by any dpifs. After unregistration
+ * new datapaths of that type cannot be opened using dpif_open(). */
+int
+dp_unregister_provider(const char *type)
+{
+ struct shash_node *node;
+ struct registered_dpif_class *registered_class;
+
+ node = shash_find(&dpif_classes, type);
+ if (!node) {
+ VLOG_WARN("attempted to unregister a datapath provider that is not "
+ "registered: %s", type);
+ return EAFNOSUPPORT;
+ }
+
+ registered_class = node->data;
+ if (registered_class->refcount) {
+ VLOG_WARN("attempted to unregister in use datapath provider: %s", type);
+ return EBUSY;
+ }
+
+ shash_delete(&dpif_classes, node);
+ free(registered_class);
+
+ return 0;
+}
+
+/* Clears 'types' and enumerates the types of all currently registered datapath
+ * providers into it. The caller must first initialize the svec. */
+void
+dp_enumerate_types(struct svec *types)
+{
+ struct shash_node *node;
+
+ dp_initialize();
+ svec_clear(types);
+
+ SHASH_FOR_EACH(node, &dpif_classes) {
+ const struct registered_dpif_class *registered_class = node->data;
+ svec_add(types, registered_class->dpif_class->type);
+ }
+}
+
+/* Clears 'names' and enumerates the names of all known created datapaths with
+ * the given 'type'. The caller must first initialize the svec. 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_names(const char *type, struct svec *names)
+{
+ const struct registered_dpif_class *registered_class;
+ const struct dpif_class *dpif_class;
+ int error;
+
+ dp_initialize();
+ svec_clear(names);
+
+ registered_class = shash_find_data(&dpif_classes, type);
+ if (!registered_class) {
+ VLOG_WARN("could not enumerate unknown type: %s", type);
+ return EAFNOSUPPORT;
+ }
+
+ dpif_class = registered_class->dpif_class;
+ error = dpif_class->enumerate ? dpif_class->enumerate(names) : 0;
+
+ if (error) {
+ VLOG_WARN("failed to enumerate %s datapaths: %s", dpif_class->type,
+ strerror(error));
+ }
+
+ return error;
+}
+
+/* Parses 'datapath name', which is of the form type@name into its
+ * component pieces. 'name' and 'type' must be freed by the caller. */
+void
+dp_parse_name(const char *datapath_name_, char **name, char **type)
+{
+ char *datapath_name = xstrdup(datapath_name_);
+ char *separator;
+
+ separator = strchr(datapath_name, '@');
+ if (separator) {
+ *separator = '\0';
+ *type = datapath_name;
+ *name = xstrdup(separator + 1);
+ } else {
+ *name = datapath_name;
+ *type = NULL;
+ }
+}
+