It was not too hard to build these commands using the database commands, but a few people have asked for them over the years, so here they are.
Signed-off-by: Ben Pfaff <[email protected]> --- NEWS | 1 + tests/ovs-vsctl.at | 60 +++++++++++++++++++++++++++++++++++++ utilities/ovs-vsctl.8.in | 70 ++++++++++++++++++++++++++++++------------- utilities/ovs-vsctl.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 185 insertions(+), 23 deletions(-) diff --git a/NEWS b/NEWS index 3b6ff74ad368..cc6dd95026de 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ Post-v2.9.0 * ovs-ofctl now accepts and display table names in place of numbers. By default it always accepts names and in interactive use it displays them; use --names or --no-names to override. See ovs-ofctl(8) for details. + - ovs-vsctl: New commands "add-bond-iface" and "del-bond-iface". v2.9.0 - xx xxx xxxx diff --git a/tests/ovs-vsctl.at b/tests/ovs-vsctl.at index 415e14833249..e6c3f4596793 100644 --- a/tests/ovs-vsctl.at +++ b/tests/ovs-vsctl.at @@ -313,6 +313,66 @@ CHECK_IFACES([a], [a1], [a2], [a3]) OVS_VSCTL_CLEANUP AT_CLEANUP +AT_SETUP([add-bond-iface and del-bond-iface]) +AT_KEYWORDS([ovs-vsctl]) +OVS_VSCTL_SETUP + +# Create 2-interface bond. +AT_CHECK([RUN_OVS_VSCTL( + [add-br a], + [add-bond a bond0 a1 a2])]) +CHECK_BRIDGES([a, a, 0]) +CHECK_PORTS([a], [bond0]) +CHECK_IFACES([a], [a1], [a2]) + +# Add interface a3 to bond. +AT_CHECK([RUN_OVS_VSCTL([add-bond-iface bond0 a3])]) +CHECK_BRIDGES([a, a, 0]) +CHECK_PORTS([a], [bond0]) +CHECK_IFACES([a], [a1], [a2], [a3]) + +# Delete interface a2 from bond. +AT_CHECK([RUN_OVS_VSCTL([del-bond-iface bond0 a2])]) +CHECK_BRIDGES([a, a, 0]) +CHECK_PORTS([a], [bond0]) +CHECK_IFACES([a], [a1], [a3]) + +# Add interface a2 to bond. +AT_CHECK([RUN_OVS_VSCTL([add-bond-iface bond0 a2])]) +CHECK_BRIDGES([a, a, 0]) +CHECK_PORTS([a], [bond0]) +CHECK_IFACES([a], [a1], [a2], [a3]) + +# Delete interface a2 from bond. +AT_CHECK([RUN_OVS_VSCTL([del-bond-iface a2])]) +CHECK_BRIDGES([a, a, 0]) +CHECK_PORTS([a], [bond0]) +CHECK_IFACES([a], [a1], [a3]) + +AT_CHECK([RUN_OVS_VSCTL([--if-exists del-bond-iface bond0 a4])]) +AT_CHECK([RUN_OVS_VSCTL([del-bond-iface bond0 a4])], [1], [], + [ovs-vsctl: no interface named a4 +]) +AT_CHECK([RUN_OVS_VSCTL([del-bond-iface a4])], [1], [], + [ovs-vsctl: no interface named a4 +]) +AT_CHECK([RUN_OVS_VSCTL_TOGETHER([add-port a a4], [del-bond-iface bond0 a4])], [1], [], + [ovs-vsctl: port bond0 does not have an interface a4 +]) +AT_CHECK([RUN_OVS_VSCTL([--may-exist add-bond-iface bond0 a3])]) +AT_CHECK([RUN_OVS_VSCTL_TOGETHER([add-bond a bond1 b1 b2 b3], [--may-exist add-bond-iface bond1 a3])], [1], [], + [ovs-vsctl: "--may-exist add-bond-iface bond1 a3" but a3 is actually attached to port bond0 +]) +AT_CHECK([RUN_OVS_VSCTL([add-bond-iface bond0 a3])], [1], [], + [ovs-vsctl: cannot create an interface named a3 because an interface named a3 already exists on bridge a +]) +AT_CHECK([RUN_OVS_VSCTL_TOGETHER([del-bond-iface a1], [del-bond-iface a3])], [1], [], + [ovs-vsctl: cannot delete last interface from port bond0 +]) + +OVS_VSCTL_CLEANUP +AT_CLEANUP + AT_SETUP([add-br a b, add-port a a1, add-port b b1, del-port a a1]) AT_KEYWORDS([ovs-vsctl]) OVS_VSCTL_SETUP diff --git a/utilities/ovs-vsctl.8.in b/utilities/ovs-vsctl.8.in index f539af5486e4..34f41e4e88e6 100644 --- a/utilities/ovs-vsctl.8.in +++ b/utilities/ovs-vsctl.8.in @@ -274,26 +274,6 @@ Without \fB\-\-may\-exist\fR, attempting to create a port that exists is an error. With \fB\-\-may\-exist\fR, this command does nothing if \fIport\fR already exists on \fIbridge\fR and is not a bonded port. . -.IP "[\fB\-\-fake\-iface\fR] \fBadd\-bond \fIbridge port iface\fR\&... [\fIcolumn\fR[\fB:\fIkey\fR]\fR=\fIvalue\fR]\&...\fR" -Creates on \fIbridge\fR a new port named \fIport\fR that bonds -together the network devices given as each \fIiface\fR. At least two -interfaces must be named. If the interfaces are DPDK enabled then -the transaction will need to include operations to explicitly set the -interface type to 'dpdk'. -.IP -Optional arguments set values of column in the Port record created by -the command. The syntax is the same as that for the \fBset\fR command -(see \fBDatabase Commands\fR below). -.IP -With \fB\-\-fake\-iface\fR, a fake interface with the name \fIport\fR is -created. This should only be used for compatibility with legacy -software that requires it. -.IP -Without \fB\-\-may\-exist\fR, attempting to create a port that exists -is an error. With \fB\-\-may\-exist\fR, this command does nothing if -\fIport\fR already exists on \fIbridge\fR and bonds together exactly -the specified interfaces. -. .IP "[\fB\-\-if\-exists\fR] \fBdel\-port \fR[\fIbridge\fR] \fIport\fR" Deletes \fIport\fR. If \fIbridge\fR is omitted, \fIport\fR is removed from whatever bridge contains it; if \fIbridge\fR is specified, it @@ -318,6 +298,56 @@ no effect. Prints the name of the bridge that contains \fIport\fR on standard output. . +.SS "Bond Commands" +. +These commands work with ports that have more than one interface, +which Open vSwitch calls ``bonds.'' +. +.IP "[\fB\-\-fake\-iface\fR] \fBadd\-bond \fIbridge port iface\fR\&... [\fIcolumn\fR[\fB:\fIkey\fR]\fR=\fIvalue\fR]\&...\fR" +Creates on \fIbridge\fR a new port named \fIport\fR that bonds +together the network devices given as each \fIiface\fR. At least two +interfaces must be named. If the interfaces are DPDK enabled then +the transaction will need to include operations to explicitly set the +interface type to 'dpdk'. +.IP +Optional arguments set values of column in the Port record created by +the command. The syntax is the same as that for the \fBset\fR command +(see \fBDatabase Commands\fR below). +.IP +With \fB\-\-fake\-iface\fR, a fake interface with the name \fIport\fR is +created. This should only be used for compatibility with legacy +software that requires it. +.IP +Without \fB\-\-may\-exist\fR, attempting to create a port that exists +is an error. With \fB\-\-may\-exist\fR, this command does nothing if +\fIport\fR already exists on \fIbridge\fR and bonds together exactly +the specified interfaces. +. +.IP "[\fB\-\-may\-exist\fR] \fBadd\-bond\-iface \fIbond iface\fR" +Adds \fIiface\fR as a new bond interface to the existing port +\fIbond\fR. If \fIbond\fR previously had only one port, this +transforms it into a bond. +.IP +Without \fB\-\-may\-exist\fR, attempting to add an \fIiface\fR that is +already part of \fIbond\fR is an error. With \fB\-\-may\-exist\fR, +this command does nothing if \fIiface\fR is already part of +\fIbond\fR. (It is still an error if \fIiface\fR is an interface of +some other port or bond.) +. +.IP "[\fB\-\-if\-exists\fR] \fBdel\-bond\-iface\fR [\fIbond\fR] \fIiface\fR" +Removes \fIiface\fR from its port. If \fIbond\fR is omitted, +\fIiface\fR is removed from whatever port contains it; if \fIbond\fR +is specified, it must be the port that contains \fIbond\fR. +.IP +If removing \fIiface\fR causes its port to have only a single +interface, then that port transforms from a bond into an ordinary +port. It is an error if \fIiface\fR is the only interface in its +port. +.IP +Without \fB\-\-if\-exists\fR, attempting to delete an interface that +does not exist is an error. With \fB\-\-if\-exists\fR, attempting to +delete an interface that does not exist has no effect. +. .SS "Interface Commands" . These commands examine the interfaces attached to an Open vSwitch diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c index 6e47ca361ac4..e22baeb28c36 100644 --- a/utilities/ovs-vsctl.c +++ b/utilities/ovs-vsctl.c @@ -1636,6 +1636,71 @@ cmd_add_bond(struct ctl_context *ctx) &ctx->argv[n_ifaces + 3], ctx->argc - 3 - n_ifaces); } +static void +cmd_add_bond_iface(struct ctl_context *ctx) +{ + vsctl_context_populate_cache(ctx); + + struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + struct vsctl_port *port = find_port(vsctl_ctx, ctx->argv[1], true); + + const char *iface_name = ctx->argv[2]; + if (may_exist) { + struct vsctl_iface *iface = find_iface(vsctl_ctx, iface_name, false); + if (iface) { + if (iface->port == port) { + return; + } + char *command = vsctl_context_to_string(ctx); + ctl_fatal("\"%s\" but %s is actually attached to port %s", + command, iface_name, iface->port->port_cfg->name); + } + } + check_conflicts(vsctl_ctx, iface_name, + xasprintf("cannot create an interface named %s", + iface_name)); + + struct ovsrec_interface *iface = ovsrec_interface_insert(ctx->txn); + ovsrec_interface_set_name(iface, iface_name); + ovsrec_port_update_interfaces_addvalue(port->port_cfg, iface); + post_db_reload_expect_iface(iface); + add_iface_to_cache(vsctl_ctx, port, iface); +} + +static void +cmd_del_bond_iface(struct ctl_context *ctx) +{ + vsctl_context_populate_cache(ctx); + + struct vsctl_context *vsctl_ctx = vsctl_context_cast(ctx); + const char *iface_name = ctx->argv[ctx->argc - 1]; + bool must_exist = !shash_find(&ctx->options, "--if-exists"); + struct vsctl_iface *iface = find_iface(vsctl_ctx, iface_name, must_exist); + if (!iface) { + ovs_assert(!must_exist); + return; + } + + const char *port_name = ctx->argc > 2 ? ctx->argv[1] : NULL; + if (port_name) { + struct vsctl_port *port = find_port(vsctl_ctx, port_name, true); + if (iface->port != port) { + ctl_fatal("port %s does not have an interface %s", + port_name, iface_name); + } + } + + if (ovs_list_is_short(&iface->port->ifaces)) { + ctl_fatal("cannot delete last interface from port %s", + iface->port->port_cfg->name); + } + + ovsrec_port_update_interfaces_delvalue(iface->port->port_cfg, + iface->iface_cfg); + del_cached_iface(vsctl_ctx, iface); +} + static void cmd_del_port(struct ctl_context *ctx) { @@ -2749,13 +2814,19 @@ static const struct ctl_command_syntax vsctl_commands[] = { RO}, {"add-port", 2, INT_MAX, "BRIDGE NEW-PORT [COLUMN[:KEY]=VALUE]...", pre_get_info, cmd_add_port, NULL, "--may-exist", RW}, - {"add-bond", 4, INT_MAX, - "BRIDGE NEW-BOND-PORT SYSIFACE... [COLUMN[:KEY]=VALUE]...", pre_get_info, - cmd_add_bond, NULL, "--may-exist,--fake-iface", RW}, {"del-port", 1, 2, "[BRIDGE] PORT|IFACE", pre_get_info, cmd_del_port, NULL, "--if-exists,--with-iface", RW}, {"port-to-br", 1, 1, "PORT", pre_get_info, cmd_port_to_br, NULL, "", RO}, + /* Bond commands. */ + {"add-bond", 4, INT_MAX, + "BRIDGE BOND IFACE... [COLUMN[:KEY]=VALUE]...", pre_get_info, + cmd_add_bond, NULL, "--may-exist,--fake-iface", RW}, + {"add-bond-iface", 2, 2, "BOND IFACE", pre_get_info, cmd_add_bond_iface, + NULL, "--may-exist", RW}, + {"del-bond-iface", 1, 2, "[BOND] IFACE", pre_get_info, cmd_del_bond_iface, + NULL, "--if-exists", RW}, + /* Interface commands. */ {"list-ifaces", 1, 1, "BRIDGE", pre_get_info, cmd_list_ifaces, NULL, "", RO}, -- 2.15.1 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
