2 * Copyright (c) 2009 Nicira Networks.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
28 #include "command-line.h"
31 #include "dynamic-string.h"
32 #include "ovsdb-idl.h"
33 #include "poll-loop.h"
34 #include "vswitchd/vswitch-idl.h"
39 #define THIS_MODULE VLM_vsctl
41 /* --db: The database server to contact. */
42 static const char *db;
44 /* --oneline: Write each command's output as a single line? */
47 static char *default_db(void);
48 static void usage(void) NO_RETURN;
49 static void parse_options(int argc, char *argv[]);
51 static void do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl);
54 main(int argc, char *argv[])
56 struct ovsdb_idl *idl;
60 set_program_name(argv[0]);
61 signal(SIGPIPE, SIG_IGN);
64 parse_options(argc, argv);
66 idl = ovsdb_idl_create(db, &ovsrec_idl_class);
67 seqno = ovsdb_idl_get_seqno(idl);
70 unsigned int new_seqno;
73 new_seqno = ovsdb_idl_get_seqno(idl);
74 if (new_seqno != seqno) {
76 ovs_fatal(0, "too many database inconsistency failures");
78 do_vsctl(argc - optind, argv + optind, idl);
88 parse_options(int argc, char *argv[])
91 OPT_DB = UCHAR_MAX + 1,
94 static struct option long_options[] = {
95 {"db", required_argument, 0, OPT_DB},
96 {"oneline", no_argument, 0, OPT_ONELINE},
97 {"verbose", optional_argument, 0, 'v'},
98 {"help", no_argument, 0, 'h'},
99 {"version", no_argument, 0, 'V'},
104 short_options = xasprintf ("+%s",
105 long_options_to_short_options(long_options));
109 c = getopt_long(argc, argv, short_options, long_options, NULL);
127 OVS_PRINT_VERSION(0, 0);
131 vlog_set_verbosity(optarg);
151 printf("%s: ovs-vswitchd management utility\n"
152 "usage: %s [OPTIONS] COMMAND [ARG...]\n",
153 program_name, program_name);
154 printf("\nBridge commands:\n"
156 "create a new bridge named BRIDGE\n"
157 " add-br BRIDGE PARENT VLAN "
158 "create new fake bridge BRIDGE in PARENT on VLAN\n"
160 "delete BRIDGE and all of its ports\n"
162 "print the names of all the bridges\n"
164 "test whether BRIDGE exists\n"
165 " br-to-vlan BRIDGE "
166 "print the VLAN which BRIDGE is on\n"
167 " br-to-parent BRIDGE "
168 "print the parent of BRIDGE\n");
169 printf("\nPort commands:\n"
170 " list-ports BRIDGE "
171 "print the names of all the ports on BRIDGE\n"
172 " add-port BRIDGE PORT "
173 "add network device PORT to BRIDGE\n"
174 " add-bond BRIDGE PORT IFACE... "
175 "add new bonded port PORT in BRIDGE from IFACES\n"
176 " del-port [BRIDGE] PORT "
177 "delete PORT (which may be bonded) from BRIDGE\n"
179 "print name of bridge that contains PORT\n"
180 "A bond is considered to be a single port.\n");
181 printf("\nInterface commands (a bond consists of multiple interfaces):\n"
182 " list-ifaces BRIDGE "
183 "print the names of all the interfaces on BRIDGE\n"
184 " iface-to-br IFACE "
185 "print name of bridge that contains IFACE\n");
186 printf("\nOptions:\n"
188 "connect to DATABASE\n"
192 "print exactly one line of output per command\n",
195 printf("\nOther options:\n"
197 "display this help message\n"
199 "display version information\n");
208 def = xasprintf("%s/ovsdb-server", ovs_rundir);
213 struct vsctl_bridge {
214 struct ovsrec_bridge *br_cfg;
216 struct vsctl_bridge *parent;
221 struct ovsrec_port *port_cfg;
222 struct vsctl_bridge *bridge;
226 struct ovsrec_interface *iface_cfg;
227 struct vsctl_port *port;
231 struct shash bridges;
236 static struct ovsdb_idl_txn *
237 txn_from_openvswitch(const struct ovsrec_open_vswitch *ovs)
239 return ovsdb_idl_txn_get(&ovs->header_);
242 static struct vsctl_bridge *
243 add_bridge(struct vsctl_info *b,
244 struct ovsrec_bridge *br_cfg, const char *name,
245 struct vsctl_bridge *parent, int vlan)
247 struct vsctl_bridge *br = xmalloc(sizeof *br);
249 br->name = xstrdup(name);
252 shash_add(&b->bridges, br->name, br);
257 port_is_fake_bridge(const struct ovsrec_port *port_cfg)
259 return (port_cfg->fake_bridge
261 && *port_cfg->tag >= 1 && *port_cfg->tag <= 4095);
264 static struct vsctl_bridge *
265 find_vlan_bridge(struct vsctl_info *info,
266 struct vsctl_bridge *parent, int vlan)
268 struct shash_node *node;
270 SHASH_FOR_EACH (node, &info->bridges) {
271 struct vsctl_bridge *br = node->data;
272 if (br->parent == parent && br->vlan == vlan) {
281 free_info(struct vsctl_info *info)
283 struct shash_node *node;
285 SHASH_FOR_EACH (node, &info->bridges) {
286 struct vsctl_bridge *bridge = node->data;
290 shash_destroy(&info->bridges);
292 SHASH_FOR_EACH (node, &info->ports) {
293 struct vsctl_port *port = node->data;
296 shash_destroy(&info->ports);
298 SHASH_FOR_EACH (node, &info->ifaces) {
299 struct vsctl_iface *iface = node->data;
302 shash_destroy(&info->ifaces);
306 get_info(const struct ovsrec_open_vswitch *ovs, struct vsctl_info *info)
308 struct shash bridges, ports;
311 shash_init(&info->bridges);
312 shash_init(&info->ports);
313 shash_init(&info->ifaces);
315 shash_init(&bridges);
317 for (i = 0; i < ovs->n_bridges; i++) {
318 struct ovsrec_bridge *br_cfg = ovs->bridges[i];
319 struct vsctl_bridge *br;
322 if (!shash_add_once(&bridges, br_cfg->name, NULL)) {
323 VLOG_WARN("%s: database contains duplicate bridge name",
327 br = add_bridge(info, br_cfg, br_cfg->name, NULL, 0);
332 for (j = 0; j < br_cfg->n_ports; j++) {
333 struct ovsrec_port *port_cfg = br_cfg->ports[j];
335 if (!shash_add_once(&ports, port_cfg->name, NULL)) {
336 VLOG_WARN("%s: database contains duplicate port name",
341 if (port_is_fake_bridge(port_cfg)
342 && shash_add_once(&bridges, br_cfg->name, NULL)) {
343 add_bridge(info, NULL, port_cfg->name, br, *port_cfg->tag);
347 shash_destroy(&bridges);
348 shash_destroy(&ports);
350 shash_init(&bridges);
352 for (i = 0; i < ovs->n_bridges; i++) {
353 struct ovsrec_bridge *br_cfg = ovs->bridges[i];
354 struct vsctl_bridge *br;
357 if (!shash_add_once(&bridges, br_cfg->name, NULL)) {
360 br = shash_find_data(&info->bridges, br_cfg->name);
361 for (j = 0; j < br_cfg->n_ports; j++) {
362 struct ovsrec_port *port_cfg = br_cfg->ports[j];
363 struct vsctl_port *port;
366 if (!shash_add_once(&ports, port_cfg->name, NULL)) {
370 if (port_is_fake_bridge(port_cfg)
371 && !shash_add_once(&bridges, br_cfg->name, NULL)) {
375 port = xmalloc(sizeof *port);
376 port->port_cfg = port_cfg;
378 && *port_cfg->tag >= 1 && *port_cfg->tag <= 4095) {
379 port->bridge = find_vlan_bridge(info, br, *port_cfg->tag);
386 shash_add(&info->ports, port_cfg->name, port);
388 for (k = 0; k < port_cfg->n_interfaces; k++) {
389 struct ovsrec_interface *iface_cfg = port_cfg->interfaces[k];
390 struct vsctl_iface *iface;
392 if (shash_find(&info->ifaces, iface_cfg->name)) {
393 VLOG_WARN("%s: database contains duplicate interface name",
398 iface = xmalloc(sizeof *iface);
399 iface->iface_cfg = iface_cfg;
404 shash_destroy(&bridges);
405 shash_destroy(&ports);
409 check_conflicts(struct vsctl_info *info, const char *name,
412 struct vsctl_iface *iface;
413 struct vsctl_port *port;
415 if (shash_find(&info->bridges, name)) {
416 ovs_fatal(0, "%s because a bridge named %s already exists", msg, name);
419 port = shash_find_data(&info->ports, name);
421 ovs_fatal(0, "%s because a port named %s already exists on bridge %s",
422 msg, name, port->bridge->name);
425 iface = shash_find_data(&info->ifaces, name);
427 ovs_fatal(0, "%s because an interface named %s already exists "
428 "on bridge %s", msg, name, iface->port->bridge->name);
434 static struct vsctl_bridge *
435 find_bridge(struct vsctl_info *info, const char *name)
437 struct vsctl_bridge *br = shash_find_data(&info->bridges, name);
439 ovs_fatal(0, "no bridge named %s", name);
444 static struct vsctl_port *
445 find_port(struct vsctl_info *info, const char *name)
447 struct vsctl_port *port = shash_find_data(&info->ports, name);
448 if (!port || !strcmp(name, port->bridge->name)) {
449 ovs_fatal(0, "no port named %s", name);
454 static struct vsctl_iface *
455 find_iface(struct vsctl_info *info, const char *name)
457 struct vsctl_iface *iface = shash_find_data(&info->ifaces, name);
459 ovs_fatal(0, "no interface named %s", name);
465 bridge_insert_port(struct ovsrec_bridge *br, struct ovsrec_port *port)
467 struct ovsrec_port **ports;
470 ports = xmalloc(sizeof *br->ports * (br->n_ports + 1));
471 for (i = 0; i < br->n_ports; i++) {
472 ports[i] = br->ports[i];
474 printf("bridge has %zu ports, adding 1\n", br->n_ports);
475 ports[br->n_ports] = port;
476 ovsrec_bridge_set_ports(br, ports, br->n_ports + 1);
481 bridge_delete_port(struct ovsrec_bridge *br, struct ovsrec_port *port)
483 struct ovsrec_port **ports;
486 ports = xmalloc(sizeof *br->ports * br->n_ports);
487 for (i = n = 0; i < br->n_ports; i++) {
488 if (br->ports[i] != port) {
489 ports[n++] = br->ports[i];
492 ovsrec_bridge_set_ports(br, ports, n);
497 ovs_insert_bridge(const struct ovsrec_open_vswitch *ovs,
498 struct ovsrec_bridge *bridge)
500 struct ovsrec_bridge **bridges;
503 bridges = xmalloc(sizeof *ovs->bridges * (ovs->n_bridges + 1));
504 for (i = 0; i < ovs->n_bridges; i++) {
505 bridges[i] = ovs->bridges[i];
507 bridges[ovs->n_bridges] = bridge;
508 ovsrec_open_vswitch_set_bridges(ovs, bridges, ovs->n_bridges + 1);
513 ovs_delete_bridge(const struct ovsrec_open_vswitch *ovs,
514 struct ovsrec_bridge *bridge)
516 struct ovsrec_bridge **bridges;
519 bridges = xmalloc(sizeof *ovs->bridges * ovs->n_bridges);
520 for (i = n = 0; i < ovs->n_bridges; i++) {
521 if (ovs->bridges[i] != bridge) {
522 bridges[n++] = ovs->bridges[i];
525 ovsrec_open_vswitch_set_bridges(ovs, bridges, n);
530 cmd_add_br(int argc, char *argv[], const struct ovsrec_open_vswitch *ovs,
531 struct ds *output UNUSED)
533 const char *br_name = argv[1];
534 struct vsctl_info info;
536 get_info(ovs, &info);
537 check_conflicts(&info, br_name,
538 xasprintf("cannot create a bridge named %s", br_name));
541 struct ovsrec_bridge *br;
542 struct ovsrec_port *port;
543 struct ovsrec_interface *iface;
545 iface = ovsrec_interface_insert(txn_from_openvswitch(ovs));
546 ovsrec_interface_set_name(iface, br_name);
548 port = ovsrec_port_insert(txn_from_openvswitch(ovs));
549 ovsrec_port_set_name(port, br_name);
550 ovsrec_port_set_interfaces(port, &iface, 1);
552 br = ovsrec_bridge_insert(txn_from_openvswitch(ovs));
553 ovsrec_bridge_set_name(br, br_name);
554 ovsrec_bridge_set_ports(br, &port, 1);
556 ovs_insert_bridge(ovs, br);
557 } else if (argc == 3) {
558 ovs_fatal(0, "'%s' comamnd takes exactly 1 or 3 arguments", argv[0]);
559 } else if (argc >= 4) {
560 const char *parent_name = argv[2];
561 int vlan = atoi(argv[3]);
562 struct ovsrec_bridge *br;
563 struct vsctl_bridge *parent;
564 struct ovsrec_port *port;
565 struct ovsrec_interface *iface;
568 if (vlan < 1 || vlan > 4095) {
569 ovs_fatal(0, "%s: vlan must be between 1 and 4095", argv[0]);
572 parent = shash_find_data(&info.bridges, parent_name);
573 if (parent && parent->vlan) {
574 ovs_fatal(0, "cannot create brdige with fake bridge as parent");
577 ovs_fatal(0, "parent bridge %s does not exist", parent_name);
581 iface = ovsrec_interface_insert(txn_from_openvswitch(ovs));
582 ovsrec_interface_set_name(iface, br_name);
583 ovsrec_interface_set_type(iface, "internal");
585 port = ovsrec_port_insert(txn_from_openvswitch(ovs));
586 ovsrec_port_set_name(port, br_name);
587 ovsrec_port_set_interfaces(port, &iface, 1);
588 ovsrec_port_set_fake_bridge(port, true);
589 ovsrec_port_set_tag(port, &tag, 1);
598 del_port(struct vsctl_info *info, struct vsctl_port *port)
600 struct shash_node *node;
602 SHASH_FOR_EACH (node, &info->ifaces) {
603 struct vsctl_iface *iface = node->data;
604 if (iface->port == port) {
605 ovsrec_interface_delete(iface->iface_cfg);
608 ovsrec_port_delete(port->port_cfg);
610 bridge_delete_port((port->bridge->parent
611 ? port->bridge->parent->br_cfg
612 : port->bridge->br_cfg), port->port_cfg);
616 cmd_del_br(int argc UNUSED, char *argv[],
617 const struct ovsrec_open_vswitch *ovs, struct ds *output UNUSED)
619 struct shash_node *node;
620 struct vsctl_info info;
621 struct vsctl_bridge *bridge;
623 get_info(ovs, &info);
624 bridge = find_bridge(&info, argv[1]);
625 SHASH_FOR_EACH (node, &info.ports) {
626 struct vsctl_port *port = node->data;
627 if (port->bridge == bridge) {
628 del_port(&info, port);
631 if (bridge->br_cfg) {
632 ovsrec_bridge_delete(bridge->br_cfg);
633 ovs_delete_bridge(ovs, bridge->br_cfg);
639 cmd_list_br(int argc UNUSED, char *argv[] UNUSED,
640 const struct ovsrec_open_vswitch *ovs, struct ds *output)
642 struct shash_node *node;
643 struct vsctl_info info;
645 get_info(ovs, &info);
646 SHASH_FOR_EACH (node, &info.bridges) {
647 struct vsctl_bridge *br = node->data;
648 ds_put_format(output, "%s\n", br->name);
654 cmd_br_exists(int argc UNUSED, char *argv[],
655 const struct ovsrec_open_vswitch *ovs, struct ds *output UNUSED)
657 struct vsctl_info info;
659 get_info(ovs, &info);
660 if (!shash_find_data(&info.bridges, argv[1])) {
667 cmd_list_ports(int argc UNUSED, char *argv[],
668 const struct ovsrec_open_vswitch *ovs, struct ds *output)
670 struct vsctl_bridge *br;
671 struct shash_node *node;
672 struct vsctl_info info;
674 get_info(ovs, &info);
675 br = find_bridge(&info, argv[1]);
676 SHASH_FOR_EACH (node, &info.ports) {
677 struct vsctl_port *port = node->data;
679 if (strcmp(port->port_cfg->name, br->name) && br == port->bridge) {
680 ds_put_format(output, "%s\n", port->port_cfg->name);
687 add_port(const struct ovsrec_open_vswitch *ovs,
688 const char *br_name, const char *port_name,
689 char *iface_names[], int n_ifaces)
691 struct vsctl_info info;
692 struct vsctl_bridge *bridge;
693 struct ovsrec_interface **ifaces;
694 struct ovsrec_port *port;
697 get_info(ovs, &info);
698 check_conflicts(&info, port_name,
699 xasprintf("cannot create a port named %s", port_name));
700 /* XXX need to check for conflicts on interfaces too */
701 bridge = find_bridge(&info, br_name);
703 ifaces = xmalloc(n_ifaces * sizeof *ifaces);
704 for (i = 0; i < n_ifaces; i++) {
705 ifaces[i] = ovsrec_interface_insert(txn_from_openvswitch(ovs));
706 ovsrec_interface_set_name(ifaces[i], iface_names[i]);
709 port = ovsrec_port_insert(txn_from_openvswitch(ovs));
710 ovsrec_port_set_name(port, port_name);
711 ovsrec_port_set_interfaces(port, ifaces, n_ifaces);
713 int64_t tag = bridge->vlan;
714 ovsrec_port_set_tag(port, &tag, 1);
717 bridge_insert_port((bridge->parent ? bridge->parent->br_cfg
718 : bridge->br_cfg), port);
724 cmd_add_port(int argc UNUSED, char *argv[],
725 const struct ovsrec_open_vswitch *ovs, struct ds *output UNUSED)
727 add_port(ovs, argv[1], argv[2], &argv[2], 1);
731 cmd_add_bond(int argc, char *argv[],
732 const struct ovsrec_open_vswitch *ovs, struct ds *output UNUSED)
734 add_port(ovs, argv[1], argv[2], &argv[3], argc - 3);
738 cmd_del_port(int argc, char *argv[],
739 const struct ovsrec_open_vswitch *ovs, struct ds *output UNUSED)
741 struct vsctl_info info;
743 get_info(ovs, &info);
745 struct vsctl_port *port = find_port(&info, argv[1]);
746 del_port(&info, port);
747 } else if (argc == 3) {
748 struct vsctl_bridge *bridge = find_bridge(&info, argv[1]);
749 struct vsctl_port *port = find_port(&info, argv[2]);
751 if (port->bridge == bridge) {
752 del_port(&info, port);
753 } else if (port->bridge->parent == bridge) {
754 ovs_fatal(0, "bridge %s does not have a port %s (although its "
755 "parent bridge %s does)",
756 argv[1], argv[2], bridge->parent->name);
758 ovs_fatal(0, "bridge %s does not have a port %s",
766 cmd_port_to_br(int argc UNUSED, char *argv[],
767 const struct ovsrec_open_vswitch *ovs, struct ds *output)
769 struct vsctl_port *port;
770 struct vsctl_info info;
772 get_info(ovs, &info);
773 port = find_port(&info, argv[1]);
774 ds_put_format(output, "%s\n", port->bridge->name);
779 cmd_br_to_vlan(int argc UNUSED, char *argv[],
780 const struct ovsrec_open_vswitch *ovs, struct ds *output)
782 struct vsctl_bridge *bridge;
783 struct vsctl_info info;
785 get_info(ovs, &info);
786 bridge = find_bridge(&info, argv[1]);
787 ds_put_format(output, "%d\n", bridge->vlan);
792 cmd_br_to_parent(int argc UNUSED, char *argv[],
793 const struct ovsrec_open_vswitch *ovs, struct ds *output)
795 struct vsctl_bridge *bridge;
796 struct vsctl_info info;
798 get_info(ovs, &info);
799 bridge = find_bridge(&info, argv[1]);
800 if (bridge->parent) {
801 bridge = bridge->parent;
803 ds_put_format(output, "%s\n", bridge->name);
808 cmd_list_ifaces(int argc UNUSED, char *argv[],
809 const struct ovsrec_open_vswitch *ovs, struct ds *output)
811 struct vsctl_bridge *br;
812 struct shash_node *node;
813 struct vsctl_info info;
815 get_info(ovs, &info);
816 br = find_bridge(&info, argv[1]);
817 SHASH_FOR_EACH (node, &info.ifaces) {
818 struct vsctl_iface *iface = node->data;
820 if (br == iface->port->bridge) {
821 ds_put_format(output, "%s\n", iface->iface_cfg->name);
828 cmd_iface_to_br(int argc UNUSED, char *argv[],
829 const struct ovsrec_open_vswitch *ovs, struct ds *output)
831 struct vsctl_iface *iface;
832 struct vsctl_info info;
834 get_info(ovs, &info);
835 iface = find_iface(&info, argv[1]);
836 ds_put_format(output, "%s\n", iface->port->bridge->name);
840 struct vsctl_command {
844 void (*handler)(int argc, char *argv[],
845 const struct ovsrec_open_vswitch *ovs, struct ds *output);
848 static void run_vsctl_command(int argc, char *argv[],
849 const struct ovsrec_open_vswitch *ovs,
853 do_vsctl(int argc, char *argv[], struct ovsdb_idl *idl)
855 struct ovsdb_idl_txn *txn;
856 const struct ovsrec_open_vswitch *ovs;
857 enum ovsdb_idl_txn_status status;
862 ovs = ovsrec_open_vswitch_first(idl);
864 /* XXX it would be more user-friendly to create a record ourselves
865 * (while verifying that the table is empty before doing so). */
866 ovs_fatal(0, "%s: database does not contain any Open vSwitch "
867 "configuration", db);
870 txn = ovsdb_idl_txn_create(idl);
871 output = xmalloc(argc * sizeof *output);
873 for (start = i = 0; i < argc; i++) {
874 if (!strcmp(argv[i], "--")) {
876 ds_init(&output[n_output]);
877 run_vsctl_command(i - start, &argv[start], ovs,
878 &output[n_output++]);
884 ds_init(&output[n_output]);
885 run_vsctl_command(i - start, &argv[start], ovs, &output[n_output++]);
888 while ((status = ovsdb_idl_txn_commit(txn)) == TXN_INCOMPLETE) {
893 ovsdb_idl_txn_destroy(txn);
900 /* Should not happen--we never call ovsdb_idl_txn_abort(). */
901 ovs_fatal(0, "transaction aborted");
907 for (i = 0; i < n_output; i++) {
908 ds_destroy(&output[i]);
913 ovs_fatal(0, "transaction error");
919 for (i = 0; i < n_output; i++) {
920 struct ds *ds = &output[i];
925 for (j = 0; j < ds->length; j++) {
926 int c = ds->string[j];
929 fputs("\\n", stdout);
933 fputs("\\\\", stdout);
942 fputs(ds_cstr(ds), stdout);
949 run_vsctl_command(int argc, char *argv[],
950 const struct ovsrec_open_vswitch *ovs, struct ds *output)
952 static const struct vsctl_command all_commands[] = {
953 {"add-br", 1, 3, cmd_add_br},
954 {"del-br", 1, 1, cmd_del_br},
955 {"list-br", 0, 0, cmd_list_br},
956 {"br-exists", 1, 1, cmd_br_exists},
957 {"list-ports", 1, 1, cmd_list_ports},
958 {"add-port", 2, 2, cmd_add_port},
959 {"add-bond", 4, INT_MAX, cmd_add_bond},
960 {"del-port", 1, 2, cmd_del_port},
961 {"port-to-br", 1, 1, cmd_port_to_br},
962 {"br-to-vlan", 1, 1, cmd_br_to_vlan},
963 {"br-to-parent", 1, 1, cmd_br_to_parent},
964 {"list-ifaces", 1, 1, cmd_list_ifaces},
965 {"iface-to-br", 1, 1, cmd_iface_to_br},
968 const struct vsctl_command *p;
971 for (p = all_commands; p->name != NULL; p++) {
972 if (!strcmp(p->name, argv[0])) {
973 int n_arg = argc - 1;
974 if (n_arg < p->min_args) {
975 ovs_fatal(0, "'%s' command requires at least %d arguments",
976 p->name, p->min_args);
977 } else if (n_arg > p->max_args) {
978 ovs_fatal(0, "'%s' command takes at most %d arguments",
979 p->name, p->max_args);
981 p->handler(argc, argv, ovs, output);
987 ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);