Merge "master" branch into "db".
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
index e873ed7..89af18e 100644 (file)
 #define MOD_PORT_CMD_FLOOD   "flood"
 #define MOD_PORT_CMD_NOFLOOD "noflood"
 
+/* Use strict matching for flow mod commands? */
+static bool strict;
 
-/* Settings that may be configured by the user. */
-struct settings {
-    bool strict;        /* Use strict matching for flow mod commands */
-};
-
-struct command {
-    const char *name;
-    int min_args;
-    int max_args;
-    void (*handler)(const struct settings *, int argc, char *argv[]);
-};
-
-static struct command all_commands[];
+static const struct command all_commands[];
 
 static void usage(void) NO_RETURN;
-static void parse_options(int argc, char *argv[], struct settings *);
+static void parse_options(int argc, char *argv[]);
 
-int main(int argc, char *argv[])
+int
+main(int argc, char *argv[])
 {
-    struct settings s;
-    struct command *p;
-
     set_program_name(argv[0]);
     time_init();
     vlog_init();
-    parse_options(argc, argv, &s);
+    parse_options(argc, argv);
     signal(SIGPIPE, SIG_IGN);
-
-    argc -= optind;
-    argv += optind;
-    if (argc < 1)
-        ovs_fatal(0, "missing command name; use --help for help");
-
-    for (p = all_commands; p->name != NULL; p++) {
-        if (!strcmp(p->name, argv[0])) {
-            int n_arg = argc - 1;
-            if (n_arg < p->min_args)
-                ovs_fatal(0, "'%s' command requires at least %d arguments",
-                          p->name, p->min_args);
-            else if (n_arg > p->max_args)
-                ovs_fatal(0, "'%s' command takes at most %d arguments",
-                          p->name, p->max_args);
-            else {
-                p->handler(&s, argc, argv);
-                if (ferror(stdout)) {
-                    ovs_fatal(0, "write to stdout failed");
-                }
-                if (ferror(stderr)) {
-                    ovs_fatal(0, "write to stderr failed");
-                }
-                exit(0);
-            }
-        }
-    }
-    ovs_fatal(0, "unknown command '%s'; use --help for help", argv[0]);
-
+    run_command(argc - optind, argv + optind, all_commands);
     return 0;
 }
 
 static void
