openflow-1.1+: OFPT_TABLE_MOD (part 1)
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
index 547d50c..95bf1bf 100644 (file)
@@ -281,6 +281,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"
+           "  mod-table SWITCH MOD        modify flow table behavior\n"
            "  get-frags SWITCH            print fragment handling behavior\n"
            "  set-frags SWITCH FRAG_MODE  set fragment handling behavior\n"
            "  dump-ports SWITCH [PORT]    print port statistics\n"
@@ -301,6 +302,13 @@ usage(void)
            "  monitor SWITCH [MISSLEN] [invalid_ttl] [watch:[...]]\n"
            "                              print packets received from SWITCH\n"
            "  snoop SWITCH                snoop on SWITCH and its controller\n"
+           "  add-group SWITCH GROUP      add group described by GROUP\n"
+           "  add-group SWITCH FILE       add group from FILE\n"
+           "  mod-group SWITCH GROUP      modify specific group\n"
+           "  del-groups SWITCH [GROUP]   delete matching GROUPs\n"
+           "  dump-group-features SWITCH  print group features\n"
+           "  dump-groups SWITCH          print group description\n"
+           "  dump-group-stats SWITCH [GROUP]  print group statistics\n"
            "\nFor OpenFlow switches and controllers:\n"
            "  probe TARGET                probe whether TARGET is up\n"
            "  ping TARGET [N]             latency of N-byte echos\n"
@@ -1656,6 +1664,42 @@ found:
     vconn_close(vconn);
 }
 
+static void
+ofctl_mod_table(int argc OVS_UNUSED, char *argv[])
+{
+    enum ofputil_protocol protocol, usable_protocols;
+    struct ofputil_table_mod tm;
+    struct vconn *vconn;
+    char *error;
+    int i;
+
+    error = parse_ofp_table_mod(&tm, argv[2], argv[3], &usable_protocols);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+
+    protocol = open_vconn(argv[1], &vconn);
+    if (!(protocol & usable_protocols)) {
+        for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
+            enum ofputil_protocol f = 1 << i;
+            if (f != protocol
+                && f & usable_protocols
+                && try_set_protocol(vconn, f, &protocol)) {
+                protocol = f;
+                break;
+            }
+        }
+    }
+
+    if (!(protocol & usable_protocols)) {
+        char *usable_s = ofputil_protocols_to_string(usable_protocols);
+        ovs_fatal(0, "Switch does not support table mod message(%s)", usable_s);
+    }
+
+    transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
+    vconn_close(vconn);
+}
+
 static void
 ofctl_get_frags(int argc OVS_UNUSED, char *argv[])
 {
@@ -1842,6 +1886,153 @@ ofctl_benchmark(int argc OVS_UNUSED, char *argv[])
            count * message_size / (duration / 1000.0));
 }
 
