ovs-ofctl: Fix write before beginning of string in "add-flow".
[openvswitch] / utilities / ovs-ofctl.c
index 852d542e864ab3073dd3e5e12d622455dbb9c845..204e9582f22975dd5877eced8a78f9b3b432c9fa 100644 (file)
@@ -153,7 +153,7 @@ usage(void)
            "  dump-desc SWITCH            print switch description\n"
            "  dump-tables SWITCH          print table stats\n"
            "  mod-port SWITCH IFACE ACT   modify port behavior\n"
-           "  dump-ports SWITCH           print port statistics\n"
+           "  dump-ports SWITCH [PORT]    print port statistics\n"
            "  dump-flows SWITCH           print all flow entries\n"
            "  dump-flows SWITCH FLOW      print matching FLOWs\n"
            "  dump-aggregate SWITCH       print aggregate flow statistics\n"
@@ -405,6 +405,20 @@ str_to_u32(const char *str)
     return value;
 }
 
+static uint64_t
+str_to_u64(const char *str) 
+{
+    char *tail;
+    uint64_t value;
+
+    errno = 0;
+    value = strtoull(str, &tail, 0);
+    if (errno == EINVAL || errno == ERANGE || *tail) {
+        ovs_fatal(0, "invalid numeric format %s", str);
+    }
+    return value;
+}
+
 static void
 str_to_mac(const char *str, uint8_t mac[6]) 
 {
@@ -469,6 +483,48 @@ str_to_ip(const char *str_, uint32_t *ip)
     return n_wild;
 }
 
+static uint16_t
+str_to_port_no(const char *vconn_name, const char *str)
+{
+    struct ofpbuf *request, *reply;
+    struct ofp_switch_features *osf;
+    struct vconn *vconn;
+    int n_ports;
+    int port_idx;
+    unsigned int port_no;
+    
+
+    /* Check if the argument is a port index.  Otherwise, treat it as
+     * the port name. */
+    if (str_to_uint(str, 10, &port_no)) {
+        return port_no;
+    }
+
+    /* Send a "Features Request" to resolve the name into a number. */
+    make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
+    open_vconn(vconn_name, &vconn);
+    run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
+
+    osf = reply->data;
+    n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
+
+    for (port_idx = 0; port_idx < n_ports; port_idx++) {
+        /* Check argument as an interface name */
+        if (!strncmp((char *)osf->ports[port_idx].name, str,
+                    sizeof osf->ports[0].name)) {
+            break;
+        }
+    }
+    if (port_idx == n_ports) {
+        ovs_fatal(0, "couldn't find monitored port: %s", str);
+    }
+
+    ofpbuf_delete(reply);
+    vconn_close(vconn);
+
+    return port_idx;
+}
+
 static void *
 put_action(struct ofpbuf *b, size_t size, uint16_t type)
 {
@@ -585,6 +641,12 @@ str_to_action(char *str, struct ofpbuf *b)
             struct ofp_action_nw_tos *nt;
             nt = put_action(b, sizeof *nt, OFPAT_SET_NW_TOS);
             nt->nw_tos = str_to_u32(arg);
+        } else if (!strcasecmp(act, "resubmit")) {
+            struct nx_action_resubmit *nar;
+            nar = put_action(b, sizeof *nar, OFPAT_VENDOR);
+            nar->vendor = htonl(NX_VENDOR_ID);
+            nar->subtype = htons(NXAST_RESUBMIT);
+            nar->in_port = htons(str_to_u32(arg));
         } else if (!strcasecmp(act, "output")) {
             put_output_action(b, str_to_u32(arg));
         } else if (!strcasecmp(act, "drop")) {
@@ -601,7 +663,7 @@ str_to_action(char *str, struct ofpbuf *b)
 
             /* Unless a numeric argument is specified, we send the whole
              * packet to the controller. */
-            if (arg && (strspn(act, "0123456789") == strlen(act))) {
+            if (arg && (strspn(arg, "0123456789") == strlen(arg))) {
                oao->max_len = htons(str_to_u32(arg));
             } else {
                 oao->max_len = htons(UINT16_MAX);
@@ -718,9 +780,9 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
         if (!act_str) {
             ovs_fatal(0, "must specify an action");
         }
-        *(act_str-1) = '\0';
+        *act_str = '\0';
 
-        act_str = strchr(act_str, '=');
+        act_str = strchr(act_str + 1, '=');
         if (!act_str) {
             ovs_fatal(0, "must specify an action");
         }
@@ -762,7 +824,7 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
             } else if (hard_timeout && !strcmp(name, "hard_timeout")) {
                 *hard_timeout = atoi(value);
             } else if (cookie && !strcmp(name, "cookie")) {
-                *cookie = atoi(value);
+                *cookie = str_to_u64(value);
             } else if (parse_field(name, &f)) {
                 void *data = (char *) match + f->offset;
                 if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
@@ -995,9 +1057,16 @@ do_monitor(int argc OVS_UNUSED, char *argv[])
 }
 
 static void
-do_dump_ports(int argc OVS_UNUSED, char *argv[])
+do_dump_ports(int argc, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPST_PORT);
+    struct ofp_port_stats_request *req;
+    struct ofpbuf *request;
+    uint16_t port;
+
+    req = alloc_stats_request(sizeof *req, OFPST_PORT, &request);
+    port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_NONE;
+    req->port_no = htons(port);
+    dump_stats_transaction(argv[1], request);
 }
 
 static void
@@ -1205,7 +1274,7 @@ static const struct command all_commands[] = {
     { "add-flows", 2, 2, do_add_flows },
     { "mod-flows", 2, 2, do_mod_flows },
     { "del-flows", 1, 2, do_del_flows },
-    { "dump-ports", 1, 1, do_dump_ports },
+    { "dump-ports", 1, 2, do_dump_ports },
     { "mod-port", 3, 3, do_mod_port },
     { "probe", 1, 1, do_probe },
     { "ping", 1, 2, do_ping },