Add support for OFPFC_MODIFY Flow Mod command.
[sliver-openvswitch.git] / utilities / dpctl.c
index 33a51f8..bd89065 100644 (file)
@@ -204,7 +204,8 @@ usage(void)
            "  dump-aggregate SWITCH FLOW  print aggregate stats for FLOWs\n"
            "  add-flow SWITCH FLOW        add flow described by FLOW\n"
            "  add-flows SWITCH FILE       add flows from FILE\n"
-           "  del-flows SWITCH FLOW       delete matching FLOWs\n"
+           "  mod-flows SWITCH FLOW       modify actions of matching FLOWs\n"
+           "  del-flows SWITCH [FLOW]     delete matching FLOWs\n"
            "  monitor SWITCH              print packets received from SWITCH\n"
            "\nFor local datapaths, remote switches, and controllers:\n"
            "  probe VCONN                 probe whether VCONN is up\n"
@@ -328,6 +329,12 @@ static void do_del_port(int argc UNUSED, char *argv[])
 \f
 /* Generic commands. */
 
+static void
+open_vconn(const char *name, struct vconn **vconnp)
+{
+    run(vconn_open_block(name, OFP_VERSION, vconnp), "connecting to %s", name);
+}
+
 static void *
 alloc_stats_request(size_t body_len, uint16_t type, struct buffer **bufferp)
 {
@@ -353,7 +360,7 @@ dump_transaction(const char *vconn_name, struct buffer *request)
     struct buffer *reply;
 
     update_openflow_length(request);
-    run(vconn_open_block(vconn_name, &vconn), "connecting to %s", vconn_name);
+    open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
     ofp_print(stdout, reply->data, reply->size, 1);
     vconn_close(vconn);
@@ -374,7 +381,7 @@ dump_stats_transaction(const char *vconn_name, struct buffer *request)
     struct vconn *vconn;
     bool done = false;
 
-    run(vconn_open_block(vconn_name, &vconn), "connecting to %s", vconn_name);
+    open_vconn(vconn_name, &vconn);
     send_openflow_buffer(vconn, request);
     while (!done) {
         uint32_t recv_xid;
@@ -426,7 +433,7 @@ do_status(int argc, char *argv[])
     if (argc > 2) {
         buffer_put(b, argv[2], strlen(argv[2]));
     }
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
+    open_vconn(argv[1], &vconn);
     run(vconn_transact(vconn, b, &b), "talking to %s", argv[1]);
     vconn_close(vconn);
 
@@ -793,8 +800,6 @@ static void do_add_flow(int argc, char *argv[])
     size_t size;
     int n_actions = MAX_ADD_ACTS;
 
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
-
     /* Parse and send. */
     size = sizeof *ofm + (sizeof ofm->actions[0] * MAX_ADD_ACTS);
     ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
@@ -810,6 +815,7 @@ static void do_add_flow(int argc, char *argv[])
     /* xxx Should we use the buffer library? */
     buffer->size -= (MAX_ADD_ACTS - n_actions) * sizeof ofm->actions[0];
 
+    open_vconn(argv[1], &vconn);
     send_openflow_buffer(vconn, buffer);
     vconn_close(vconn);
 }
@@ -817,7 +823,6 @@ static void do_add_flow(int argc, char *argv[])
 static void do_add_flows(int argc, char *argv[])
 {
     struct vconn *vconn;
-
     FILE *file;
     char line[1024];
 
@@ -826,7 +831,7 @@ static void do_add_flows(int argc, char *argv[])
         fatal(errno, "%s: open", argv[2]);
     }
 
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
+    open_vconn(argv[1], &vconn);
     while (fgets(line, sizeof line, file)) {
         struct buffer *buffer;
         struct ofp_flow_mod *ofm;
@@ -868,17 +873,43 @@ static void do_add_flows(int argc, char *argv[])
     fclose(file);
 }
 
+static void do_mod_flows(int argc, char *argv[])
+{
+    uint16_t idle_timeout, hard_timeout;
+    struct vconn *vconn;
+    struct buffer *buffer;
+    struct ofp_flow_mod *ofm;
+    size_t size;
+    int n_actions = MAX_ADD_ACTS;
+
+    /* Parse and send. */
+    size = sizeof *ofm + (sizeof ofm->actions[0] * MAX_ADD_ACTS);
+    ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
+    str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &n_actions, 
+                NULL, NULL, &idle_timeout, &hard_timeout);
+    ofm->command = htons(OFPFC_MODIFY);
+    ofm->idle_timeout = htons(idle_timeout);
+    ofm->hard_timeout = htons(hard_timeout);
+    ofm->buffer_id = htonl(UINT32_MAX);
+    ofm->priority = htons(0);
+    ofm->reserved = htonl(0);
+
+    /* xxx Should we use the buffer library? */
+    buffer->size -= (MAX_ADD_ACTS - n_actions) * sizeof ofm->actions[0];
+
+    open_vconn(argv[1], &vconn);
+    send_openflow_buffer(vconn, buffer);
+    vconn_close(vconn);
+}
+
 static void do_del_flows(int argc, char *argv[])
 {
     struct vconn *vconn;
     uint16_t priority;
-
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
     struct buffer *buffer;
     struct ofp_flow_mod *ofm;
     size_t size;
 
-
     /* Parse and send. */
     size = sizeof *ofm;
     ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
@@ -891,8 +922,8 @@ static void do_del_flows(int argc, char *argv[])
     ofm->priority = htons(priority);
     ofm->reserved = htonl(0);
 
+    open_vconn(argv[1], &vconn);
     send_openflow_buffer(vconn, buffer);
-
     vconn_close(vconn);
 }
 
