Allow ovsdb-tool to accept a schema-list, a list of schema files, in addition to a single schema file, for all applicable options.
There is no limit on how many schemas can be joined together, but they can not have a shared schema name and they have to be compatible for joining. Compatible basically means overlapping tables and columns have to be of the same type. A single joined schema, formed by joining schemas from the schema-list, is used for DB operations. See man page changes for more details. Signed-off-by: Andy Zhou <az...@nicira.com> --- ovsdb/file.c | 41 ----------- ovsdb/file.h | 9 --- ovsdb/ovsdb-tool.1.in | 77 +++++++++++--------- ovsdb/ovsdb-tool.c | 193 +++++++++++++++++++++++++++++++++++++++----------- ovsdb/ovsdb.c | 6 +- ovsdb/ovsdb.h | 7 -- 6 files changed, 198 insertions(+), 135 deletions(-) diff --git a/ovsdb/file.c b/ovsdb/file.c index 7709047..74e0c09 100644 --- a/ovsdb/file.c +++ b/ovsdb/file.c @@ -117,26 +117,6 @@ ovsdb_file_open_as_schemas(const char *file_name, return ovsdb_file_open__(file_name, schemas, true, dbp, NULL); } -struct ovsdb_error * -ovsdb_file_open_as_schema(const char *file_name, - const struct ovsdb_schema *schema, - struct ovsdb **dbp) -{ - struct shash *schemas; - struct ovsdb_error *err; - - schemas = xmalloc(sizeof *schemas); - shash_init(schemas); - shash_add(schemas, schema->name, ovsdb_schema_clone(schema)); - - err = ovsdb_file_open__(file_name, schemas, true, dbp, NULL); - if (err) { - ovsdb_schemas_destroy(schemas); - } - - return err; -} - static struct ovsdb_error * ovsdb_file_open_log(const char *file_name, enum ovsdb_log_open_mode open_mode, struct ovsdb_log **logp, struct shash **schemasp) @@ -527,27 +507,6 @@ ovsdb_file_read_schemas(const char *file_name, struct shash **schemasp) return ovsdb_file_open_log(file_name, OVSDB_LOG_READ_ONLY, NULL, schemasp); } -struct ovsdb_error * -ovsdb_file_read_schema(const char *file_name, struct ovsdb_schema **schemap) -{ - struct shash *schemas = NULL; - struct ovsdb_schema *schema = NULL; - struct ovsdb_error *err; - - ovs_assert(schemap != NULL); - err = ovsdb_file_read_schemas(file_name, &schemas); - if (err) { - goto error; - } - - err = ovsdb_schemas_join(schemas, &schema); - ovsdb_schemas_destroy(schemas); - -error: - *schemap = schema; - return err; -} - /* Replica implementation. */ diff --git a/ovsdb/file.h b/ovsdb/file.h index 799c915..f40c2df 100644 --- a/ovsdb/file.h +++ b/ovsdb/file.h @@ -29,11 +29,6 @@ struct ovsdb_error *ovsdb_file_open(const char *file_name, bool read_only, struct ovsdb **, struct ovsdb_file **) OVS_WARN_UNUSED_RESULT; -struct ovsdb_error *ovsdb_file_open_as_schema(const char *file_name, - const struct ovsdb_schema *, - struct ovsdb **) - OVS_WARN_UNUSED_RESULT; - struct ovsdb_error *ovsdb_file_open_as_schemas(const char *file_name, const struct shash *, struct ovsdb **) @@ -46,10 +41,6 @@ struct ovsdb_error *ovsdb_file_save_copy(const char *file_name, int locking, struct ovsdb_error *ovsdb_file_compact(struct ovsdb_file *); -struct ovsdb_error *ovsdb_file_read_schema(const char *file_name, - struct ovsdb_schema **) - OVS_WARN_UNUSED_RESULT; - struct ovsdb_error *ovsdb_file_read_schemas(const char *file_name, struct shash **) OVS_WARN_UNUSED_RESULT; diff --git a/ovsdb/ovsdb-tool.1.in b/ovsdb/ovsdb-tool.1.in index a2f1f22..e6c04c9 100644 --- a/ovsdb/ovsdb-tool.1.in +++ b/ovsdb/ovsdb-tool.1.in @@ -12,22 +12,22 @@ ovsdb\-tool \- Open vSwitch database management utility . .SH SYNOPSIS -\fBovsdb\-tool \fR[\fIoptions\fR] \fBcreate \fR[\fIdb\fR [\fIschema\fR]] +\fBovsdb\-tool \fR[\fIoptions\fR] \fBcreate \fR[\fIdb\fR [\fIschema-list\fR]] .br \fBovsdb\-tool \fR[\fIoptions\fR] \fBcompact \fR[\fIdb\fR [\fItarget\fR]] .br -\fBovsdb\-tool \fR[\fIoptions\fR] \fBconvert \fR[\fIdb\fR [\fIschema +\fBovsdb\-tool \fR[\fIoptions\fR] \fBconvert \fR[\fIdb\fR [\fIschema-list \fR[\fItarget\fR]]] .br -\fBovsdb\-tool \fR[\fIoptions\fR] \fBneeds\-conversion \fR[\fIdb\fR [\fIschema\fR]] +\fBovsdb\-tool \fR[\fIoptions\fR] \fBneeds\-conversion \fR[\fIdb\fR [\fIschema-list\fR]] .br \fBovsdb\-tool \fR[\fIoptions\fR] \fBdb\-version \fR[\fIdb\fR] .br -\fBovsdb\-tool \fR[\fIoptions\fR] \fBschema\-version \fR[\fIschema\fR] +\fBovsdb\-tool \fR[\fIoptions\fR] \fBschema\-version \fR[\fIschema-list\fR] .br \fBovsdb\-tool \fR[\fIoptions\fR] \fBdb\-cksum \fR[\fIdb\fR] .br -\fBovsdb\-tool \fR[\fIoptions\fR] \fBschema\-cksum \fR[\fIschema\fR] +\fBovsdb\-tool \fR[\fIoptions\fR] \fBschema\-cksum \fR[\fIschema-list\fR] .br \fBovsdb\-tool \fR[\fIoptions\fR] \fBquery \fR[\fIdb\fR] \fItransaction\fR .br @@ -44,16 +44,22 @@ The \fBovsdb\-tool\fR program is a command-line tool for managing Open vSwitch database (OVSDB) files. It does not interact directly with running Open vSwitch database servers (instead, use \fBovsdb\-client\fR). -. + .SS "Basic Commands" -.IP "\fBcreate\fI db schema\fR" -Reads an OVSDB schema from the file named \fIschema\fR and creates a -new OVSDB database file named \fIdb\fR using that schema. The new +.IP "\fBcreate\fI db schema-list\fR" +Reads OVSDB schemas from the files listed in \fIschema-list\fR and creates a +new OVSDB database file named \fIdb\fR using those schemas. The new database is initially empty. This command will not overwrite an existing \fIdb\fR. + .IP -\fIschema\fR must contain an OVSDB schema in JSON format. Refer to -the OVSDB specification for details. +The \fIschema-list\fR argument accepts either a single file name, or a +comma seperated list of file names. Quating is usually required for them +to appear as a single argument to ovsdb-tool. Schemas can not share +the same name. + +Each \fBschema\fR must containan OVSDB schema in JSON format. +Refer to the OVSDB specification for details. . .IP "\fBcompact\fI db \fR[\fItarget\fR]" Reads \fIdb\fR and writes a compacted version. If \fItarget\fR is @@ -62,47 +68,52 @@ specified, the compacted version is written as a new file named omitted, then the compacted version of the database replaces \fIdb\fR in-place. . -.IP "\fBconvert\fI db schema \fR[\fItarget\fR]" -Reads \fIdb\fR, translating it into to the schema specified in -\fIschema\fR, and writes out the new interpretation. If \fItarget\fR +.IP "\fBconvert\fI db schema-list \fR[\fItarget\fR]" +Reads \fIdb\fR, translating it into to the schemas specified in +\fIschema-list\fR, and writes out the new interpretation. If \fItarget\fR is specified, the translated version is written as a new file named \fItarget\fR, which must not already exist. If \fItarget\fR is omitted, then the translated version of the database replaces \fIdb\fR in-place. .IP This command can do simple ``upgrades'' and ``downgrades'' on a -database's schema. The data in \fIdb\fR must be valid when -interpreted under \fIschema\fR, with only one exception: data in -\fIdb\fR for tables and columns that do not exist in \fIschema\fR are -ignored. Columns that exist in \fIschema\fR but not in \fIdb\fR are -set to their default values. All of \fIschema\fR's constraints apply +database's schemas. The data in \fIdb\fR must be valid when +interpreted under \fIschema-list\fR, with only one exception: data in +\fIdb\fR for tables and columns that do not exist in \fIschema-list\fR are +ignored. Columns that exist in \fIschema-list\fR but not in \fIdb\fR are +set to their default values. All of \fIschema-list\fR's constraints apply in full. . -.IP "\fBneeds\-conversion\fI db schema\fR" -Reads the schema embedded in \fIdb\fR and the standalone schema in -\fIschema\fR and compares them. If the schemas are the same, prints +.IP "\fBneeds\-conversion\fI db schema-list\fR" +Reads the schemas embedded in \fIdb\fR and the standalone schemas in +\fIschema-list\fR and compares them. If the schemas are the same, prints \fBno\fR on stdout; if they differ, print \fByes\fR. . .IP "\fBdb\-version\fI db\fR" -.IQ "\fBschema\-version\fI schema\fR" -Prints the version number in the schema embedded within the database -\fIdb\fR or in the standalone schema \fIschema\fR on stdout. A schema -version number has the form \fIx\fB.\fIy\fB.\fIz\fR. See -\fBovs\-vswitchd.conf.db\fR(5) for details. +.IQ "\fBschema\-version\fI schema-list\fR" +Prints the version number in the schemas embedded within the database +\fIdb\fR or in the standalone schemas \fIschema-list\fR on stdout. A single +schema version number has the form \fIx\fB.\fIy\fB.\fIz\fR. +Multiple schemas have the form \fIschema-name\fB:\fIx\fB.\fIy\fB.\fIz\fR. +One line per schema. See \fBovs\-vswitchd.conf.db\fR(5) for details. + .IP Schema version numbers and Open vSwitch version numbers are independent. .IP -If \fIschema\fR or \fIdb\fR was created before schema versioning was +If \fIschema-list\fR or \fIdb\fR was created before schema versioning was introduced, then it will not have a version number and this command will print a blank line. . .IP "\fBdb\-cksum\fI db\fR" -.IQ "\fBschema\-cksum\fI schema\fR" -Prints the checksum in the schema embedded within the database -\fIdb\fR or of the standalone schema \fIschema\fR on stdout. +.IQ "\fBschema\-cksum\fI schema-list\fR" +Prints the checksum in the schemas embedded within the database +\fIdb\fR or of the standalone schemas \fIschema-list\fR on stdout. +Multiple schemas output are prefixed with \fIschema-name\fB:\fR. +One line per schema. + .IP -If \fIschema\fR or \fIdb\fR was created before schema checksums were +If \fIschema-list\fR or \fIdb\fR was created before schema checksums were introduced, then it will not have a checksum and this command will print a blank line. . @@ -149,7 +160,7 @@ record. .so lib/common.man .SH "FILES" The default \fIdb\fR is \fB@DBDIR@/conf.db\fR. The -default \fIschema\fR is \fB@pkgdatadir@/vswitch.ovsschema\fR. The +default \fIschema-list\fR is \fB@pkgdatadir@/vswitch.ovsschema\fR. The \fBhelp\fR command also displays these defaults. .SH "SEE ALSO" . diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c index 32883e2..49a4cbe 100644 --- a/ovsdb/ovsdb-tool.c +++ b/ovsdb/ovsdb-tool.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,7 +35,9 @@ #include "ovsdb.h" #include "ovsdb-data.h" #include "ovsdb-error.h" +#include "shash.h" #include "socket-util.h" +#include "sset.h" #include "table.h" #include "timeval.h" #include "util.h" @@ -188,20 +190,33 @@ check_ovsdb_error(struct ovsdb_error *error) ovs_fatal(0, "%s", ovsdb_error_to_string(error)); } } + +static void +parse_schema_file_names(const char *file_names, struct sset *names) +{ + ovsdb_parse_schema_file_names(file_names, names, default_schema()); + ovs_assert(!sset_is_empty(names)); +} + static void do_create(struct ovs_cmdl_context *ctx) { const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); - const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : default_schema(); - struct ovsdb_schema *schema; + const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : NULL; struct ovsdb_log *log; struct json *json; + struct shash *schemas; + struct sset schema_names = SSET_INITIALIZER(&schema_names); - /* Read schema from file and convert to JSON. */ - check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema)); - json = ovsdb_schema_to_json(schema); - ovsdb_schema_destroy(schema); + /* Read schema from file(s) and convert to JSON. */ + parse_schema_file_names(schema_file_name, &schema_names); + + check_ovsdb_error(ovsdb_schemas_from_files(&schema_names, &schemas)); + sset_destroy(&schema_names); + + json = ovsdb_schemas_to_json(schemas); + ovsdb_schemas_destroy(schemas); /* Create database file. */ check_ovsdb_error(ovsdb_log_open(db_file_name, OVSDB_LOG_CREATE, @@ -215,7 +230,7 @@ do_create(struct ovs_cmdl_context *ctx) static void compact_or_convert(const char *src_name_, const char *dst_name_, - const struct ovsdb_schema *new_schema, + struct shash *new_schemas, const char *comment) { char *src_name, *dst_name; @@ -249,8 +264,8 @@ compact_or_convert(const char *src_name_, const char *dst_name_, } /* Save a copy. */ - check_ovsdb_error(new_schema - ? ovsdb_file_open_as_schema(src_name, new_schema, &db) + check_ovsdb_error(new_schemas + ? ovsdb_file_open_as_schemas(src_name, new_schemas, &db) : ovsdb_file_open(src_name, true, &db, NULL)); check_ovsdb_error(ovsdb_file_save_copy(dst_name, false, comment, db)); ovsdb_destroy(db); @@ -287,72 +302,158 @@ static void do_convert(struct ovs_cmdl_context *ctx) { const char *db = ctx->argc >= 2 ? ctx->argv[1] : default_db(); - const char *schema = ctx->argc >= 3 ? ctx->argv[2] : default_schema(); + const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : NULL; const char *target = ctx->argc >= 4 ? ctx->argv[3] : NULL; - struct ovsdb_schema *new_schema; + struct shash *schemas; + struct sset schema_names = SSET_INITIALIZER(&schema_names); + + parse_schema_file_names(schema_file_name, &schema_names); + check_ovsdb_error(ovsdb_schemas_from_files(&schema_names, &schemas)); + sset_destroy(&schema_names); - check_ovsdb_error(ovsdb_schema_from_file(schema, &new_schema)); - compact_or_convert(db, target, new_schema, + compact_or_convert(db, target, schemas, "converted by ovsdb-tool "VERSION); - ovsdb_schema_destroy(new_schema); + ovsdb_schemas_destroy(schemas); } static void do_needs_conversion(struct ovs_cmdl_context *ctx) { const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); - const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : default_schema(); - struct ovsdb_schema *schema1, *schema2; - - check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema1)); - check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema2)); - puts(ovsdb_schema_equal(schema1, schema2) ? "no" : "yes"); - ovsdb_schema_destroy(schema1); - ovsdb_schema_destroy(schema2); + const char *schema_file_name = ctx->argc >= 3 ? ctx->argv[2] : NULL; + struct sset schema_names = SSET_INITIALIZER(&schema_names); + struct shash *schemas1; + struct shash *schemas2; + struct shash_node *node1, *node2; + + /* Read schema from file(s) and convert to JSON. */ + parse_schema_file_names(schema_file_name, &schema_names); + check_ovsdb_error(ovsdb_schemas_from_files(&schema_names, &schemas1)); + sset_destroy(&schema_names); + + check_ovsdb_error(ovsdb_file_read_schemas(db_file_name, &schemas2)); + + if (shash_count(schemas1) == shash_count(schemas2)) { + SHASH_FOR_EACH (node1, schemas1) { + struct ovsdb_schema *schema1 = node1->data, *schema2; + + node2 = shash_find(schemas2, schema1->name); + if (!node2) { + /* Schmea names do not overlap. Conversion is necessary. */ + puts("yes"); + goto done; + } + + schema2 = node2->data; + if(!ovsdb_schema_equal(schema1, schema2)) { + /* Schemas that have the same name are not equivalent. + * Conversion is necessary. */ + puts("yes"); + goto done; + } + } + /* All schemas are identical, No conversion is necessary */ + puts("no"); + } + +done: + ovsdb_schemas_destroy(schemas1); + ovsdb_schemas_destroy(schemas2); } static void do_db_version(struct ovs_cmdl_context *ctx) { const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); + struct shash *schemas; struct ovsdb_schema *schema; - check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema)); - puts(schema->version); - ovsdb_schema_destroy(schema); + check_ovsdb_error(ovsdb_file_read_schemas(db_file_name, &schemas)); + + if (shash_count(schemas) == 1) { + schema = shash_first(schemas)->data; + puts(schema->version); + } else { + struct shash_node *node; + SHASH_FOR_EACH (node, schemas) { + schema = node->data; + printf("%s:%s\n", schema->name, schema->version); + } + } + + ovsdb_schemas_destroy(schemas); } static void do_db_cksum(struct ovs_cmdl_context *ctx) { const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); + struct shash *schemas; struct ovsdb_schema *schema; - check_ovsdb_error(ovsdb_file_read_schema(db_file_name, &schema)); - puts(schema->cksum); - ovsdb_schema_destroy(schema); + check_ovsdb_error(ovsdb_file_read_schemas(db_file_name, &schemas)); + + if (shash_count(schemas) == 1) { + schema = shash_first(schemas)->data; + puts(schema->cksum); + } else { + struct shash_node *node; + SHASH_FOR_EACH (node, schemas) { + schema = node->data; + printf("%s:%s\n", schema->name, schema->cksum); + } + } + ovsdb_schemas_destroy(schemas); } static void do_schema_version(struct ovs_cmdl_context *ctx) { const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_schema(); + struct shash *schemas; struct ovsdb_schema *schema; - - check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema)); - puts(schema->version); - ovsdb_schema_destroy(schema); + struct sset schema_names = SSET_INITIALIZER(&schema_names); + + parse_schema_file_names(schema_file_name, &schema_names); + check_ovsdb_error(ovsdb_schemas_from_files(&schema_names, &schemas)); + sset_destroy(&schema_names); + + if (shash_count(schemas) == 1) { + schema = shash_first(schemas)->data; + puts(schema->version); + } else { + struct shash_node *node; + SHASH_FOR_EACH (node, schemas) { + schema = node->data; + printf("%s:%s\n", schema->name, schema->version); + } + } + ovsdb_schemas_destroy(schemas); } static void do_schema_cksum(struct ovs_cmdl_context *ctx) { - const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_schema(); + const char *schema_file_name = ctx->argc >= 2 ? ctx->argv[1] : NULL; + struct shash *schemas; struct ovsdb_schema *schema; - - check_ovsdb_error(ovsdb_schema_from_file(schema_file_name, &schema)); - puts(schema->cksum); - ovsdb_schema_destroy(schema); + struct sset schema_names = SSET_INITIALIZER(&schema_names); + + parse_schema_file_names(schema_file_name, &schema_names); + check_ovsdb_error(ovsdb_schemas_from_files(&schema_names, &schemas)); + sset_destroy(&schema_names); + + if (shash_count(schemas) == 1) { + schema = shash_first(schemas)->data; + puts(schema->cksum); + } else { + struct shash_node *node; + SHASH_FOR_EACH (node, schemas) { + schema = node->data; + printf("%s:%s\n", schema->name, schema->cksum); + } + } + ovsdb_schemas_destroy(schemas); } static void @@ -503,13 +604,13 @@ do_show_log(struct ovs_cmdl_context *ctx) const char *db_file_name = ctx->argc >= 2 ? ctx->argv[1] : default_db(); struct shash names; struct ovsdb_log *log; + struct shash *schemas; struct ovsdb_schema *schema; unsigned int i; check_ovsdb_error(ovsdb_log_open(db_file_name, OVSDB_LOG_READ_ONLY, -1, &log)); shash_init(&names); - schema = NULL; for (i = 0; ; i++) { struct json *json; @@ -520,9 +621,16 @@ do_show_log(struct ovs_cmdl_context *ctx) printf("record %u:", i); if (i == 0) { - check_ovsdb_error(ovsdb_schema_from_json(json, &schema)); - printf(" \"%s\" schema, version=\"%s\", cksum=\"%s\"\n", - schema->name, schema->version, schema->cksum); + struct shash_node *node; + + check_ovsdb_error(ovsdb_schemas_from_json(json, &schemas)); + SHASH_FOR_EACH (node, schemas) { + struct ovsdb_schema *schema = node->data; + + printf(" \"%s\" schema, version=\"%s\", cksum=\"%s\"\n", + schema->name, schema->version, schema->cksum); + } + check_ovsdb_error(ovsdb_schemas_join(schemas, &schema)); } else if (json->type == JSON_OBJECT) { struct json *date, *comment; @@ -556,6 +664,7 @@ do_show_log(struct ovs_cmdl_context *ctx) } ovsdb_log_close(log); + ovsdb_schemas_destroy(schemas); ovsdb_schema_destroy(schema); /* XXX free 'names'. */ } diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c index 5305360..287b839 100644 --- a/ovsdb/ovsdb.c +++ b/ovsdb/ovsdb.c @@ -28,7 +28,7 @@ #include "table.h" #include "transaction.h" -struct ovsdb_schema * +static struct ovsdb_schema * ovsdb_schema_create(const char *name, const char *version, const char *cksum) { struct ovsdb_schema *schema; @@ -42,7 +42,7 @@ ovsdb_schema_create(const char *name, const char *version, const char *cksum) return schema; } -struct ovsdb_schema * +static struct ovsdb_schema * ovsdb_schema_clone(const struct ovsdb_schema *old) { struct ovsdb_schema *new; @@ -115,7 +115,7 @@ ovsdb_schema_join(struct ovsdb_schema *dst, const struct ovsdb_schema *src) return NULL; } -struct ovsdb_error * +static struct ovsdb_error * ovsdb_schema_from_file(const char *file_name, struct ovsdb_schema **schemap) { struct ovsdb_schema *schema; diff --git a/ovsdb/ovsdb.h b/ovsdb/ovsdb.h index b61b6ba..4af6cab 100644 --- a/ovsdb/ovsdb.h +++ b/ovsdb/ovsdb.h @@ -37,15 +37,8 @@ struct ovsdb_schema { struct shash tables; /* Contains "struct ovsdb_table_schema *"s. */ }; -struct ovsdb_schema *ovsdb_schema_create(const char *name, - const char *version, - const char *cksum); -struct ovsdb_schema *ovsdb_schema_clone(const struct ovsdb_schema *); void ovsdb_schema_destroy(struct ovsdb_schema *); -struct ovsdb_error *ovsdb_schema_from_file(const char *file_name, - struct ovsdb_schema **) - OVS_WARN_UNUSED_RESULT; struct ovsdb_error *ovsdb_schema_from_json(struct json *, struct ovsdb_schema **) OVS_WARN_UNUSED_RESULT; -- 1.9.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev