OVS_VSCTL_CLEANUP
AT_CLEANUP
+AT_SETUP([external IDs])
+AT_KEYWORDS([ovs-vsctl])
+OVS_VSCTL_SETUP
+AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
+ [--oneline add-br a],
+ [add-port a a1],
+ [add-bond a bond0 a2 a3],
+ [br-set-external-id a key0 value0],
+ [port-set-external-id a1 key1 value1],
+ [iface-set-external-id a2 key2 value2],
+ [iface-set-external-id a2 key3 value3],
+ [iface-set-external-id a3 key4 value4],
+ [br-get-external-id a],
+ [br-get-external-id a key0],
+ [br-get-external-id a key1],
+ [br-set-external-id a key0 othervalue],
+ [br-get-external-id a],
+ [br-set-external-id a key0],
+ [br-get-external-id a],
+ [port-get-external-id a1],
+ [iface-get-external-id a2],
+ [iface-get-external-id a3])], [0], [
+
+
+
+
+
+
+
+key0=value0
+value0
+
+
+key0=othervalue
+
+
+key1=value1
+key2=value2\nkey3=value3
+key4=value4
+], [], [OVS_VSCTL_CLEANUP])
+AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
+ [--oneline br-get-external-id a],
+ [port-get-external-id a1],
+ [iface-get-external-id a2],
+ [iface-get-external-id a3])], [0],
+[
+key1=value1
+key2=value2\nkey3=value3
+key4=value4
+], [], [OVS_VSCTL_CLEANUP])
+CHECK_BRIDGES([a, a, 0])
+CHECK_PORTS([a], [a1], [bond0])
+CHECK_IFACES([a], [a1], [a2], [a3])
+OVS_VSCTL_CLEANUP
+AT_CLEANUP
+
dnl ----------------------------------------------------------------------
AT_BANNER([ovs-vsctl unit tests -- fake bridges])
OVS_VSCTL_CLEANUP
AT_CLEANUP
+AT_SETUP([simple fake bridge + external IDs])
+AT_KEYWORDS([ovs-vsctl fake-bridge])
+OVS_VSCTL_SETUP
+OVS_VSCTL_SETUP_SIMPLE_FAKE_CONF
+AT_CHECK([RUN_OVS_VSCTL_TOGETHER(
+ [--oneline br-set-external-id xenbr0 key0 value0],
+ [br-set-external-id xapi1 key1 value1],
+ [br-get-external-id xenbr0],
+ [br-get-external-id xenbr0 key0],
+ [br-get-external-id xapi1],
+ [br-get-external-id xapi1 key1])], [0], [
+
+key0=value0
+value0
+key1=value1
+value1
+], [], [OVS_VSCTL_CLEANUP])
+CHECK_BRIDGES([xapi1, xenbr0, 9], [xenbr0, xenbr0, 0])
+CHECK_PORTS([xenbr0], [eth0])
+CHECK_IFACES([xenbr0], [eth0])
+CHECK_PORTS([xapi1], [eth0.9])
+CHECK_IFACES([xapi1], [eth0.9])
+OVS_VSCTL_CLEANUP
+AT_CLEANUP
+
m4_define([OVS_VSCTL_SETUP_BOND_FAKE_CONF],
[AT_CHECK(
[RUN_OVS_VSCTL(
If \fIbridge\fR is a fake bridge, prints the name of its parent
bridge. If \fIbridge\fR is a real bridge, print \fIbridge\fR.
.
+.IP "\fBbr\-set\-external\-id \fIbridge key\fR [\fIvalue\fR]"
+Sets or clears an ``external ID'' value on \fIbridge\fR. These values
+are intended to identify entities external to Open vSwitch with which
+\fIbridge\fR is associated, e.g. the bridge's identifier in a
+virtualization management platform. The Open vSwitch database schema
+specifies well-known \fIkey\fR values, but \fIkey\fR and \fIvalue\fR
+are otherwise arbitrary strings.
+.IP
+If \fIvalue\fR is specified, then \fIkey\fR is set to \fIvalue\fR for
+\fIbridge\fR, overwriting any previous value. If \fIvalue\fR is
+omitted, then \fIkey\fR is removed from \fIbridge\fR's set of external
+IDs (if it was present).
+.
+.IP "\fBbr\-get\-external\-id \fIbridge\fR [\fIkey\fR]"
+Queries the external IDs on \fIbridge\fR. If \fIkey\fR is specified,
+the output is the value for that \fIkey\fR or the empty string if
+\fIkey\fR is unset. If \fIkey\fR is omitted, the output is
+\fIkey\fB=\fIvalue\fR, one per line, for each key-value pair.
+.
.SS "Port Commands"
.
These commands examine and manipulate Open vSwitch ports. These
Prints the name of the bridge that contains \fIport\fR on standard
output.
.
+.IP "\fBport\-set\-external\-id \fIport key\fR [\fIvalue\fR]"
+Sets or clears an ``external ID'' value on \fIport\fR. These value
+are intended to identify entities external to Open vSwitch with which
+\fIport\fR is associated, e.g. the port's identifier in a
+virtualization management platform. The Open vSwitch database schema
+specifies well-known \fIkey\fR values, but \fIkey\fR and \fIvalue\fR
+are otherwise arbitrary strings.
+.IP
+If \fIvalue\fR is specified, then \fIkey\fR is set to \fIvalue\fR for
+\fIport\fR, overwriting any previous value. If \fIvalue\fR is
+omitted, then \fIkey\fR is removed from \fIport\fR's set of external
+IDs (if it was present).
+.
+.IP "\fBbr\-get\-external\-id \fIport\fR [\fIkey\fR]"
+Queries the external IDs on \fIport\fR. If \fIkey\fR is specified,
+the output is the value for that \fIkey\fR or the empty string if
+\fIkey\fR is unset. If \fIkey\fR is omitted, the output is
+\fIkey\fB=\fIvalue\fR, one per line, for each key-value pair.
+.
.SS "Interface Commands"
.
These commands examine the interfaces attached to an Open vSwitch
.IP "\fBiface\-to\-br \fIiface\fR"
Prints the name of the bridge that contains \fIiface\fR on standard
output.
+.
+.IP "\fBiface\-set\-external\-id \fIiface key\fR [\fIvalue\fR]"
+Sets or clears an ``external ID'' value on \fIiface\fR. These value
+are intended to identify entities external to Open vSwitch with which
+\fIiface\fR is associated, e.g. the interface's identifier in a
+virtualization management platform. The Open vSwitch database schema
+specifies well-known \fIkey\fR values, but \fIkey\fR and \fIvalue\fR
+are otherwise arbitrary strings.
+.IP
+If \fIvalue\fR is specified, then \fIkey\fR is set to \fIvalue\fR for
+\fIiface\fR, overwriting any previous value. If \fIvalue\fR is
+omitted, then \fIkey\fR is removed from \fIiface\fR's set of external
+IDs (if it was present).
+.
+.IP "\fBbr\-get\-external\-id \fIiface\fR [\fIkey\fR]"
+Queries the external IDs on \fIiface\fR. If \fIkey\fR is specified,
+the output is the value for that \fIkey\fR or the empty string if
+\fIkey\fR is unset. If \fIkey\fR is omitted, the output is
+\fIkey\fB=\fIvalue\fR, one per line, for each key-value pair.
+.
.SH "EXAMPLES"
Create a new bridge named br0 and add port eth0 to it:
.IP
free_info(&info);
}
+/* Returns true if 'b_prefix' (of length 'b_prefix_len') concatenated with 'b'
+ * equals 'a', false otherwise. */
+static bool
+key_matches(const char *a,
+ const char *b_prefix, size_t b_prefix_len, const char *b)
+{
+ return !strncmp(a, b_prefix, b_prefix_len) && !strcmp(a + b_prefix_len, b);
+}
+
+static void
+set_external_id(char **old_keys, char **old_values, size_t old_n,
+ char *key, char *value,
+ char ***new_keysp, char ***new_valuesp, size_t *new_np)
+{
+ char **new_keys;
+ char **new_values;
+ size_t new_n;
+ size_t i;
+
+ new_keys = xmalloc(sizeof *new_keys * (old_n + 1));
+ new_values = xmalloc(sizeof *new_values * (old_n + 1));
+ new_n = 0;
+ for (i = 0; i < old_n; i++) {
+ if (strcmp(key, old_keys[i])) {
+ new_keys[new_n] = old_keys[i];
+ new_values[new_n] = old_values[i];
+ new_n++;
+ }
+ }
+ if (value) {
+ new_keys[new_n] = key;
+ new_values[new_n] = value;
+ new_n++;
+ }
+ *new_keysp = new_keys;
+ *new_valuesp = new_values;
+ *new_np = new_n;
+}
+
+static void
+cmd_br_set_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output UNUSED)
+{
+ struct vsctl_info info;
+ struct vsctl_bridge *bridge;
+ char **keys, **values;
+ size_t n;
+
+ get_info(ovs, &info);
+ bridge = find_bridge(&info, argv[1]);
+ if (bridge->br_cfg) {
+ set_external_id(bridge->br_cfg->key_external_ids,
+ bridge->br_cfg->value_external_ids,
+ bridge->br_cfg->n_external_ids,
+ argv[2], argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_bridge_set_external_ids(bridge->br_cfg, keys, values, n);
+ } else {
+ char *key = xasprintf("fake-bridge-%s", argv[2]);
+ struct vsctl_port *port = shash_find_data(&info.ports, argv[1]);
+ set_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ key, argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_port_set_external_ids(port->port_cfg, keys, values, n);
+ free(key);
+ }
+ free(keys);
+ free(values);
+
+ free_info(&info);
+}
+
+static void
+get_external_id(char **keys, char **values, size_t n,
+ const char *prefix, const char *key,
+ struct ds *output)
+{
+ size_t prefix_len = strlen(prefix);
+ struct svec svec;
+ size_t i;
+
+ svec_init(&svec);
+ for (i = 0; i < n; i++) {
+ if (!key && !strncmp(keys[i], prefix, prefix_len)) {
+ svec_add_nocopy(&svec, xasprintf("%s=%s",
+ keys[i] + prefix_len, values[i]));
+ } else if (key_matches(keys[i], prefix, prefix_len, key)) {
+ svec_add(&svec, values[i]);
+ break;
+ }
+ }
+ output_sorted(&svec, output);
+ svec_destroy(&svec);
+}
+
+static void
+cmd_br_get_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output)
+{
+ struct vsctl_info info;
+ struct vsctl_bridge *bridge;
+
+ get_info(ovs, &info);
+ bridge = find_bridge(&info, argv[1]);
+ if (bridge->br_cfg) {
+ get_external_id(bridge->br_cfg->key_external_ids,
+ bridge->br_cfg->value_external_ids,
+ bridge->br_cfg->n_external_ids,
+ "", argc >= 3 ? argv[2] : NULL, output);
+ } else {
+ struct vsctl_port *port = shash_find_data(&info.ports, argv[1]);
+ get_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ "fake-bridge-", argc >= 3 ? argv[2] : NULL, output);
+ }
+ free_info(&info);
+}
+
+
static void
cmd_list_ports(int argc UNUSED, char *argv[],
const struct ovsrec_open_vswitch *ovs, struct ds *output)
free_info(&info);
}
+static void
+cmd_port_set_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output UNUSED)
+{
+ struct vsctl_info info;
+ struct vsctl_port *port;
+ char **keys, **values;
+ size_t n;
+
+ get_info(ovs, &info);
+ port = find_port(&info, argv[1]);
+ set_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ argv[2], argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_port_set_external_ids(port->port_cfg, keys, values, n);
+ free(keys);
+ free(values);
+
+ free_info(&info);
+}
+
+static void
+cmd_port_get_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output)
+{
+ struct vsctl_info info;
+ struct vsctl_port *port;
+
+ get_info(ovs, &info);
+ port = find_port(&info, argv[1]);
+ get_external_id(port->port_cfg->key_external_ids,
+ port->port_cfg->value_external_ids,
+ port->port_cfg->n_external_ids,
+ "", argc >= 3 ? argv[2] : NULL, output);
+ free_info(&info);
+}
+
static void
cmd_br_to_vlan(int argc UNUSED, char *argv[],
const struct ovsrec_open_vswitch *ovs, struct ds *output)
ds_put_format(output, "%s\n", iface->port->bridge->name);
free_info(&info);
}
+
+static void
+cmd_iface_set_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output UNUSED)
+{
+ struct vsctl_info info;
+ struct vsctl_iface *iface;
+ char **keys, **values;
+ size_t n;
+
+ get_info(ovs, &info);
+ iface = find_iface(&info, argv[1]);
+ set_external_id(iface->iface_cfg->key_external_ids,
+ iface->iface_cfg->value_external_ids,
+ iface->iface_cfg->n_external_ids,
+ argv[2], argc >= 4 ? argv[3] : NULL,
+ &keys, &values, &n);
+ ovsrec_interface_set_external_ids(iface->iface_cfg, keys, values, n);
+ free(keys);
+ free(values);
+
+ free_info(&info);
+}
+
+static void
+cmd_iface_get_external_id(int argc, char *argv[],
+ const struct ovsrec_open_vswitch *ovs,
+ struct ds *output)
+{
+ struct vsctl_info info;
+ struct vsctl_iface *iface;
+
+ get_info(ovs, &info);
+ iface = find_iface(&info, argv[1]);
+ get_external_id(iface->iface_cfg->key_external_ids,
+ iface->iface_cfg->value_external_ids,
+ iface->iface_cfg->n_external_ids,
+ "", argc >= 3 ? argv[2] : NULL, output);
+ free_info(&info);
+}
\f
typedef void vsctl_handler_func(int argc, char *argv[],
const struct ovsrec_open_vswitch *,
get_vsctl_handler(int argc, char *argv[])
{
static const struct vsctl_command all_commands[] = {
+ /* Bridge commands. */
{"add-br", 1, 3, cmd_add_br},
{"del-br", 1, 1, cmd_del_br},
{"list-br", 0, 0, cmd_list_br},
{"br-exists", 1, 1, cmd_br_exists},
+ {"br-to-vlan", 1, 1, cmd_br_to_vlan},
+ {"br-to-parent", 1, 1, cmd_br_to_parent},
+ {"br-set-external-id", 2, 3, cmd_br_set_external_id},
+ {"br-get-external-id", 1, 2, cmd_br_get_external_id},
+
+ /* Port commands. */
{"list-ports", 1, 1, cmd_list_ports},
{"add-port", 2, 2, cmd_add_port},
{"add-bond", 4, INT_MAX, cmd_add_bond},
{"del-port", 1, 2, cmd_del_port},
{"port-to-br", 1, 1, cmd_port_to_br},
- {"br-to-vlan", 1, 1, cmd_br_to_vlan},
- {"br-to-parent", 1, 1, cmd_br_to_parent},
+ {"port-set-external-id", 2, 3, cmd_port_set_external_id},
+ {"port-get-external-id", 1, 2, cmd_port_get_external_id},
+
+ /* Interface commands. */
{"list-ifaces", 1, 1, cmd_list_ifaces},
{"iface-to-br", 1, 1, cmd_iface_to_br},
+ {"iface-set-external-id", 2, 3, cmd_iface_set_external_id},
+ {"iface-get-external-id", 1, 2, cmd_iface_get_external_id},
};
const struct vsctl_command *p;
"type": {"key": "uuid", "keyRefTable": "NetFlow", "min": 0, "max": 1}},
"controller": {
"comment": "OpenFlow controller. If unset, defaults to that specified by the parent Open_vSwitch.",
- "type": {"key": "uuid", "keyRefTable": "Controller", "min": 0, "max": 1}}}},
+ "type": {"key": "uuid", "keyRefTable": "Controller", "min": 0, "max": 1}},
+ "external_ids": {
+ "comment": "Key-value pairs that identify this bridge's role in external systems. The currently defined key-value pairs are: \"xs-network-uuid\", a space-delimited set of the Citrix XenServer network UUIDs with which this bridge is associated.",
+ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}},
"Port": {
"comment": "A port within a Bridge. May contain a single Interface or multiple (bonded) Interfaces.",
"columns": {
"type": "boolean"},
"fake_bridge": {
"comment": "Does this port represent a sub-bridge for its tagged VLAN within the Bridge? See ovs-vsctl(8) for more information.",
- "type": "boolean"}}},
+ "type": "boolean"},
+ "external_ids": {
+ "comment": "Key-value pairs that identify this port's role in external systems. No key-value pairs native to Port are currently defined. For fake bridges (see the \"fake-bridge\" column), external IDs for the fake bridge are defined here by prefixing their keys with \"fake-bridge\", e.g. \"fake-bridge-xs-network-uuids\".",
+ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}},
"Interface": {
"comment": "An interface within a Port.",
"columns": {
"comment": "Ethernet address to set for this interface. If unset then the default MAC address is used. May not be supported on all interfaces. Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
"type": {"key": "string", "min": 0, "max": 1}},
"external_ids": {
- "comment": "Key-value pairs that identify this interface's role in external systems. The only currently defined key is \"xs-vif-uuid\", whose value is the UUID of the Citrix XenServer VIF associated with this interface.",
+ "comment": "Key-value pairs that identify this interface's role in external systems. The currently defined key-value pairs are: \"xs-vif-uuid\", the UUID of the Citrix XenServer VIF associated with this interface; \"xs-network-uuid\", the UUID of the Citrix XenServer network to which this interface is attached; \"xs-vif-vm-uuid\", the UUID of the Citrix XenServer VM to which this interface belongs; \"xs-vif-mac\", the value of the \"MAC\" field in the Citrix XenServer VIF record for this interface.",
"type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
"ofport": {
"comment": "OpenFlow port number for this interface. This is populated when the port number becomes known. Before it is populated its value will be missing. If the interface cannot be added then this is indicated by a value of -1.",