diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 2bf329f45..db69589a9 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -1,5 +1,5 @@ /* - * 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. @@ -95,7 +95,7 @@ dpif_linux_enumerate(struct svec *all_dps) 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); @@ -107,7 +107,7 @@ dpif_linux_enumerate(struct svec *all_dps) } 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; @@ -116,11 +116,11 @@ dpif_linux_open(const char *name UNUSED, char *suffix, bool create, && 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; } @@ -135,7 +135,7 @@ dpif_linux_open(const char *name UNUSED, char *suffix, bool create, int error; if (minor < 0) { - error = lookup_minor(suffix, &minor); + error = lookup_minor(name, &minor); if (error) { return error; } @@ -446,8 +446,7 @@ dpif_linux_recv_wait(struct dpif *dpif_) } const struct dpif_class dpif_linux_class = { - "", /* This is the default class. */ - "linux", + "system", NULL, NULL, dpif_linux_enumerate, diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 1d496177e..e9fb216fe 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -196,7 +196,7 @@ create_dpif_netdev(struct dp_netdev *dp) 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; @@ -245,20 +245,20 @@ create_dp_netdev(const char *name, int dp_idx, struct dpif **dpifp) } 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; } @@ -269,7 +269,7 @@ dpif_netdev_open(const char *name UNUSED, char *suffix, bool create, } } } 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; @@ -1303,7 +1303,6 @@ dp_netdev_execute_actions(struct dp_netdev *dp, } const struct dpif_class dpif_netdev_class = { - "netdev", "netdev", dp_netdev_run, dp_netdev_wait, diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 020e017cd..9a495443b 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -1,5 +1,5 @@ /* - * 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. @@ -28,7 +28,8 @@ * 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; }; @@ -52,15 +53,11 @@ static inline void dpif_assert_class(const struct dpif *dpif, * 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. */ @@ -81,16 +78,14 @@ struct dpif_class { * 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. */ diff --git a/lib/dpif.c b/lib/dpif.c index 793eaa118..5947179b0 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1,5 +1,5 @@ /* - * 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. @@ -95,57 +95,86 @@ dp_wait(void) } } -/* 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; } } @@ -156,38 +185,41 @@ 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)); @@ -204,17 +236,28 @@ void 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 @@ -238,7 +281,7 @@ dpif_get_all_names(const struct dpif *dpif, struct svec *all_names) } return error; } else { - svec_add(all_names, dpif_name(dpif)); + svec_add(all_names, dpif_base_name(dpif)); return 0; } } @@ -927,7 +970,8 @@ dpif_init(struct dpif *dpif, const struct dpif_class *class, const char *name, 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; } diff --git a/lib/dpif.h b/lib/dpif.h index 1d109c2d2..aa54a387d 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -1,5 +1,5 @@ /* - * 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. @@ -18,10 +18,6 @@ #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 #include @@ -33,14 +29,17 @@ struct svec; 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 *); diff --git a/lib/dpif.man b/lib/dpif.man index 3a58cafb6..63e172fca 100644 --- a/lib/dpif.man +++ b/lib/dpif.man @@ -1,11 +1,13 @@ .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. diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 46b577afb..941803d79 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -257,7 +257,8 @@ static int init_ports(struct ofproto *); 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; @@ -268,7 +269,7 @@ ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux, *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; diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 5fe8d774b..cf99a3992 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -1,5 +1,5 @@ /* - * 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. @@ -36,7 +36,8 @@ struct ofexpired { 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 *); diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index ee545a61a..fceab4c1a 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -174,11 +174,30 @@ static int if_up(const char *netdev_name) 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); @@ -189,7 +208,7 @@ static void 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); } @@ -216,7 +235,7 @@ do_add_if(int argc UNUSED, char *argv[]) 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; @@ -294,7 +313,7 @@ do_del_if(int argc UNUSED, char *argv[]) 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; @@ -366,7 +385,7 @@ do_show(int argc, char *argv[]) struct dpif *dpif; int error; - error = dpif_open(name, &dpif); + error = parsed_dpif_open(name, false, &dpif); if (!error) { show_dpif(dpif); } else { @@ -382,7 +401,7 @@ do_show(int argc, char *argv[]) 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) { @@ -399,22 +418,34 @@ do_show(int argc, char *argv[]) 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); } @@ -429,7 +460,7 @@ do_dump_flows(int argc UNUSED, char *argv[]) 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); @@ -455,7 +486,7 @@ do_del_flows(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_flow_flush(dpif), "deleting all flows"); dpif_close(dpif); } @@ -467,7 +498,7 @@ do_dump_groups(int argc UNUSED, char *argv[]) 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; diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index cf4ead96d..17b5a4006 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -32,9 +32,14 @@ are supported: 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 diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 61ca23e3b..52ec0b6b3 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -204,25 +204,36 @@ static void run(int retval, const char *message, ...) /* 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); @@ -240,15 +251,15 @@ open_vconn(const char *name, struct vconn **vconnp) 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 * diff --git a/utilities/ovs-openflowd.c b/utilities/ovs-openflowd.c index e0cfdc957..5e63f1b24 100644 --- a/utilities/ovs-openflowd.c +++ b/utilities/ovs-openflowd.c @@ -137,7 +137,7 @@ main(int argc, char *argv[]) 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"); } @@ -152,7 +152,7 @@ main(int argc, char *argv[]) } /* 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"); } diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index 318f42937..07d9ae2ca 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -1394,6 +1394,7 @@ struct vsctl_column { 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}, diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 726d759be..6fc24414c 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -193,7 +193,7 @@ static struct list all_bridges = LIST_INITIALIZER(&all_bridges); /* 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; @@ -285,7 +285,7 @@ void 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); @@ -297,31 +297,37 @@ bridge_init(const struct ovsrec_open_vswitch *cfg) 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); @@ -560,11 +566,16 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) 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); @@ -1071,31 +1082,35 @@ bridge_unixctl_fdb_show(struct unixctl_conn *conn, /* 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); diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index 2c7fdf18e..e9f615b68 100644 --- a/vswitchd/vswitch.ovsschema +++ b/vswitchd/vswitch.ovsschema @@ -31,6 +31,9 @@ "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},