@@ -910,7 +941,7 @@ do_monitor(int argc UNUSED, char *argv[])
     } else {
         name = argv[1];
     }
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", name);
+    open_vconn(argv[1], &vconn);
     for (;;) {
         struct buffer *b;
         run(vconn_recv_block(vconn, &b), "vconn_recv");
@@ -933,7 +964,7 @@ do_probe(int argc, char *argv[])
     struct buffer *reply;
 
     make_openflow(sizeof(struct ofp_header), OFPT_ECHO_REQUEST, &request);
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
+    open_vconn(argv[1], &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
     if (reply->size != request->size) {
         fatal(0, "reply does not match request");
@@ -965,7 +996,7 @@ do_mod_port(int argc, char *argv[])
     /* Send a "Features Request" to get the information we need in order 
      * to modify the port. */
     make_openflow(sizeof(struct ofp_header), OFPT_FEATURES_REQUEST, &request);
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
+    open_vconn(argv[1], &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", argv[1]);
 
     osf = reply->data;
@@ -1033,7 +1064,7 @@ do_ping(int argc, char *argv[])
         fatal(0, "payload must be between 0 and %zu bytes", max_payload);
     }
 
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
+    open_vconn(argv[1], &vconn);
     for (i = 0; i < 10; i++) {
         struct timeval start, end;
         struct buffer *request, *reply;
@@ -1089,7 +1120,7 @@ do_benchmark(int argc, char *argv[])
     printf("Sending %d packets * %u bytes (with header) = %u bytes total\n",
            count, message_size, count * message_size);
 
-    run(vconn_open_block(argv[1], &vconn), "connecting to %s", argv[1]);
+    open_vconn(argv[1], &vconn);
     gettimeofday(&start, NULL);
     for (i = 0; i < count; i++) {
         struct buffer *request, *reply;
@@ -1134,6 +1165,7 @@ static struct command all_commands[] = {
     { "dump-aggregate", 1, 2, do_dump_aggregate },
     { "add-flow", 2, 2, do_add_flow },
     { "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 },
     { "mod-port", 3, 3, do_mod_port },