#include "table.h"
#include "timeval.h"
#include "util.h"
-#include "vconn.h"
-#include "vlog.h"
+#include "openvswitch/vconn.h"
+#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(vsctl);
static struct ovsdb_idl *the_idl;
static struct ovsdb_idl_txn *the_idl_txn;
-static void vsctl_exit(int status) NO_RETURN;
-static void vsctl_fatal(const char *, ...) PRINTF_FORMAT(1, 2) NO_RETURN;
+OVS_NO_RETURN static void vsctl_exit(int status);
+OVS_NO_RETURN static void vsctl_fatal(const char *, ...) OVS_PRINTF_FORMAT(1, 2);
static char *default_db(void);
-static void usage(void) NO_RETURN;
+OVS_NO_RETURN static void usage(void);
static void parse_options(int argc, char *argv[], struct shash *local_options);
static bool might_write_to_db(char **argv);
set_program_name(argv[0]);
fatal_ignore_sigpipe();
vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
- vlog_set_levels(&VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
+ vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
ovsrec_init();
/* Log our arguments. This is often valuable for debugging systems. */
del-ssl delete the SSL configuration\n\
set-ssl PRIV-KEY CERT CA-CERT set the SSL configuration\n\
\n\
+Auto Attach commands:\n\
+ add-aa-mapping BRIDGE I-SID VLAN add Auto Attach mapping to BRIDGE\n\
+ del-aa-mapping BRIDGE I-SID VLAN delete Auto Attach mapping VLAN from BRIDGE\n\
+ get-aa-mapping BRIDGE get Auto Attach mappings from BRIDGE\n\
+\n\
Switch commands:\n\
emer-reset reset switch to known good state\n\
\n\
struct vsctl_bridge {
struct ovsrec_bridge *br_cfg;
char *name;
- struct list ports; /* Contains "struct vsctl_port"s. */
+ struct ovs_list ports; /* Contains "struct vsctl_port"s. */
/* VLAN ("fake") bridge support.
*
};
struct vsctl_port {
- struct list ports_node; /* In struct vsctl_bridge's 'ports' list. */
- struct list ifaces; /* Contains "struct vsctl_iface"s. */
+ struct ovs_list ports_node; /* In struct vsctl_bridge's 'ports' list. */
+ struct ovs_list ifaces; /* Contains "struct vsctl_iface"s. */
struct ovsrec_port *port_cfg;
struct vsctl_bridge *bridge;
};
struct vsctl_iface {
- struct list ifaces_node; /* In struct vsctl_port's 'ifaces' list. */
+ struct ovs_list ifaces_node; /* In struct vsctl_port's 'ifaces' list. */
struct ovsrec_interface *iface_cfg;
struct vsctl_port *port;
};
+static struct vsctl_bridge *find_vlan_bridge(struct vsctl_bridge *parent,
+ int vlan);
+
static char *
vsctl_context_to_string(const struct vsctl_context *ctx)
{
br->vlan = vlan;
hmap_init(&br->children);
if (parent) {
- hmap_insert(&parent->children, &br->children_node, hash_int(vlan, 0));
+ struct vsctl_bridge *conflict = find_vlan_bridge(parent, vlan);
+ if (conflict) {
+ VLOG_WARN("%s: bridge has multiple VLAN bridges (%s and %s) "
+ "for VLAN %d, but only one is allowed",
+ parent->name, name, conflict->name, vlan);
+ } else {
+ hmap_insert(&parent->children, &br->children_node,
+ hash_int(vlan, 0));
+ }
}
shash_add(&ctx->bridges, br->name, br);
return br;
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_controller);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_fail_mode);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ports);
+ ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach);
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_name);
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_fake_bridge);
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_interfaces);
ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_name);
+
+ ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings);
ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_ofport);
}
if (!parent_name) {
struct ovsrec_port *port;
+ struct ovsrec_autoattach *aa;
struct ovsrec_bridge *br;
iface = ovsrec_interface_insert(ctx->txn);
ovsrec_port_set_name(port, br_name);
ovsrec_port_set_interfaces(port, &iface, 1);
+ aa = ovsrec_autoattach_insert(ctx->txn);
+
br = ovsrec_bridge_insert(ctx->txn);
ovsrec_bridge_set_name(br, br_name);
ovsrec_bridge_set_ports(br, &port, 1);
+ ovsrec_bridge_set_auto_attach(br, aa);
ovs_insert_bridge(ctx->ovs, br);
} else {
+ struct vsctl_bridge *conflict;
struct vsctl_bridge *parent;
struct ovsrec_port *port;
struct ovsrec_bridge *br;
if (!parent) {
vsctl_fatal("parent bridge %s does not exist", parent_name);
}
+ conflict = find_vlan_bridge(parent, vlan);
+ if (conflict) {
+ vsctl_fatal("bridge %s already has a child VLAN bridge %s "
+ "on VLAN %d", parent_name, conflict->name, vlan);
+ }
br = parent->br_cfg;
iface = ovsrec_interface_insert(ctx->txn);
ovsrec_open_vswitch_set_ssl(ctx->ovs, ssl);
}
+
+static void
+autoattach_insert_mapping(struct ovsrec_autoattach *aa,
+ int64_t isid,
+ int64_t vlan)
+{
+ int64_t *key_mappings, *value_mappings;
+ size_t i;
+
+ key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings + 1));
+ value_mappings = xmalloc(sizeof *aa->value_mappings * (aa->n_mappings + 1));
+
+ for (i = 0; i < aa->n_mappings; i++) {
+ key_mappings[i] = aa->key_mappings[i];
+ value_mappings[i] = aa->value_mappings[i];
+ }
+ key_mappings[aa->n_mappings] = isid;
+ value_mappings[aa->n_mappings] = vlan;
+
+ ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings,
+ aa->n_mappings + 1);
+
+ free(key_mappings);
+ free(value_mappings);
+}
+
+static void
+cmd_add_aa_mapping(struct vsctl_context *ctx)
+{
+ struct vsctl_bridge *br;
+ int64_t isid, vlan;
+ char *nptr = NULL;
+
+ isid = strtoull(ctx->argv[2], &nptr, 10);
+ if (nptr == ctx->argv[2] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[2]);
+ return;
+ }
+
+ vlan = strtoull(ctx->argv[3], &nptr, 10);
+ if (nptr == ctx->argv[3] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[3]);
+ return;
+ }
+
+ vsctl_context_populate_cache(ctx);
+
+ br = find_bridge(ctx, ctx->argv[1], true);
+ if (br->parent) {
+ br = br->parent;
+ }
+
+ if (br && br->br_cfg) {
+ autoattach_insert_mapping(br->br_cfg->auto_attach, isid, vlan);
+ }
+}
+
+static void
+del_aa_mapping(struct ovsrec_autoattach *aa,
+ int64_t isid,
+ int64_t vlan)
+{
+ int64_t *key_mappings, *value_mappings;
+ size_t i, n;
+
+ key_mappings = xmalloc(sizeof *aa->key_mappings * (aa->n_mappings));
+ value_mappings = xmalloc(sizeof *value_mappings * (aa->n_mappings));
+
+ for (i = n = 0; i < aa->n_mappings; i++) {
+ if (aa->key_mappings[i] != isid && aa->value_mappings[i] != vlan) {
+ key_mappings[n] = aa->key_mappings[i];
+ value_mappings[n++] = aa->value_mappings[i];
+ }
+ }
+
+ ovsrec_autoattach_set_mappings(aa, key_mappings, value_mappings, n);
+
+ free(key_mappings);
+ free(value_mappings);
+}
+
+static void
+cmd_del_aa_mapping(struct vsctl_context *ctx)
+{
+ struct vsctl_bridge *br;
+ int64_t isid, vlan;
+ char *nptr = NULL;
+
+ isid = strtoull(ctx->argv[2], &nptr, 10);
+ if (nptr == ctx->argv[2] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[2]);
+ return;
+ }
+
+ vlan = strtoull(ctx->argv[3], &nptr, 10);
+ if (nptr == ctx->argv[3] || nptr == NULL) {
+ vsctl_fatal("Invalid argument %s", ctx->argv[3]);
+ return;
+ }
+
+ vsctl_context_populate_cache(ctx);
+
+ br = find_bridge(ctx, ctx->argv[1], true);
+ if (br->parent) {
+ br = br->parent;
+ }
+
+ if (br && br->br_cfg && br->br_cfg->auto_attach &&
+ br->br_cfg->auto_attach->key_mappings &&
+ br->br_cfg->auto_attach->value_mappings) {
+ size_t i;
+
+ for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) {
+ if (br->br_cfg->auto_attach->key_mappings[i] == isid &&
+ br->br_cfg->auto_attach->value_mappings[i] == vlan) {
+ del_aa_mapping(br->br_cfg->auto_attach, isid, vlan);
+ break;
+ }
+ }
+ }
+}
+
+static void
+pre_aa_mapping(struct vsctl_context *ctx)
+{
+ pre_get_info(ctx);
+
+ ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings);
+}
+
+static void
+verify_auto_attach(struct ovsrec_bridge *bridge)
+{
+ if (bridge) {
+ ovsrec_bridge_verify_auto_attach(bridge);
+
+ if (bridge->auto_attach) {
+ ovsrec_autoattach_verify_mappings(bridge->auto_attach);
+ }
+ }
+}
+
+static void
+cmd_get_aa_mapping(struct vsctl_context *ctx)
+{
+ struct vsctl_bridge *br;
+
+ vsctl_context_populate_cache(ctx);
+
+ br = find_bridge(ctx, ctx->argv[1], true);
+ if (br->parent) {
+ br = br->parent;
+ }
+
+ verify_auto_attach(br->br_cfg);
+
+ if (br && br->br_cfg && br->br_cfg->auto_attach &&
+ br->br_cfg->auto_attach->key_mappings &&
+ br->br_cfg->auto_attach->value_mappings) {
+ size_t i;
+
+ for (i = 0; i < br->br_cfg->auto_attach->n_mappings; i++) {
+ ds_put_format(&ctx->output, "%"PRId64" %"PRId64"\n",
+ (long int) br->br_cfg->auto_attach->key_mappings[i],
+ (long int) br->br_cfg->auto_attach->value_mappings[i]);
+ }
+ }
+}
+
\f
/* Parameter commands. */
{&ovsrec_table_flow_sample_collector_set, NULL,
&ovsrec_flow_sample_collector_set_col_ipfix}}},
+ {&ovsrec_table_autoattach,
+ {{&ovsrec_table_bridge,
+ &ovsrec_bridge_col_name,
+ &ovsrec_bridge_col_auto_attach},
+ {NULL, NULL, NULL}}},
+
{&ovsrec_table_flow_sample_collector_set,
{{NULL, NULL, NULL},
{NULL, NULL, NULL}}},
const struct ovsdb_idl_row *row;
struct uuid uuid;
+ row = NULL;
if (uuid_from_string(&uuid, record_id)) {
row = ovsdb_idl_get_row_for_uuid(ctx->idl, table->class, &uuid);
- } else {
+ }
+ if (!row) {
int i;
for (i = 0; i < ARRAY_SIZE(table->row_ids); i++) {
*
* On success, returns NULL. On failure, returned a malloc()'d string error
* message and stores NULL into all of the nonnull output arguments. */
-static char * WARN_UNUSED_RESULT
+static char * OVS_WARN_UNUSED_RESULT
parse_column_key_value(const char *arg,
const struct vsctl_table_class *table,
const struct ovsdb_idl_column **columnp, char **keyp,
}
static void
-check_mutable(const struct vsctl_table_class *table,
+check_mutable(const struct ovsdb_idl_row *row,
const struct ovsdb_idl_column *column)
{
- if (!column->mutable) {
+ if (!ovsdb_idl_is_mutable(row, column)) {
vsctl_fatal("cannot modify read-only column %s in table %s",
- column->name, table->class->name);
+ column->name, row->table->class->name);
}
}
table = pre_get_table(ctx, table_name);
for (i = 3; i < ctx->argc; i++) {
- const struct ovsdb_idl_column *column;
-
- column = pre_parse_column_key_value(ctx, ctx->argv[i], table);
- check_mutable(table, column);
+ pre_parse_column_key_value(ctx, ctx->argv[i], table);
}
}
if (!value_string) {
vsctl_fatal("%s: missing value", arg);
}
+ check_mutable(row, column);
if (key_string) {
union ovsdb_atom key, value;
table = pre_get_table(ctx, table_name);
pre_get_column(ctx, table, column_name, &column);
- check_mutable(table, column);
}
static void
if (!row) {
return;
}
+ check_mutable(row, column);
type = &column->type;
ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type);
table = pre_get_table(ctx, table_name);
pre_get_column(ctx, table, column_name, &column);
- check_mutable(table, column);
}
static void
if (!row) {
return;
}
+ check_mutable(row, column);
type = &column->type;
ovsdb_datum_clone(&old, ovsdb_idl_read(row, column), &column->type);
rm_type.n_max = UINT_MAX;
error = ovsdb_datum_from_string(&rm, &rm_type,
ctx->argv[i], ctx->symtab);
- if (error && ovsdb_type_is_map(&rm_type)) {
- free(error);
- rm_type.value.type = OVSDB_TYPE_VOID;
- die_if_error(ovsdb_datum_from_string(&rm, &rm_type,
- ctx->argv[i], ctx->symtab));
+ if (error) {
+ if (ovsdb_type_is_map(&rm_type)) {
+ rm_type.value.type = OVSDB_TYPE_VOID;
+ free(error);
+ die_if_error(ovsdb_datum_from_string(
+ &rm, &rm_type, ctx->argv[i], ctx->symtab));
+ } else {
+ vsctl_fatal("%s", error);
+ }
}
ovsdb_datum_subtract(&old, type, &rm, &rm_type);
ovsdb_datum_destroy(&rm, &rm_type);
const struct ovsdb_idl_column *column;
pre_get_column(ctx, table, ctx->argv[i], &column);
- check_mutable(table, column);
}
}
struct ovsdb_datum datum;
die_if_error(get_column(table, ctx->argv[i], &column));
+ check_mutable(row, column);
type = &column->type;
if (type->n_min > 0) {
{"del-ssl", 0, 0, pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW},
{"set-ssl", 3, 3, pre_cmd_set_ssl, cmd_set_ssl, NULL, "--bootstrap", RW},
+ /* Auto Attach commands. */
+ {"add-aa-mapping", 3, 3, pre_get_info, cmd_add_aa_mapping, NULL, "", RW},
+ {"del-aa-mapping", 3, 3, pre_aa_mapping, cmd_del_aa_mapping, NULL, "", RW},
+ {"get-aa-mapping", 1, 1, pre_aa_mapping, cmd_get_aa_mapping, NULL, "", RO},
+
/* Switch commands. */
{"emer-reset", 0, 0, pre_cmd_emer_reset, cmd_emer_reset, NULL, "", RW},