+ if (ctx->argc == 1) {
+ if (info.ctrl && info.ctrl->fail_mode) {
+ ovsrec_controller_set_fail_mode(info.ctrl, NULL);
+ }
+ } else {
+ struct vsctl_bridge *br = find_real_bridge(&info, ctx->argv[1], true);
+
+ if (br->ctrl && br->ctrl->fail_mode) {
+ ovsrec_controller_set_fail_mode(br->ctrl, NULL);
+ }
+ }
+
+ free_info(&info);
+}
+
+static void
+cmd_set_fail_mode(struct vsctl_context *ctx)
+{
+ struct vsctl_info info;
+ const char *fail_mode;
+
+ get_info(ctx->ovs, &info);
+
+ fail_mode = (ctx->argc == 2) ? ctx->argv[1] : ctx->argv[2];
+
+ if (strcmp(fail_mode, "standalone") && strcmp(fail_mode, "secure")) {
+ vsctl_fatal("fail-mode must be \"standalone\" or \"secure\"");
+ }
+
+ if (ctx->argc == 2) {
+ /* Set the fail-mode in the "Open_vSwitch" table. */
+ if (!info.ctrl) {
+ vsctl_fatal("no controller declared");
+ }
+ ovsrec_controller_set_fail_mode(info.ctrl, fail_mode);
+ } else {
+ struct vsctl_bridge *br = find_real_bridge(&info, ctx->argv[1], true);
+
+ if (!br->ctrl) {
+ vsctl_fatal("no controller declared for %s", br->name);
+ }
+ ovsrec_controller_set_fail_mode(br->ctrl, fail_mode);
+ }
+
+ free_info(&info);
+}
+
+static void
+cmd_get_ssl(struct vsctl_context *ctx)
+{
+ struct ovsrec_ssl *ssl = ctx->ovs->ssl;
+
+ if (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);
+ ds_put_format(&ctx->output, "Bootstrap: %s\n",
+ ssl->bootstrap_ca_cert ? "true" : "false");
+ }
+}
+
+static void
+cmd_del_ssl(struct vsctl_context *ctx)
+{
+ struct ovsrec_ssl *ssl = ctx->ovs->ssl;
+
+ if (ssl) {
+ ovsrec_ssl_delete(ssl);
+ ovsrec_open_vswitch_set_ssl(ctx->ovs, NULL);
+ }
+}
+
+static void
+cmd_set_ssl(struct vsctl_context *ctx)
+{
+ bool bootstrap = shash_find(&ctx->options, "--bootstrap");
+ struct ovsrec_ssl *ssl = ctx->ovs->ssl;
+
+ if (ssl) {
+ ovsrec_ssl_delete(ssl);
+ }
+ ssl = ovsrec_ssl_insert(ctx->txn);
+
+ ovsrec_ssl_set_private_key(ssl, ctx->argv[1]);
+ ovsrec_ssl_set_certificate(ssl, ctx->argv[2]);
+ ovsrec_ssl_set_ca_cert(ssl, ctx->argv[3]);
+
+ ovsrec_ssl_set_bootstrap_ca_cert(ssl, bootstrap);
+
+ ovsrec_open_vswitch_set_ssl(ctx->ovs, ssl);
+}
+\f
+/* Parameter commands. */
+
+/* POSIX extended regular expression for an 8-bit unsigned decimal integer. */
+#define OCTET_RE "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
+
+/* POSIX extended regular expression for an IP address. */
+#define IP_RE "("OCTET_RE"\\."OCTET_RE"\\."OCTET_RE"\\."OCTET_RE")"
+
+/* POSIX extended regular expression for a netmask. */
+#define NETMASK_RE \
+ "255.255.255."NETMASK_END_RE"|" \
+ "255.255."NETMASK_END_RE".0|" \
+ "255."NETMASK_END_RE".0.0|" \
+ NETMASK_END_RE".0.0.0"
+#define NETMASK_END_RE "(255|254|252|248|240|224|192|128|0)"
+
+/* POSIX extended regular expression for an Ethernet address. */
+#define XX_RE "[0-9a-fA-F][0-9a-fA-F]"
+#define MAC_RE XX_RE":"XX_RE":"XX_RE":"XX_RE":"XX_RE":"XX_RE
+
+/* POSIX extended regular expression for a TCP or UDP port number. */
+#define PORT_RE \
+ "([0-9]|" \
+ "[1-9][0-9]|" \
+ "[1-9][0-9][0-9]|" \
+ "[1-9][0-9][0-9][0-9]|" \
+ "[1-5][0-9][0-9][0-9][0-9]|" \
+ "6[1-4][0-9][0-9][0-9]|" \
+ "65[1-4][0-9][0-9]|" \
+ "655[1-2][0-9]|" \
+ "6553[1-5])"
+
+enum {
+ VSCF_READONLY = 1 << 0,
+ VSCF_HIDDEN = 1 << 1
+};
+
+struct vsctl_column {
+ struct ovsdb_idl_column *idl;
+ int flags;
+ const char *constraint;
+};
+
+static const struct vsctl_column bridge_columns[] = {
+ {&ovsrec_bridge_col_controller, VSCF_READONLY, NULL},
+ {&ovsrec_bridge_col_datapath_id, VSCF_READONLY, NULL},
+ {&ovsrec_bridge_col_datapath_type, VSCF_READONLY, NULL},
+ {&ovsrec_bridge_col_external_ids, 0, NULL},
+ {&ovsrec_bridge_col_flood_vlans, 0, "[1,4095]"},
+ {&ovsrec_bridge_col_mirrors, VSCF_READONLY, NULL},
+ {&ovsrec_bridge_col_name, VSCF_READONLY, NULL},
+ {&ovsrec_bridge_col_netflow, VSCF_READONLY, NULL},
+ {&ovsrec_bridge_col_other_config, 0, NULL},
+ {&ovsrec_bridge_col_ports, VSCF_READONLY, NULL},
+ {NULL, 0, NULL},
+};
+
+static const struct vsctl_column controller_columns[] = {
+ {&ovsrec_controller_col_connection_mode, 0, "in-band|out-of-band"},
+ {&ovsrec_controller_col_controller_burst_limit, 0, "[25,]"},
+ {&ovsrec_controller_col_controller_rate_limit, 0, "[100,]"},
+ {&ovsrec_controller_col_discover_accept_regex, 0, NULL},
+ {&ovsrec_controller_col_discover_update_resolv_conf, 0, NULL},
+ {&ovsrec_controller_col_fail_mode, 0, "standalone|secure"},
+ {&ovsrec_controller_col_inactivity_probe, 0, "[5000,]"},
+ {&ovsrec_controller_col_local_gateway, 0, IP_RE},
+ {&ovsrec_controller_col_local_ip, 0, IP_RE},
+ {&ovsrec_controller_col_local_netmask, 0, NETMASK_RE},
+ {&ovsrec_controller_col_max_backoff, 0, "[1000,]"},
+ {&ovsrec_controller_col_target, 0, NULL},
+ {NULL, 0, NULL},
+};
+
+static const struct vsctl_column interface_columns[] = {
+ {&ovsrec_interface_col_external_ids, 0, NULL},
+ {&ovsrec_interface_col_ingress_policing_burst, 0, "[10,]"},
+ {&ovsrec_interface_col_ingress_policing_rate, 0, "[100,]"},
+ {&ovsrec_interface_col_mac, 0, MAC_RE},
+ {&ovsrec_interface_col_name, VSCF_READONLY, NULL},
+ {&ovsrec_interface_col_ofport, VSCF_READONLY, NULL},
+ {&ovsrec_interface_col_options, 0, NULL},
+ {&ovsrec_interface_col_type, VSCF_READONLY, NULL},
+ {NULL, 0, NULL},
+};
+
+static const struct vsctl_column mirror_columns[] = {
+ {&ovsrec_mirror_col_name, VSCF_READONLY, NULL},
+ {&ovsrec_mirror_col_output_port, 0, "Port"},
+ {&ovsrec_mirror_col_output_vlan, 0, "[1,4095]"},
+ {&ovsrec_mirror_col_select_dst_port, 0, "Port"},
+ {&ovsrec_mirror_col_select_src_port, 0, "Port"},
+ {&ovsrec_mirror_col_select_vlan, 0, "[1,4095]"},
+ {NULL, 0, NULL},
+};
+
+static const struct vsctl_column netflow_columns[] = {
+ {&ovsrec_netflow_col_active_timeout, 0, "[-1,]"},
+ {&ovsrec_netflow_col_add_id_to_interface, 0, NULL},
+ {&ovsrec_netflow_col_engine_id, 0, "[0,255]"},
+ {&ovsrec_netflow_col_engine_type, 0, "[0,255]"},
+ {&ovsrec_netflow_col_targets, 0, IP_RE":"PORT_RE},
+ {NULL, 0, NULL},
+};
+
+static const struct vsctl_column open_vswitch_columns[] = {
+ {&ovsrec_open_vswitch_col_bridges, VSCF_READONLY, NULL},
+ {&ovsrec_open_vswitch_col_controller, VSCF_READONLY, NULL},
+ {&ovsrec_open_vswitch_col_cur_cfg, VSCF_HIDDEN, NULL},
+ {&ovsrec_open_vswitch_col_managers, 0, "p?(ssl|tcp|unix):.*"},
+ {&ovsrec_open_vswitch_col_next_cfg, VSCF_HIDDEN, NULL},
+ {&ovsrec_open_vswitch_col_ssl, VSCF_READONLY, NULL},
+ {NULL, 0, NULL},
+};
+
+static const struct vsctl_column port_columns[] = {
+ {&ovsrec_port_col_bond_downdelay, 0, "[0,]"},
+ {&ovsrec_port_col_bond_fake_iface, VSCF_READONLY, NULL},
+ {&ovsrec_port_col_bond_updelay, 0, "[0,]"},
+ {&ovsrec_port_col_external_ids, 0, NULL},
+ {&ovsrec_port_col_fake_bridge, VSCF_READONLY, NULL},
+ {&ovsrec_port_col_interfaces, VSCF_READONLY, NULL},
+ {&ovsrec_port_col_mac, 0, MAC_RE},
+ {&ovsrec_port_col_name, VSCF_READONLY, NULL},
+ {&ovsrec_port_col_other_config, 0, NULL},
+ {&ovsrec_port_col_tag, 0, "[0,4095]"},
+ {&ovsrec_port_col_trunks, 0, "[0,4095]"},
+ {NULL, 0, NULL},
+};
+
+static const struct vsctl_column ssl_columns[] = {
+ {&ovsrec_ssl_col_bootstrap_ca_cert, 0, NULL},
+ {&ovsrec_ssl_col_ca_cert, 0, NULL},
+ {&ovsrec_ssl_col_certificate, 0, NULL},
+ {&ovsrec_ssl_col_private_key, 0, NULL},
+ {NULL, 0, NULL},
+};
+
+struct vsctl_row_id {
+ const struct ovsdb_idl_table_class *table;
+ const struct ovsdb_idl_column *name_column;
+ const struct ovsdb_idl_column *uuid_column;
+};
+
+struct vsctl_table_class {
+ struct ovsdb_idl_table_class *class;
+ const struct vsctl_column *columns;
+ struct vsctl_row_id row_ids[2];
+};
+
+static const struct vsctl_table_class tables[] = {
+ {&ovsrec_table_bridge, bridge_columns,
+ {{&ovsrec_table_bridge, &ovsrec_bridge_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&ovsrec_table_controller, controller_columns,
+ {{&ovsrec_table_bridge,
+ &ovsrec_bridge_col_name,
+ &ovsrec_bridge_col_controller},
+ {&ovsrec_table_open_vswitch,
+ NULL,
+ &ovsrec_open_vswitch_col_controller}}},
+
+ {&ovsrec_table_interface, interface_columns,
+ {{&ovsrec_table_interface, &ovsrec_interface_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&ovsrec_table_mirror, mirror_columns,
+ {{&ovsrec_table_mirror, &ovsrec_mirror_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&ovsrec_table_netflow, netflow_columns,
+ {{&ovsrec_table_bridge,
+ &ovsrec_bridge_col_name,
+ &ovsrec_bridge_col_netflow},
+ {NULL, NULL, NULL}}},
+
+ {&ovsrec_table_open_vswitch, open_vswitch_columns,
+ {{&ovsrec_table_open_vswitch, NULL, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&ovsrec_table_port, port_columns,
+ {{&ovsrec_table_port, &ovsrec_port_col_name, NULL},
+ {NULL, NULL, NULL}}},
+
+ {&ovsrec_table_ssl, ssl_columns,
+ {{&ovsrec_table_open_vswitch, NULL, &ovsrec_open_vswitch_col_ssl}}},
+
+ {NULL, NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
+};
+
+static void
+die_if_error(char *error)
+{
+ if (error) {
+ ovs_fatal(0, "%s", error);
+ }
+}
+
+static int
+to_lower_and_underscores(unsigned c)
+{
+ return c == '-' ? '_' : tolower(c);
+}
+
+static unsigned int
+score_partial_match(const char *name, const char *s)
+{
+ int score;
+
+ if (!strcmp(name, s)) {
+ return UINT_MAX;
+ }
+ for (score = 0; ; score++, name++, s++) {
+ if (to_lower_and_underscores(*name) != to_lower_and_underscores(*s)) {
+ break;
+ } else if (*name == '\0') {
+ return UINT_MAX - 1;
+ }
+ }
+ return *s == '\0' ? score : 0;
+}
+
+static const struct vsctl_table_class *
+get_table(const char *table_name)
+{
+ const struct vsctl_table_class *table;
+ const struct vsctl_table_class *best_match = NULL;
+ unsigned int best_score = 0;
+
+ for (table = tables; table->class; table++) {
+ unsigned int score = score_partial_match(table->class->name,
+ table_name);
+ if (score > best_score) {
+ best_match = table;
+ best_score = score;
+ } else if (score == best_score) {
+ best_match = NULL;
+ }
+ }
+ if (best_match) {
+ return best_match;
+ } else if (best_score) {
+ ovs_fatal(0, "multiple table names match \"%s\"", table_name);
+ } else {
+ ovs_fatal(0, "unknown table \"%s\"", table_name);
+ }
+}
+
+static const struct ovsdb_idl_row *
+get_row_by_id(struct vsctl_context *ctx, const struct vsctl_table_class *table,
+ const struct vsctl_row_id *id, const char *record_id)
+{
+ const struct ovsdb_idl_row *referrer, *final;
+
+ if (!id->table) {
+ return NULL;
+ }
+
+ if (!id->name_column) {
+ if (strcmp(record_id, ".")) {
+ return NULL;
+ }
+ referrer = ovsdb_idl_first_row(ctx->idl, id->table);
+ if (!referrer || ovsdb_idl_next_row(referrer)) {
+ return NULL;
+ }
+ } else {
+ const struct ovsdb_idl_row *row;
+ unsigned int best_score = 0;
+
+ /* It might make sense to relax this assertion. */
+ assert(id->name_column->type.key_type == OVSDB_TYPE_STRING);
+
+ referrer = NULL;
+ for (row = ovsdb_idl_first_row(ctx->idl, id->table);
+ row != NULL && best_score != UINT_MAX;
+ row = ovsdb_idl_next_row(row))
+ {
+ struct ovsdb_datum name;
+
+ ovsdb_idl_txn_read(row, id->name_column, &name);
+ if (name.n == 1) {
+ unsigned int score = score_partial_match(name.keys[0].string,
+ record_id);
+ if (score > best_score) {
+ referrer = row;
+ best_score = score;
+ } else if (score == best_score) {
+ referrer = NULL;