#include "ofpbuf.h"
#include "packets.h"
#include "poll-loop.h"
+#include "shash.h"
#include "svec.h"
#include "util.h"
#include "valgrind.h"
#include "vlog.h"
#define THIS_MODULE VLM_dpif
-static const struct dpif_class *dpif_classes[] = {
+static const struct dpif_class *base_dpif_classes[] = {
&dpif_linux_class,
&dpif_netdev_class,
};
-enum { N_DPIF_CLASSES = ARRAY_SIZE(dpif_classes) };
+
+struct registered_dpif_class {
+ struct dpif_class dpif_class;
+ int refcount;
+};
+static struct shash dpif_classes = SHASH_INITIALIZER(&dpif_classes);
/* Rate limit for individual messages going to or from the datapath, output at
* DBG level. This is very high because, if these are enabled, it is because
static bool should_log_flow_message(int error);
static void check_rw_odp_flow(struct odp_flow *);
+static void
+dp_initialize(void)
+{
+ static int status = -1;
+
+ if (status < 0) {
+ int i;
+
+ status = 0;
+ for (i = 0; i < ARRAY_SIZE(base_dpif_classes); i++) {
+ dp_register_provider(base_dpif_classes[i]);
+ }
+ }
+}
+
/* Performs periodic work needed by all the various kinds of dpifs.
*
* If your program opens any dpifs, it must call both this function and
void
dp_run(void)
{
- int i;
- for (i = 0; i < N_DPIF_CLASSES; i++) {
- const struct dpif_class *class = dpif_classes[i];
- if (class->run) {
- class->run();
+ struct shash_node *node;
+ SHASH_FOR_EACH(node, &dpif_classes) {
+ const struct registered_dpif_class *registered_class = node->data;
+ if (registered_class->dpif_class.run) {
+ registered_class->dpif_class.run();
}
}
}
void
dp_wait(void)
{
- int i;
- for (i = 0; i < N_DPIF_CLASSES; i++) {
- const struct dpif_class *class = dpif_classes[i];
- if (class->wait) {
- class->wait();
+ struct shash_node *node;
+ SHASH_FOR_EACH(node, &dpif_classes) {
+ const struct registered_dpif_class *registered_class = node->data;
+ if (registered_class->dpif_class.wait) {
+ registered_class->dpif_class.wait();
}
}
}
+/* 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;
+ }
-/* Clears 'types' and enumerates the types of all known datapath providers,
- * into it. The caller must first initialize the svec. */
+ registered_class = xmalloc(sizeof *registered_class);
+ memcpy(®istered_class->dpif_class, new_class,
+ sizeof registered_class->dpif_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)
{
- int i;
+ struct shash_node *node;
+ dp_initialize();
svec_clear(types);
- for (i = 0; i < N_DPIF_CLASSES; i++) {
- svec_add(types, dpif_classes[i]->type);
+ SHASH_FOR_EACH(node, &dpif_classes) {
+ const struct registered_dpif_class *registered_class = node->data;
+ svec_add(types, registered_class->dpif_class.type);
}
}
int
dp_enumerate_names(const char *type, struct svec *names)
{
- int i;
+ const struct registered_dpif_class *registered_class;
+ const struct dpif_class *dpif_class;
+ int error;
+ dp_initialize();
svec_clear(names);
- for (i = 0; i < N_DPIF_CLASSES; i++) {
- const struct dpif_class *class = dpif_classes[i];
-
- if (!strcmp(type, class->type)) {
- int error = class->enumerate ? class->enumerate(names) : 0;
+ registered_class = shash_find_data(&dpif_classes, type);
+ if (!registered_class) {
+ VLOG_WARN("could not enumerate unknown type: %s", type);
+ return EAFNOSUPPORT;
+ }
- if (error) {
- VLOG_WARN("failed to enumerate %s datapaths: %s",
- class->type, strerror(error));
- }
+ dpif_class = ®istered_class->dpif_class;
+ error = dpif_class->enumerate ? dpif_class->enumerate(names) : 0;
- return error;
- }
+ if (error) {
+ VLOG_WARN("failed to enumerate %s datapaths: %s", dpif_class->type,
+ strerror(error));
}
- return EAFNOSUPPORT;
+ return error;
}
/* Parses 'datapath name', which is of the form type@name into its
{
struct dpif *dpif = NULL;
int error;
- int i;
+ struct registered_dpif_class *registered_class;
+
+ dp_initialize();
if (!type || *type == '\0') {
type = "system";
}
- for (i = 0; i < N_DPIF_CLASSES; i++) {
- const struct dpif_class *class = dpif_classes[i];
- if (!strcmp(type, class->type)) {
- error = class->open(name, type, create, &dpif);
- goto exit;
- }
+ registered_class = shash_find_data(&dpif_classes, type);
+ if (!registered_class) {
+ VLOG_WARN("could not create datapath %s of unknown type %s", name,
+ type);
+ error = EAFNOSUPPORT;
+ goto exit;
+ }
+
+ error = registered_class->dpif_class.open(name, type, create, &dpif);
+ if (!error) {
+ registered_class->refcount++;
}
- error = EAFNOSUPPORT;
exit:
*dpifp = error ? NULL : dpif;
dpif_close(struct dpif *dpif)
{
if (dpif) {
- char *base_name = dpif->base_name;
- char *full_name = dpif->full_name;
- dpif->class->close(dpif);
- free(base_name);
- free(full_name);
+ struct registered_dpif_class *registered_class;
+
+ registered_class = shash_find_data(&dpif_classes, dpif->class->type);
+ assert(registered_class);
+ assert(registered_class->refcount);
+
+ registered_class->refcount--;
+ dpif_uninit(dpif, true);
}
}
dpif->netflow_engine_type = netflow_engine_type;
dpif->netflow_engine_id = netflow_engine_id;
}
+
+/* Undoes the results of initialization.
+ *
+ * Normally this function only needs to be called from dpif_close().
+ * However, it may be called by providers due to an error on opening
+ * that occurs after initialization. It this case dpif_close() would
+ * never be called. */
+void
+dpif_uninit(struct dpif *dpif, bool close)
+{
+ char *base_name = dpif->base_name;
+ char *full_name = dpif->full_name;
+
+ if (close) {
+ dpif->class->close(dpif);
+ }
+
+ free(base_name);
+ free(full_name);
+}
\f
static void
log_operation(const struct dpif *dpif, const char *operation, int error)