struct dpif dpif;
int fd;
+ /* Used by dpif_linux_get_all_names(). */
+ char *local_ifname;
+ int minor;
+
/* Change notification. */
int local_ifindex; /* Ifindex of local port. */
struct svec changed_ports; /* Ports that have changed. */
linux_netdev_notifier_wait();
}
+static int
+dpif_linux_enumerate(struct svec *all_dps)
+{
+ int error;
+ int i;
+
+ error = 0;
+ for (i = 0; i < ODP_MAX; i++) {
+ struct dpif *dpif;
+ char devname[16];
+ int retval;
+
+ sprintf(devname, "dp%d", i);
+ retval = dpif_open(devname, &dpif);
+ if (!retval) {
+ svec_add(all_dps, devname);
+ dpif_close(dpif);
+ } else if (retval != ENODEV && !error) {
+ error = retval;
+ }
+ }
+ return error;
+}
+
static int
dpif_linux_open(const char *name UNUSED, char *suffix, bool create,
struct dpif **dpifp)
struct dpif_linux *dpif = dpif_linux_cast(dpif_);
linux_netdev_notifier_unregister(&dpif->port_notifier);
svec_destroy(&dpif->changed_ports);
+ free(dpif->local_ifname);
close(dpif->fd);
free(dpif);
}
+static int
+dpif_linux_get_all_names(const struct dpif *dpif_, struct svec *all_names)
+{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+
+ svec_add_nocopy(all_names, xasprintf("dp%d", dpif->minor));
+ svec_add(all_names, dpif->local_ifname);
+ return 0;
+}
+
static int
dpif_linux_delete(struct dpif *dpif_)
{
"linux",
dpif_linux_run,
dpif_linux_wait,
+ dpif_linux_enumerate,
dpif_linux_open,
dpif_linux_close,
+ dpif_linux_get_all_names,
dpif_linux_delete,
dpif_linux_get_stats,
dpif_linux_get_drop_frags,
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_ifindex = if_nametoindex(local_ifname);
if (!dpif->local_ifindex) {
int error = errno;
free(name);
dpif->fd = fd;
+ dpif->local_ifname = NULL;
+ dpif->minor = minor;
dpif->local_ifindex = 0;
svec_init(&dpif->changed_ports);
*dpifp = &dpif->dpif;
"netdev",
dp_netdev_run,
dp_netdev_wait,
+ NULL, /* enumerate */
dpif_netdev_open,
dpif_netdev_close,
+ NULL, /* get_all_names */
dpif_netdev_delete,
dpif_netdev_get_stats,
dpif_netdev_get_drop_frags,
* to be called. */
void (*wait)(void);
+ /* Enumerates the names of all known created datapaths, if possible, into
+ * 'all_dps'. The caller has already initialized 'all_dps' and other dpif
+ * classes might already have added names to it.
+ *
+ * This is used by the vswitch at startup, so that it can delete any
+ * datapaths that are not configured.
+ *
+ * Some kinds of datapaths might not be practically enumerable, in which
+ * case this function may be a null pointer. */
+ int (*enumerate)(struct svec *all_dps);
+
/* Attempts to open an existing dpif, if 'create' is false, or to open an
* existing dpif or create a new one, if 'create' is true. 'name' is the
* full dpif name provided by the user, e.g. "udatapath:/var/run/mypath".
/* Closes 'dpif' and frees associated memory. */
void (*close)(struct dpif *dpif);
+ /* 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 should be enumerated.
+ *
+ * The caller has already initialized 'all_names' and might already have
+ * added some names to it. This function should not disturb any existing
+ * names in 'all_names'.
+ *
+ * If a datapath class does not support multiple names for a datapath, this
+ * function may be a null pointer.
+ *
+ * This is used by the vswitch at startup, */
+ int (*get_all_names)(const struct dpif *dpif, struct svec *all_names);
+
/* Attempts to destroy the dpif underlying 'dpif'.
*
* If successful, 'dpif' will not be used again except as an argument for
#include "ofpbuf.h"
#include "packets.h"
#include "poll-loop.h"
+#include "svec.h"
#include "util.h"
#include "valgrind.h"
}
}
+/* Initializes 'all_dps' and enumerates the names of all known created
+ * datapaths, where possible, into it. 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_init(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)
{
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(). */
struct dpif;
struct ofpbuf;
+struct svec;
void dp_run(void);
void dp_wait(void);
+int dp_enumerate(struct svec *);
int dpif_open(const char *name, struct dpif **);
int dpif_create(const char *name, struct dpif **);
void dpif_close(struct dpif *);
const char *dpif_name(const struct dpif *);
+int dpif_get_all_names(const struct dpif *, struct svec *);
int dpif_delete(struct dpif *);
void
bridge_init(void)
{
- int retval;
- int i;
-
- bond_init();
+ struct svec dpif_names;
+ size_t i;
- for (i = 0; i < DP_MAX; i++) {
+ dp_enumerate(&dpif_names);
+ for (i = 0; i < dpif_names.n; i++) {
+ const char *dpif_name = dpif_names.names[i];
struct dpif *dpif;
- char devname[16];
+ int retval;
- sprintf(devname, "dp%d", i);
- retval = dpif_open(devname, &dpif);
+ retval = dpif_open(dpif_name, &dpif);
if (!retval) {
- char dpif_name[IF_NAMESIZE];
- if (dpif_port_get_name(dpif, ODPP_LOCAL,
- dpif_name, sizeof dpif_name)
- || !cfg_has("bridge.%s.port", dpif_name)) {
- dpif_delete(dpif);
+ struct svec all_names;
+ size_t j;
+
+ svec_init(&all_names);
+ dpif_get_all_names(dpif, &all_names);
+ for (j = 0; j < all_names.n; j++) {
+ if (cfg_has("bridge.%s.port", all_names.names[j])) {
+ goto found;
+ }
}
+ dpif_delete(dpif);
+ found:
+ svec_destroy(&all_names);
dpif_close(dpif);
- } else if (retval != ENODEV) {
- VLOG_ERR("failed to delete datapath dp%d: %s",
- i, strerror(retval));
}
}
+ bond_init();
bridge_reconfigure();
}