Merge "master" into "wdp".
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
index c21c4f9..aba8f84 100644 (file)
@@ -29,9 +29,9 @@
 #include "command-line.h"
 #include "compiler.h"
 #include "dirs.h"
-#include "dpif.h"
+#include "dynamic-string.h"
+#include "netdev.h"
 #include "netlink.h"
-#include "odp-util.h"
 #include "ofp-parse.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
@@ -44,6 +44,8 @@
 #include "util.h"
 #include "vconn.h"
 #include "vlog.h"
+#include "xfif.h"
+#include "xflow-util.h"
 #include "xtoxll.h"
 
 VLOG_DEFINE_THIS_MODULE(ofctl)
@@ -210,12 +212,12 @@ static void
 open_vconn__(const char *name, const char *default_suffix,
              struct vconn **vconnp)
 {
-    struct dpif *dpif;
+    struct xfif *xfif;
     struct stat s;
     char *bridge_path, *datapath_name, *datapath_type;
 
     bridge_path = xasprintf("%s/%s.%s", ovs_rundir, name, default_suffix);
-    dp_parse_name(name, &datapath_name, &datapath_type);
+    xf_parse_name(name, &datapath_name, &datapath_type);
 
     if (strstr(name, ":")) {
         run(vconn_open_block(name, OFP_VERSION, vconnp),
@@ -224,19 +226,19 @@ open_vconn__(const char *name, const char *default_suffix,
         open_vconn_socket(name, vconnp);
     } else if (!stat(bridge_path, &s) && S_ISSOCK(s.st_mode)) {
         open_vconn_socket(bridge_path, vconnp);
-    } else if (!dpif_open(datapath_name, datapath_type, &dpif)) {
-        char dpif_name[IF_NAMESIZE + 1];
+    } else if (!xfif_open(datapath_name, datapath_type, &xfif)) {
+        char xfif_name[IF_NAMESIZE + 1];
         char *socket_name;
 
-        run(dpif_port_get_name(dpif, ODPP_LOCAL, dpif_name, sizeof dpif_name),
-            "obtaining name of %s", dpif_name);
-        dpif_close(dpif);
-        if (strcmp(dpif_name, name)) {
-            VLOG_INFO("datapath %s is named %s", name, dpif_name);
+        run(xfif_port_get_name(xfif, XFLOWP_LOCAL, xfif_name, sizeof xfif_name),
+            "obtaining name of %s", xfif_name);
+        xfif_close(xfif);
+        if (strcmp(xfif_name, name)) {
+            VLOG_INFO("datapath %s is named %s", name, xfif_name);
         }
 
         socket_name = xasprintf("%s/%s.%s",
-                                ovs_rundir, dpif_name, default_suffix);
+                                ovs_rundir, xfif_name, default_suffix);
         if (stat(socket_name, &s)) {
             ovs_fatal(errno, "cannot connect to %s: stat failed on %s",
                       name, socket_name);
@@ -465,6 +467,12 @@ do_dump_aggregate(int argc, char *argv[])
     dump_stats_transaction(argv[1], request);
 }
 
+static void
+enable_flow_mod_table_id_ext(struct vconn *vconn, bool enable)
+{
+    send_openflow_buffer(vconn, make_nxt_flow_mod_table_id(enable));
+}
+
 static void
 do_queue_stats(int argc, char *argv[])
 {
@@ -498,13 +506,14 @@ do_add_flow(int argc OVS_UNUSED, char *argv[])
     uint16_t priority, idle_timeout, hard_timeout;
     uint64_t cookie;
     struct ofp_match match;
+    uint8_t table_idx;
 
     /* Parse and send.  parse_ofp_str() will expand and reallocate the
      * data in 'buffer', so we can't keep pointers to across the
      * parse_ofp_str() call. */
     make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
     parse_ofp_str(argv[2], &match, buffer,
-                  NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+                  &table_idx, NULL, &priority, &idle_timeout, &hard_timeout,
                   &cookie);
     ofm = buffer->data;
     ofm->match = match;
@@ -516,6 +525,10 @@ do_add_flow(int argc OVS_UNUSED, char *argv[])
     ofm->priority = htons(priority);
 
     open_vconn(argv[1], &vconn);
+    if (table_idx != 0xff) {
+        enable_flow_mod_table_id_ext(vconn, 1);
+        ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
+    }
     send_openflow_buffer(vconn, buffer);
     vconn_close(vconn);
 }
@@ -526,6 +539,8 @@ do_add_flows(int argc OVS_UNUSED, char *argv[])
     struct vconn *vconn;
     struct ofpbuf *b;
     FILE *file;
+    bool table_id_enabled = false;
+    uint8_t table_idx;
 
     file = fopen(argv[2], "r");
     if (file == NULL) {
@@ -533,7 +548,11 @@ do_add_flows(int argc OVS_UNUSED, char *argv[])
     }
 
     open_vconn(argv[1], &vconn);
-    while ((b = parse_ofp_add_flow_file(file)) != NULL) {
+    while ((b = parse_ofp_add_flow_file(file, &table_idx)) != NULL) {
+        if ((table_idx != 0xff) != table_id_enabled) {
+            table_id_enabled = table_idx != 0xff;
+            enable_flow_mod_table_id_ext(vconn, table_id_enabled);
+        }
         send_openflow_buffer(vconn, b);
     }
     vconn_close(vconn);
@@ -549,13 +568,14 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[])
     struct ofpbuf *buffer;
     struct ofp_flow_mod *ofm;
     struct ofp_match match;
+    uint8_t table_idx;
 
     /* Parse and send.  parse_ofp_str() will expand and reallocate the
      * data in 'buffer', so we can't keep pointers to across the
      * parse_ofp_str() call. */
     make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
     parse_ofp_str(argv[2], &match, buffer,
-                  NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+                  &table_idx, NULL, &priority, &idle_timeout, &hard_timeout,
                   &cookie);
     ofm = buffer->data;
     ofm->match = match;
@@ -571,6 +591,10 @@ do_mod_flows(int argc OVS_UNUSED, char *argv[])
     ofm->priority = htons(priority);
 
     open_vconn(argv[1], &vconn);
+    if (table_idx != 0xff) {
+        enable_flow_mod_table_id_ext(vconn, 1);
+        ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
+    }
     send_openflow_buffer(vconn, buffer);
     vconn_close(vconn);
 }
@@ -582,10 +606,11 @@ static void do_del_flows(int argc, char *argv[])
     uint16_t out_port;
     struct ofpbuf *buffer;
     struct ofp_flow_mod *ofm;
+    uint8_t table_idx;
 
     /* Parse and send. */
     ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
-    parse_ofp_str(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
+    parse_ofp_str(argc > 2 ? argv[2] : "", &ofm->match, NULL, &table_idx,
                   &out_port, &priority, NULL, NULL, NULL);
     if (strict) {
         ofm->command = htons(OFPFC_DELETE_STRICT);
@@ -599,6 +624,10 @@ static void do_del_flows(int argc, char *argv[])
     ofm->priority = htons(priority);
 
     open_vconn(argv[1], &vconn);
+    if (table_idx != 0xff) {
+        enable_flow_mod_table_id_ext(vconn, 1);
+        ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
+    }
     send_openflow_buffer(vconn, buffer);
     vconn_close(vconn);
 }
@@ -859,6 +888,27 @@ do_benchmark(int argc OVS_UNUSED, char *argv[])
            count * message_size / (duration / 1000.0));
 }
 
+/* This command is really only useful for testing the flow parser (ofp_parse),
+ * so it is undocumented. */
+static void
+do_parse_flows(int argc OVS_UNUSED, char *argv[])
+{
+    uint8_t table_idx;
+    struct ofpbuf *b;
+    FILE *file;
+
+    file = fopen(argv[1], "r");
+    if (file == NULL) {
+        ovs_fatal(errno, "%s: open", argv[2]);
+    }
+
+    while ((b = parse_ofp_add_flow_file(file, &table_idx)) != NULL) {
+        ofp_print(stdout, b->data, b->size, 0);
+        ofpbuf_delete(b);
+    }
+    fclose(file);
+}
+
 static void
 do_help(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 {
@@ -885,6 +935,7 @@ static const struct command all_commands[] = {
     { "probe", 1, 1, do_probe },
     { "ping", 1, 2, do_ping },
     { "benchmark", 3, 3, do_benchmark },
+    { "parse-flows", 1, 1, do_parse_flows },
     { "help", 0, INT_MAX, do_help },
     { NULL, 0, 0, NULL },
 };