]> git.proxmox.com Git - mirror_ovs.git/blame - utilities/ovs-ofctl.c
ofproto: Get rid of archaic "switch status" OpenFlow extension.
[mirror_ovs.git] / utilities / ovs-ofctl.c
CommitLineData
064af421 1/*
fec00620 2 * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
064af421 3 *
a14bc59f
BP
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:
064af421 7 *
a14bc59f
BP
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
064af421
BP
15 */
16
17#include <config.h>
064af421
BP
18#include <errno.h>
19#include <getopt.h>
20#include <inttypes.h>
21#include <net/if.h>
064af421 22#include <signal.h>
064af421
BP
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28
10a24935 29#include "byte-order.h"
09246b99 30#include "classifier.h"
064af421
BP
31#include "command-line.h"
32#include "compiler.h"
33#include "dirs.h"
34#include "dpif.h"
09246b99 35#include "dynamic-string.h"
064af421 36#include "netlink.h"
09246b99 37#include "nx-match.h"
064af421 38#include "odp-util.h"
f22716dc 39#include "ofp-parse.h"
064af421 40#include "ofp-print.h"
fa37b408 41#include "ofp-util.h"
064af421
BP
42#include "ofpbuf.h"
43#include "openflow/nicira-ext.h"
44#include "openflow/openflow.h"
064af421 45#include "random.h"
fe55ad15 46#include "stream-ssl.h"
064af421
BP
47#include "timeval.h"
48#include "util.h"
064af421 49#include "vconn.h"
5136ce49 50#include "vlog.h"
064af421 51
d98e6007 52VLOG_DEFINE_THIS_MODULE(ofctl);
064af421 53
88ca35ee 54/* --strict: Use strict matching for flow mod commands? */
675febfa 55static bool strict;
064af421 56
88ca35ee
BP
57/* -F, --flow-format: Flow format to use. Either one of NXFF_* to force a
58 * particular flow format or -1 to let ovs-ofctl choose intelligently. */
59static int preferred_flow_format = -1;
60
4f564f8d
BP
61/* -m, --more: Additional verbosity for ofp-print functions. */
62static int verbosity;
63
675febfa 64static const struct command all_commands[];
064af421
BP
65
66static void usage(void) NO_RETURN;
675febfa 67static void parse_options(int argc, char *argv[]);
064af421 68
675febfa
BP
69int
70main(int argc, char *argv[])
064af421 71{
064af421 72 set_program_name(argv[0]);
675febfa 73 parse_options(argc, argv);
064af421 74 signal(SIGPIPE, SIG_IGN);
675febfa 75 run_command(argc - optind, argv + optind, all_commands);
064af421
BP
76 return 0;
77}
78
79static void
675febfa 80parse_options(int argc, char *argv[])
064af421
BP
81{
82 enum {
87c84891
JP
83 OPT_STRICT = UCHAR_MAX + 1,
84 VLOG_OPTION_ENUMS
064af421
BP
85 };
86 static struct option long_options[] = {
87 {"timeout", required_argument, 0, 't'},
064af421 88 {"strict", no_argument, 0, OPT_STRICT},
88ca35ee 89 {"flow-format", required_argument, 0, 'F'},
4f564f8d 90 {"more", no_argument, 0, 'm'},
064af421
BP
91 {"help", no_argument, 0, 'h'},
92 {"version", no_argument, 0, 'V'},
87c84891 93 VLOG_LONG_OPTIONS,
fe55ad15 94 STREAM_SSL_LONG_OPTIONS
064af421
BP
95 {0, 0, 0, 0},
96 };
97 char *short_options = long_options_to_short_options(long_options);
98
064af421
BP
99 for (;;) {
100 unsigned long int timeout;
101 int c;
102
103 c = getopt_long(argc, argv, short_options, long_options, NULL);
104 if (c == -1) {
105 break;
106 }
107
108 switch (c) {
109 case 't':
110 timeout = strtoul(optarg, NULL, 10);
111 if (timeout <= 0) {
112 ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
113 optarg);
114 } else {
115 time_alarm(timeout);
116 }
117 break;
118
88ca35ee
BP
119 case 'F':
120 preferred_flow_format = ofputil_flow_format_from_string(optarg);
121 if (preferred_flow_format < 0) {
122 ovs_fatal(0, "unknown flow format `%s'", optarg);
123 }
124 break;
125
4f564f8d
BP
126 case 'm':
127 verbosity++;
128 break;
129
064af421
BP
130 case 'h':
131 usage();
132
133 case 'V':
134 OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION);
135 exit(EXIT_SUCCESS);
136
064af421 137 case OPT_STRICT:
675febfa 138 strict = true;
064af421
BP
139 break;
140
87c84891 141 VLOG_OPTION_HANDLERS
fe55ad15 142 STREAM_SSL_OPTION_HANDLERS
064af421
BP
143
144 case '?':
145 exit(EXIT_FAILURE);
146
147 default:
148 abort();
149 }
150 }
151 free(short_options);
152}
153
154static void
155usage(void)
156{
157 printf("%s: OpenFlow switch management utility\n"
158 "usage: %s [OPTIONS] COMMAND [ARG...]\n"
159 "\nFor OpenFlow switches:\n"
160 " show SWITCH show OpenFlow information\n"
064af421
BP
161 " dump-desc SWITCH print switch description\n"
162 " dump-tables SWITCH print table stats\n"
163 " mod-port SWITCH IFACE ACT modify port behavior\n"
abaad8cf 164 " dump-ports SWITCH [PORT] print port statistics\n"
064af421
BP
165 " dump-flows SWITCH print all flow entries\n"
166 " dump-flows SWITCH FLOW print matching FLOWs\n"
167 " dump-aggregate SWITCH print aggregate flow statistics\n"
168 " dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
d2805da2 169 " queue-stats SWITCH [PORT [QUEUE]] dump queue stats\n"
064af421
BP
170 " add-flow SWITCH FLOW add flow described by FLOW\n"
171 " add-flows SWITCH FILE add flows from FILE\n"
172 " mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
173 " del-flows SWITCH [FLOW] delete matching FLOWs\n"
a6bc4a03 174 " monitor SWITCH [MISSLEN] print packets received from SWITCH\n"
064af421
BP
175 "\nFor OpenFlow switches and controllers:\n"
176 " probe VCONN probe whether VCONN is up\n"
177 " ping VCONN [N] latency of N-byte echos\n"
178 " benchmark VCONN N COUNT bandwidth of COUNT N-byte echos\n"
179 "where each SWITCH is an active OpenFlow connection method.\n",
180 program_name, program_name);
181 vconn_usage(true, false, false);
182 vlog_usage();
183 printf("\nOther options:\n"
184 " --strict use strict match for flow commands\n"
88ca35ee 185 " -F, --flow-format=FORMAT force particular flow format\n"
4f564f8d 186 " -m, --more be more verbose printing OpenFlow\n"
064af421
BP
187 " -t, --timeout=SECS give up after SECS seconds\n"
188 " -h, --help display this help message\n"
189 " -V, --version display version information\n");
190 exit(EXIT_SUCCESS);
191}
192
193static void run(int retval, const char *message, ...)
194 PRINTF_FORMAT(2, 3);
195
196static void run(int retval, const char *message, ...)
197{
198 if (retval) {
199 va_list args;
200
201 fprintf(stderr, "%s: ", program_name);
202 va_start(args, message);
203 vfprintf(stderr, message, args);
204 va_end(args);
205 if (retval == EOF) {
206 fputs(": unexpected end of file\n", stderr);
207 } else {
208 fprintf(stderr, ": %s\n", strerror(retval));
209 }
210
211 exit(EXIT_FAILURE);
212 }
213}
214\f
215/* Generic commands. */
216
1a6f1e2a
JG
217static void
218open_vconn_socket(const char *name, struct vconn **vconnp)
219{
220 char *vconn_name = xasprintf("unix:%s", name);
24cd0dee 221 VLOG_DBG("connecting to %s", vconn_name);
1a6f1e2a
JG
222 run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
223 "connecting to %s", vconn_name);
224 free(vconn_name);
225}
226
064af421 227static void
0caf6bde
BP
228open_vconn__(const char *name, const char *default_suffix,
229 struct vconn **vconnp)
064af421 230{
c228a364 231 struct dpif *dpif;
064af421 232 struct stat s;
1a6f1e2a
JG
233 char *bridge_path, *datapath_name, *datapath_type;
234
b43c6fe2 235 bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, default_suffix);
1a6f1e2a 236 dp_parse_name(name, &datapath_name, &datapath_type);
064af421
BP
237
238 if (strstr(name, ":")) {
239 run(vconn_open_block(name, OFP_VERSION, vconnp),
240 "connecting to %s", name);
241 } else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
1a6f1e2a
JG
242 open_vconn_socket(name, vconnp);
243 } else if (!stat(bridge_path, &s) && S_ISSOCK(s.st_mode)) {
244 open_vconn_socket(bridge_path, vconnp);
245 } else if (!dpif_open(datapath_name, datapath_type, &dpif)) {
064af421
BP
246 char dpif_name[IF_NAMESIZE + 1];
247 char *socket_name;
064af421 248
c228a364 249 run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name),
064af421 250 "obtaining name of %s", dpif_name);
c228a364 251 dpif_close(dpif);
064af421 252 if (strcmp(dpif_name, name)) {
24cd0dee 253 VLOG_DBG("datapath %s is named %s", name, dpif_name);
064af421
BP
254 }
255
0caf6bde 256 socket_name = xasprintf("%s/%s.%s",
b43c6fe2 257 ovs_rundir(), dpif_name, default_suffix);
064af421
BP
258 if (stat(socket_name, &s)) {
259 ovs_fatal(errno, "cannot connect to %s: stat failed on %s",
260 name, socket_name);
261 } else if (!S_ISSOCK(s.st_mode)) {
262 ovs_fatal(0, "cannot connect to %s: %s is not a socket",
263 name, socket_name);
264 }
265
1a6f1e2a 266 open_vconn_socket(socket_name, vconnp);
064af421 267 free(socket_name);
064af421
BP
268 } else {
269 ovs_fatal(0, "%s is not a valid connection method", name);
270 }
1a6f1e2a
JG
271
272 free(datapath_name);
273 free(datapath_type);
274 free(bridge_path);
064af421
BP
275}
276
0caf6bde
BP
277static void
278open_vconn(const char *name, struct vconn **vconnp)
279{
280 return open_vconn__(name, "mgmt", vconnp);
281}
282
064af421
BP
283static void *
284alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp)
285{
286 struct ofp_stats_request *rq;
287 rq = make_openflow((offsetof(struct ofp_stats_request, body)
288 + body_len), OFPT_STATS_REQUEST, bufferp);
289 rq->type = htons(type);
290 rq->flags = htons(0);
291 return rq->body;
292}
293
294static void
295send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
296{
297 update_openflow_length(buffer);
298 run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
299}
300
301static void
302dump_transaction(const char *vconn_name, struct ofpbuf *request)
303{
304 struct vconn *vconn;
305 struct ofpbuf *reply;
306
307 update_openflow_length(request);
308 open_vconn(vconn_name, &vconn);
309 run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
4f564f8d 310 ofp_print(stdout, reply->data, reply->size, verbosity + 1);
064af421
BP
311 vconn_close(vconn);
312}
313
314static void
315dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
316{
317 struct ofpbuf *request;
318 make_openflow(sizeof(struct ofp_header), request_type, &request);
319 dump_transaction(vconn_name, request);
320}
321
322static void
323dump_stats_transaction(const char *vconn_name, struct ofpbuf *request)
324{
44381c1b 325 ovs_be32 send_xid = ((struct ofp_header *) request->data)->xid;
064af421
BP
326 struct vconn *vconn;
327 bool done = false;
328
329 open_vconn(vconn_name, &vconn);
330 send_openflow_buffer(vconn, request);
331 while (!done) {
332 uint32_t recv_xid;
333 struct ofpbuf *reply;
334
335 run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
336 recv_xid = ((struct ofp_header *) reply->data)->xid;
337 if (send_xid == recv_xid) {
338 struct ofp_stats_reply *osr;
339
4f564f8d 340 ofp_print(stdout, reply->data, reply->size, verbosity + 1);
064af421
BP
341
342 osr = ofpbuf_at(reply, 0, sizeof *osr);
343 done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE);
344 } else {
345 VLOG_DBG("received reply with xid %08"PRIx32" "
346 "!= expected %08"PRIx32, recv_xid, send_xid);
347 }
348 ofpbuf_delete(reply);
349 }
350 vconn_close(vconn);
351}
352
353static void
354dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
355{
356 struct ofpbuf *request;
357 alloc_stats_request(0, stats_type, &request);
358 dump_stats_transaction(vconn_name, request);
359}
360
d12513f7
BP
361/* Sends 'request', which should be a request that only has a reply if an error
362 * occurs, and waits for it to succeed or fail. If an error does occur, prints
363 * it and exits with an error. */
364static void
88ca35ee 365transact_multiple_noreply(struct vconn *vconn, struct list *requests)
d12513f7 366{
88ca35ee 367 struct ofpbuf *request, *reply;
d12513f7 368
88ca35ee
BP
369 LIST_FOR_EACH (request, list_node, requests) {
370 update_openflow_length(request);
371 }
372
373 run(vconn_transact_multiple_noreply(vconn, requests, &reply),
d12513f7
BP
374 "talking to %s", vconn_get_name(vconn));
375 if (reply) {
4f564f8d 376 ofp_print(stderr, reply->data, reply->size, verbosity + 2);
d12513f7
BP
377 exit(1);
378 }
379 ofpbuf_delete(reply);
380}
381
88ca35ee
BP
382/* Sends 'request', which should be a request that only has a reply if an error
383 * occurs, and waits for it to succeed or fail. If an error does occur, prints
384 * it and exits with an error. */
385static void
386transact_noreply(struct vconn *vconn, struct ofpbuf *request)
387{
388 struct list requests;
389
390 list_init(&requests);
391 list_push_back(&requests, &request->list_node);
392 transact_multiple_noreply(vconn, &requests);
393}
394
064af421 395static void
c69ee87c 396do_show(int argc OVS_UNUSED, char *argv[])
064af421
BP
397{
398 dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
399 dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
400}
401
064af421 402static void
c69ee87c 403do_dump_desc(int argc OVS_UNUSED, char *argv[])
064af421
BP
404{
405 dump_trivial_stats_transaction(argv[1], OFPST_DESC);
406}
407
408static void
c69ee87c 409do_dump_tables(int argc OVS_UNUSED, char *argv[])
064af421
BP
410{
411 dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
412}
413
0df0e81d
BP
414/* Opens a connection to 'vconn_name', fetches the ofp_phy_port structure for
415 * 'port_name' (which may be a port name or number), and copies it into
416 * '*oppp'. */
417static void
418fetch_ofp_phy_port(const char *vconn_name, const char *port_name,
419 struct ofp_phy_port *oppp)
abaad8cf
JP
420{
421 struct ofpbuf *request, *reply;
422 struct ofp_switch_features *osf;
0df0e81d 423 unsigned int port_no;
abaad8cf
JP
424 struct vconn *vconn;
425 int n_ports;
426 int port_idx;
abaad8cf 427
0df0e81d
BP
428 /* Try to interpret the argument as a port number. */
429 if (!str_to_uint(port_name, 10, &port_no)) {
430 port_no = UINT_MAX;
abaad8cf
JP
431 }
432
0df0e81d 433 /* Fetch the switch's ofp_switch_features. */
abaad8cf
JP
434 make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
435 open_vconn(vconn_name, &vconn);
436 run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
437
438 osf = reply->data;
0df0e81d
BP
439 if (reply->size < sizeof *osf) {
440 ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
441 vconn_name, reply->size);
442 }
abaad8cf
JP
443 n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
444
445 for (port_idx = 0; port_idx < n_ports; port_idx++) {
0df0e81d
BP
446 const struct ofp_phy_port *opp = &osf->ports[port_idx];
447
448 if (port_no != UINT_MAX
449 ? htons(port_no) == opp->port_no
0b61210e 450 : !strncmp(opp->name, port_name, sizeof opp->name)) {
0df0e81d
BP
451 *oppp = *opp;
452 ofpbuf_delete(reply);
453 vconn_close(vconn);
454 return;
abaad8cf
JP
455 }
456 }
0df0e81d
BP
457 ovs_fatal(0, "%s: couldn't find port `%s'", vconn_name, port_name);
458}
abaad8cf 459
0df0e81d
BP
460/* Returns the port number corresponding to 'port_name' (which may be a port
461 * name or number) within the switch 'vconn_name'. */
462static uint16_t
463str_to_port_no(const char *vconn_name, const char *port_name)
464{
465 unsigned int port_no;
466
467 if (str_to_uint(port_name, 10, &port_no)) {
468 return port_no;
469 } else {
470 struct ofp_phy_port opp;
abaad8cf 471
0df0e81d
BP
472 fetch_ofp_phy_port(vconn_name, port_name, &opp);
473 return ntohs(opp.port_no);
474 }
abaad8cf
JP
475}
476
88ca35ee
BP
477static bool
478try_set_flow_format(struct vconn *vconn, enum nx_flow_format flow_format)
479{
480 struct ofpbuf *sff, *reply;
481
482 sff = ofputil_make_set_flow_format(flow_format);
483 run(vconn_transact_noreply(vconn, sff, &reply),
484 "talking to %s", vconn_get_name(vconn));
485 if (reply) {
486 char *s = ofp_to_string(reply->data, reply->size, 2);
487 VLOG_DBG("%s: failed to set flow format %s, controller replied: %s",
488 vconn_get_name(vconn),
489 ofputil_flow_format_to_string(flow_format),
490 s);
491 free(s);
492 ofpbuf_delete(reply);
493 return false;
494 }
495 return true;
496}
497
064af421 498static void
88ca35ee 499set_flow_format(struct vconn *vconn, enum nx_flow_format flow_format)
064af421 500{
88ca35ee
BP
501 struct ofpbuf *sff = ofputil_make_set_flow_format(flow_format);
502 transact_noreply(vconn, sff);
503 VLOG_DBG("%s: using user-specified flow format %s",
504 vconn_get_name(vconn),
505 ofputil_flow_format_to_string(flow_format));
506}
064af421 507
88ca35ee
BP
508static enum nx_flow_format
509negotiate_highest_flow_format(struct vconn *vconn, const struct cls_rule *rule,
510 bool cookie_support, ovs_be64 cookie)
511{
f9cbfbe4 512 enum nx_flow_format min_format;
064af421 513
f9cbfbe4 514 min_format = ofputil_min_flow_format(rule, cookie_support, cookie);
88ca35ee 515 if (preferred_flow_format != -1) {
f9cbfbe4
BP
516 if (preferred_flow_format < min_format) {
517 ovs_fatal(0, "%s: cannot use requested flow format %s for "
518 "specified flow", vconn_get_name(vconn),
519 ofputil_flow_format_to_string(min_format));
520 }
521
522 set_flow_format(vconn, preferred_flow_format);
523 return preferred_flow_format;
524 } else {
525 enum nx_flow_format flow_format;
88ca35ee 526
f9cbfbe4
BP
527 if (try_set_flow_format(vconn, NXFF_NXM)) {
528 flow_format = NXFF_NXM;
529 } else if (try_set_flow_format(vconn, NXFF_TUN_ID_FROM_COOKIE)) {
530 flow_format = NXFF_TUN_ID_FROM_COOKIE;
531 } else {
532 flow_format = NXFF_OPENFLOW10;
88ca35ee
BP
533 }
534
f9cbfbe4
BP
535 if (flow_format < min_format) {
536 ovs_fatal(0, "%s: cannot use switch's most advanced flow format "
537 "%s for specified flow", vconn_get_name(vconn),
538 ofputil_flow_format_to_string(min_format));
539 }
88ca35ee 540
f9cbfbe4
BP
541 VLOG_DBG("%s: negotiated flow format %s", vconn_get_name(vconn),
542 ofputil_flow_format_to_string(flow_format));
543 return flow_format;
88ca35ee 544 }
064af421
BP
545}
546
547static void
88ca35ee 548do_dump_flows__(int argc, char *argv[], bool aggregate)
064af421 549{
88ca35ee
BP
550 enum nx_flow_format flow_format;
551 struct flow_stats_request fsr;
064af421 552 struct ofpbuf *request;
88ca35ee 553 struct vconn *vconn;
064af421 554
88ca35ee 555 parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "");
064af421 556
88ca35ee
BP
557 open_vconn(argv[1], &vconn);
558 flow_format = negotiate_highest_flow_format(vconn, &fsr.match, false, 0);
559 request = ofputil_encode_flow_stats_request(&fsr, flow_format);
064af421 560 dump_stats_transaction(argv[1], request);
88ca35ee
BP
561 vconn_close(vconn);
562}
563
564static void
565do_dump_flows(int argc, char *argv[])
566{
567 return do_dump_flows__(argc, argv, false);
568}
569
570static void
571do_dump_aggregate(int argc, char *argv[])
572{
573 return do_dump_flows__(argc, argv, true);
064af421
BP
574}
575
d2805da2
BP
576static void
577do_queue_stats(int argc, char *argv[])
578{
579 struct ofp_queue_stats_request *req;
580 struct ofpbuf *request;
581
582 req = alloc_stats_request(sizeof *req, OFPST_QUEUE, &request);
583
584 if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) {
585 req->port_no = htons(str_to_port_no(argv[1], argv[2]));
586 } else {
587 req->port_no = htons(OFPP_ALL);
588 }
589 if (argc > 3 && argv[3][0] && strcasecmp(argv[3], "all")) {
590 req->queue_id = htonl(atoi(argv[3]));
591 } else {
592 req->queue_id = htonl(OFPQ_ALL);
593 }
594
595 memset(req->pad, 0, sizeof req->pad);
596
597 dump_stats_transaction(argv[1], request);
598}
599
0fbc9f11
BP
600/* Sets up the flow format for a vconn that will be used to modify the flow
601 * table. Returns the flow format used, after possibly adding an OpenFlow
602 * request to 'requests'.
603 *
604 * If 'preferred_flow_format' is -1, returns NXFF_OPENFLOW10 without modifying
605 * 'requests', since NXFF_OPENFLOW10 is the default flow format for any
606 * OpenFlow connection.
607 *
608 * If 'preferred_flow_format' is a specific format, adds a request to set that
609 * format to 'requests' and returns the format. */
610static enum nx_flow_format
611set_initial_format_for_flow_mod(struct list *requests)
612{
613 if (preferred_flow_format < 0) {
614 return NXFF_OPENFLOW10;
615 } else {
616 struct ofpbuf *sff;
617
618 sff = ofputil_make_set_flow_format(preferred_flow_format);
619 list_push_back(requests, &sff->list_node);
620 return preferred_flow_format;
621 }
622}
623
624/* Checks that 'flow_format' is acceptable as a flow format after a flow_mod
625 * operation, given the global 'preferred_flow_format'. */
626static void
627check_final_format_for_flow_mod(enum nx_flow_format flow_format)
628{
629 if (preferred_flow_format >= 0 && flow_format != preferred_flow_format) {
630 ovs_fatal(0, "flow cannot be expressed in flow format %s "
631 "(flow format %s or better is required)",
632 ofputil_flow_format_to_string(preferred_flow_format),
633 ofputil_flow_format_to_string(flow_format));
634 }
635}
636
064af421 637static void
88ca35ee 638do_flow_mod__(int argc OVS_UNUSED, char *argv[], uint16_t command)
064af421 639{
88ca35ee
BP
640 enum nx_flow_format flow_format;
641 struct list requests;
064af421 642 struct vconn *vconn;
049c8dc2 643
88ca35ee 644 list_init(&requests);
0fbc9f11
BP
645 flow_format = set_initial_format_for_flow_mod(&requests);
646
640c7c94
BP
647 parse_ofp_flow_mod_str(&requests, &flow_format, argc > 2 ? argv[2] : "",
648 command);
0fbc9f11 649 check_final_format_for_flow_mod(flow_format);
064af421
BP
650
651 open_vconn(argv[1], &vconn);
88ca35ee 652 transact_multiple_noreply(vconn, &requests);
064af421
BP
653 vconn_close(vconn);
654}
655
88ca35ee
BP
656static void
657do_add_flow(int argc, char *argv[])
658{
659 do_flow_mod__(argc, argv, OFPFC_ADD);
660}
661
064af421 662static void
c69ee87c 663do_add_flows(int argc OVS_UNUSED, char *argv[])
064af421 664{
88ca35ee
BP
665 enum nx_flow_format flow_format;
666 struct list requests;
064af421
BP
667 struct vconn *vconn;
668 FILE *file;
064af421 669
70315176 670 file = !strcmp(argv[2], "-") ? stdin : fopen(argv[2], "r");
064af421
BP
671 if (file == NULL) {
672 ovs_fatal(errno, "%s: open", argv[2]);
673 }
674
88ca35ee 675 list_init(&requests);
0fbc9f11 676 flow_format = set_initial_format_for_flow_mod(&requests);
88ca35ee 677
064af421 678 open_vconn(argv[1], &vconn);
88ca35ee 679 while (parse_ofp_add_flow_file(&requests, &flow_format, file)) {
0fbc9f11 680 check_final_format_for_flow_mod(flow_format);
88ca35ee 681 transact_multiple_noreply(vconn, &requests);
064af421
BP
682 }
683 vconn_close(vconn);
88ca35ee 684
70315176
BP
685 if (file != stdin) {
686 fclose(file);
687 }
064af421
BP
688}
689
690static void
88ca35ee 691do_mod_flows(int argc, char *argv[])
064af421 692{
88ca35ee 693 do_flow_mod__(argc, argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY);
064af421
BP
694}
695
88ca35ee
BP
696static void
697do_del_flows(int argc, char *argv[])
064af421 698{
88ca35ee 699 do_flow_mod__(argc, argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE);
064af421
BP
700}
701
702static void
0caf6bde
BP
703monitor_vconn(struct vconn *vconn)
704{
705 for (;;) {
706 struct ofpbuf *b;
707 run(vconn_recv_block(vconn, &b), "vconn_recv");
4f564f8d 708 ofp_print(stderr, b->data, b->size, verbosity + 2);
0caf6bde
BP
709 ofpbuf_delete(b);
710 }
711}
712
713static void
714do_monitor(int argc, char *argv[])
064af421
BP
715{
716 struct vconn *vconn;
717
718 open_vconn(argv[1], &vconn);
719 if (argc > 2) {
720 int miss_send_len = atoi(argv[2]);
064af421
BP
721 struct ofp_switch_config *osc;
722 struct ofpbuf *buf;
723
724 osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
064af421 725 osc->miss_send_len = htons(miss_send_len);
88ca35ee 726 transact_noreply(vconn, buf);
064af421 727 }
0caf6bde
BP
728 monitor_vconn(vconn);
729}
730
731static void
732do_snoop(int argc OVS_UNUSED, char *argv[])
733{
734 struct vconn *vconn;
735
736 open_vconn__(argv[1], "snoop", &vconn);
737 monitor_vconn(vconn);
064af421
BP
738}
739
740static void
abaad8cf 741do_dump_ports(int argc, char *argv[])
064af421 742{
abaad8cf
JP
743 struct ofp_port_stats_request *req;
744 struct ofpbuf *request;
745 uint16_t port;
746
747 req = alloc_stats_request(sizeof *req, OFPST_PORT, &request);
748 port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
749 req->port_no = htons(port);
750 dump_stats_transaction(argv[1], request);
064af421
BP
751}
752
753static void
c69ee87c 754do_probe(int argc OVS_UNUSED, char *argv[])
064af421
BP
755{
756 struct ofpbuf *request;
757 struct vconn *vconn;
758 struct ofpbuf *reply;
759
760 make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
761 open_vconn(argv[1], &vconn);
762 run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
763 if (reply->size != sizeof(struct ofp_header)) {
764 ovs_fatal(0, "reply does not match request");
765 }
766 ofpbuf_delete(reply);
767 vconn_close(vconn);
768}
769
770static void
c69ee87c 771do_mod_port(int argc OVS_UNUSED, char *argv[])
064af421 772{
064af421 773 struct ofp_port_mod *opm;
0df0e81d
BP
774 struct ofp_phy_port opp;
775 struct ofpbuf *request;
064af421 776 struct vconn *vconn;
064af421 777
0df0e81d 778 fetch_ofp_phy_port(argv[1], argv[2], &opp);
064af421
BP
779
780 opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
0df0e81d
BP
781 opm->port_no = opp.port_no;
782 memcpy(opm->hw_addr, opp.hw_addr, sizeof opm->hw_addr);
064af421
BP
783 opm->config = htonl(0);
784 opm->mask = htonl(0);
785 opm->advertise = htonl(0);
786
f4866781 787 if (!strcasecmp(argv[3], "up")) {
064af421 788 opm->mask |= htonl(OFPPC_PORT_DOWN);
f4866781 789 } else if (!strcasecmp(argv[3], "down")) {
064af421
BP
790 opm->mask |= htonl(OFPPC_PORT_DOWN);
791 opm->config |= htonl(OFPPC_PORT_DOWN);
f4866781 792 } else if (!strcasecmp(argv[3], "flood")) {
064af421 793 opm->mask |= htonl(OFPPC_NO_FLOOD);
f4866781 794 } else if (!strcasecmp(argv[3], "noflood")) {
064af421
BP
795 opm->mask |= htonl(OFPPC_NO_FLOOD);
796 opm->config |= htonl(OFPPC_NO_FLOOD);
797 } else {
798 ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
799 }
800
0df0e81d 801 open_vconn(argv[1], &vconn);
88ca35ee 802 transact_noreply(vconn, request);
064af421
BP
803 vconn_close(vconn);
804}
805
806static void
675febfa 807do_ping(int argc, char *argv[])
064af421
BP
808{
809 size_t max_payload = 65535 - sizeof(struct ofp_header);
810 unsigned int payload;
811 struct vconn *vconn;
812 int i;
813
814 payload = argc > 2 ? atoi(argv[2]) : 64;
815 if (payload > max_payload) {
816 ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
817 }
818
819 open_vconn(argv[1], &vconn);
820 for (i = 0; i < 10; i++) {
821 struct timeval start, end;
822 struct ofpbuf *request, *reply;
823 struct ofp_header *rq_hdr, *rpy_hdr;
824
825 rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
826 OFPT_ECHO_REQUEST, &request);
827 random_bytes(rq_hdr + 1, payload);
828
829 gettimeofday(&start, NULL);
830 run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
831 gettimeofday(&end, NULL);
832
833 rpy_hdr = reply->data;
834 if (reply->size != request->size
835 || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
836 || rpy_hdr->xid != rq_hdr->xid
837 || rpy_hdr->type != OFPT_ECHO_REPLY) {
838 printf("Reply does not match request. Request:\n");
4f564f8d 839 ofp_print(stdout, request, request->size, verbosity + 2);
064af421 840 printf("Reply:\n");
4f564f8d 841 ofp_print(stdout, reply, reply->size, verbosity + 2);
064af421 842 }
2886875a 843 printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
44381c1b 844 reply->size - sizeof *rpy_hdr, argv[1], ntohl(rpy_hdr->xid),
064af421
BP
845 (1000*(double)(end.tv_sec - start.tv_sec))
846 + (.001*(end.tv_usec - start.tv_usec)));
847 ofpbuf_delete(request);
848 ofpbuf_delete(reply);
849 }
850 vconn_close(vconn);
851}
852
853static void
c69ee87c 854do_benchmark(int argc OVS_UNUSED, char *argv[])
064af421
BP
855{
856 size_t max_payload = 65535 - sizeof(struct ofp_header);
857 struct timeval start, end;
858 unsigned int payload_size, message_size;
859 struct vconn *vconn;
860 double duration;
861 int count;
862 int i;
863
864 payload_size = atoi(argv[2]);
865 if (payload_size > max_payload) {
866 ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
867 }
868 message_size = sizeof(struct ofp_header) + payload_size;
869
870 count = atoi(argv[3]);
871
872 printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
873 count, message_size, count * message_size);
874
875 open_vconn(argv[1], &vconn);
876 gettimeofday(&start, NULL);
877 for (i = 0; i < count; i++) {
878 struct ofpbuf *request, *reply;
879 struct ofp_header *rq_hdr;
880
881 rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
882 memset(rq_hdr + 1, 0, payload_size);
883 run(vconn_transact(vconn, request, &reply), "transact");
884 ofpbuf_delete(reply);
885 }
886 gettimeofday(&end, NULL);
887 vconn_close(vconn);
888
889 duration = ((1000*(double)(end.tv_sec - start.tv_sec))
890 + (.001*(end.tv_usec - start.tv_usec)));
891 printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
892 duration, count / (duration / 1000.0),
893 count * message_size / (duration / 1000.0));
894}
895
09246b99
BP
896static void
897do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
898{
899 usage();
900}
901\f
902/* Undocumented commands for unit testing. */
903
770f1f66
BP
904static void
905print_packet_list(struct list *packets)
906{
907 struct ofpbuf *packet, *next;
908
909 LIST_FOR_EACH_SAFE (packet, next, list_node, packets) {
910 ofp_print(stdout, packet->data, packet->size, verbosity);
911 list_remove(&packet->list_node);
912 ofpbuf_delete(packet);
913 }
914}
915
916/* "parse-flow FLOW": parses the argument as a flow (like add-flow) and prints
917 * it back to stdout. */
918static void
919do_parse_flow(int argc OVS_UNUSED, char *argv[])
920{
921 enum nx_flow_format flow_format;
922 struct list packets;
923
924 flow_format = NXFF_OPENFLOW10;
925 if (preferred_flow_format > 0) {
926 flow_format = preferred_flow_format;
927 }
928
929 list_init(&packets);
930 parse_ofp_flow_mod_str(&packets, &flow_format, argv[1], OFPFC_ADD);
931 print_packet_list(&packets);
932}
933
fec00620
BP
934/* "parse-flows FILENAME": reads the named file as a sequence of flows (like
935 * add-flows) and prints each of the flows back to stdout. */
0e581146
BP
936static void
937do_parse_flows(int argc OVS_UNUSED, char *argv[])
938{
88ca35ee
BP
939 enum nx_flow_format flow_format;
940 struct list packets;
0e581146
BP
941 FILE *file;
942
943 file = fopen(argv[1], "r");
944 if (file == NULL) {
945 ovs_fatal(errno, "%s: open", argv[2]);
946 }
947
88ca35ee
BP
948 flow_format = NXFF_OPENFLOW10;
949 if (preferred_flow_format > 0) {
950 flow_format = preferred_flow_format;
951 }
952
770f1f66 953 list_init(&packets);
88ca35ee 954 while (parse_ofp_add_flow_file(&packets, &flow_format, file)) {
770f1f66 955 print_packet_list(&packets);
0e581146
BP
956 }
957 fclose(file);
958}
959
fec00620
BP
960/* "parse-nx-match": reads a series of nx_match specifications as strings from
961 * stdin, does some internal fussing with them, and then prints them back as
962 * strings on stdout. */
064af421 963static void
09246b99
BP
964do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
965{
966 struct ds in;
967
968 ds_init(&in);
969 while (!ds_get_line(&in, stdin)) {
970 struct ofpbuf nx_match;
971 struct cls_rule rule;
972 int match_len;
973 int error;
974 char *s;
975
976 /* Delete comments, skip blank lines. */
977 s = ds_cstr(&in);
978 if (*s == '#') {
979 puts(s);
980 continue;
981 }
982 if (strchr(s, '#')) {
983 *strchr(s, '#') = '\0';
984 }
985 if (s[strspn(s, " ")] == '\0') {
986 putchar('\n');
987 continue;
988 }
989
990 /* Convert string to nx_match. */
991 ofpbuf_init(&nx_match, 0);
992 match_len = nx_match_from_string(ds_cstr(&in), &nx_match);
993
994 /* Convert nx_match to cls_rule. */
995 error = nx_pull_match(&nx_match, match_len, 0, &rule);
996 if (!error) {
997 char *out;
998
999 /* Convert cls_rule back to nx_match. */
1000 ofpbuf_uninit(&nx_match);
1001 ofpbuf_init(&nx_match, 0);
1002 match_len = nx_put_match(&nx_match, &rule);
1003
1004 /* Convert nx_match to string. */
1005 out = nx_match_to_string(nx_match.data, match_len);
1006 puts(out);
1007 free(out);
1008 } else {
1009 printf("nx_pull_match() returned error %x\n", error);
1010 }
1011
1012 ofpbuf_uninit(&nx_match);
1013 }
1014 ds_destroy(&in);
064af421
BP
1015}
1016
fec00620
BP
1017/* "ofp-print HEXSTRING [VERBOSITY]": Converts the hex digits in HEXSTRING into
1018 * binary data, interpreting them as an OpenFlow message, and prints the
1019 * OpenFlow message on stdout, at VERBOSITY (level 2 by default). */
1020static void
1021do_ofp_print(int argc, char *argv[])
1022{
1023 struct ofpbuf packet;
1024
1025 ofpbuf_init(&packet, strlen(argv[1]) / 2);
1026 if (ofpbuf_put_hex(&packet, argv[1], NULL)[0] != '\0') {
1027 ovs_fatal(0, "trailing garbage following hex bytes");
1028 }
1029 ofp_print(stdout, packet.data, packet.size, argc > 2 ? atoi(argv[2]) : 2);
1030 ofpbuf_uninit(&packet);
1031}
1032
675febfa 1033static const struct command all_commands[] = {
064af421 1034 { "show", 1, 1, do_show },
7f1089b5 1035 { "monitor", 1, 2, do_monitor },
0caf6bde 1036 { "snoop", 1, 1, do_snoop },
064af421
BP
1037 { "dump-desc", 1, 1, do_dump_desc },
1038 { "dump-tables", 1, 1, do_dump_tables },
1039 { "dump-flows", 1, 2, do_dump_flows },
1040 { "dump-aggregate", 1, 2, do_dump_aggregate },
d2805da2 1041 { "queue-stats", 1, 3, do_queue_stats },
064af421
BP
1042 { "add-flow", 2, 2, do_add_flow },
1043 { "add-flows", 2, 2, do_add_flows },
1044 { "mod-flows", 2, 2, do_mod_flows },
1045 { "del-flows", 1, 2, do_del_flows },
abaad8cf 1046 { "dump-ports", 1, 2, do_dump_ports },
064af421
BP
1047 { "mod-port", 3, 3, do_mod_port },
1048 { "probe", 1, 1, do_probe },
1049 { "ping", 1, 2, do_ping },
1050 { "benchmark", 3, 3, do_benchmark },
064af421 1051 { "help", 0, INT_MAX, do_help },
09246b99
BP
1052
1053 /* Undocumented commands for testing. */
770f1f66 1054 { "parse-flow", 1, 1, do_parse_flow },
09246b99
BP
1055 { "parse-flows", 1, 1, do_parse_flows },
1056 { "parse-nx-match", 0, 0, do_parse_nx_match },
fec00620 1057 { "ofp-print", 1, 2, do_ofp_print },
09246b99 1058
064af421
BP
1059 { NULL, 0, 0, NULL },
1060};