Merge "master" into "wdp".
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
1 /*
2  * Copyright (c) 2008, 2009, 2010 Nicira Networks.
3  *
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:
7  *
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.
15  */
16
17 #include <config.h>
18 #include <errno.h>
19 #include <getopt.h>
20 #include <inttypes.h>
21 #include <net/if.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/time.h>
28
29 #include "command-line.h"
30 #include "compiler.h"
31 #include "dirs.h"
32 #include "dynamic-string.h"
33 #include "netdev.h"
34 #include "netlink.h"
35 #include "ofp-parse.h"
36 #include "ofp-print.h"
37 #include "ofp-util.h"
38 #include "ofpbuf.h"
39 #include "openflow/nicira-ext.h"
40 #include "openflow/openflow.h"
41 #include "random.h"
42 #include "stream-ssl.h"
43 #include "timeval.h"
44 #include "util.h"
45 #include "vconn.h"
46 #include "vlog.h"
47 #include "xfif.h"
48 #include "xflow-util.h"
49 #include "xtoxll.h"
50
51 VLOG_DEFINE_THIS_MODULE(ofctl)
52
53
54 #define MOD_PORT_CMD_UP      "up"
55 #define MOD_PORT_CMD_DOWN    "down"
56 #define MOD_PORT_CMD_FLOOD   "flood"
57 #define MOD_PORT_CMD_NOFLOOD "noflood"
58
59 /* Use strict matching for flow mod commands? */
60 static bool strict;
61
62 static const struct command all_commands[];
63
64 static void usage(void) NO_RETURN;
65 static void parse_options(int argc, char *argv[]);
66
67 int
68 main(int argc, char *argv[])
69 {
70     set_program_name(argv[0]);
71     parse_options(argc, argv);
72     signal(SIGPIPE, SIG_IGN);
73     run_command(argc - optind, argv + optind, all_commands);
74     return 0;
75 }
76
77 static void
78 parse_options(int argc, char *argv[])
79 {
80     enum {
81         OPT_STRICT = UCHAR_MAX + 1,
82         VLOG_OPTION_ENUMS
83     };
84     static struct option long_options[] = {
85         {"timeout", required_argument, 0, 't'},
86         {"strict", no_argument, 0, OPT_STRICT},
87         {"help", no_argument, 0, 'h'},
88         {"version", no_argument, 0, 'V'},
89         VLOG_LONG_OPTIONS,
90         STREAM_SSL_LONG_OPTIONS
91         {0, 0, 0, 0},
92     };
93     char *short_options = long_options_to_short_options(long_options);
94
95     for (;;) {
96         unsigned long int timeout;
97         int c;
98
99         c = getopt_long(argc, argv, short_options, long_options, NULL);
100         if (c == -1) {
101             break;
102         }
103
104         switch (c) {
105         case 't':
106             timeout = strtoul(optarg, NULL, 10);
107             if (timeout <= 0) {
108                 ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
109                           optarg);
110             } else {
111                 time_alarm(timeout);
112             }
113             break;
114
115         case 'h':
116             usage();
117
118         case 'V':
119             OVS_PRINT_VERSION(OFP_VERSION, OFP_VERSION);
120             exit(EXIT_SUCCESS);
121
122         case OPT_STRICT:
123             strict = true;
124             break;
125
126         VLOG_OPTION_HANDLERS
127         STREAM_SSL_OPTION_HANDLERS
128
129         case '?':
130             exit(EXIT_FAILURE);
131
132         default:
133             abort();
134         }
135     }
136     free(short_options);
137 }
138
139 static void
140 usage(void)
141 {
142     printf("%s: OpenFlow switch management utility\n"
143            "usage: %s [OPTIONS] COMMAND [ARG...]\n"
144            "\nFor OpenFlow switches:\n"
145            "  show SWITCH                 show OpenFlow information\n"
146            "  status SWITCH [KEY]         report statistics (about KEY)\n"
147            "  dump-desc SWITCH            print switch description\n"
148            "  dump-tables SWITCH          print table stats\n"
149            "  mod-port SWITCH IFACE ACT   modify port behavior\n"
150            "  dump-ports SWITCH [PORT]    print port statistics\n"
151            "  dump-flows SWITCH           print all flow entries\n"
152            "  dump-flows SWITCH FLOW      print matching FLOWs\n"
153            "  dump-aggregate SWITCH       print aggregate flow statistics\n"
154            "  dump-aggregate SWITCH FLOW  print aggregate stats for FLOWs\n"
155            "  queue-stats SWITCH [PORT [QUEUE]]  dump queue stats\n"
156            "  add-flow SWITCH FLOW        add flow described by FLOW\n"
157            "  add-flows SWITCH FILE       add flows from FILE\n"
158            "  mod-flows SWITCH FLOW       modify actions of matching FLOWs\n"
159            "  del-flows SWITCH [FLOW]     delete matching FLOWs\n"
160            "  monitor SWITCH [MISSLEN]    print packets received from SWITCH\n"
161            "\nFor OpenFlow switches and controllers:\n"
162            "  probe VCONN                 probe whether VCONN is up\n"
163            "  ping VCONN [N]              latency of N-byte echos\n"
164            "  benchmark VCONN N COUNT     bandwidth of COUNT N-byte echos\n"
165            "where each SWITCH is an active OpenFlow connection method.\n",
166            program_name, program_name);
167     vconn_usage(true, false, false);
168     vlog_usage();
169     printf("\nOther options:\n"
170            "  --strict                    use strict match for flow commands\n"
171            "  -t, --timeout=SECS          give up after SECS seconds\n"
172            "  -h, --help                  display this help message\n"
173            "  -V, --version               display version information\n");
174     exit(EXIT_SUCCESS);
175 }
176
177 static void run(int retval, const char *message, ...)
178     PRINTF_FORMAT(2, 3);
179
180 static void run(int retval, const char *message, ...)
181 {
182     if (retval) {
183         va_list args;
184
185         fprintf(stderr, "%s: ", program_name);
186         va_start(args, message);
187         vfprintf(stderr, message, args);
188         va_end(args);
189         if (retval == EOF) {
190             fputs(": unexpected end of file\n", stderr);
191         } else {
192             fprintf(stderr, ": %s\n", strerror(retval));
193         }
194
195         exit(EXIT_FAILURE);
196     }
197 }
198 \f
199 /* Generic commands. */
200
201 static void
202 open_vconn_socket(const char *name, struct vconn **vconnp)
203 {
204     char *vconn_name = xasprintf("unix:%s", name);
205     VLOG_INFO("connecting to %s", vconn_name);
206     run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
207         "connecting to %s", vconn_name);
208     free(vconn_name);
209 }
210
211 static void
212 open_vconn__(const char *name, const char *default_suffix,
213              struct vconn **vconnp)
214 {
215     struct xfif *xfif;
216     struct stat s;
217     char *bridge_path, *datapath_name, *datapath_type;
218
219     bridge_path = xasprintf("%s/%s.%s", ovs_rundir, name, default_suffix);
220     xf_parse_name(name, &datapath_name, &datapath_type);
221
222     if (strstr(name, ":")) {
223         run(vconn_open_block(name, OFP_VERSION, vconnp),
224             "connecting to %s", name);
225     } else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
226         open_vconn_socket(name, vconnp);
227     } else if (!stat(bridge_path, &s) && S_ISSOCK(s.st_mode)) {
228         open_vconn_socket(bridge_path, vconnp);
229     } else if (!xfif_open(datapath_name, datapath_type, &xfif)) {
230         char xfif_name[IF_NAMESIZE + 1];
231         char *socket_name;
232
233         run(xfif_port_get_name(xfif, XFLOWP_LOCAL, xfif_name, sizeof xfif_name),
234             "obtaining name of %s", xfif_name);
235         xfif_close(xfif);
236         if (strcmp(xfif_name, name)) {
237             VLOG_INFO("datapath %s is named %s", name, xfif_name);
238         }
239
240         socket_name = xasprintf("%s/%s.%s",
241                                 ovs_rundir, xfif_name, default_suffix);
242         if (stat(socket_name, &s)) {
243             ovs_fatal(errno, "cannot connect to %s: stat failed on %s",
244                       name, socket_name);
245         } else if (!S_ISSOCK(s.st_mode)) {
246             ovs_fatal(0, "cannot connect to %s: %s is not a socket",
247                       name, socket_name);
248         }
249
250         open_vconn_socket(socket_name, vconnp);
251         free(socket_name);
252     } else {
253         ovs_fatal(0, "%s is not a valid connection method", name);
254     }
255
256     free(datapath_name);
257     free(datapath_type);
258     free(bridge_path);
259 }
260
261 static void
262 open_vconn(const char *name, struct vconn **vconnp)
263 {
264     return open_vconn__(name, "mgmt", vconnp);
265 }
266
267 static void *
268 alloc_stats_request(size_t body_len, uint16_t type, struct ofpbuf **bufferp)
269 {
270     struct ofp_stats_request *rq;
271     rq = make_openflow((offsetof(struct ofp_stats_request, body)
272                         + body_len), OFPT_STATS_REQUEST, bufferp);
273     rq->type = htons(type);
274     rq->flags = htons(0);
275     return rq->body;
276 }
277
278 static void
279 send_openflow_buffer(struct vconn *vconn, struct ofpbuf *buffer)
280 {
281     update_openflow_length(buffer);
282     run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
283 }
284
285 static void
286 dump_transaction(const char *vconn_name, struct ofpbuf *request)
287 {
288     struct vconn *vconn;
289     struct ofpbuf *reply;
290
291     update_openflow_length(request);
292     open_vconn(vconn_name, &vconn);
293     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
294     ofp_print(stdout, reply->data, reply->size, 1);
295     vconn_close(vconn);
296 }
297
298 static void
299 dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
300 {
301     struct ofpbuf *request;
302     make_openflow(sizeof(struct ofp_header), request_type, &request);
303     dump_transaction(vconn_name, request);
304 }
305
306 static void
307 dump_stats_transaction(const char *vconn_name, struct ofpbuf *request)
308 {
309     uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
310     struct vconn *vconn;
311     bool done = false;
312
313     open_vconn(vconn_name, &vconn);
314     send_openflow_buffer(vconn, request);
315     while (!done) {
316         uint32_t recv_xid;
317         struct ofpbuf *reply;
318
319         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
320         recv_xid = ((struct ofp_header *) reply->data)->xid;
321         if (send_xid == recv_xid) {
322             struct ofp_stats_reply *osr;
323
324             ofp_print(stdout, reply->data, reply->size, 1);
325
326             osr = ofpbuf_at(reply, 0, sizeof *osr);
327             done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE);
328         } else {
329             VLOG_DBG("received reply with xid %08"PRIx32" "
330                      "!= expected %08"PRIx32, recv_xid, send_xid);
331         }
332         ofpbuf_delete(reply);
333     }
334     vconn_close(vconn);
335 }
336
337 static void
338 dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
339 {
340     struct ofpbuf *request;
341     alloc_stats_request(0, stats_type, &request);
342     dump_stats_transaction(vconn_name, request);
343 }
344
345 static void
346 do_show(int argc OVS_UNUSED, char *argv[])
347 {
348     dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
349     dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
350 }
351
352 static void
353 do_status(int argc, char *argv[])
354 {
355     struct nicira_header *request, *reply;
356     struct vconn *vconn;
357     struct ofpbuf *b;
358
359     request = make_openflow(sizeof *request, OFPT_VENDOR, &b);
360     request->vendor = htonl(NX_VENDOR_ID);
361     request->subtype = htonl(NXT_STATUS_REQUEST);
362     if (argc > 2) {
363         ofpbuf_put(b, argv[2], strlen(argv[2]));
364         update_openflow_length(b);
365     }
366     open_vconn(argv[1], &vconn);
367     run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]);
368     vconn_close(vconn);
369
370     if (b->size < sizeof *reply) {
371         ovs_fatal(0, "short reply (%zu bytes)", b->size);
372     }
373     reply = b->data;
374     if (reply->header.type != OFPT_VENDOR
375         || reply->vendor != ntohl(NX_VENDOR_ID)
376         || reply->subtype != ntohl(NXT_STATUS_REPLY)) {
377         ofp_print(stderr, b->data, b->size, 2);
378         ovs_fatal(0, "bad reply");
379     }
380
381     fwrite(reply + 1, b->size - sizeof *reply, 1, stdout);
382 }
383
384 static void
385 do_dump_desc(int argc OVS_UNUSED, char *argv[])
386 {
387     dump_trivial_stats_transaction(argv[1], OFPST_DESC);
388 }
389
390 static void
391 do_dump_tables(int argc OVS_UNUSED, char *argv[])
392 {
393     dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
394 }
395
396 static uint16_t
397 str_to_port_no(const char *vconn_name, const char *str)
398 {
399     struct ofpbuf *request, *reply;
400     struct ofp_switch_features *osf;
401     struct vconn *vconn;
402     int n_ports;
403     int port_idx;
404     unsigned int port_no;
405
406
407     /* Check if the argument is a port index.  Otherwise, treat it as
408      * the port name. */
409     if (str_to_uint(str, 10, &port_no)) {
410         return port_no;
411     }
412
413     /* Send a "Features Request" to resolve the name into a number. */
414     make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
415     open_vconn(vconn_name, &vconn);
416     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
417
418     osf = reply->data;
419     n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
420
421     for (port_idx = 0; port_idx < n_ports; port_idx++) {
422         /* Check argument as an interface name */
423         if (!strncmp((char *)osf->ports[port_idx].name, str,
424                     sizeof osf->ports[0].name)) {
425             break;
426         }
427     }
428     if (port_idx == n_ports) {
429         ovs_fatal(0, "couldn't find monitored port: %s", str);
430     }
431
432     ofpbuf_delete(reply);
433     vconn_close(vconn);
434
435     return port_idx;
436 }
437
438 static void
439 do_dump_flows(int argc, char *argv[])
440 {
441     struct ofp_flow_stats_request *req;
442     uint16_t out_port;
443     struct ofpbuf *request;
444
445     req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
446     parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL,
447                   &req->table_id, &out_port, NULL, NULL, NULL, NULL);
448     memset(&req->pad, 0, sizeof req->pad);
449     req->out_port = htons(out_port);
450
451     dump_stats_transaction(argv[1], request);
452 }
453
454 static void
455 do_dump_aggregate(int argc, char *argv[])
456 {
457     struct ofp_aggregate_stats_request *req;
458     struct ofpbuf *request;
459     uint16_t out_port;
460
461     req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
462     parse_ofp_str(argc > 2 ? argv[2] : "", &req->match, NULL,
463                   &req->table_id, &out_port, NULL, NULL, NULL, NULL);
464     memset(&req->pad, 0, sizeof req->pad);
465     req->out_port = htons(out_port);
466
467     dump_stats_transaction(argv[1], request);
468 }
469
470 static void
471 enable_flow_mod_table_id_ext(struct vconn *vconn, bool enable)
472 {
473     send_openflow_buffer(vconn, make_nxt_flow_mod_table_id(enable));
474 }
475
476 static void
477 do_queue_stats(int argc, char *argv[])
478 {
479     struct ofp_queue_stats_request *req;
480     struct ofpbuf *request;
481
482     req = alloc_stats_request(sizeof *req, OFPST_QUEUE, &request);
483
484     if (argc > 2 && argv[2][0] && strcasecmp(argv[2], "all")) {
485         req->port_no = htons(str_to_port_no(argv[1], argv[2]));
486     } else {
487         req->port_no = htons(OFPP_ALL);
488     }
489     if (argc > 3 && argv[3][0] && strcasecmp(argv[3], "all")) {
490         req->queue_id = htonl(atoi(argv[3]));
491     } else {
492         req->queue_id = htonl(OFPQ_ALL);
493     }
494
495     memset(req->pad, 0, sizeof req->pad);
496
497     dump_stats_transaction(argv[1], request);
498 }
499
500 static void
501 do_add_flow(int argc OVS_UNUSED, char *argv[])
502 {
503     struct vconn *vconn;
504     struct ofpbuf *buffer;
505     struct ofp_flow_mod *ofm;
506     uint16_t priority, idle_timeout, hard_timeout;
507     uint64_t cookie;
508     struct ofp_match match;
509     uint8_t table_idx;
510
511     /* Parse and send.  parse_ofp_str() will expand and reallocate the
512      * data in 'buffer', so we can't keep pointers to across the
513      * parse_ofp_str() call. */
514     make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
515     parse_ofp_str(argv[2], &match, buffer,
516                   &table_idx, NULL, &priority, &idle_timeout, &hard_timeout,
517                   &cookie);
518     ofm = buffer->data;
519     ofm->match = match;
520     ofm->command = htons(OFPFC_ADD);
521     ofm->cookie = htonll(cookie);
522     ofm->idle_timeout = htons(idle_timeout);
523     ofm->hard_timeout = htons(hard_timeout);
524     ofm->buffer_id = htonl(UINT32_MAX);
525     ofm->priority = htons(priority);
526
527     open_vconn(argv[1], &vconn);
528     if (table_idx != 0xff) {
529         enable_flow_mod_table_id_ext(vconn, 1);
530         ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
531     }
532     send_openflow_buffer(vconn, buffer);
533     vconn_close(vconn);
534 }
535
536 static void
537 do_add_flows(int argc OVS_UNUSED, char *argv[])
538 {
539     struct vconn *vconn;
540     struct ofpbuf *b;
541     FILE *file;
542     bool table_id_enabled = false;
543     uint8_t table_idx;
544
545     file = fopen(argv[2], "r");
546     if (file == NULL) {
547         ovs_fatal(errno, "%s: open", argv[2]);
548     }
549
550     open_vconn(argv[1], &vconn);
551     while ((b = parse_ofp_add_flow_file(file, &table_idx)) != NULL) {
552         if ((table_idx != 0xff) != table_id_enabled) {
553             table_id_enabled = table_idx != 0xff;
554             enable_flow_mod_table_id_ext(vconn, table_id_enabled);
555         }
556         send_openflow_buffer(vconn, b);
557     }
558     vconn_close(vconn);
559     fclose(file);
560 }
561
562 static void
563 do_mod_flows(int argc OVS_UNUSED, char *argv[])
564 {
565     uint16_t priority, idle_timeout, hard_timeout;
566     uint64_t cookie;
567     struct vconn *vconn;
568     struct ofpbuf *buffer;
569     struct ofp_flow_mod *ofm;
570     struct ofp_match match;
571     uint8_t table_idx;
572
573     /* Parse and send.  parse_ofp_str() will expand and reallocate the
574      * data in 'buffer', so we can't keep pointers to across the
575      * parse_ofp_str() call. */
576     make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
577     parse_ofp_str(argv[2], &match, buffer,
578                   &table_idx, NULL, &priority, &idle_timeout, &hard_timeout,
579                   &cookie);
580     ofm = buffer->data;
581     ofm->match = match;
582     if (strict) {
583         ofm->command = htons(OFPFC_MODIFY_STRICT);
584     } else {
585         ofm->command = htons(OFPFC_MODIFY);
586     }
587     ofm->idle_timeout = htons(idle_timeout);
588     ofm->hard_timeout = htons(hard_timeout);
589     ofm->cookie = htonll(cookie);
590     ofm->buffer_id = htonl(UINT32_MAX);
591     ofm->priority = htons(priority);
592
593     open_vconn(argv[1], &vconn);
594     if (table_idx != 0xff) {
595         enable_flow_mod_table_id_ext(vconn, 1);
596         ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
597     }
598     send_openflow_buffer(vconn, buffer);
599     vconn_close(vconn);
600 }
601
602 static void do_del_flows(int argc, char *argv[])
603 {
604     struct vconn *vconn;
605     uint16_t priority;
606     uint16_t out_port;
607     struct ofpbuf *buffer;
608     struct ofp_flow_mod *ofm;
609     uint8_t table_idx;
610
611     /* Parse and send. */
612     ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
613     parse_ofp_str(argc > 2 ? argv[2] : "", &ofm->match, NULL, &table_idx,
614                   &out_port, &priority, NULL, NULL, NULL);
615     if (strict) {
616         ofm->command = htons(OFPFC_DELETE_STRICT);
617     } else {
618         ofm->command = htons(OFPFC_DELETE);
619     }
620     ofm->idle_timeout = htons(0);
621     ofm->hard_timeout = htons(0);
622     ofm->buffer_id = htonl(UINT32_MAX);
623     ofm->out_port = htons(out_port);
624     ofm->priority = htons(priority);
625
626     open_vconn(argv[1], &vconn);
627     if (table_idx != 0xff) {
628         enable_flow_mod_table_id_ext(vconn, 1);
629         ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
630     }
631     send_openflow_buffer(vconn, buffer);
632     vconn_close(vconn);
633 }
634
635 static void
636 do_tun_cookie(int argc OVS_UNUSED, char *argv[])
637 {
638     struct nxt_tun_id_cookie *tun_id_cookie;
639     struct ofpbuf *buffer;
640     struct vconn *vconn;
641
642     tun_id_cookie = make_openflow(sizeof *tun_id_cookie, OFPT_VENDOR, &buffer);
643
644     tun_id_cookie->vendor = htonl(NX_VENDOR_ID);
645     tun_id_cookie->subtype = htonl(NXT_TUN_ID_FROM_COOKIE);
646     tun_id_cookie->set = !strcmp(argv[2], "true");
647
648     open_vconn(argv[1], &vconn);
649     send_openflow_buffer(vconn, buffer);
650     vconn_close(vconn);
651 }
652
653 static void
654 monitor_vconn(struct vconn *vconn)
655 {
656     for (;;) {
657         struct ofpbuf *b;
658         run(vconn_recv_block(vconn, &b), "vconn_recv");
659         ofp_print(stderr, b->data, b->size, 2);
660         ofpbuf_delete(b);
661     }
662 }
663
664 static void
665 do_monitor(int argc, char *argv[])
666 {
667     struct vconn *vconn;
668
669     open_vconn(argv[1], &vconn);
670     if (argc > 2) {
671         int miss_send_len = atoi(argv[2]);
672         struct ofp_switch_config *osc;
673         struct ofpbuf *buf;
674
675         osc = make_openflow(sizeof *osc, OFPT_SET_CONFIG, &buf);
676         osc->miss_send_len = htons(miss_send_len);
677         send_openflow_buffer(vconn, buf);
678     }
679     monitor_vconn(vconn);
680 }
681
682 static void
683 do_snoop(int argc OVS_UNUSED, char *argv[])
684 {
685     struct vconn *vconn;
686
687     open_vconn__(argv[1], "snoop", &vconn);
688     monitor_vconn(vconn);
689 }
690
691 static void
692 do_dump_ports(int argc, char *argv[])
693 {
694     struct ofp_port_stats_request *req;
695     struct ofpbuf *request;
696     uint16_t port;
697
698     req = alloc_stats_request(sizeof *req, OFPST_PORT, &request);
699     port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
700     req->port_no = htons(port);
701     dump_stats_transaction(argv[1], request);
702 }
703
704 static void
705 do_probe(int argc OVS_UNUSED, char *argv[])
706 {
707     struct ofpbuf *request;
708     struct vconn *vconn;
709     struct ofpbuf *reply;
710
711     make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
712     open_vconn(argv[1], &vconn);
713     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
714     if (reply->size != sizeof(struct ofp_header)) {
715         ovs_fatal(0, "reply does not match request");
716     }
717     ofpbuf_delete(reply);
718     vconn_close(vconn);
719 }
720
721 static void
722 do_mod_port(int argc OVS_UNUSED, char *argv[])
723 {
724     struct ofpbuf *request, *reply;
725     struct ofp_switch_features *osf;
726     struct ofp_port_mod *opm;
727     struct vconn *vconn;
728     char *endptr;
729     int n_ports;
730     int port_idx;
731     int port_no;
732
733
734     /* Check if the argument is a port index.  Otherwise, treat it as
735      * the port name. */
736     port_no = strtol(argv[2], &endptr, 10);
737     if (port_no == 0 && endptr == argv[2]) {
738         port_no = -1;
739     }
740
741     /* Send a "Features Request" to get the information we need in order
742      * to modify the port. */
743     make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
744     open_vconn(argv[1], &vconn);
745     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
746
747     osf = reply->data;
748     n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
749
750     for (port_idx = 0; port_idx < n_ports; port_idx++) {
751         if (port_no != -1) {
752             /* Check argument as a port index */
753             if (osf->ports[port_idx].port_no == htons(port_no)) {
754                 break;
755             }
756         } else {
757             /* Check argument as an interface name */
758             if (!strncmp((char *)osf->ports[port_idx].name, argv[2],
759                         sizeof osf->ports[0].name)) {
760                 break;
761             }
762
763         }
764     }
765     if (port_idx == n_ports) {
766         ovs_fatal(0, "couldn't find monitored port: %s", argv[2]);
767     }
768
769     opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
770     opm->port_no = osf->ports[port_idx].port_no;
771     memcpy(opm->hw_addr, osf->ports[port_idx].hw_addr, sizeof opm->hw_addr);
772     opm->config = htonl(0);
773     opm->mask = htonl(0);
774     opm->advertise = htonl(0);
775
776     printf("modifying port: %s\n", osf->ports[port_idx].name);
777
778     if (!strncasecmp(argv[3], MOD_PORT_CMD_UP, sizeof MOD_PORT_CMD_UP)) {
779         opm->mask |= htonl(OFPPC_PORT_DOWN);
780     } else if (!strncasecmp(argv[3], MOD_PORT_CMD_DOWN,
781                 sizeof MOD_PORT_CMD_DOWN)) {
782         opm->mask |= htonl(OFPPC_PORT_DOWN);
783         opm->config |= htonl(OFPPC_PORT_DOWN);
784     } else if (!strncasecmp(argv[3], MOD_PORT_CMD_FLOOD,
785                 sizeof MOD_PORT_CMD_FLOOD)) {
786         opm->mask |= htonl(OFPPC_NO_FLOOD);
787     } else if (!strncasecmp(argv[3], MOD_PORT_CMD_NOFLOOD,
788                 sizeof MOD_PORT_CMD_NOFLOOD)) {
789         opm->mask |= htonl(OFPPC_NO_FLOOD);
790         opm->config |= htonl(OFPPC_NO_FLOOD);
791     } else {
792         ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
793     }
794
795     send_openflow_buffer(vconn, request);
796
797     ofpbuf_delete(reply);
798     vconn_close(vconn);
799 }
800
801 static void
802 do_ping(int argc, char *argv[])
803 {
804     size_t max_payload = 65535 - sizeof(struct ofp_header);
805     unsigned int payload;
806     struct vconn *vconn;
807     int i;
808
809     payload = argc > 2 ? atoi(argv[2]) : 64;
810     if (payload > max_payload) {
811         ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
812     }
813
814     open_vconn(argv[1], &vconn);
815     for (i = 0; i < 10; i++) {
816         struct timeval start, end;
817         struct ofpbuf *request, *reply;
818         struct ofp_header *rq_hdr, *rpy_hdr;
819
820         rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
821                                OFPT_ECHO_REQUEST, &request);
822         random_bytes(rq_hdr + 1, payload);
823
824         gettimeofday(&start, NULL);
825         run(vconn_transact(vconn, ofpbuf_clone(request), &reply), "transact");
826         gettimeofday(&end, NULL);
827
828         rpy_hdr = reply->data;
829         if (reply->size != request->size
830             || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
831             || rpy_hdr->xid != rq_hdr->xid
832             || rpy_hdr->type != OFPT_ECHO_REPLY) {
833             printf("Reply does not match request.  Request:\n");
834             ofp_print(stdout, request, request->size, 2);
835             printf("Reply:\n");
836             ofp_print(stdout, reply, reply->size, 2);
837         }
838         printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
839                reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid,
840                    (1000*(double)(end.tv_sec - start.tv_sec))
841                    + (.001*(end.tv_usec - start.tv_usec)));
842         ofpbuf_delete(request);
843         ofpbuf_delete(reply);
844     }
845     vconn_close(vconn);
846 }
847
848 static void
849 do_benchmark(int argc OVS_UNUSED, char *argv[])
850 {
851     size_t max_payload = 65535 - sizeof(struct ofp_header);
852     struct timeval start, end;
853     unsigned int payload_size, message_size;
854     struct vconn *vconn;
855     double duration;
856     int count;
857     int i;
858
859     payload_size = atoi(argv[2]);
860     if (payload_size > max_payload) {
861         ovs_fatal(0, "payload must be between 0 and %zu bytes", max_payload);
862     }
863     message_size = sizeof(struct ofp_header) + payload_size;
864
865     count = atoi(argv[3]);
866
867     printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
868            count, message_size, count * message_size);
869
870     open_vconn(argv[1], &vconn);
871     gettimeofday(&start, NULL);
872     for (i = 0; i < count; i++) {
873         struct ofpbuf *request, *reply;
874         struct ofp_header *rq_hdr;
875
876         rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
877         memset(rq_hdr + 1, 0, payload_size);
878         run(vconn_transact(vconn, request, &reply), "transact");
879         ofpbuf_delete(reply);
880     }
881     gettimeofday(&end, NULL);
882     vconn_close(vconn);
883
884     duration = ((1000*(double)(end.tv_sec - start.tv_sec))
885                 + (.001*(end.tv_usec - start.tv_usec)));
886     printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
887            duration, count / (duration / 1000.0),
888            count * message_size / (duration / 1000.0));
889 }
890
891 /* This command is really only useful for testing the flow parser (ofp_parse),
892  * so it is undocumented. */
893 static void
894 do_parse_flows(int argc OVS_UNUSED, char *argv[])
895 {
896     uint8_t table_idx;
897     struct ofpbuf *b;
898     FILE *file;
899
900     file = fopen(argv[1], "r");
901     if (file == NULL) {
902         ovs_fatal(errno, "%s: open", argv[2]);
903     }
904
905     while ((b = parse_ofp_add_flow_file(file, &table_idx)) != NULL) {
906         ofp_print(stdout, b->data, b->size, 0);
907         ofpbuf_delete(b);
908     }
909     fclose(file);
910 }
911
912 static void
913 do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
914 {
915     usage();
916 }
917
918 static const struct command all_commands[] = {
919     { "show", 1, 1, do_show },
920     { "status", 1, 2, do_status },
921     { "monitor", 1, 2, do_monitor },
922     { "snoop", 1, 1, do_snoop },
923     { "dump-desc", 1, 1, do_dump_desc },
924     { "dump-tables", 1, 1, do_dump_tables },
925     { "dump-flows", 1, 2, do_dump_flows },
926     { "dump-aggregate", 1, 2, do_dump_aggregate },
927     { "queue-stats", 1, 3, do_queue_stats },
928     { "add-flow", 2, 2, do_add_flow },
929     { "add-flows", 2, 2, do_add_flows },
930     { "mod-flows", 2, 2, do_mod_flows },
931     { "del-flows", 1, 2, do_del_flows },
932     { "tun-cookie", 2, 2, do_tun_cookie },
933     { "dump-ports", 1, 2, do_dump_ports },
934     { "mod-port", 3, 3, do_mod_port },
935     { "probe", 1, 1, do_probe },
936     { "ping", 1, 2, do_ping },
937     { "benchmark", 3, 3, do_benchmark },
938     { "parse-flows", 1, 1, do_parse_flows },
939     { "help", 0, INT_MAX, do_help },
940     { NULL, 0, 0, NULL },
941 };