From: Ben Pfaff Date: Fri, 22 Oct 2010 21:46:30 +0000 (-0700) Subject: ovs-vsctl: Check for dirty reads within transactions. X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=ac4ec5f6e1685d60a0dda58fea77ec736761e2a2 ovs-vsctl: Check for dirty reads within transactions. OVSDB is transactional but it does not implement any form of locking. This means that read-modify-write operations must verify that the values that they read are still in place before writing. This commit adds such checking. Bug #2387. Bug #3856. Bug #3906. --- diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index f370d6ba4..916ac659a 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -507,6 +507,7 @@ struct vsctl_context { struct ovsdb_idl_txn *txn; struct ovsdb_symbol_table *symtab; const struct ovsrec_open_vswitch *ovs; + bool verified_ports; /* A command may set this member to true if some prerequisite is not met * and the caller should wait for something to change and then retry. */ @@ -564,6 +565,25 @@ vsctl_context_to_string(const struct vsctl_context *ctx) return s; } +static void +verify_ports(struct vsctl_context *ctx) +{ + if (!ctx->verified_ports) { + const struct ovsrec_bridge *bridge; + const struct ovsrec_port *port; + + ovsrec_open_vswitch_verify_bridges(ctx->ovs); + OVSREC_BRIDGE_FOR_EACH (bridge, ctx->idl) { + ovsrec_bridge_verify_ports(bridge); + } + OVSREC_PORT_FOR_EACH (port, ctx->idl) { + ovsrec_port_verify_interfaces(port); + } + + ctx->verified_ports = true; + } +} + static struct vsctl_bridge * add_bridge(struct vsctl_info *b, struct ovsrec_bridge *br_cfg, const char *name, @@ -740,6 +760,8 @@ check_conflicts(struct vsctl_info *info, const char *name, struct vsctl_iface *iface; struct vsctl_port *port; + verify_ports(info->ctx); + if (shash_find(&info->bridges, name)) { vsctl_fatal("%s because a bridge named %s already exists", msg, name); @@ -767,6 +789,7 @@ find_bridge(struct vsctl_info *info, const char *name, bool must_exist) if (must_exist && !br) { vsctl_fatal("no bridge named %s", name); } + ovsrec_open_vswitch_verify_bridges(info->ctx->ovs); return br; } @@ -790,6 +813,7 @@ find_port(struct vsctl_info *info, const char *name, bool must_exist) if (must_exist && !port) { vsctl_fatal("no port named %s", name); } + verify_ports(info->ctx); return port; } @@ -803,6 +827,7 @@ find_iface(struct vsctl_info *info, const char *name, bool must_exist) if (must_exist && !iface) { vsctl_fatal("no interface named %s", name); } + verify_ports(info->ctx); return iface; } @@ -1202,6 +1227,7 @@ cmd_br_set_external_id(struct vsctl_context *ctx) bridge->br_cfg->n_external_ids, ctx->argv[2], ctx->argc >= 4 ? ctx->argv[3] : NULL, &keys, &values, &n); + ovsrec_bridge_verify_external_ids(bridge->br_cfg); ovsrec_bridge_set_external_ids(bridge->br_cfg, keys, values, n); } else { char *key = xasprintf("fake-bridge-%s", ctx->argv[2]); @@ -1211,6 +1237,7 @@ cmd_br_set_external_id(struct vsctl_context *ctx) port->port_cfg->n_external_ids, key, ctx->argc >= 4 ? ctx->argv[3] : NULL, &keys, &values, &n); + ovsrec_port_verify_external_ids(port->port_cfg); ovsrec_port_set_external_ids(port->port_cfg, keys, values, n); free(key); } @@ -1252,6 +1279,7 @@ cmd_br_get_external_id(struct vsctl_context *ctx) get_info(ctx, &info); bridge = find_bridge(&info, ctx->argv[1], true); if (bridge->br_cfg) { + ovsrec_bridge_verify_external_ids(bridge->br_cfg); get_external_id(bridge->br_cfg->key_external_ids, bridge->br_cfg->value_external_ids, bridge->br_cfg->n_external_ids, @@ -1259,6 +1287,7 @@ cmd_br_get_external_id(struct vsctl_context *ctx) &ctx->output); } else { struct vsctl_port *port = shash_find_data(&info.ports, ctx->argv[1]); + ovsrec_port_verify_external_ids(port->port_cfg); get_external_id(port->port_cfg->key_external_ids, port->port_cfg->value_external_ids, port->port_cfg->n_external_ids, @@ -1278,6 +1307,7 @@ cmd_list_ports(struct vsctl_context *ctx) get_info(ctx, &info); br = find_bridge(&info, ctx->argv[1], true); + ovsrec_bridge_verify_ports(br->br_cfg ? br->br_cfg : br->parent->br_cfg); svec_init(&ports); SHASH_FOR_EACH (node, &info.ports) { @@ -1518,6 +1548,7 @@ cmd_list_ifaces(struct vsctl_context *ctx) get_info(ctx, &info); br = find_bridge(&info, ctx->argv[1], true); + verify_ports(ctx); svec_init(&ifaces); SHASH_FOR_EACH (node, &info.ifaces) { @@ -1546,6 +1577,19 @@ cmd_iface_to_br(struct vsctl_context *ctx) free_info(&info); } +static void +verify_controllers(struct ovsrec_bridge *bridge) +{ + if (bridge) { + size_t i; + + ovsrec_bridge_verify_controller(bridge); + for (i = 0; i < bridge->n_controller; i++) { + ovsrec_controller_verify_target(bridge->controller[i]); + } + } +} + static void cmd_get_controller(struct vsctl_context *ctx) { @@ -1556,6 +1600,7 @@ cmd_get_controller(struct vsctl_context *ctx) get_info(ctx, &info); br = find_bridge(&info, ctx->argv[1], true); + verify_controllers(br->br_cfg); /* Print the targets in sorted order for reproducibility. */ svec_init(&targets); @@ -1591,6 +1636,7 @@ cmd_del_controller(struct vsctl_context *ctx) get_info(ctx, &info); br = find_real_bridge(&info, ctx->argv[1], true); + verify_controllers(br->br_cfg); if (br->ctrl) { delete_controllers(br->ctrl, br->n_ctrl); @@ -1625,6 +1671,7 @@ cmd_set_controller(struct vsctl_context *ctx) get_info(ctx, &info); br = find_real_bridge(&info, ctx->argv[1], true); + verify_controllers(br->br_cfg); delete_controllers(br->ctrl, br->n_ctrl); @@ -1645,6 +1692,9 @@ cmd_get_fail_mode(struct vsctl_context *ctx) get_info(ctx, &info); br = find_bridge(&info, ctx->argv[1], true); + if (br->br_cfg) { + ovsrec_bridge_verify_fail_mode(br->br_cfg); + } if (br->fail_mode && strlen(br->fail_mode)) { ds_put_format(&ctx->output, "%s\n", br->fail_mode); } @@ -1690,7 +1740,13 @@ cmd_get_ssl(struct vsctl_context *ctx) { struct ovsrec_ssl *ssl = ctx->ovs->ssl; + ovsrec_open_vswitch_verify_ssl(ctx->ovs); if (ssl) { + ovsrec_ssl_verify_private_key(ssl); + ovsrec_ssl_verify_certificate(ssl); + ovsrec_ssl_verify_ca_cert(ssl); + ovsrec_ssl_verify_bootstrap_ca_cert(ssl); + ds_put_format(&ctx->output, "Private key: %s\n", ssl->private_key); ds_put_format(&ctx->output, "Certificate: %s\n", ssl->certificate); ds_put_format(&ctx->output, "CA Certificate: %s\n", ssl->ca_cert); @@ -1705,6 +1761,7 @@ cmd_del_ssl(struct vsctl_context *ctx) struct ovsrec_ssl *ssl = ctx->ovs->ssl; if (ssl) { + ovsrec_open_vswitch_verify_ssl(ctx->ovs); ovsrec_ssl_delete(ssl); ovsrec_open_vswitch_set_ssl(ctx->ovs, NULL); } @@ -1716,6 +1773,7 @@ cmd_set_ssl(struct vsctl_context *ctx) bool bootstrap = shash_find(&ctx->options, "--bootstrap"); struct ovsrec_ssl *ssl = ctx->ovs->ssl; + ovsrec_open_vswitch_verify_ssl(ctx->ovs); if (ssl) { ovsrec_ssl_delete(ssl); } @@ -1900,6 +1958,7 @@ get_row_by_id(struct vsctl_context *ctx, const struct vsctl_table_class *table, if (id->uuid_column) { const struct ovsdb_datum *uuid; + ovsdb_idl_txn_verify(referrer, id->uuid_column); uuid = ovsdb_idl_get(referrer, id->uuid_column, OVSDB_TYPE_UUID, OVSDB_TYPE_VOID); if (uuid->n == 1) { @@ -2173,6 +2232,7 @@ cmd_get(struct vsctl_context *ctx) &column, &key_string, NULL, NULL, 0, NULL)); + ovsdb_idl_txn_verify(row, column); datum = ovsdb_idl_read(row, column); if (key_string) { union ovsdb_atom key; @@ -2365,6 +2425,7 @@ cmd_add(struct vsctl_context *ctx) type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs", column->name, table->class->name, type->n_max); } + ovsdb_idl_txn_verify(row, column); ovsdb_idl_txn_write(row, column, &old); } @@ -2413,6 +2474,7 @@ cmd_remove(struct vsctl_context *ctx) type->value.type == OVSDB_TYPE_VOID ? "values" : "pairs", column->name, table->class->name, type->n_min); } + ovsdb_idl_txn_verify(row, column); ovsdb_idl_txn_write(row, column, &old); } @@ -2653,6 +2715,7 @@ vsctl_context_init(struct vsctl_context *ctx, struct vsctl_command *command, ctx->txn = txn; ctx->ovs = ovs; ctx->symtab = symtab; + ctx->verified_ports = false; ctx->try_again = false; }