From 1a6f1e2a6d6aea97f97fc378ec29f7d04ad8c047 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 22 Jan 2010 14:37:10 -0500 Subject: [PATCH] dpif: Update dpif interface to match netdev. This brings over some features that were added to the netdev interface, most notably the separation between the name and the type. In addition to being cleaner, this also avoids problems where it is expected that the local port has the same name as the datapath. --- lib/dpif-linux.c | 15 ++-- lib/dpif-netdev.c | 15 ++-- lib/dpif-provider.h | 29 +++---- lib/dpif.c | 150 ++++++++++++++++++++++++------------- lib/dpif.h | 17 ++--- lib/dpif.man | 10 ++- ofproto/ofproto.c | 5 +- ofproto/ofproto.h | 5 +- utilities/ovs-dpctl.c | 69 ++++++++++++----- utilities/ovs-ofctl.8.in | 11 ++- utilities/ovs-ofctl.c | 35 ++++++--- utilities/ovs-openflowd.c | 4 +- utilities/ovs-vsctl.c | 1 + vswitchd/bridge.c | 71 +++++++++++------- vswitchd/vswitch.ovsschema | 3 + 15 files changed, 273 insertions(+), 167 deletions(-) diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 2bf329f4..db69589a 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 1d496177..e9fb216f 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 020e017c..9a495443 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 793eaa11..5947179b 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 1d109c2d..aa54a387 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 3a58cafb..63e172fc 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 46b577af..941803d7 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 5fe8d774..cf99a399 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 ee545a61..fceab4c1 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 cf4ead96..17b5a400 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 61ca23e3..52ec0b6b 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 e0cfdc95..5e63f1b2 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 318f4293..07d9ae2c 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 726d759b..6fc24414 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 2c7fdf18..e9f615b6 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}, -- 2.30.2