-parse_options(int argc, char *argv[], struct settings *s)
+parse_options(int argc, char *argv[])
 {
     enum {
         OPT_STRICT = UCHAR_MAX + 1
@@ -136,9 +96,6 @@ parse_options(int argc, char *argv[], struct settings *s)
     };
     char *short_options = long_options_to_short_options(long_options);
 
-    /* Set defaults that we can figure out before parsing options. */
-    s->strict = false;
-
     for (;;) {
         unsigned long int timeout;
         int c;
@@ -171,7 +128,7 @@ parse_options(int argc, char *argv[], struct settings *s)
             break;
 
         case OPT_STRICT:
-            s->strict = true;
+            strict = true;
             break;
 
         VCONN_SSL_OPTION_HANDLERS
@@ -374,14 +331,14 @@ dump_trivial_stats_transaction(const char *vconn_name, uint8_t stats_type)
 }
 
 static void
-do_show(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_show(int argc UNUSED, char *argv[])
 {
     dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
     dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
 }
 
 static void
-do_status(const struct settings *s UNUSED, int argc, char *argv[])
+do_status(int argc, char *argv[])
 {
     struct nicira_header *request, *reply;
     struct vconn *vconn;
@@ -413,13 +370,13 @@ do_status(const struct settings *s UNUSED, int argc, char *argv[])
 }
 
 static void
-do_dump_desc(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_dump_desc(int argc UNUSED, char *argv[])
 {
     dump_trivial_stats_transaction(argv[1], OFPST_DESC);
 }
 
 static void
-do_dump_tables(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_dump_tables(int argc UNUSED, char *argv[])
 {
     dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
 }
@@ -599,6 +556,22 @@ str_to_action(char *str, struct ofpbuf *b)
             put_dl_addr_action(b, OFPAT_SET_DL_SRC, arg);
         } else if (!strcasecmp(act, "mod_dl_dst")) {
             put_dl_addr_action(b, OFPAT_SET_DL_DST, arg);
+        } else if (!strcasecmp(act, "mod_nw_src")) {
+            struct ofp_action_nw_addr *na;
+            na = put_action(b, sizeof *na, OFPAT_SET_NW_SRC);
+            str_to_ip(arg, &na->nw_addr);
+        } else if (!strcasecmp(act, "mod_nw_dst")) {
+            struct ofp_action_nw_addr *na;
+            na = put_action(b, sizeof *na, OFPAT_SET_NW_DST);
+            str_to_ip(arg, &na->nw_addr);
+        } else if (!strcasecmp(act, "mod_tp_src")) {
+            struct ofp_action_tp_port *ta;
+            ta = put_action(b, sizeof *ta, OFPAT_SET_TP_SRC);
+            ta->tp_port = htons(str_to_u32(arg));
+        } else if (!strcasecmp(act, "mod_tp_dst")) {
+            struct ofp_action_tp_port *ta;
+            ta = put_action(b, sizeof *ta, OFPAT_SET_TP_DST);
+            ta->tp_port = htons(str_to_u32(arg));
         } else if (!strcasecmp(act, "output")) {
             put_output_action(b, str_to_u32(arg));
         } else if (!strcasecmp(act, "drop")) {
@@ -799,7 +772,7 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
 }
 
 static void
-do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[])
+do_dump_flows(int argc, char *argv[])
 {
     struct ofp_flow_stats_request *req;
     uint16_t out_port;
@@ -815,7 +788,7 @@ do_dump_flows(const struct settings *s UNUSED, int argc, char *argv[])
 }
 
 static void
-do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
+do_dump_aggregate(int argc, char *argv[])
 {
     struct ofp_aggregate_stats_request *req;
     struct ofpbuf *request;
@@ -831,7 +804,7 @@ do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
 }
 
 static void
-do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_add_flow(int argc UNUSED, char *argv[])
 {
     struct vconn *vconn;
     struct ofpbuf *buffer;
@@ -859,7 +832,7 @@ do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 }
 
 static void
-do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_add_flows(int argc UNUSED, char *argv[])
 {
     struct vconn *vconn;
     FILE *file;
@@ -912,18 +885,22 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 }
 
 static void
-do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
+do_mod_flows(int argc UNUSED, char *argv[])
 {
     uint16_t priority, idle_timeout, hard_timeout;
     struct vconn *vconn;
     struct ofpbuf *buffer;
     struct ofp_flow_mod *ofm;
+    struct ofp_match match;
 
-    /* Parse and send. */
-    ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
-    str_to_flow(argv[2], &ofm->match, buffer,
+    /* Parse and send.  str_to_flow() will expand and reallocate the data in
+     * 'buffer', so we can't keep pointers to across the str_to_flow() call. */
+    make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
+    str_to_flow(argv[2], &match, buffer,
                 NULL, NULL, &priority, &idle_timeout, &hard_timeout);
-    if (s->strict) {
+    ofm = buffer->data;
+    ofm->match = match;
+    if (strict) {
         ofm->command = htons(OFPFC_MODIFY_STRICT);
     } else {
         ofm->command = htons(OFPFC_MODIFY);
@@ -939,7 +916,7 @@ do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
     vconn_close(vconn);
 }
 
-static void do_del_flows(const struct settings *s, int argc, char *argv[])
+static void do_del_flows(int argc, char *argv[])
 {
     struct vconn *vconn;
     uint16_t priority;
@@ -951,7 +928,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
     ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
     str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL, 
                 &out_port, &priority, NULL, NULL);
-    if (s->strict) {
+    if (strict) {
         ofm->command = htons(OFPFC_DELETE_STRICT);
     } else {
         ofm->command = htons(OFPFC_DELETE);
@@ -969,7 +946,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
 }
 
 static void
-do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_monitor(int argc UNUSED, char *argv[])
 {
     struct vconn *vconn;
 
@@ -994,13 +971,13 @@ do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 }
 
 static void
-do_dump_ports(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_dump_ports(int argc UNUSED, char *argv[])
 {
     dump_trivial_stats_transaction(argv[1], OFPST_PORT);
 }
 
 static void
-do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_probe(int argc UNUSED, char *argv[])
 {
     struct ofpbuf *request;
     struct vconn *vconn;
@@ -1017,7 +994,7 @@ do_probe(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 }
 
 static void
-do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_mod_port(int argc UNUSED, char *argv[])
 {
     struct ofpbuf *request, *reply;
     struct ofp_switch_features *osf;
@@ -1097,7 +1074,7 @@ do_mod_port(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 }
 
 static void
-do_ping(const struct settings *s UNUSED, int argc, char *argv[])
+do_ping(int argc, char *argv[])
 {
     size_t max_payload = 65535 - sizeof(struct ofp_header);
     unsigned int payload;
@@ -1133,7 +1110,7 @@ do_ping(const struct settings *s UNUSED, int argc, char *argv[])
             printf("Reply:\n");
             ofp_print(stdout, reply, reply->size, 2);
         }
-        printf("%d bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
+        printf("%zu bytes from %s: xid=%08"PRIx32" time=%.1f ms\n",
                reply->size - sizeof *rpy_hdr, argv[1], rpy_hdr->xid,
                    (1000*(double)(end.tv_sec - start.tv_sec))
                    + (.001*(end.tv_usec - start.tv_usec)));
@@ -1144,7 +1121,7 @@ do_ping(const struct settings *s UNUSED, int argc, char *argv[])
 }
 
 static void
-do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
+do_benchmark(int argc UNUSED, char *argv[])
 {
     size_t max_payload = 65535 - sizeof(struct ofp_header);
     struct timeval start, end;
@@ -1187,7 +1164,7 @@ do_benchmark(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
 }
 
 static void
-do_execute(const struct settings *s UNUSED, int argc, char *argv[])
+do_execute(int argc, char *argv[])
 {
     struct vconn *vconn;
     struct ofpbuf *request;
@@ -1252,12 +1229,12 @@ do_execute(const struct settings *s UNUSED, int argc, char *argv[])
 }
 
 static void
-do_help(const struct settings *s UNUSED, int argc UNUSED, char *argv[] UNUSED)
+do_help(int argc UNUSED, char *argv[] UNUSED)
 {
     usage();
 }
 
-static struct command all_commands[] = {
+static const struct command all_commands[] = {
     { "show", 1, 1, do_show },
     { "status", 1, 2, do_status },
     { "monitor", 1, 3, do_monitor },