[ovs-dev] [ovsdb join 4/5] ovsdb: expand ovsdb-tool to support multiple schemas
Ansis Atteka
ansisatteka at gmail.com
Sun Jun 21 21:10:30 UTC 2015
On 15 June 2015 at 19:35, Andy Zhou <azhou at nicira.com> wrote:
> ovsdb-tool now accepts multiple schema files for all applicable options.
If these schema can be joined together without compatibility error,
>
s/schema/[schemas|schemata]
> the joined schema will be used as the runtime DB schema.
>
> When storing joined schemata into a database file, A JSON array will
> be store as its first record, with every individual schema as the
>
s/store/stored
> element of the array. The joined schema is not stored into the file.
> Since one can be rebuilt by rejoining the schmeata represented by
> the JSON array.
>
This file also requires updates to man pages.
>
> Signed-off-by: Andy Zhou <azhou at nicira.com>
> ---
> ovsdb/file.c | 85 ++++++++++++++----------
> ovsdb/file.h | 14 ++--
> ovsdb/ovsdb-server.c | 2 +-
> ovsdb/ovsdb-tool.c | 178
> +++++++++++++++++++++++++++++++++++++++------------
> 4 files changed, 199 insertions(+), 80 deletions(-)
>
> diff --git a/ovsdb/file.c b/ovsdb/file.c
> index 8c3c31b..041b538 100644
> --- a/ovsdb/file.c
> +++ b/ovsdb/file.c
> @@ -64,7 +64,7 @@ static struct ovsdb_error *ovsdb_file_txn_commit(struct
> json *,
> struct ovsdb_log *);
>
> static struct ovsdb_error *ovsdb_file_open__(const char *file_name,
> - const struct ovsdb_schema *,
> + struct shash *schemata,
> bool read_only, struct ovsdb
> **,
> struct ovsdb_file **);
> static struct ovsdb_error *ovsdb_file_txn_from_json(
> @@ -85,20 +85,28 @@ static struct ovsdb_error *ovsdb_file_create(struct
> ovsdb *,
> * '*filep' to an ovsdb_file that represents the open file. This
> ovsdb_file
> * persists until '*dbp' is destroyed.
> *
> + * If 'schemata' is nonnull, it needs to be an empty shash. On success,
> + * it contains the schemata read from the log file. Caller is repsonsible
> + * for freeing memory.
+ *
> * On success, returns NULL. On failure, returns an ovsdb_error (which
> the
> * caller must destroy) and sets '*dbp' and '*filep' to NULL. */
> struct ovsdb_error *
> ovsdb_file_open(const char *file_name, bool read_only,
> - struct ovsdb **dbp, struct ovsdb_file **filep)
> + struct ovsdb **dbp, struct ovsdb_file **filep,
> + struct shash *schemata)
> {
> - return ovsdb_file_open__(file_name, NULL, read_only, dbp, filep);
> + if (schemata) {
> + ovs_assert(shash_count(schemata) == 0);
> + }
> + return ovsdb_file_open__(file_name, schemata, read_only, dbp, filep);
> }
>
> -/* Opens database 'file_name' with an alternate schema. The specified
> 'schema'
> - * is used to interpret the data in 'file_name', ignoring the schema
> actually
> - * stored in the file. Data in the file for tables or columns that do not
> - * exist in 'schema' are ignored, but the ovsdb file format must
> otherwise be
> - * observed, including column constraints.
> +/* Opens database 'file_name' with an alternate schemata. The specified
> + * 'schemata' * is used to interpret the data in 'file_name', ignoring the
> + * schemata actually stored in the file. Data in the file for tables or
> + * columns that do not exist in 'schemata' are ignored, but the ovsdb file
> + * format must otherwise be observed, including column constraints.
> *
> * This function can be useful for upgrading or downgrading databases to
> * "almost-compatible" formats.
> @@ -110,23 +118,22 @@ ovsdb_file_open(const char *file_name, bool
> read_only,
> * null pointer. On failure, returns an ovsdb_error (which the caller
> must
> * destroy) and sets '*dbp' to NULL. */
> struct ovsdb_error *
> -ovsdb_file_open_as_schema(const char *file_name,
> - const struct ovsdb_schema *schema,
> - struct ovsdb **dbp)
> +ovsdb_file_open_as_schemata(const char *file_name,
> + struct shash *schemata,
> + struct ovsdb **dbp)
> {
> - return ovsdb_file_open__(file_name, schema, true, dbp, NULL);
> + return ovsdb_file_open__(file_name, schemata, true, dbp, NULL);
> }
>
> static struct ovsdb_error *
> ovsdb_file_open_log(const char *file_name, enum ovsdb_log_open_mode
> open_mode,
> - struct ovsdb_log **logp, struct ovsdb_schema
> **schemap)
> + struct ovsdb_log **logp, struct shash *schemata)
> {
> - struct ovsdb_schema *schema = NULL;
> struct ovsdb_log *log = NULL;
> struct ovsdb_error *error;
> struct json *json = NULL;
>
> - ovs_assert(logp || schemap);
> + ovs_assert(logp || schemata);
>
> error = ovsdb_log_open(file_name, open_mode, -1, &log);
> if (error) {
> @@ -142,8 +149,8 @@ ovsdb_file_open_log(const char *file_name, enum
> ovsdb_log_open_mode open_mode,
> goto error;
> }
>
> - if (schemap) {
> - error = ovsdb_schema_from_json(json, &schema);
> + if (ovsdb_schemata_is_empty(schemata)) {
> + error = ovsdb_schemata_from_json(json, schemata);
> if (error) {
> error = ovsdb_wrap_error(error,
> "failed to parse \"%s\" as ovsdb
> schema",
> @@ -158,9 +165,6 @@ ovsdb_file_open_log(const char *file_name, enum
> ovsdb_log_open_mode open_mode,
> } else {
> ovsdb_log_close(log);
> }
> - if (schemap) {
> - *schemap = schema;
> - }
> return NULL;
>
> error:
> @@ -169,44 +173,57 @@ error:
> if (logp) {
> *logp = NULL;
> }
> - if (schemap) {
> - *schemap = NULL;
> - }
> return error;
> }
>
> static struct ovsdb_error *
> ovsdb_file_open__(const char *file_name,
> - const struct ovsdb_schema *alternate_schema,
> + struct shash *schemata,
> bool read_only, struct ovsdb **dbp,
> struct ovsdb_file **filep)
> {
> enum ovsdb_log_open_mode open_mode;
> unsigned int n_transactions;
> - struct ovsdb_schema *schema = NULL;
> + struct ovsdb_schema *joined_schema;
> struct ovsdb_error *error;
> struct ovsdb_log *log;
> struct json *json;
> struct ovsdb *db = NULL;
> + bool convert = ovsdb_schemata_is_non_empty(schemata);
> + struct shash local_schemata = SHASH_INITIALIZER(&local_schemata);
> +
> + /* If caller passed in non empty 'schemata', we will use it
> + * instead of the schemata stored int the log file. Otherwise,
> + * it will be the container for storing the schemata read from
> + * the log file. */
> + if (!schemata) {
> + /* Caller don't need the schmeta information, we use
> 'local_schemata'
>
typo "schmeta"
> + * to read it from the db file. */
> + schemata = &local_schemata;
> + }
>
> /* In read-only mode there is no ovsdb_file so 'filep' must be null.
> */
> ovs_assert(!(read_only && filep));
>
> open_mode = read_only ? OVSDB_LOG_READ_ONLY : OVSDB_LOG_READ_WRITE;
> - error = ovsdb_file_open_log(file_name, open_mode, &log,
> - alternate_schema ? NULL : &schema);
> + error = ovsdb_file_open_log(file_name, open_mode, &log, schemata);
> + if (error) {
> + goto error;
> + }
> +
> + error = ovsdb_schemata_join(schemata, &joined_schema);
> if (error) {
> goto error;
> }
>
> - db = ovsdb_create(schema ? schema :
> ovsdb_schema_clone(alternate_schema));
> + /* 'db' will take the ownership of joined_schema */
> + db = ovsdb_create(joined_schema);
>
> n_transactions = 0;
> while ((error = ovsdb_log_read(log, &json)) == NULL && json) {
> struct ovsdb_txn *txn;
>
> - error = ovsdb_file_txn_from_json(db, json, alternate_schema !=
> NULL,
> - &txn);
> + error = ovsdb_file_txn_from_json(db, json, convert, &txn);
> json_destroy(json);
> if (error) {
> ovsdb_log_unread(log);
> @@ -246,6 +263,7 @@ ovsdb_file_open__(const char *file_name,
> }
>
> *dbp = db;
>
For example, ovsdb_file_open_log()->ovsdb_schemata_from_json() might have
already called ovsdb_schemata_destroy() for you in case of error. So this
would potentially lead to double free. Is it right?
> + ovsdb_schemata_destroy(&local_schemata);
> return NULL;
>
> error:
> @@ -253,6 +271,7 @@ error:
> if (filep) {
> *filep = NULL;
> }
> + ovsdb_schemata_destroy(&local_schemata);
> ovsdb_destroy(db);
> ovsdb_log_close(log);
> return error;
> @@ -484,10 +503,10 @@ ovsdb_file_save_copy(const char *file_name, int
> locking,
> * schema. On failure, returns an ovsdb_error (which the caller must
> destroy)
> * and sets '*dbp' to NULL. */
> struct ovsdb_error *
> -ovsdb_file_read_schema(const char *file_name, struct ovsdb_schema
> **schemap)
> +ovsdb_file_read_schemata(const char *file_name, struct shash *schemata)
> {
> - ovs_assert(schemap != NULL);
> - return ovsdb_file_open_log(file_name, OVSDB_LOG_READ_ONLY, NULL,
> schemap);
> + ovs_assert(schemata && ovsdb_schemata_is_empty(schemata));
> + return ovsdb_file_open_log(file_name, OVSDB_LOG_READ_ONLY, NULL,
> schemata);
> }
>
> /* Replica implementation. */
> diff --git a/ovsdb/file.h b/ovsdb/file.h
> index ee67b12..aaa9c8c 100644
> --- a/ovsdb/file.h
> +++ b/ovsdb/file.h
> @@ -18,6 +18,7 @@
>
> #include <stdbool.h>
> #include "compiler.h"
> +#include "shash.h"
> #include "log.h"
>
> struct ovsdb;
> @@ -25,12 +26,13 @@ struct ovsdb_file;
> struct ovsdb_schema;
>
> struct ovsdb_error *ovsdb_file_open(const char *file_name, bool read_only,
> - struct ovsdb **, struct ovsdb_file **)
> + struct ovsdb **, struct ovsdb_file **,
> + struct shash *schemata)
> OVS_WARN_UNUSED_RESULT;
>
> -struct ovsdb_error *ovsdb_file_open_as_schema(const char *file_name,
> - const struct ovsdb_schema *,
> - struct ovsdb **)
> +struct ovsdb_error *ovsdb_file_open_as_schemata(const char *file_name,
> + struct shash *schemata,
> + struct ovsdb **)
> OVS_WARN_UNUSED_RESULT;
>
> struct ovsdb_error *ovsdb_file_save_copy(const char *file_name, int
> locking,
> @@ -40,8 +42,8 @@ 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 **)
> +struct ovsdb_error *ovsdb_file_read_schemata(const char *file_name,
> + struct shash *schemata)
> OVS_WARN_UNUSED_RESULT;
>
> #endif /* ovsdb/file.h */
> diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
> index cd13b0d..c52af17 100644
> --- a/ovsdb/ovsdb-server.c
> +++ b/ovsdb/ovsdb-server.c
> @@ -407,7 +407,7 @@ open_db(struct server_config *config, const char
> *filename)
> db = xzalloc(sizeof *db);
> db->filename = xstrdup(filename);
>
> - db_error = ovsdb_file_open(db->filename, false, &db->db, &db->file);
> + db_error = ovsdb_file_open(db->filename, false, &db->db, &db->file,
> NULL);
> if (db_error) {
> error = ovsdb_error_to_string(db_error);
> } else if (!ovsdb_jsonrpc_server_add_db(config->jsonrpc, db->db)) {
> diff --git a/ovsdb/ovsdb-tool.c b/ovsdb/ovsdb-tool.c
> index 32883e2..a91d8b2 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.
> @@ -38,7 +38,9 @@
> #include "socket-util.h"
> #include "table.h"
> #include "timeval.h"
> +#include "sset.h"
>
Alphabetical order?
> #include "util.h"
> +#include "shash.h"
> #include "openvswitch/vlog.h"
>
> /* -m, --more: Verbosity level for "show-log" command output. */
> @@ -56,12 +58,14 @@ int
> main(int argc, char *argv[])
> {
> struct ovs_cmdl_context ctx = { .argc = 0, };
> +
> set_program_name(argv[0]);
> parse_options(argc, argv);
> fatal_ignore_sigpipe();
> ctx.argc = argc - optind;
> ctx.argv = argv + optind;
> ovs_cmdl_run_command(&ctx, get_all_commands());
> +
> return 0;
> }
>
> @@ -188,20 +192,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 schemata = SHASH_INITIALIZER(&schemata);
> + 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_schemata_from_files(&schema_names,
> &schemata));
> + sset_destroy(&schema_names);
> +
> + json = ovsdb_schemata_to_json(&schemata);
> + ovsdb_schemata_destroy(&schemata);
>
> /* Create database file. */
> check_ovsdb_error(ovsdb_log_open(db_file_name, OVSDB_LOG_CREATE,
> @@ -215,7 +232,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_schemata,
> const char *comment)
> {
> char *src_name, *dst_name;
> @@ -249,9 +266,9 @@ 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)
> - : ovsdb_file_open(src_name, true, &db, NULL));
> + check_ovsdb_error(ovsdb_schemata_is_null_or_empty(new_schemata)
> + ? ovsdb_file_open(src_name, true, &db, NULL,
> new_schemata)
> + : ovsdb_file_open_as_schemata(src_name,
> new_schemata, &db));
> check_ovsdb_error(ovsdb_file_save_copy(dst_name, false, comment, db));
> ovsdb_destroy(db);
>
> @@ -287,72 +304,153 @@ 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 schemata = SHASH_INITIALIZER(&schemata);
> + struct sset schema_names = SSET_INITIALIZER(&schema_names);
>
> - check_ovsdb_error(ovsdb_schema_from_file(schema, &new_schema));
> - compact_or_convert(db, target, new_schema,
> + parse_schema_file_names(schema_file_name, &schema_names);
> + check_ovsdb_error(ovsdb_schemata_from_files(&schema_names,
> &schemata));
> + sset_destroy(&schema_names);
> +
> + compact_or_convert(db, target, &schemata,
> "converted by ovsdb-tool "VERSION);
> - ovsdb_schema_destroy(new_schema);
> + ovsdb_schemata_destroy(&schemata);
> }
>
> 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 shash schemata1 = SHASH_INITIALIZER(&schemata1);
> + struct shash schemata2 = SHASH_INITIALIZER(&schemata2);
> + struct shash_node *node1, *node2;
> + bool need_conversion = false;
> + struct sset schema_names = SSET_INITIALIZER(&schema_names);
> +
> +
> + /* Read schema from file(s) and convert to JSON. */
> + parse_schema_file_names(schema_file_name, &schema_names);
> + check_ovsdb_error(ovsdb_schemata_from_files(&schema_names,
> &schemata1));
> + sset_destroy(&schema_names);
> +
> + check_ovsdb_error(ovsdb_file_read_schemata(db_file_name, &schemata2));
> +
> + SHASH_FOR_EACH (node1, &schemata1) {
> + struct ovsdb_schema *schema1 = node1->data;
> +
> + node2 = shash_find(&schemata2, schema1->name);
> + if (node2) {
> + const struct ovsdb_schema *schema2 = node2->data;
> +
> + need_conversion = ovsdb_schema_equal(schema1, schema2);
> + }
> +
> + if (!need_conversion) {
> + break;
> + }
> + }
> +
> + puts(need_conversion ? "no" : "yes");
>
Do you have this reverse way? ovsdb-tool man page says this:
needs-conversion db schema
Reads the schema embedded in db and the standalone schema
in
schema and compares them. If the schemas are the same,
prints
no on stdout; if they differ, print yes.
in your case I think "need_conversion" actually should be renamed to
"schemas_are_equal" because "need_conversion" is negation of that?
> +
> + ovsdb_schemata_destroy(&schemata1);
> + ovsdb_schemata_destroy(&schemata2);
> }
>
> 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 schemata = SHASH_INITIALIZER(&schemata);
> 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_schemata(db_file_name, &schemata));
> +
> + if (shash_count(&schemata) == 1) {
> + schema = shash_first(&schemata)->data;
> + puts(schema->version);
> + } else {
> + struct shash_node *node;
> + SHASH_FOR_EACH (node, &schemata) {
> + schema = node->data;
> + printf("%s:%s\n", schema->name, schema->version);
> + }
> + }
> +
> + ovsdb_schemata_destroy(&schemata);
> }
>
> 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 schemata = SHASH_INITIALIZER(&schemata);
> 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_schemata(db_file_name, &schemata));
> +
> + if (shash_count(&schemata) == 1) {
> + schema = shash_first(&schemata)->data;
> + puts(schema->cksum);
> + } else {
> + struct shash_node *node;
> + SHASH_FOR_EACH (node, &schemata) {
> + schema = node->data;
> + printf("%s:%s\n", schema->name, schema->cksum);
> + }
> + }
> + ovsdb_schemata_destroy(&schemata);
> }
>
> 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 schemata = SHASH_INITIALIZER(&schemata);
> 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_schemata_from_files(&schema_names,
> &schemata));
> + sset_destroy(&schema_names);
> +
> + if (shash_count(&schemata) == 1) {
> + schema = shash_first(&schemata)->data;
> + puts(schema->version);
> + } else {
> + struct shash_node *node;
> + SHASH_FOR_EACH (node, &schemata) {
> + schema = node->data;
> + printf("%s:%s\n", schema->name, schema->version);
> + }
> + }
> + ovsdb_schemata_destroy(&schemata);
> }
>
> 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 schemata = SHASH_INITIALIZER(&schemata);
> 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_schemata_from_files(&schema_names,
> &schemata));
+ sset_destroy(&schema_names);
> +
> + if (shash_count(&schemata) == 1) {
> + schema = shash_first(&schemata)->data;
> + puts(schema->cksum);
> + } else {
> + struct shash_node *node;
> + SHASH_FOR_EACH (node, &schemata) {
> + schema = node->data;
> + printf("%s:%s\n", schema->name, schema->cksum);
> + }
> + }
>
+ ovsdb_schemata_destroy(&schemata);
> }
>
> static void
> @@ -363,7 +461,7 @@ transact(bool read_only, int argc, char *argv[])
> struct json *request, *result;
> struct ovsdb *db;
>
> - check_ovsdb_error(ovsdb_file_open(db_file_name, read_only, &db,
> NULL));
> + check_ovsdb_error(ovsdb_file_open(db_file_name, read_only, &db, NULL,
> NULL));
>
> request = parse_json(transaction);
> result = ovsdb_execute(db, NULL, request, 0, NULL);
> --
> 1.9.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
More information about the dev
mailing list