2 * Copyright (c) 2008, 2009, 2010 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.
29 #include "byte-order.h"
30 #include "classifier.h"
31 #include "command-line.h"
35 #include "dynamic-string.h"
39 #include "ofp-parse.h"
40 #include "ofp-print.h"
43 #include "openflow/nicira-ext.h"
44 #include "openflow/openflow.h"
46 #include "stream-ssl.h"
52 VLOG_DEFINE_THIS_MODULE(ofctl
);
54 /* Use strict matching for flow mod commands? */
57 static const struct command all_commands
[];
59 static void usage(void) NO_RETURN
;
60 static void parse_options(int argc
, char *argv
[]);
63 main(int argc
, char *argv
[])
65 set_program_name(argv
[0]);
66 parse_options(argc
, argv
);
67 signal(SIGPIPE
, SIG_IGN
);
68 run_command(argc
- optind
, argv
+ optind
, all_commands
);
73 parse_options(int argc
, char *argv
[])
76 OPT_STRICT
= UCHAR_MAX
+ 1,
79 static struct option long_options
[] = {
80 {"timeout", required_argument
, 0, 't'},
81 {"strict", no_argument
, 0, OPT_STRICT
},
82 {"help", no_argument
, 0, 'h'},
83 {"version", no_argument
, 0, 'V'},
85 STREAM_SSL_LONG_OPTIONS
88 char *short_options
= long_options_to_short_options(long_options
);
91 unsigned long int timeout
;
94 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
101 timeout
= strtoul(optarg
, NULL
, 10);
103 ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
114 OVS_PRINT_VERSION(OFP_VERSION
, OFP_VERSION
);
122 STREAM_SSL_OPTION_HANDLERS
137 printf("%s: OpenFlow switch management utility\n"
138 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
139 "\nFor OpenFlow switches:\n"
140 " show SWITCH show OpenFlow information\n"
141 " status SWITCH [KEY] report statistics (about KEY)\n"
142 " dump-desc SWITCH print switch description\n"
143 " dump-tables SWITCH print table stats\n"
144 " mod-port SWITCH IFACE ACT modify port behavior\n"
145 " dump-ports SWITCH [PORT] print port statistics\n"
146 " dump-flows SWITCH print all flow entries\n"
147 " dump-flows SWITCH FLOW print matching FLOWs\n"
148 " dump-aggregate SWITCH print aggregate flow statistics\n"
149 " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
150 " queue-stats SWITCH [PORT [QUEUE]] dump queue stats\n"
151 " add-flow SWITCH FLOW add flow described by FLOW\n"
152 " add-flows SWITCH FILE add flows from FILE\n"
153 " mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
154 " del-flows SWITCH [FLOW] delete matching FLOWs\n"
155 " monitor SWITCH [MISSLEN] print packets received from SWITCH\n"
156 "\nFor OpenFlow switches and controllers:\n"
157 " probe VCONN probe whether VCONN is up\n"
158 " ping VCONN [N] latency of N-byte echos\n"
159 " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n"
160 "where each SWITCH is an active OpenFlow connection method.\n",
161 program_name
, program_name
);
162 vconn_usage(true, false, false);
164 printf("\nOther options:\n"
165 " --strict use strict match for flow commands\n"
166 " -t, --timeout=SECS give up after SECS seconds\n"
167 " -h, --help display this help message\n"
168 " -V, --version display version information\n");
172 static void run(int retval
, const char *message
, ...)
175 static void run(int retval
, const char *message
, ...)
180 fprintf(stderr
, "%s: ", program_name
);
181 va_start(args
, message
);
182 vfprintf(stderr
, message
, args
);
185 fputs(": unexpected end of file\n", stderr
);
187 fprintf(stderr
, ": %s\n", strerror(retval
));
194 /* Generic commands. */
197 open_vconn_socket(const char *name
, struct vconn
**vconnp
)
199 char *vconn_name
= xasprintf("unix:%s", name
);
200 VLOG_INFO("connecting to %s", vconn_name
);
201 run(vconn_open_block(vconn_name
, OFP_VERSION
, vconnp
),
202 "connecting to %s", vconn_name
);
207 open_vconn__(const char *name
, const char *default_suffix
,
208 struct vconn
**vconnp
)
212 char *bridge_path
, *datapath_name
, *datapath_type
;
214 bridge_path
= xasprintf("%s/%s.%s", ovs_rundir(), name
, default_suffix
);
215 dp_parse_name(name
, &datapath_name
, &datapath_type
);
217 if (strstr(name
, ":")) {
218 run(vconn_open_block(name
, OFP_VERSION
, vconnp
),
219 "connecting to %s", name
);
220 } else if (!stat(name
, &s
) && S_ISSOCK(s
.st_mode
)) {
221 open_vconn_socket(name
, vconnp
);
222 } else if (!stat(bridge_path
, &s
) && S_ISSOCK(s
.st_mode
)) {
223 open_vconn_socket(bridge_path
, vconnp
);
224 } else if (!dpif_open(datapath_name
, datapath_type
, &dpif
)) {
225 char dpif_name
[IF_NAMESIZE
+ 1];
228 run(dpif_port_get_name(dpif
, ODPP_LOCAL
, dpif_name
, sizeof dpif_name
),
229 "obtaining name of %s", dpif_name
);
231 if (strcmp(dpif_name
, name
)) {
232 VLOG_INFO("datapath %s is named %s", name
, dpif_name
);
235 socket_name
= xasprintf("%s/%s.%s",
236 ovs_rundir(), dpif_name
, default_suffix
);
237 if (stat(socket_name
, &s
)) {
238 ovs_fatal(errno
, "cannot connect to %s: stat failed on %s",
240 } else if (!S_ISSOCK(s
.st_mode
)) {
241 ovs_fatal(0, "cannot connect to %s: %s is not a socket",
245 open_vconn_socket(socket_name
, vconnp
);
248 ovs_fatal(0, "%s is not a valid connection method", name
);
257 open_vconn(const char *name
, struct vconn
**vconnp
)
259 return open_vconn__(name
, "mgmt", vconnp
);
263 alloc_stats_request(size_t body_len
, uint16_t type
, struct ofpbuf
**bufferp
)
265 struct ofp_stats_request
*rq
;
266 rq
= make_openflow((offsetof(struct ofp_stats_request
, body
)
267 + body_len
), OFPT_STATS_REQUEST
, bufferp
);
268 rq
->type
= htons(type
);
269 rq
->flags
= htons(0);
274 send_openflow_buffer(struct vconn
*vconn
, struct ofpbuf
*buffer
)
276 update_openflow_length(buffer
);
277 run(vconn_send_block(vconn
, buffer
), "failed to send packet to switch");
281 dump_transaction(const char *vconn_name
, struct ofpbuf
*request
)
284 struct ofpbuf
*reply
;
286 update_openflow_length(request
);
287 open_vconn(vconn_name
, &vconn
);
288 run(vconn_transact(vconn
, request
, &reply
), "talking to %s", vconn_name
);
289 ofp_print(stdout
, reply
->data
, reply
->size
, 1);
294 dump_trivial_transaction(const char *vconn_name
, uint8_t request_type
)
296 struct ofpbuf
*request
;
297 make_openflow(sizeof(struct ofp_header
), request_type
, &request
);
298 dump_transaction(vconn_name
, request
);
302 dump_stats_transaction(const char *vconn_name
, struct ofpbuf
*request
)
304 ovs_be32 send_xid
= ((struct ofp_header
*) request
->data
)->xid
;
308 open_vconn(vconn_name
, &vconn
);
309 send_openflow_buffer(vconn
, request
);
312 struct ofpbuf
*reply
;
314 run(vconn_recv_block(vconn
, &reply
), "OpenFlow packet receive failed");
315 recv_xid
= ((struct ofp_header
*) reply
->data
)->xid
;
316 if (send_xid
== recv_xid
) {
317 struct ofp_stats_reply
*osr
;
319 ofp_print(stdout
, reply
->data
, reply
->size
, 1);
321 osr
= ofpbuf_at(reply
, 0, sizeof *osr
);
322 done
= !osr
|| !(ntohs(osr
->flags
) & OFPSF_REPLY_MORE
);
324 VLOG_DBG("received reply with xid %08"PRIx32
" "
325 "!= expected %08"PRIx32
, recv_xid
, send_xid
);
327 ofpbuf_delete(reply
);
333 dump_trivial_stats_transaction(const char *vconn_name
, uint8_t stats_type
)
335 struct ofpbuf
*request
;
336 alloc_stats_request(0, stats_type
, &request
);
337 dump_stats_transaction(vconn_name
, request
);
340 /* Sends 'request', which should be a request that only has a reply if an error
341 * occurs, and waits for it to succeed or fail. If an error does occur, prints
342 * it and exits with an error. */
344 dump_noreply_transaction(struct vconn
*vconn
, struct ofpbuf
*request
)
346 struct ofpbuf
*reply
;
348 update_openflow_length(request
);
349 run(vconn_transact_noreply(vconn
, request
, &reply
),
350 "talking to %s", vconn_get_name(vconn
));
352 ofp_print(stderr
, reply
->data
, reply
->size
, 2);
355 ofpbuf_delete(reply
);
359 do_show(int argc OVS_UNUSED
, char *argv
[])
361 dump_trivial_transaction(argv
[1], OFPT_FEATURES_REQUEST
);
362 dump_trivial_transaction(argv
[1], OFPT_GET_CONFIG_REQUEST
);
366 do_status(int argc
, char *argv
[])
368 struct nicira_header
*request
, *reply
;
372 request
= make_nxmsg(sizeof *request
, NXT_STATUS_REQUEST
, &b
);
374 ofpbuf_put(b
, argv
[2], strlen(argv
[2]));
375 update_openflow_length(b
);
377 open_vconn(argv
[1], &vconn
);
378 run(vconn_transact(vconn
, b
, &b
), "talking to %s", argv
[1]);
381 if (b
->size
< sizeof *reply
) {
382 ovs_fatal(0, "short reply (%zu bytes)", b
->size
);
385 if (reply
->header
.type
!= OFPT_VENDOR
386 || reply
->vendor
!= ntohl(NX_VENDOR_ID
)
387 || reply
->subtype
!= ntohl(NXT_STATUS_REPLY
)) {
388 ofp_print(stderr
, b
->data
, b
->size
, 2);
389 ovs_fatal(0, "bad reply");
392 fwrite(reply
+ 1, b
->size
- sizeof *reply
, 1, stdout
);
396 do_dump_desc(int argc OVS_UNUSED
, char *argv
[])
398 dump_trivial_stats_transaction(argv
[1], OFPST_DESC
);
402 do_dump_tables(int argc OVS_UNUSED
, char *argv
[])
404 dump_trivial_stats_transaction(argv
[1], OFPST_TABLE
);
407 /* Opens a connection to 'vconn_name', fetches the ofp_phy_port structure for
408 * 'port_name' (which may be a port name or number), and copies it into
411 fetch_ofp_phy_port(const char *vconn_name
, const char *port_name
,
412 struct ofp_phy_port
*oppp
)
414 struct ofpbuf
*request
, *reply
;
415 struct ofp_switch_features
*osf
;
416 unsigned int port_no
;
421 /* Try to interpret the argument as a port number. */
422 if (!str_to_uint(port_name
, 10, &port_no
)) {
426 /* Fetch the switch's ofp_switch_features. */
427 make_openflow(sizeof(struct ofp_header
), OFPT_FEATURES_REQUEST
, &request
);
428 open_vconn(vconn_name
, &vconn
);
429 run(vconn_transact(vconn
, request
, &reply
), "talking to %s", vconn_name
);
432 if (reply
->size
< sizeof *osf
) {
433 ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
434 vconn_name
, reply
->size
);
436 n_ports
= (reply
->size
- sizeof *osf
) / sizeof *osf
->ports
;
438 for (port_idx
= 0; port_idx
< n_ports
; port_idx
++) {
439 const struct ofp_phy_port
*opp
= &osf
->ports
[port_idx
];
441 if (port_no
!= UINT_MAX
442 ? htons(port_no
) == opp
->port_no
443 : !strncmp(opp
->name
, port_name
, sizeof opp
->name
)) {
445 ofpbuf_delete(reply
);
450 ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name
, port_name
);
453 /* Returns the port number corresponding to 'port_name' (which may be a port
454 * name or number) within the switch 'vconn_name'. */
456 str_to_port_no(const char *vconn_name
, const char *port_name
)
458 unsigned int port_no
;
460 if (str_to_uint(port_name
, 10, &port_no
)) {
463 struct ofp_phy_port opp
;
465 fetch_ofp_phy_port(vconn_name
, port_name
, &opp
);
466 return ntohs(opp
.port_no
);
471 do_dump_flows(int argc
, char *argv
[])
473 struct ofp_flow_stats_request
*req
;
474 struct parsed_flow pf
;
475 struct ofpbuf
*request
;
477 req
= alloc_stats_request(sizeof *req
, OFPST_FLOW
, &request
);
478 parse_ofp_str(&pf
, NULL
, argc
> 2 ? argv
[2] : "");
479 ofputil_cls_rule_to_match(&pf
.rule
, NXFF_OPENFLOW10
, &req
->match
);
480 memset(&req
->pad
, 0, sizeof req
->pad
);
481 req
->out_port
= htons(pf
.out_port
);
483 dump_stats_transaction(argv
[1], request
);
487 do_dump_aggregate(int argc
, char *argv
[])
489 struct ofp_aggregate_stats_request
*req
;
490 struct ofpbuf
*request
;
491 struct parsed_flow pf
;
493 req
= alloc_stats_request(sizeof *req
, OFPST_AGGREGATE
, &request
);
494 parse_ofp_str(&pf
, NULL
, argc
> 2 ? argv
[2] : "");
495 ofputil_cls_rule_to_match(&pf
.rule
, NXFF_OPENFLOW10
, &req
->match
);
496 memset(&req
->pad
, 0, sizeof req
->pad
);
497 req
->out_port
= htons(pf
.out_port
);
499 dump_stats_transaction(argv
[1], request
);
503 do_queue_stats(int argc
, char *argv
[])
505 struct ofp_queue_stats_request
*req
;
506 struct ofpbuf
*request
;
508 req
= alloc_stats_request(sizeof *req
, OFPST_QUEUE
, &request
);
510 if (argc
> 2 && argv
[2][0] && strcasecmp(argv
[2], "all")) {
511 req
->port_no
= htons(str_to_port_no(argv
[1], argv
[2]));
513 req
->port_no
= htons(OFPP_ALL
);
515 if (argc
> 3 && argv
[3][0] && strcasecmp(argv
[3], "all")) {
516 req
->queue_id
= htonl(atoi(argv
[3]));
518 req
->queue_id
= htonl(OFPQ_ALL
);
521 memset(req
->pad
, 0, sizeof req
->pad
);
523 dump_stats_transaction(argv
[1], request
);
527 do_add_flow(int argc OVS_UNUSED
, char *argv
[])
530 struct ofpbuf
*request
;
532 request
= parse_ofp_flow_mod_str(argv
[2], OFPFC_ADD
);
534 open_vconn(argv
[1], &vconn
);
535 dump_noreply_transaction(vconn
, request
);
540 do_add_flows(int argc OVS_UNUSED
, char *argv
[])
546 file
= fopen(argv
[2], "r");
548 ovs_fatal(errno
, "%s: open", argv
[2]);
551 open_vconn(argv
[1], &vconn
);
552 while ((b
= parse_ofp_add_flow_file(file
)) != NULL
) {
553 dump_noreply_transaction(vconn
, b
);
560 do_mod_flows(int argc OVS_UNUSED
, char *argv
[])
563 struct ofpbuf
*buffer
;
566 command
= strict
? OFPFC_MODIFY_STRICT
: OFPFC_MODIFY
;
567 buffer
= parse_ofp_flow_mod_str(argv
[2], command
);
568 open_vconn(argv
[1], &vconn
);
569 dump_noreply_transaction(vconn
, buffer
);
573 static void do_del_flows(int argc
, char *argv
[])
576 struct ofpbuf
*buffer
;
579 command
= strict
? OFPFC_DELETE_STRICT
: OFPFC_DELETE
;
580 buffer
= parse_ofp_flow_mod_str(argc
> 2 ? argv
[2] : "", command
);
582 open_vconn(argv
[1], &vconn
);
583 dump_noreply_transaction(vconn
, buffer
);
588 monitor_vconn(struct vconn
*vconn
)
592 run(vconn_recv_block(vconn
, &b
), "vconn_recv");
593 ofp_print(stderr
, b
->data
, b
->size
, 2);
599 do_monitor(int argc
, char *argv
[])
603 open_vconn(argv
[1], &vconn
);
605 int miss_send_len
= atoi(argv
[2]);
606 struct ofp_switch_config
*osc
;
609 osc
= make_openflow(sizeof *osc
, OFPT_SET_CONFIG
, &buf
);
610 osc
->miss_send_len
= htons(miss_send_len
);
611 dump_noreply_transaction(vconn
, buf
);
613 monitor_vconn(vconn
);
617 do_snoop(int argc OVS_UNUSED
, char *argv
[])
621 open_vconn__(argv
[1], "snoop", &vconn
);
622 monitor_vconn(vconn
);
626 do_dump_ports(int argc
, char *argv
[])
628 struct ofp_port_stats_request
*req
;
629 struct ofpbuf
*request
;
632 req
= alloc_stats_request(sizeof *req
, OFPST_PORT
, &request
);
633 port
= argc
> 2 ? str_to_port_no(argv
[1], argv
[2]) : OFPP_NONE
;
634 req
->port_no
= htons(port
);
635 dump_stats_transaction(argv
[1], request
);
639 do_probe(int argc OVS_UNUSED
, char *argv
[])
641 struct ofpbuf
*request
;
643 struct ofpbuf
*reply
;
645 make_openflow(sizeof(struct ofp_header
), OFPT_ECHO_REQUEST
, &request
);
646 open_vconn(argv
[1], &vconn
);
647 run(vconn_transact(vconn
, request
, &reply
), "talking to %s", argv
[1]);
648 if (reply
->size
!= sizeof(struct ofp_header
)) {
649 ovs_fatal(0, "reply does not match request");
651 ofpbuf_delete(reply
);
656 do_mod_port(int argc OVS_UNUSED
, char *argv
[])
658 struct ofp_port_mod
*opm
;
659 struct ofp_phy_port opp
;
660 struct ofpbuf
*request
;
663 fetch_ofp_phy_port(argv
[1], argv
[2], &opp
);
665 opm
= make_openflow(sizeof(struct ofp_port_mod
), OFPT_PORT_MOD
, &request
);
666 opm
->port_no
= opp
.port_no
;
667 memcpy(opm
->hw_addr
, opp
.hw_addr
, sizeof opm
->hw_addr
);
668 opm
->config
= htonl(0);
669 opm
->mask
= htonl(0);
670 opm
->advertise
= htonl(0);
672 if (!strcasecmp(argv
[3], "up")) {
673 opm
->mask
|= htonl(OFPPC_PORT_DOWN
);
674 } else if (!strcasecmp(argv
[3], "down")) {
675 opm
->mask
|= htonl(OFPPC_PORT_DOWN
);
676 opm
->config
|= htonl(OFPPC_PORT_DOWN
);
677 } else if (!strcasecmp(argv
[3], "flood")) {
678 opm
->mask
|= htonl(OFPPC_NO_FLOOD
);
679 } else if (!strcasecmp(argv
[3], "noflood")) {
680 opm
->mask
|= htonl(OFPPC_NO_FLOOD
);
681 opm
->config
|= htonl(OFPPC_NO_FLOOD
);
683 ovs_fatal(0, "unknown mod-port command '%s'", argv
[3]);
686 open_vconn(argv
[1], &vconn
);
687 dump_noreply_transaction(vconn
, request
);
692 do_ping(int argc
, char *argv
[])
694 size_t max_payload
= 65535 - sizeof(struct ofp_header
);
695 unsigned int payload
;
699 payload
= argc
> 2 ? atoi(argv
[2]) : 64;
700 if (payload
> max_payload
) {
701 ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload
);
704 open_vconn(argv
[1], &vconn
);
705 for (i
= 0; i
< 10; i
++) {
706 struct timeval start
, end
;
707 struct ofpbuf
*request
, *reply
;
708 struct ofp_header
*rq_hdr
, *rpy_hdr
;
710 rq_hdr
= make_openflow(sizeof(struct ofp_header
) + payload
,
711 OFPT_ECHO_REQUEST
, &request
);
712 random_bytes(rq_hdr
+ 1, payload
);
714 gettimeofday(&start
, NULL
);
715 run(vconn_transact(vconn
, ofpbuf_clone(request
), &reply
), "transact");
716 gettimeofday(&end
, NULL
);
718 rpy_hdr
= reply
->data
;
719 if (reply
->size
!= request
->size
720 || memcmp(rpy_hdr
+ 1, rq_hdr
+ 1, payload
)
721 || rpy_hdr
->xid
!= rq_hdr
->xid
722 || rpy_hdr
->type
!= OFPT_ECHO_REPLY
) {
723 printf("Reply does not match request. Request:\n");
724 ofp_print(stdout
, request
, request
->size
, 2);
726 ofp_print(stdout
, reply
, reply
->size
, 2);
728 printf("%zu bytes from %s: xid=%08"PRIx32
" time=%.1f ms\n",
729 reply
->size
- sizeof *rpy_hdr
, argv
[1], ntohl(rpy_hdr
->xid
),
730 (1000*(double)(end
.tv_sec
- start
.tv_sec
))
731 + (.001*(end
.tv_usec
- start
.tv_usec
)));
732 ofpbuf_delete(request
);
733 ofpbuf_delete(reply
);
739 do_benchmark(int argc OVS_UNUSED
, char *argv
[])
741 size_t max_payload
= 65535 - sizeof(struct ofp_header
);
742 struct timeval start
, end
;
743 unsigned int payload_size
, message_size
;
749 payload_size
= atoi(argv
[2]);
750 if (payload_size
> max_payload
) {
751 ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload
);
753 message_size
= sizeof(struct ofp_header
) + payload_size
;
755 count
= atoi(argv
[3]);
757 printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
758 count
, message_size
, count
* message_size
);
760 open_vconn(argv
[1], &vconn
);
761 gettimeofday(&start
, NULL
);
762 for (i
= 0; i
< count
; i
++) {
763 struct ofpbuf
*request
, *reply
;
764 struct ofp_header
*rq_hdr
;
766 rq_hdr
= make_openflow(message_size
, OFPT_ECHO_REQUEST
, &request
);
767 memset(rq_hdr
+ 1, 0, payload_size
);
768 run(vconn_transact(vconn
, request
, &reply
), "transact");
769 ofpbuf_delete(reply
);
771 gettimeofday(&end
, NULL
);
774 duration
= ((1000*(double)(end
.tv_sec
- start
.tv_sec
))
775 + (.001*(end
.tv_usec
- start
.tv_usec
)));
776 printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
777 duration
, count
/ (duration
/ 1000.0),
778 count
* message_size
/ (duration
/ 1000.0));
782 do_help(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
787 /* Undocumented commands for unit testing. */
790 do_parse_flows(int argc OVS_UNUSED
, char *argv
[])
795 file
= fopen(argv
[1], "r");
797 ovs_fatal(errno
, "%s: open", argv
[2]);
800 while ((b
= parse_ofp_add_flow_file(file
)) != NULL
) {
801 ofp_print(stdout
, b
->data
, b
->size
, 0);
808 do_parse_nx_match(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
813 while (!ds_get_line(&in
, stdin
)) {
814 struct ofpbuf nx_match
;
815 struct cls_rule rule
;
820 /* Delete comments, skip blank lines. */
826 if (strchr(s
, '#')) {
827 *strchr(s
, '#') = '\0';
829 if (s
[strspn(s
, " ")] == '\0') {
834 /* Convert string to nx_match. */
835 ofpbuf_init(&nx_match
, 0);
836 match_len
= nx_match_from_string(ds_cstr(&in
), &nx_match
);
838 /* Convert nx_match to cls_rule. */
839 error
= nx_pull_match(&nx_match
, match_len
, 0, &rule
);
843 /* Convert cls_rule back to nx_match. */
844 ofpbuf_uninit(&nx_match
);
845 ofpbuf_init(&nx_match
, 0);
846 match_len
= nx_put_match(&nx_match
, &rule
);
848 /* Convert nx_match to string. */
849 out
= nx_match_to_string(nx_match
.data
, match_len
);
853 printf("nx_pull_match() returned error %x\n", error
);
856 ofpbuf_uninit(&nx_match
);
861 static const struct command all_commands
[] = {
862 { "show", 1, 1, do_show
},
863 { "status", 1, 2, do_status
},
864 { "monitor", 1, 2, do_monitor
},
865 { "snoop", 1, 1, do_snoop
},
866 { "dump-desc", 1, 1, do_dump_desc
},
867 { "dump-tables", 1, 1, do_dump_tables
},
868 { "dump-flows", 1, 2, do_dump_flows
},
869 { "dump-aggregate", 1, 2, do_dump_aggregate
},
870 { "queue-stats", 1, 3, do_queue_stats
},
871 { "add-flow", 2, 2, do_add_flow
},
872 { "add-flows", 2, 2, do_add_flows
},
873 { "mod-flows", 2, 2, do_mod_flows
},
874 { "del-flows", 1, 2, do_del_flows
},
875 { "dump-ports", 1, 2, do_dump_ports
},
876 { "mod-port", 3, 3, do_mod_port
},
877 { "probe", 1, 1, do_probe
},
878 { "ping", 1, 2, do_ping
},
879 { "benchmark", 3, 3, do_benchmark
},
880 { "help", 0, INT_MAX
, do_help
},
882 /* Undocumented commands for testing. */
883 { "parse-flows", 1, 1, do_parse_flows
},
884 { "parse-nx-match", 0, 0, do_parse_nx_match
},
886 { NULL
, 0, 0, NULL
},