From: Jesse Gross Date: Mon, 1 Feb 2010 16:36:01 +0000 (-0500) Subject: dpif: Allow providers to be managed at runtime. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=999401aa9caf241400406192ca7e55d7732a1c44;p=openvswitch dpif: Allow providers to be managed at runtime. The list of datapath providers was previously staticly defined at compile time. This allows new providers to be added and removed at runtime. --- diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index db69589a..94c3cf5c 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -98,7 +98,7 @@ dpif_linux_enumerate(struct svec *all_dps) retval = dpif_open(devname, "system", &dpif); if (!retval) { svec_add(all_dps, devname); - dpif_close(dpif); + dpif_uninit(dpif, true); } else if (retval != ENODEV && !error) { error = retval; } @@ -157,7 +157,7 @@ dpif_linux_open(const char *name, const char *type UNUSED, bool create, VLOG_WARN("%s: probe returned unexpected error: %s", dpif_name(*dpifp), strerror(error)); } - dpif_close(*dpifp); + dpif_uninit(*dpifp, true); return error; } @@ -668,11 +668,11 @@ static int finish_open(struct dpif *dpif_, const char *local_ifname) { struct dpif_linux *dpif = dpif_linux_cast(dpif_); - dpif->local_ifname = strdup(local_ifname); + dpif->local_ifname = xstrdup(local_ifname); dpif->local_ifindex = if_nametoindex(local_ifname); if (!dpif->local_ifindex) { int error = errno; - dpif_close(dpif_); + dpif_uninit(dpif_, true); VLOG_WARN("could not get ifindex of %s device: %s", local_ifname, strerror(errno)); return error; @@ -689,7 +689,7 @@ create_minor(const char *name, int minor, struct dpif **dpifp) if (!error) { error = finish_open(*dpifp, name); } else { - dpif_close(*dpifp); + dpif_uninit(*dpifp, true); } } return error; diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 9a495443..699f724a 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -36,6 +36,8 @@ struct dpif { void dpif_init(struct dpif *, const struct dpif_class *, const char *name, uint8_t netflow_engine_type, uint8_t netflow_engine_id); +void dpif_uninit(struct dpif *dpif, bool close); + static inline void dpif_assert_class(const struct dpif *dpif, const struct dpif_class *class) { diff --git a/lib/dpif.c b/lib/dpif.c index 5947179b..f3d6713d 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -33,6 +33,7 @@ #include "ofpbuf.h" #include "packets.h" #include "poll-loop.h" +#include "shash.h" #include "svec.h" #include "util.h" #include "valgrind.h" @@ -40,11 +41,16 @@ #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 @@ -63,6 +69,21 @@ static void log_flow_put(struct dpif *, int error, 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 @@ -70,11 +91,11 @@ static void check_rw_odp_flow(struct odp_flow *); 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(); } } } @@ -86,27 +107,79 @@ dp_run(void) 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); } } @@ -119,26 +192,28 @@ dp_enumerate_types(struct svec *types) 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 @@ -165,20 +240,26 @@ do_open(const char *name, const char *type, bool create, struct dpif **dpifp) { 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; @@ -236,11 +317,14 @@ void 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); } } @@ -975,6 +1059,26 @@ dpif_init(struct dpif *dpif, const struct dpif_class *class, const char *name, 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); +} static void log_operation(const struct dpif *dpif, const char *operation, int error) diff --git a/lib/dpif.h b/lib/dpif.h index aa54a387..dae0ef83 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -26,10 +26,15 @@ struct dpif; struct ofpbuf; struct svec; +struct dpif_class; void dp_run(void); void dp_wait(void); + +int dp_register_provider(const struct dpif_class *); +int dp_unregister_provider(const char *type); void dp_enumerate_types(struct svec *types); + int dp_enumerate_names(const char *type, struct svec *names); void dp_parse_name(const char *datapath_name, char **name, char **type);