37ee65974a3d8c8071b4cd0ab580da53679a81ae
[sliver-openvswitch.git] / utilities / dpctl.c
1 /* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
2  * Junior University
3  * 
4  * We are making the OpenFlow specification and associated documentation
5  * (Software) available for public use and benefit with the expectation
6  * that others will use, modify and enhance the Software and contribute
7  * those enhancements back to the community. However, since we would
8  * like to make the Software available for broadest use, with as few
9  * restrictions as possible permission is hereby granted, free of
10  * charge, to any person obtaining a copy of this Software to deal in
11  * the Software under the copyrights without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  * 
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  * 
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  * 
29  * The name and trademarks of copyright holder(s) may NOT be used in
30  * advertising or publicity pertaining to the Software or any
31  * derivatives without specific, written prior permission.
32  */
33
34 #include <config.h>
35 #include <arpa/inet.h>
36 #include <errno.h>
37 #include <getopt.h>
38 #include <inttypes.h>
39 #include <netinet/in.h>
40 #include <signal.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <sys/time.h>
46
47 #include "command-line.h"
48 #include "compiler.h"
49 #include "buffer.h"
50 #include "dpif.h"
51 #ifdef HAVE_NETLINK
52 #include "netlink.h"
53 #include "openflow-netlink.h"
54 #endif
55 #include "util.h"
56 #include "socket-util.h"
57 #include "openflow.h"
58 #include "ofp-print.h"
59 #include "random.h"
60 #include "timeval.h"
61 #include "vconn.h"
62 #include "vconn-ssl.h"
63
64 #include "vlog.h"
65 #define THIS_MODULE VLM_dpctl
66
67 #define DEFAULT_IDLE_TIMEOUT 60
68 #define MAX_ADD_ACTS 5
69
70 static const char* ifconfigbin = "/sbin/ifconfig";
71
72 struct command {
73     const char *name;
74     int min_args;
75     int max_args;
76     void (*handler)(int argc, char *argv[]);
77 };
78
79 static struct command all_commands[];
80
81 static void usage(void) NO_RETURN;
82 static void parse_options(int argc, char *argv[]);
83
84 int main(int argc, char *argv[])
85 {
86     struct command *p;
87
88     set_program_name(argv[0]);
89     time_init();
90     vlog_init();
91     parse_options(argc, argv);
92     signal(SIGPIPE, SIG_IGN);
93
94     argc -= optind;
95     argv += optind;
96     if (argc < 1)
97         fatal(0, "missing command name; use --help for help");
98
99     for (p = all_commands; p->name != NULL; p++) {
100         if (!strcmp(p->name, argv[0])) {
101             int n_arg = argc - 1;
102             if (n_arg < p->min_args)
103                 fatal(0, "'%s' command requires at least %d arguments",
104                       p->name, p->min_args);
105             else if (n_arg > p->max_args)
106                 fatal(0, "'%s' command takes at most %d arguments",
107                       p->name, p->max_args);
108             else {
109                 p->handler(argc, argv);
110                 exit(0);
111             }
112         }
113     }
114     fatal(0, "unknown command '%s'; use --help for help", argv[0]);
115
116     return 0;
117 }
118
119 static void
120 parse_options(int argc, char *argv[])
121 {
122     static struct option long_options[] = {
123         {"timeout", required_argument, 0, 't'},
124         {"verbose", optional_argument, 0, 'v'},
125         {"help", no_argument, 0, 'h'},
126         {"version", no_argument, 0, 'V'},
127         VCONN_SSL_LONG_OPTIONS
128         {0, 0, 0, 0},
129     };
130     char *short_options = long_options_to_short_options(long_options);
131
132     for (;;) {
133         unsigned long int timeout;
134         int c;
135
136         c = getopt_long(argc, argv, short_options, long_options, NULL);
137         if (c == -1) {
138             break;
139         }
140
141         switch (c) {
142         case 't':
143             timeout = strtoul(optarg, NULL, 10);
144             if (timeout <= 0) {
145                 fatal(0, "value %s on -t or --timeout is not at least 1",
146                       optarg);
147             } else {
148                 time_alarm(timeout);
149             }
150             break;
151
152         case 'h':
153             usage();
154
155         case 'V':
156             printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
157             exit(EXIT_SUCCESS);
158
159         case 'v':
160             vlog_set_verbosity(optarg);
161             break;
162
163         VCONN_SSL_OPTION_HANDLERS
164
165         case '?':
166             exit(EXIT_FAILURE);
167
168         default:
169             abort();
170         }
171     }
172     free(short_options);
173 }
174
175 static void
176 usage(void)
177 {
178     printf("%s: OpenFlow switch management utility\n"
179            "usage: %s [OPTIONS] COMMAND [ARG...]\n"
180 #ifdef HAVE_NETLINK
181            "\nFor local datapaths only:\n"
182            "  adddp nl:DP_ID              add a new local datapath DP_ID\n"
183            "  deldp nl:DP_ID              delete local datapath DP_ID\n"
184            "  addif nl:DP_ID IFACE        add IFACE as a port on DP_ID\n"
185            "  delif nl:DP_ID IFACE        delete IFACE as a port on DP_ID\n"
186            "  monitor nl:DP_ID            print packets received\n"
187 #endif
188            "\nFor local datapaths and remote switches:\n"
189            "  show SWITCH                 show information\n"
190            "  dump-version SWITCH         print version information\n"
191            "  dump-tables SWITCH          print table stats\n"
192            "  dump-ports SWITCH           print port statistics\n"
193            "  dump-flows SWITCH           print all flow entries\n"
194            "  dump-flows SWITCH FLOW      print matching FLOWs\n"
195            "  dump-aggregate SWITCH       print aggregate flow statistics\n"
196            "  dump-aggregate SWITCH FLOW  print aggregate stats for FLOWs\n"
197            "  add-flow SWITCH FLOW        add flow described by FLOW\n"
198            "  add-flows SWITCH FILE       add flows from FILE\n"
199            "  del-flows SWITCH FLOW       delete matching FLOWs\n"
200            "\nFor local datapaths, remote switches, and controllers:\n"
201            "  probe VCONN                 probe whether VCONN is up\n"
202            "  ping VCONN [N]              latency of N-byte echos\n"
203            "  benchmark VCONN N COUNT     bandwidth of COUNT N-byte echos\n"
204            "where each SWITCH is an active OpenFlow connection method.\n",
205            program_name, program_name);
206     vconn_usage(true, false);
207     printf("\nOptions:\n"
208            "  -t, --timeout=SECS          give up after SECS seconds\n"
209            "  -v, --verbose=MODULE[:FACILITY[:LEVEL]]  set logging levels\n"
210            "  -v, --verbose               set maximum verbosity level\n"
211            "  -h, --help                  display this help message\n"
212            "  -V, --version               display version information\n");
213     exit(EXIT_SUCCESS);
214 }
215
216 static void run(int retval, const char *message, ...)
217     PRINTF_FORMAT(2, 3);
218
219 static void run(int retval, const char *message, ...)
220 {
221     if (retval) {
222         va_list args;
223
224         fprintf(stderr, "%s: ", program_name);
225         va_start(args, message);
226         vfprintf(stderr, message, args);
227         va_end(args);
228         if (retval == EOF) {
229             fputs(": unexpected end of file\n", stderr);
230         } else {
231             fprintf(stderr, ": %s\n", strerror(retval));
232         }
233
234         exit(EXIT_FAILURE);
235     }
236 }
237 \f
238 #ifdef HAVE_NETLINK
239 /* Netlink-only commands. */
240
241 static int  if_up(const char* intf)
242 {
243     char command[256];
244     snprintf(command, sizeof command, "%s %s up &> /dev/null",
245             ifconfigbin, intf);
246     return system(command);
247 }
248
249 static void open_nl_vconn(const char *name, bool subscribe, struct dpif *dpif)
250 {
251     if (strncmp(name, "nl:", 3)
252         || strlen(name) < 4
253         || name[strspn(name + 3, "0123456789") + 3]) {
254         fatal(0, "%s: argument is not of the form \"nl:DP_ID\"", name);
255     }
256     run(dpif_open(atoi(name + 3), subscribe, dpif), "opening datapath");
257 }
258
259 static void do_add_dp(int argc UNUSED, char *argv[])
260 {
261     struct dpif dp;
262     open_nl_vconn(argv[1], false, &dp);
263     run(dpif_add_dp(&dp), "add_dp");
264     dpif_close(&dp);
265 }
266
267 static void do_del_dp(int argc UNUSED, char *argv[])
268 {
269     struct dpif dp;
270     open_nl_vconn(argv[1], false, &dp);
271     run(dpif_del_dp(&dp), "del_dp");
272     dpif_close(&dp);
273 }
274
275 static void do_add_port(int argc UNUSED, char *argv[])
276 {
277     struct dpif dp;
278     if_up(argv[2]);
279     open_nl_vconn(argv[1], false, &dp);
280     run(dpif_add_port(&dp, argv[2]), "add_port");
281     dpif_close(&dp);
282 }
283
284 static void do_del_port(int argc UNUSED, char *argv[])
285 {
286     struct dpif dp;
287     open_nl_vconn(argv[1], false, &dp);
288     run(dpif_del_port(&dp, argv[2]), "del_port");
289     dpif_close(&dp);
290 }
291
292 static void do_monitor(int argc UNUSED, char *argv[])
293 {
294     struct dpif dp;
295     open_nl_vconn(argv[1], true, &dp);
296     for (;;) {
297         struct buffer *b;
298         run(dpif_recv_openflow(&dp, &b, true), "dpif_recv_openflow");
299         ofp_print(stderr, b->data, b->size, 2);
300         buffer_delete(b);
301     }
302 }
303 #endif /* HAVE_NETLINK */
304 \f
305 /* Generic commands. */
306
307 static void *
308 alloc_stats_request(size_t body_len, uint16_t type, struct buffer **bufferp)
309 {
310     struct ofp_stats_request *rq;
311     rq = make_openflow((offsetof(struct ofp_stats_request, body)
312                         + body_len), OFPT_STATS_REQUEST, bufferp);
313     rq->type = htons(type);
314     rq->flags = htons(0);
315     return rq->body;
316 }
317
318 static void
319 send_openflow_buffer(struct vconn *vconn, struct buffer *buffer)
320 {
321     update_openflow_length(buffer);
322     run(vconn_send_block(vconn, buffer), "failed to send packet to switch");
323 }
324
325 static void
326 dump_transaction(const char *vconn_name, struct buffer *request)
327 {
328     struct vconn *vconn;
329     struct buffer *reply;
330
331     update_openflow_length(request);
332     run(vconn_open_block(vconn_name, &vconn), "connecting to %s", vconn_name);
333     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
334     ofp_print(stdout, reply->data, reply->size, 1);
335     vconn_close(vconn);
336 }
337
338 static void
339 dump_trivial_transaction(const char *vconn_name, uint8_t request_type)
340 {
341     struct buffer *request;
342     make_openflow(sizeof(struct ofp_header), request_type, &request);
343     dump_transaction(vconn_name, request);
344 }
345
346 static void
347 dump_stats_transaction(const char *vconn_name, struct buffer *request)
348 {
349     uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
350     struct vconn *vconn;
351     bool done = false;
352
353     run(vconn_open_block(vconn_name, &vconn), "connecting to %s", vconn_name);
354     send_openflow_buffer(vconn, request);
355     while (!done) {
356         uint32_t recv_xid;
357         struct buffer *reply;
358
359         run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
360         recv_xid = ((struct ofp_header *) reply->data)->xid;
361         if (send_xid == recv_xid) {
362             struct ofp_stats_reply *osr;
363
364             ofp_print(stdout, reply->data, reply->size, 1);
365
366             osr = buffer_at(reply, 0, sizeof *osr);
367             done = !osr || !(ntohs(osr->flags) & OFPSF_REPLY_MORE);
368         } else {
369             VLOG_DBG("received reply with xid %08"PRIx32" "
370                      "!= expected %08"PRIx32, recv_xid, send_xid);
371         }
372         buffer_delete(reply);
373     }
374     vconn_close(vconn);
375 }
376
377 static void
378 dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
379 {
380     struct buffer *request;
381     alloc_stats_request(0, stats_type, &request);
382     dump_stats_transaction(vconn_name, request);
383 }
384
385 static void
386 do_show(int argc UNUSED, char *argv[])
387 {
388     dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
389     dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
390 }
391
392
393 static void
394 do_dump_version(int argc, char *argv[])
395 {
396     dump_trivial_stats_transaction(argv[1], OFPST_VERSION);
397 }
398
399 static void
400 do_dump_tables(int argc, char *argv[])
401 {
402     dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
403 }
404
405
406 static uint32_t
407 str_to_int(const char *str) 
408 {
409     char *tail;
410     uint32_t value;
411
412     errno = 0;
413     value = strtoul(str, &tail, 0);
414     if (errno == EINVAL || errno == ERANGE || *tail) {
415         fatal(0, "invalid numeric format %s", str);
416     }
417     return value;
418 }
419
420 static void
421 str_to_mac(const char *str, uint8_t mac[6]) 
422 {
423     if (sscanf(str, "%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8":%"SCNx8,
424                &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
425         fatal(0, "invalid mac address %s", str);
426     }
427 }
428
429 static uint32_t
430 str_to_ip(const char *str_, uint32_t *ip)
431 {
432     char *str = xstrdup(str_);
433     char *save_ptr = NULL;
434     const char *name, *netmask;
435     struct in_addr in_addr;
436     int n_wild, retval;
437
438     name = strtok_r(str, "//", &save_ptr);
439     retval = name ? lookup_ip(name, &in_addr) : EINVAL;
440     if (retval) {
441         fatal(0, "%s: could not convert to IP address", str);
442     }
443     *ip = in_addr.s_addr;
444
445     netmask = strtok_r(NULL, "//", &save_ptr);
446     if (netmask) {
447         uint8_t o[4];
448         if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8,
449                    &o[0], &o[1], &o[2], &o[3]) == 4) {
450             uint32_t nm = (o[0] << 24) | (o[1] << 16) | (o[2] << 8) | o[3];
451             int i;
452
453             /* Find first 1-bit. */
454             for (i = 0; i < 32; i++) {
455                 if (nm & (1u << i)) {
456                     break;
457                 }
458             }
459             n_wild = i;
460
461             /* Verify that the rest of the bits are 1-bits. */
462             for (; i < 32; i++) {
463                 if (!(nm & (1u << i))) {
464                     fatal(0, "%s: %s is not a valid netmask", str, netmask);
465                 }
466             }
467         } else {
468             int prefix = atoi(netmask);
469             if (prefix <= 0 || prefix > 32) {
470                 fatal(0, "%s: network prefix bits not between 1 and 32", str);
471             }
472             n_wild = 32 - prefix;
473         }
474     } else {
475         n_wild = 0;
476     }
477
478     free(str);
479     return n_wild;
480 }
481
482 static void
483 str_to_action(char *str, struct ofp_action *action, int *n_actions) 
484 {
485     uint16_t port;
486     int i;
487     int max_actions = *n_actions;
488     char *act, *arg;
489     char *saveptr = NULL;
490     
491     memset(action, 0, sizeof(*action) * max_actions);
492     for (i=0, act = strtok_r(str, ", \t\r\n", &saveptr); 
493          i<max_actions && act;
494          i++, act = strtok_r(NULL, ", \t\r\n", &saveptr)) 
495     {
496         port = OFPP_MAX;
497
498         /* Arguments are separated by colons */
499         arg = strchr(act, ':');
500         if (arg) {
501             *arg = '\0';
502             arg++;
503         } 
504
505         if (!strcasecmp(act, "mod_vlan")) {
506             action[i].type = htons(OFPAT_SET_DL_VLAN);
507
508             if (!strcasecmp(arg, "strip")) {
509                 action[i].arg.vlan_id = htons(OFP_VLAN_NONE);
510             } else {
511                 action[i].arg.vlan_id = htons(str_to_int(arg));
512             }
513         } else if (!strcasecmp(act, "output")) {
514             port = str_to_int(arg);
515         } else if (!strcasecmp(act, "TABLE")) {
516             port = OFPP_TABLE;
517         } else if (!strcasecmp(act, "NORMAL")) {
518             port = OFPP_NORMAL;
519         } else if (!strcasecmp(act, "FLOOD")) {
520             port = OFPP_FLOOD;
521         } else if (!strcasecmp(act, "ALL")) {
522             port = OFPP_ALL;
523         } else if (!strcasecmp(act, "CONTROLLER")) {
524             port = OFPP_CONTROLLER;
525             if (arg) {
526                 if (!strcasecmp(arg, "all")) {
527                     action[i].arg.output.max_len= htons(0);
528                 } else {
529                     action[i].arg.output.max_len= htons(str_to_int(arg));
530                 }
531             }
532         } else if (!strcasecmp(act, "LOCAL")) {
533             port = OFPP_LOCAL;
534         } else if (strspn(act, "0123456789") == strlen(act)) {
535             port = str_to_int(act);
536         } else {
537             fatal(0, "Unknown action: %s", act);
538         }
539
540         if (port != OFPP_MAX) {
541             action[i].type = htons(OFPAT_OUTPUT);
542             action[i].arg.output.port = htons(port);
543         }
544     }
545
546     *n_actions = i;
547 }
548
549 static void
550 str_to_flow(char *string, struct ofp_match *match, 
551         struct ofp_action *action, int *n_actions, uint8_t *table_idx, 
552             uint16_t *priority, uint16_t *idle_timeout, uint16_t *hard_timeout)
553 {
554     struct field {
555         const char *name;
556         uint32_t wildcard;
557         enum { F_U8, F_U16, F_MAC, F_IP } type;
558         size_t offset, shift;
559     };
560
561 #define F_OFS(MEMBER) offsetof(struct ofp_match, MEMBER)
562     static const struct field fields[] = { 
563         { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port) },
564         { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan) },
565         { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src) },
566         { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst) },
567         { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type) },
568         { "nw_src", OFPFW_NW_SRC_MASK, F_IP,
569           F_OFS(nw_src), OFPFW_NW_SRC_SHIFT },
570         { "nw_dst", OFPFW_NW_DST_MASK, F_IP,
571           F_OFS(nw_dst), OFPFW_NW_DST_SHIFT },
572         { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto) },
573         { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src) },
574         { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst) },
575     };
576
577     char *name, *value;
578     uint32_t wildcards;
579     char *act_str;
580
581     if (table_idx) {
582         *table_idx = 0xff;
583     }
584     if (priority) {
585         *priority = OFP_DEFAULT_PRIORITY;
586     }
587     if (idle_timeout) {
588         *idle_timeout = DEFAULT_IDLE_TIMEOUT;
589     }
590     if (hard_timeout) {
591         *hard_timeout = OFP_FLOW_PERMANENT;
592     }
593     if (action) {
594         act_str = strstr(string, "action");
595         if (!act_str) {
596             fatal(0, "must specify an action");
597         }
598         *(act_str-1) = '\0';
599
600         act_str = strchr(act_str, '=');
601         if (!act_str) {
602             fatal(0, "must specify an action");
603         }
604
605         act_str++;
606
607         str_to_action(act_str, action, n_actions);
608     }
609     memset(match, 0, sizeof *match);
610     wildcards = OFPFW_ALL;
611     for (name = strtok(string, "="), value = strtok(NULL, ", \t\r\n");
612          name && value;
613          name = strtok(NULL, "="), value = strtok(NULL, ", \t\r\n"))
614     {
615         const struct field *f;
616         void *data;
617
618         if (table_idx && !strcmp(name, "table")) {
619             *table_idx = atoi(value);
620             continue;
621         }
622
623         if (priority && !strcmp(name, "priority")) {
624             *priority = atoi(value);
625             continue;
626         }
627
628         if (idle_timeout && !strcmp(name, "idle_timeout")) {
629             *idle_timeout = atoi(value);
630             continue;
631         }
632
633         if (hard_timeout && !strcmp(name, "hard_timeout")) {
634             *hard_timeout = atoi(value);
635             continue;
636         }
637
638         for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
639             if (!strcmp(f->name, name)) {
640                 goto found;
641             }
642         }
643         fprintf(stderr, "%s: unknown field %s (fields are",
644                 program_name, name);
645         for (f = fields; f < &fields[ARRAY_SIZE(fields)]; f++) {
646             if (f != fields) {
647                 putc(',', stderr);
648             }
649             fprintf(stderr, " %s", f->name);
650         }
651         fprintf(stderr, ")\n");
652         exit(1);
653
654     found:
655         data = (char *) match + f->offset;
656         if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
657             wildcards |= f->wildcard;
658         } else {
659             wildcards &= ~f->wildcard;
660             if (f->type == F_U8) {
661                 *(uint8_t *) data = str_to_int(value);
662             } else if (f->type == F_U16) {
663                 *(uint16_t *) data = htons(str_to_int(value));
664             } else if (f->type == F_MAC) {
665                 str_to_mac(value, data);
666             } else if (f->type == F_IP) {
667                 wildcards |= str_to_ip(value, data) << f->shift;
668             } else {
669                 NOT_REACHED();
670             }
671         }
672     }
673     if (name && !value) {
674         fatal(0, "field %s missing value", name);
675     }
676     match->wildcards = htonl(wildcards);
677 }
678
679 static void do_dump_flows(int argc, char *argv[])
680 {
681     struct ofp_flow_stats_request *req;
682     struct buffer *request;
683
684     req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
685     str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, 0, 
686                 &req->table_id, NULL, NULL, NULL);
687     memset(req->pad, 0, sizeof req->pad);
688
689     dump_stats_transaction(argv[1], request);
690 }
691
692 static void do_dump_aggregate(int argc, char *argv[])
693 {
694     struct ofp_aggregate_stats_request *req;
695     struct buffer *request;
696
697     req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
698     str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, 0,
699                 &req->table_id, NULL, NULL, NULL);
700     memset(req->pad, 0, sizeof req->pad);
701
702     dump_stats_transaction(argv[1], request);
703 }
704
705 static void do_add_flow(int argc, char *argv[])
706 {
707     struct vconn *vconn;
708     struct buffer *buffer;
709     struct ofp_flow_mod *ofm;
710     uint16_t priority, idle_timeout, hard_timeout;
711     size_t size;
712     int n_actions = MAX_ADD_ACTS;
713
714     run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
715
716     /* Parse and send. */
717     size = sizeof *ofm + (sizeof ofm->actions[0] * MAX_ADD_ACTS);
718     ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
719     str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &n_actions, 
720                 NULL, &priority, &idle_timeout, &hard_timeout);
721     ofm->command = htons(OFPFC_ADD);
722     ofm->idle_timeout = htons(idle_timeout);
723     ofm->hard_timeout = htons(hard_timeout);
724     ofm->buffer_id = htonl(UINT32_MAX);
725     ofm->priority = htons(priority);
726     ofm->reserved = htonl(0);
727
728     /* xxx Should we use the buffer library? */
729     buffer->size -= (MAX_ADD_ACTS - n_actions) * sizeof ofm->actions[0];
730
731     send_openflow_buffer(vconn, buffer);
732     vconn_close(vconn);
733 }
734
735 static void do_add_flows(int argc, char *argv[])
736 {
737     struct vconn *vconn;
738
739     FILE *file;
740     char line[1024];
741
742     file = fopen(argv[2], "r");
743     if (file == NULL) {
744         fatal(errno, "%s: open", argv[2]);
745     }
746
747     run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
748     while (fgets(line, sizeof line, file)) {
749         struct buffer *buffer;
750         struct ofp_flow_mod *ofm;
751         uint16_t priority, idle_timeout, hard_timeout;
752         size_t size;
753         int n_actions = MAX_ADD_ACTS;
754
755         char *comment;
756
757         /* Delete comments. */
758         comment = strchr(line, '#');
759         if (comment) {
760             *comment = '\0';
761         }
762
763         /* Drop empty lines. */
764         if (line[strspn(line, " \t\n")] == '\0') {
765             continue;
766         }
767
768         /* Parse and send. */
769         size = sizeof *ofm + (sizeof ofm->actions[0] * MAX_ADD_ACTS);
770         ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
771         str_to_flow(line, &ofm->match, &ofm->actions[0], &n_actions, 
772                     NULL, &priority, &idle_timeout, &hard_timeout);
773         ofm->command = htons(OFPFC_ADD);
774         ofm->idle_timeout = htons(idle_timeout);
775         ofm->hard_timeout = htons(hard_timeout);
776         ofm->buffer_id = htonl(UINT32_MAX);
777         ofm->priority = htons(priority);
778         ofm->reserved = htonl(0);
779
780         /* xxx Should we use the buffer library? */
781         buffer->size -= (MAX_ADD_ACTS - n_actions) * sizeof ofm->actions[0];
782
783         send_openflow_buffer(vconn, buffer);
784     }
785     vconn_close(vconn);
786     fclose(file);
787 }
788
789 static void do_del_flows(int argc, char *argv[])
790 {
791     struct vconn *vconn;
792     uint16_t priority;
793
794     run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
795     struct buffer *buffer;
796     struct ofp_flow_mod *ofm;
797     size_t size;
798
799
800     /* Parse and send. */
801     size = sizeof *ofm;
802     ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
803     str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, 0, NULL, 
804                 &priority, NULL, NULL);
805     ofm->command = htons(OFPFC_DELETE);
806     ofm->idle_timeout = htons(0);
807     ofm->hard_timeout = htons(0);
808     ofm->buffer_id = htonl(UINT32_MAX);
809     ofm->priority = htons(priority);
810     ofm->reserved = htonl(0);
811
812     send_openflow_buffer(vconn, buffer);
813
814     vconn_close(vconn);
815 }
816
817 static void
818 do_dump_ports(int argc, char *argv[])
819 {
820     dump_trivial_stats_transaction(argv[1], OFPST_PORT);
821 }
822
823 static void
824 do_probe(int argc, char *argv[])
825 {
826     struct buffer *request;
827     struct vconn *vconn;
828     struct buffer *reply;
829
830     make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
831     run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
832     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
833     if (reply->size != request->size) {
834         fatal(0, "reply does not match request");
835     }
836     buffer_delete(reply);
837     vconn_close(vconn);
838 }
839
840 static void
841 do_ping(int argc, char *argv[])
842 {
843     size_t max_payload = 65535 - sizeof(struct ofp_header);
844     unsigned int payload;
845     struct vconn *vconn;
846     int i;
847
848     payload = argc > 2 ? atoi(argv[2]) : 64;
849     if (payload > max_payload) {
850         fatal(0, "payload must be between 0 and %zu bytes", max_payload);
851     }
852
853     run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
854     for (i = 0; i < 10; i++) {
855         struct timeval start, end;
856         struct buffer *request, *reply;
857         struct ofp_header *rq_hdr, *rpy_hdr;
858
859         rq_hdr = make_openflow(sizeof(struct ofp_header) + payload,
860                                OFPT_ECHO_REQUEST, &request);
861         random_bytes(rq_hdr + 1, payload);
862
863         gettimeofday(&start, NULL);
864         run(vconn_transact(vconn, buffer_clone(request), &reply), "transact");
865         gettimeofday(&end, NULL);
866
867         rpy_hdr = reply->data;
868         if (reply->size != request->size
869             || memcmp(rpy_hdr + 1, rq_hdr + 1, payload)
870             || rpy_hdr->xid != rq_hdr->xid
871             || rpy_hdr->type != OFPT_ECHO_REPLY) {
872             printf("Reply does not match request.  Request:\n");
873             ofp_print(stdout, request, request->size, 2);
874             printf("Reply:\n");
875             ofp_print(stdout, reply, reply->size, 2);
876         }
877         printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
878                reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid,
879                    (1000*(double)(end.tv_sec - start.tv_sec))
880                    + (.001*(end.tv_usec - start.tv_usec)));
881         buffer_delete(request);
882         buffer_delete(reply);
883     }
884     vconn_close(vconn);
885 }
886
887 static void
888 do_benchmark(int argc, char *argv[])
889 {
890     size_t max_payload = 65535 - sizeof(struct ofp_header);
891     struct timeval start, end;
892     unsigned int payload_size, message_size;
893     struct vconn *vconn;
894     double duration;
895     int count;
896     int i;
897
898     payload_size = atoi(argv[2]);
899     if (payload_size > max_payload) {
900         fatal(0, "payload must be between 0 and %zu bytes", max_payload);
901     }
902     message_size = sizeof(struct ofp_header) + payload_size;
903
904     count = atoi(argv[3]);
905
906     printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
907            count, message_size, count * message_size);
908
909     run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
910     gettimeofday(&start, NULL);
911     for (i = 0; i < count; i++) {
912         struct buffer *request, *reply;
913         struct ofp_header *rq_hdr;
914
915         rq_hdr = make_openflow(message_size, OFPT_ECHO_REQUEST, &request);
916         memset(rq_hdr + 1, 0, payload_size);
917         run(vconn_transact(vconn, request, &reply), "transact");
918         buffer_delete(reply);
919     }
920     gettimeofday(&end, NULL);
921     vconn_close(vconn);
922
923     duration = ((1000*(double)(end.tv_sec - start.tv_sec))
924                 + (.001*(end.tv_usec - start.tv_usec)));
925     printf("Finished in %.1f ms (%.0f packets/s) (%.0f bytes/s)\n",
926            duration, count / (duration / 1000.0),
927            count * message_size / (duration / 1000.0));
928 }
929
930 static void do_help(int argc UNUSED, char *argv[] UNUSED)
931 {
932     usage();
933 }
934
935 static struct command all_commands[] = {
936 #ifdef HAVE_NETLINK
937     { "adddp", 1, 1, do_add_dp },
938     { "deldp", 1, 1, do_del_dp },
939     { "addif", 2, 2, do_add_port },
940     { "delif", 2, 2, do_del_port },
941 #endif
942
943     { "show", 1, 1, do_show },
944
945     { "help", 0, INT_MAX, do_help },
946     { "monitor", 1, 1, do_monitor },
947     { "dump-version", 1, 1, do_dump_version },
948     { "dump-tables", 1, 1, do_dump_tables },
949     { "dump-flows", 1, 2, do_dump_flows },
950     { "dump-aggregate", 1, 2, do_dump_aggregate },
951     { "add-flow", 2, 2, do_add_flow },
952     { "add-flows", 2, 2, do_add_flows },
953     { "del-flows", 1, 2, do_del_flows },
954     { "dump-ports", 1, 1, do_dump_ports },
955     { "probe", 1, 1, do_probe },
956     { "ping", 1, 2, do_ping },
957     { "benchmark", 3, 3, do_benchmark },
958     { NULL, 0, 0, NULL },
959 };