/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
int retval;
sprintf(devname, "dp%d", i);
- retval = dpif_open(devname, &dpif);
+ retval = dpif_open(devname, "system", &dpif);
if (!retval) {
svec_add(all_dps, devname);
dpif_close(dpif);
}
static int
-dpif_linux_open(const char *name UNUSED, char *suffix, bool create,
+dpif_linux_open(const char *name, const char *type UNUSED, bool create,
struct dpif **dpifp)
{
int minor;
&& isdigit((unsigned char)name[2]) ? atoi(name + 2) : -1;
if (create) {
if (minor >= 0) {
- return create_minor(suffix, minor, dpifp);
+ return create_minor(name, minor, dpifp);
} else {
/* Scan for unused minor number. */
for (minor = 0; minor < ODP_MAX; minor++) {
- int error = create_minor(suffix, minor, dpifp);
+ int error = create_minor(name, minor, dpifp);
if (error != EBUSY) {
return error;
}
int error;
if (minor < 0) {
- error = lookup_minor(suffix, &minor);
+ error = lookup_minor(name, &minor);
if (error) {
return error;
}
}
const struct dpif_class dpif_linux_class = {
- "", /* This is the default class. */
- "linux",
+ "system",
NULL,
NULL,
dpif_linux_enumerate,
dp->open_cnt++;
- dpname = xasprintf("netdev:dp%d", dp->dp_idx);
+ dpname = xasprintf("dp%d", dp->dp_idx);
dpif = xmalloc(sizeof *dpif);
dpif_init(&dpif->dpif, &dpif_netdev_class, dpname, dp->dp_idx, dp->dp_idx);
dpif->dp = dp;
}
static int
-dpif_netdev_open(const char *name UNUSED, char *suffix, bool create,
+dpif_netdev_open(const char *name, const char *type UNUSED, bool create,
struct dpif **dpifp)
{
if (create) {
- if (find_dp_netdev(suffix)) {
+ if (find_dp_netdev(name)) {
return EEXIST;
} else {
- int dp_idx = name_to_dp_idx(suffix);
+ int dp_idx = name_to_dp_idx(name);
if (dp_idx >= 0) {
- return create_dp_netdev(suffix, dp_idx, dpifp);
+ return create_dp_netdev(name, dp_idx, dpifp);
} else {
/* Scan for unused dp_idx number. */
for (dp_idx = 0; dp_idx < N_DP_NETDEVS; dp_idx++) {
- int error = create_dp_netdev(suffix, dp_idx, dpifp);
+ int error = create_dp_netdev(name, dp_idx, dpifp);
if (error != EBUSY) {
return error;
}
}
}
} else {
- struct dp_netdev *dp = find_dp_netdev(suffix);
+ struct dp_netdev *dp = find_dp_netdev(name);
if (dp) {
*dpifp = create_dpif_netdev(dp);
return 0;
}
const struct dpif_class dpif_netdev_class = {
- "netdev",
"netdev",
dp_netdev_run,
dp_netdev_wait,
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* This structure should be treated as opaque by dpif implementations. */
struct dpif {
const struct dpif_class *class;
- char *name;
+ char *base_name;
+ char *full_name;
uint8_t netflow_engine_type;
uint8_t netflow_engine_id;
};
* EWOULDBLOCK or EINPROGRESS. We may relax this requirement in the future if
* and when we encounter performance problems. */
struct dpif_class {
- /* Prefix for names of dpifs in this class, e.g. "netdev:".
+ /* Type of dpif in this class, e.g. "system", "netdev", etc.
*
- * One dpif class may have the empty string "" as its prefix, in which case
- * that dpif class is associated with dpif names that don't match any other
- * class name. */
- const char *prefix;
-
- /* Class name, for use in error messages. */
- const char *name;
+ * One of the providers should supply a "system" type, since this is
+ * the type assumed if no type is specified when opening a dpif. */
+ const char *type;
/* Performs periodic work needed by dpifs of this class, if any is
* necessary. */
* 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".
- * This name is useful for error messages but must not be modified.
- *
- * 'suffix' is a copy of 'name' following the dpif's 'prefix'.
+ /* Attempts to open an existing dpif called 'name', if 'create' is false,
+ * or to open an existing dpif or create a new one, if 'create' is true.
+ * 'type' corresponds to the 'type' field used in the dpif_class
+ * structure.
*
* If successful, stores a pointer to the new dpif in '*dpifp'. On failure
* there are no requirements on what is stored in '*dpifp'. */
- int (*open)(const char *name, char *suffix, bool create,
+ int (*open)(const char *name, const char *type, bool create,
struct dpif **dpifp);
/* Closes 'dpif' and frees associated memory. */
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
}
}
-/* 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.
+
+/* Clears 'types' and enumerates the types of all known datapath providers,
+ * into it. The caller must first initialize the svec. */
+void
+dp_enumerate_types(struct svec *types)
+{
+ int i;
+
+ svec_clear(types);
+
+ for (i = 0; i < N_DPIF_CLASSES; i++) {
+ svec_add(types, dpif_classes[i]->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(struct svec *all_dps)
+dp_enumerate_names(const char *type, struct svec *names)
{
- int error;
int i;
- svec_clear(all_dps);
- error = 0;
+ svec_clear(names);
+
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;
+
+ if (!strcmp(type, class->type)) {
+ int error = class->enumerate ? class->enumerate(names) : 0;
+
+ if (error) {
+ VLOG_WARN("failed to enumerate %s datapaths: %s",
+ class->type, strerror(error));
}
+
+ return error;
}
}
- return error;
+
+ return EAFNOSUPPORT;
+}
+
+/* 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;
+ }
}
static int
-do_open(const char *name_, bool create, struct dpif **dpifp)
+do_open(const char *name, const char *type, bool create, struct dpif **dpifp)
{
- char *name = xstrdup(name_);
- char *prefix, *suffix, *colon;
struct dpif *dpif = NULL;
int error;
int i;
- colon = strchr(name, ':');
- if (colon) {
- *colon = '\0';
- prefix = name;
- suffix = colon + 1;
- } else {
- prefix = "";
- suffix = name;
+ if (!type || *type == '\0') {
+ type = "system";
}
for (i = 0; i < N_DPIF_CLASSES; i++) {
const struct dpif_class *class = dpif_classes[i];
- if (!strcmp(prefix, class->prefix)) {
- error = class->open(name_, suffix, create, &dpif);
+ if (!strcmp(type, class->type)) {
+ error = class->open(name, type, create, &dpif);
goto exit;
}
}
return error;
}
-/* Tries to open an existing datapath named 'name'. Will fail if no datapath
- * named 'name' exists. Returns 0 if successful, otherwise a positive errno
- * value. On success stores a pointer to the datapath in '*dpifp', otherwise a
- * null pointer. */
+/* Tries to open an existing datapath named 'name' and type 'type'. Will fail
+ * if no datapath with 'name' and 'type' exists. 'type' may be either NULL or
+ * the empty string to specify the default system type. 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_open(const char *name, struct dpif **dpifp)
+dpif_open(const char *name, const char *type, struct dpif **dpifp)
{
- return do_open(name, false, dpifp);
+ return do_open(name, type, false, 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. */
+/* Tries to create and open a new datapath with the given 'name' and 'type'.
+ * 'type' may be either NULL or the empty string to specify the default system
+ * type. Will fail if a datapath with 'name' and 'type' 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. */
int
-dpif_create(const char *name, struct dpif **dpifp)
+dpif_create(const char *name, const char *type, struct dpif **dpifp)
{
- return do_open(name, true, dpifp);
+ return do_open(name, type, 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. */
+/* Tries to open a datapath with the given 'name' and 'type', creating it if it
+ * does not exist. 'type' may be either NULL or the empty string to specify
+ * the default system type. 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)
+dpif_create_and_open(const char *name, const char *type, struct dpif **dpifp)
{
int error;
- error = dpif_create(name, dpifp);
+ error = dpif_create(name, type, dpifp);
if (error == EEXIST || error == EBUSY) {
- error = dpif_open(name, dpifp);
+ error = dpif_open(name, type, dpifp);
if (error) {
VLOG_WARN("datapath %s already exists but cannot be opened: %s",
name, strerror(error));
dpif_close(struct dpif *dpif)
{
if (dpif) {
- char *name = dpif->name;
+ char *base_name = dpif->base_name;
+ char *full_name = dpif->full_name;
dpif->class->close(dpif);
- free(name);
+ free(base_name);
+ free(full_name);
}
}
-/* Returns the name of datapath 'dpif' (for use in log messages). */
+/* Returns the name of datapath 'dpif' prefixed with the type
+ * (for use in log messages). */
const char *
dpif_name(const struct dpif *dpif)
{
- return dpif->name;
+ return dpif->full_name;
+}
+
+/* Returns the name of datapath 'dpif' without the type
+ * (for use in device names). */
+const char *
+dpif_base_name(const struct dpif *dpif)
+{
+ return dpif->base_name;
}
/* Enumerates all names that may be used to open 'dpif' into 'all_names'. The
}
return error;
} else {
- svec_add(all_names, dpif_name(dpif));
+ svec_add(all_names, dpif_base_name(dpif));
return 0;
}
}
uint8_t netflow_engine_type, uint8_t netflow_engine_id)
{
dpif->class = class;
- dpif->name = xstrdup(name);
+ dpif->base_name = xstrdup(name);
+ dpif->full_name = xasprintf("%s@%s", class->type, name);
dpif->netflow_engine_type = netflow_engine_type;
dpif->netflow_engine_id = netflow_engine_id;
}
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#ifndef DPIF_H
#define DPIF_H 1
-/* Operations for the datapath running in the local kernel. The interface can
- * generalize to multiple types of local datapaths, but the implementation only
- * supports the openflow kernel module. */
-
#include "openvswitch/datapath-protocol.h"
#include <stdbool.h>
#include <stddef.h>
void dp_run(void);
void dp_wait(void);
-int dp_enumerate(struct svec *);
+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);
-int dpif_open(const char *name, struct dpif **);
-int dpif_create(const char *name, struct dpif **);
-int dpif_create_and_open(const char *name, struct dpif **);
+int dpif_open(const char *name, const char *type, struct dpif **);
+int dpif_create(const char *name, const char *type, struct dpif **);
+int dpif_create_and_open(const char *name, const char *type, struct dpif **);
void dpif_close(struct dpif *);
const char *dpif_name(const struct dpif *);
+const char *dpif_base_name(const struct dpif *);
int dpif_get_all_names(const struct dpif *, struct svec *);
int dpif_delete(struct dpif *);
.RS
.TP
-\fBdp\fIN\fR
+[\fItype\fB@\fR]\fBdp\fIN\fR
Datapath number \fIN\fR, where \fIN\fR is a number between 0 and 255,
-inclusive.
+inclusive. If \fItype\fR is given, it specifies the datapath provider of
+\fBdp\fIN\fR, otherwise the default provider \fBsystem\fR is assumed.
.TP
-\fIname\fR
+[\fItype\fB@\fR]\fIname\fR
The name of the network device associated with the datapath's local
port. (\fB\*(PN\fR internally converts this into a datapath number,
-as above.)
+as above.) If \fItype\fR is given, it specifies the datapath provider of
+\fIname\fR, otherwise the default provider \fBsystem\fR is assumed.
static void reinit_ports(struct ofproto *);
int
-ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux,
+ofproto_create(const char *datapath, const char *datapath_type,
+ const struct ofhooks *ofhooks, void *aux,
struct ofproto **ofprotop)
{
struct odp_stats stats;
*ofprotop = NULL;
/* Connect to datapath and start listening for messages. */
- error = dpif_open(datapath, &dpif);
+ error = dpif_open(datapath, datapath_type, &dpif);
if (error) {
VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
return error;
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
long long int used; /* Last-used time (0 if never used). */
};
-int ofproto_create(const char *datapath, const struct ofhooks *, void *aux,
+int ofproto_create(const char *datapath, const char *datapath_type,
+ const struct ofhooks *, void *aux,
struct ofproto **ofprotop);
void ofproto_destroy(struct ofproto *);
int ofproto_run(struct ofproto *);
return retval;
}
+static int
+parsed_dpif_open(const char *arg_, bool create, struct dpif **dpifp)
+{
+ int result;
+ char *name, *type;
+
+ dp_parse_name(arg_, &name, &type);
+
+ if (create) {
+ result = dpif_create(name, type, dpifp);
+ } else {
+ result = dpif_open(name, type, dpifp);
+ }
+
+ free(name);
+ free(type);
+ return result;
+}
+
static void
do_add_dp(int argc UNUSED, char *argv[])
{
struct dpif *dpif;
- run(dpif_create(argv[1], &dpif), "add_dp");
+ run(parsed_dpif_open(argv[1], true, &dpif), "add_dp");
dpif_close(dpif);
if (argc > 2) {
do_add_if(argc, argv);
do_del_dp(int argc UNUSED, char *argv[])
{
struct dpif *dpif;
- run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
run(dpif_delete(dpif), "del_dp");
dpif_close(dpif);
}
struct dpif *dpif;
int i;
- run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
for (i = 2; i < argc; i++) {
char *save_ptr = NULL;
char *devname, *suboptions;
struct dpif *dpif;
int i;
- run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
for (i = 2; i < argc; i++) {
const char *name = argv[i];
uint16_t port;
struct dpif *dpif;
int error;
- error = dpif_open(name, &dpif);
+ error = parsed_dpif_open(name, false, &dpif);
if (!error) {
show_dpif(dpif);
} else {
int error;
sprintf(name, "dp%u", i);
- error = dpif_open(name, &dpif);
+ error = parsed_dpif_open(name, false, &dpif);
if (!error) {
show_dpif(dpif);
} else if (error != ENODEV) {
static void
do_dump_dps(int argc UNUSED, char *argv[] UNUSED)
{
- struct svec all_dps;
+ struct svec dpif_names, dpif_types;
unsigned int i;
- int error;
+ int error = 0;
- svec_init(&all_dps);
- error = dp_enumerate(&all_dps);
+ svec_init(&dpif_names);
+ svec_init(&dpif_types);
+ dp_enumerate_types(&dpif_types);
- for (i = 0; i < all_dps.n; i++) {
- struct dpif *dpif;
- if (!dpif_open(all_dps.names[i], &dpif)) {
- printf("%s\n", dpif_name(dpif));
- dpif_close(dpif);
+ for (i = 0; i < dpif_types.n; i++) {
+ unsigned int j;
+ int retval;
+
+ retval = dp_enumerate_names(dpif_types.names[i], &dpif_names);
+ if (retval) {
+ error = retval;
+ }
+
+ for (j = 0; j < dpif_names.n; j++) {
+ struct dpif *dpif;
+ if (!dpif_open(dpif_names.names[j], dpif_types.names[i], &dpif)) {
+ printf("%s\n", dpif_name(dpif));
+ dpif_close(dpif);
+ }
}
}
- svec_destroy(&all_dps);
+ svec_destroy(&dpif_names);
+ svec_destroy(&dpif_types);
if (error) {
exit(EXIT_FAILURE);
}
struct ds ds;
size_t i;
- run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
run(dpif_flow_list_all(dpif, &flows, &n_flows), "listing all flows");
ds_init(&ds);
{
struct dpif *dpif;
- run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
run(dpif_flow_flush(dpif), "deleting all flows");
dpif_close(dpif);
}
struct dpif *dpif;
unsigned int i;
- run(dpif_open(argv[1], &dpif), "opening datapath");
+ run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
run(dpif_get_dp_stats(dpif, &stats), "get datapath stats");
for (i = 0; i < stats.max_groups; i++) {
uint16_t *ports;
This is short for \fBunix:\fIfile\fR, as long as \fIfile\fR does not
contain a colon.
.
-.IP \fIdp\fR
-This is short for \fBunix:@RUNDIR@/\fIdp\fB.mgmt\fR, as long as
-\fIdp\fR does not contain a colon.
+.IP \fIbridge\fR
+This is short for \fBunix:@RUNDIR@/\fIbridge\fB.mgmt\fR, as long as
+\fIbridge\fR does not contain a colon.
+.
+.IP [\fItype\fB@\fR]\fIdp\fR
+Attempts to look up the bridge associated with \fIdp\fR and open as
+above. If \fItype\fR is given, it specifies the datapath provider of
+\fIdp\fR, otherwise the default provider \fBsystem\fR is assumed.
.RE
.TP
\f
/* Generic commands. */
+static void
+open_vconn_socket(const char *name, struct vconn **vconnp)
+{
+ char *vconn_name = xasprintf("unix:%s", name);
+ VLOG_INFO("connecting to %s", vconn_name);
+ run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
+ "connecting to %s", vconn_name);
+ free(vconn_name);
+}
+
static void
open_vconn(const char *name, struct vconn **vconnp)
{
struct dpif *dpif;
struct stat s;
+ char *bridge_path, *datapath_name, *datapath_type;
+
+ bridge_path = xasprintf("%s/%s.mgmt", ovs_rundir, name);
+ dp_parse_name(name, &datapath_name, &datapath_type);
if (strstr(name, ":")) {
run(vconn_open_block(name, OFP_VERSION, vconnp),
"connecting to %s", name);
} else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
- char *vconn_name = xasprintf("unix:%s", name);
- VLOG_INFO("connecting to %s", vconn_name);
- run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
- "connecting to %s", vconn_name);
- free(vconn_name);
- } else if (!dpif_open(name, &dpif)) {
+ open_vconn_socket(name, vconnp);
+ } else if (!stat(bridge_path, &s) && S_ISSOCK(s.st_mode)) {
+ open_vconn_socket(bridge_path, vconnp);
+ } else if (!dpif_open(datapath_name, datapath_type, &dpif)) {
char dpif_name[IF_NAMESIZE + 1];
char *socket_name;
- char *vconn_name;
run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name),
"obtaining name of %s", dpif_name);
name, socket_name);
}
- vconn_name = xasprintf("unix:%s", socket_name);
- VLOG_INFO("connecting to %s", vconn_name);
- run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
- "connecting to %s", vconn_name);
+ open_vconn_socket(socket_name, vconnp);
free(socket_name);
- free(vconn_name);
} else {
ovs_fatal(0, "%s is not a valid connection method", name);
}
+
+ free(datapath_name);
+ free(datapath_type);
+ free(bridge_path);
}
static void *
const char *port;
size_t i;
- error = dpif_create_and_open(s.dp_name, &dpif);
+ error = dpif_create_and_open(s.dp_name, NULL, &dpif);
if (error) {
ovs_fatal(error, "could not create datapath");
}
}
/* Start OpenFlow processing. */
- error = ofproto_create(s.dp_name, NULL, NULL, &ofproto);
+ error = ofproto_create(s.dp_name, NULL, NULL, NULL, &ofproto);
if (error) {
ovs_fatal(error, "could not initialize openflow switch");
}
static const struct vsctl_column bridge_columns[] = {
{&ovsrec_bridge_col_datapath_id, VSCF_READONLY, NULL},
+ {&ovsrec_bridge_col_datapath_type, VSCF_READONLY, NULL},
{&ovsrec_bridge_col_name, VSCF_READONLY, NULL},
{&ovsrec_bridge_col_mirrors, VSCF_READONLY, NULL},
{&ovsrec_bridge_col_other_config, 0, NULL},
/* Maximum number of datapaths. */
enum { DP_MAX = 256 };
-static struct bridge *bridge_create(const char *name);
+static struct bridge *bridge_create(const struct ovsrec_bridge *br_cfg);
static void bridge_destroy(struct bridge *);
static struct bridge *bridge_lookup(const char *name);
static unixctl_cb_func bridge_unixctl_dump_flows;
bridge_init(const struct ovsrec_open_vswitch *cfg)
{
struct svec bridge_names;
- struct svec dpif_names;
+ struct svec dpif_names, dpif_types;
size_t i;
unixctl_command_register("fdb/show", bridge_unixctl_fdb_show, NULL);
svec_sort(&bridge_names);
svec_init(&dpif_names);
- dp_enumerate(&dpif_names);
- for (i = 0; i < dpif_names.n; i++) {
- const char *dpif_name = dpif_names.names[i];
+ svec_init(&dpif_types);
+ dp_enumerate_types(&dpif_types);
+ for (i = 0; i < dpif_types.n; i++) {
struct dpif *dpif;
int retval;
+ size_t j;
- retval = dpif_open(dpif_name, &dpif);
- if (!retval) {
- struct svec all_names;
- size_t j;
+ dp_enumerate_names(dpif_types.names[i], &dpif_names);
- svec_init(&all_names);
- dpif_get_all_names(dpif, &all_names);
- for (j = 0; j < all_names.n; j++) {
- if (svec_contains(&bridge_names, all_names.names[j])) {
- goto found;
+ for (j = 0; j < dpif_names.n; j++) {
+ retval = dpif_open(dpif_names.names[j], dpif_types.names[i], &dpif);
+ if (!retval) {
+ struct svec all_names;
+ size_t k;
+
+ svec_init(&all_names);
+ dpif_get_all_names(dpif, &all_names);
+ for (k = 0; k < all_names.n; k++) {
+ if (svec_contains(&bridge_names, all_names.names[k])) {
+ goto found;
+ }
}
+ dpif_delete(dpif);
+ found:
+ svec_destroy(&all_names);
+ dpif_close(dpif);
}
- dpif_delete(dpif);
- found:
- svec_destroy(&all_names);
- dpif_close(dpif);
}
}
svec_destroy(&dpif_names);
+ svec_destroy(&dpif_types);
unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows,
NULL);
SHASH_FOR_EACH (node, &new_br) {
const char *br_name = node->name;
const struct ovsrec_bridge *br_cfg = node->data;
- if (!shash_find_data(&old_br, br_name)) {
- br = bridge_create(br_name);
- if (br) {
- br->cfg = br_cfg;
+ br = shash_find_data(&old_br, br_name);
+ if (br) {
+ /* If the bridge datapath type has changed, we need to tear it
+ * down and recreate. */
+ if (strcmp(br->cfg->datapath_type, br_cfg->datapath_type)) {
+ bridge_destroy(br);
+ bridge_create(br_cfg);
}
+ } else {
+ bridge_create(br_cfg);
}
}
shash_destroy(&old_br);
\f
/* Bridge reconfiguration functions. */
static struct bridge *
-bridge_create(const char *name)
+bridge_create(const struct ovsrec_bridge *br_cfg)
{
struct bridge *br;
int error;
- assert(!bridge_lookup(name));
+ assert(!bridge_lookup(br_cfg->name));
br = xzalloc(sizeof *br);
- error = dpif_create_and_open(name, &br->dpif);
+ error = dpif_create_and_open(br_cfg->name, br_cfg->datapath_type,
+ &br->dpif);
if (error) {
free(br);
return NULL;
}
dpif_flow_flush(br->dpif);
- error = ofproto_create(name, &bridge_ofhooks, br, &br->ofproto);
+ error = ofproto_create(br_cfg->name, br_cfg->datapath_type, &bridge_ofhooks,
+ br, &br->ofproto);
if (error) {
- VLOG_ERR("failed to create switch %s: %s", name, strerror(error));
+ VLOG_ERR("failed to create switch %s: %s", br_cfg->name,
+ strerror(error));
dpif_delete(br->dpif);
dpif_close(br->dpif);
free(br);
return NULL;
}
- br->name = xstrdup(name);
+ br->name = xstrdup(br_cfg->name);
+ br->cfg = br_cfg;
br->ml = mac_learning_create();
br->sent_config_request = false;
eth_addr_random(br->default_ea);
"name": {
"comment": "Bridge identifier. Should be alphanumeric and no more than about 8 bytes long. Must be unique among the names of ports, interfaces, and bridges on a host.",
"type": "string"},
+ "datapath_type": {
+ "comment": "Name of datapath provider. The kernel datapath has type \"system\". The userspace datapath has type \"netdev\".",
+ "type": "string"},
"datapath_id": {
"comment": "Reports the OpenFlow datapath ID in use. Exactly 12 hex digits.",
"type": {"key": "string", "min": 0, "max": 1},