+static void
+ofctl_group_mod__(const char *remote, struct ofputil_group_mod *gms,
+                 size_t n_gms)
+{
+    struct ofputil_group_mod *gm;
+    struct ofpbuf *request;
+
+    struct vconn *vconn;
+    size_t i;
+
+    open_vconn(remote, &vconn);
+
+    for (i = 0; i < n_gms; i++) {
+        gm = &gms[i];
+        request = ofputil_encode_group_mod(vconn_get_version(vconn), gm);
+        if (request) {
+            transact_noreply(vconn, request);
+        }
+    }
+
+    vconn_close(vconn);
+
+}
+
+
+static void
+ofctl_group_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command)
+{
+    struct ofputil_group_mod *gms = NULL;
+    enum ofputil_protocol usable_protocols;
+    size_t n_gms = 0;
+    char *error;
+
+    error = parse_ofp_group_mod_file(argv[2], command, &gms, &n_gms,
+                                     &usable_protocols);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+    ofctl_group_mod__(argv[1], gms, n_gms);
+    free(gms);
+}
+
+static void
+ofctl_group_mod(int argc, char *argv[], uint16_t command)
+{
+    if (argc > 2 && !strcmp(argv[2], "-")) {
+        ofctl_group_mod_file(argc, argv, command);
+    } else {
+        enum ofputil_protocol usable_protocols;
+        struct ofputil_group_mod gm;
+        char *error;
+
+        error = parse_ofp_group_mod_str(&gm, command, argc > 2 ? argv[2] : "",
+                                        &usable_protocols);
+        if (error) {
+            ovs_fatal(0, "%s", error);
+        }
+        ofctl_group_mod__(argv[1], &gm, 1);
+    }
+}
+
+static void
+ofctl_add_group(int argc, char *argv[])
+{
+    ofctl_group_mod(argc, argv, OFPGC11_ADD);
+}
+
+static void
+ofctl_add_groups(int argc, char *argv[])
+{
+    ofctl_group_mod_file(argc, argv, OFPGC11_ADD);
+}
+
+static void
+ofctl_mod_group(int argc, char *argv[])
+{
+    ofctl_group_mod(argc, argv, OFPGC11_MODIFY);
+}
+
+static void
+ofctl_del_groups(int argc, char *argv[])
+{
+    ofctl_group_mod(argc, argv, OFPGC11_DELETE);
+}
+
+static void
+ofctl_dump_group_stats(int argc, char *argv[])
+{
+    enum ofputil_protocol usable_protocols;
+    struct ofputil_group_mod gm;
+    struct ofpbuf *request;
+    struct vconn *vconn;
+    uint32_t group_id;
+    char *error;
+
+    memset(&gm, 0, sizeof gm);
+
+    error = parse_ofp_group_mod_str(&gm, OFPGC11_DELETE,
+                                    argc > 2 ? argv[2] : "",
+                                    &usable_protocols);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+
+    group_id = gm.group_id;
+
+    open_vconn(argv[1], &vconn);
+    request = ofputil_encode_group_stats_request(vconn_get_version(vconn),
+                                                 group_id);
+    if (request) {
+        dump_stats_transaction(vconn, request);
+    }
+
+    vconn_close(vconn);
+}
+
+static void
+ofctl_dump_group_desc(int argc OVS_UNUSED, char *argv[])
+{
+    struct ofpbuf *request;
+    struct vconn *vconn;
+
+    open_vconn(argv[1], &vconn);
+
+    request = ofputil_encode_group_desc_request(vconn_get_version(vconn));
+    if (request) {
+        dump_stats_transaction(vconn, request);
+    }
+
+    vconn_close(vconn);
+}
+
+static void
+ofctl_dump_group_features(int argc OVS_UNUSED, char *argv[])
+{
+    struct ofpbuf *request;
+    struct vconn *vconn;
+
+    open_vconn(argv[1], &vconn);
+    request = ofputil_encode_group_features_request(vconn_get_version(vconn));
+    if (request) {
+        dump_stats_transaction(vconn, request);
+    }
+
+    vconn_close(vconn);
+}
+
 static void
 ofctl_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
@@ -2998,12 +3189,21 @@ static const struct command all_commands[] = {
     { "dump-ports", 1, 2, ofctl_dump_ports },
     { "dump-ports-desc", 1, 1, ofctl_dump_ports_desc },
     { "mod-port", 3, 3, ofctl_mod_port },
+    { "mod-table", 3, 3, ofctl_mod_table },
     { "get-frags", 1, 1, ofctl_get_frags },
     { "set-frags", 2, 2, ofctl_set_frags },
     { "ofp-parse", 1, 1, ofctl_ofp_parse },
     { "probe", 1, 1, ofctl_probe },
     { "ping", 1, 2, ofctl_ping },
     { "benchmark", 3, 3, ofctl_benchmark },
+
+    { "add-group", 1, 2, ofctl_add_group },
+    { "add-groups", 1, 2, ofctl_add_groups },
+    { "mod-group", 1, 2, ofctl_mod_group },
+    { "del-groups", 1, 2, ofctl_del_groups },
+    { "dump-groups", 1, 1, ofctl_dump_group_desc },
+    { "dump-group-stats", 1, 2, ofctl_dump_group_stats },
+    { "dump-group-features", 1, 1, ofctl_dump_group_features },
     { "help", 0, INT_MAX, ofctl_help },
 
     /* Undocumented commands for testing. */