ofproto: Add support for OF1.3 port description multipart message.
[sliver-openvswitch.git] / utilities / ovs-ofctl.c
index 7936c11..4a37067 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -168,7 +168,7 @@ parse_options(int argc, char *argv[])
             usage();
 
         case 'V':
-            ovs_print_version(OFP_VERSION, OFP_VERSION);
+            ovs_print_version(OFP10_VERSION, OFP10_VERSION);
             exit(EXIT_SUCCESS);
 
         case OPT_STRICT:
@@ -210,6 +210,7 @@ usage(void)
            "  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"
+           "  dump-ports-desc SWITCH      print port descriptions\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"
@@ -277,7 +278,7 @@ open_vconn_socket(const char *name, struct vconn **vconnp)
 {
     char *vconn_name = xasprintf("unix:%s", name);
     VLOG_DBG("connecting to %s", vconn_name);
-    run(vconn_open_block(vconn_name, OFP_VERSION, vconnp),
+    run(vconn_open_block(vconn_name, OFP10_VERSION, vconnp),
         "connecting to %s", vconn_name);
     free(vconn_name);
 }
@@ -301,7 +302,7 @@ open_vconn__(const char *name, const char *default_suffix,
     free(datapath_type);
 
     if (strchr(name, ':')) {
-        run(vconn_open_block(name, OFP_VERSION, vconnp),
+        run(vconn_open_block(name, OFP10_VERSION, vconnp),
             "connecting to %s", name);
     } else if (!stat(name, &s) && S_ISSOCK(s.st_mode)) {
         open_vconn_socket(name, vconnp);
@@ -340,7 +341,7 @@ alloc_stats_request(size_t rq_len, uint16_t type, struct ofpbuf **bufferp)
 {
     struct ofp_stats_msg *rq;
 
-    rq = make_openflow(rq_len, OFPT_STATS_REQUEST, bufferp);
+    rq = make_openflow(rq_len, OFPT10_STATS_REQUEST, bufferp);
     rq->type = htons(type);
     rq->flags = htons(0);
     return rq;
@@ -363,6 +364,7 @@ dump_transaction(const char *vconn_name, struct ofpbuf *request)
     open_vconn(vconn_name, &vconn);
     run(vconn_transact(vconn, request, &reply), "talking to %s", vconn_name);
     ofp_print(stdout, reply->data, reply->size, verbosity + 1);
+    ofpbuf_delete(reply);
     vconn_close(vconn);
 }
 
@@ -510,19 +512,20 @@ do_dump_tables(int argc OVS_UNUSED, char *argv[])
     dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
 }
 
-/* Opens a connection to 'vconn_name', fetches the ofp_phy_port structure for
+/* Opens a connection to 'vconn_name', fetches the port structure for
  * 'port_name' (which may be a port name or number), and copies it into
  * '*oppp'. */
 static void
-fetch_ofp_phy_port(const char *vconn_name, const char *port_name,
-                   struct ofp_phy_port *oppp)
+fetch_ofputil_phy_port(const char *vconn_name, const char *port_name,
+                       struct ofputil_phy_port *pp)
 {
+    struct ofputil_switch_features features;
+    const struct ofp_switch_features *osf;
     struct ofpbuf *request, *reply;
-    struct ofp_switch_features *osf;
     unsigned int port_no;
     struct vconn *vconn;
-    int n_ports;
-    int port_idx;
+    enum ofperr error;
+    struct ofpbuf b;
 
     /* Try to interpret the argument as a port number. */
     if (!str_to_uint(port_name, 10, &port_no)) {
@@ -539,15 +542,16 @@ fetch_ofp_phy_port(const char *vconn_name, const char *port_name,
         ovs_fatal(0, "%s: received too-short features reply (only %zu bytes)",
                   vconn_name, reply->size);
     }
-    n_ports = (reply->size - sizeof *osf) / sizeof *osf->ports;
-
-    for (port_idx = 0; port_idx < n_ports; port_idx++) {
-        const struct ofp_phy_port *opp = &osf->ports[port_idx];
+    error = ofputil_decode_switch_features(osf, &features, &b);
+    if (error) {
+        ovs_fatal(0, "%s: failed to decode features reply (%s)",
+                  vconn_name, ofperr_to_string(error));
+    }
 
+    while (!ofputil_pull_phy_port(osf->header.version, &b, pp)) {
         if (port_no != UINT_MAX
-            ? htons(port_no) == opp->port_no
-            : !strncmp(opp->name, port_name, sizeof opp->name)) {
-            *oppp = *opp;
+            ? port_no == pp->port_no
+            : !strcmp(pp->name, port_name)) {
             ofpbuf_delete(reply);
             vconn_close(vconn);
             return;
@@ -566,10 +570,10 @@ str_to_port_no(const char *vconn_name, const char *port_name)
     if (str_to_uint(port_name, 10, &port_no)) {
         return port_no;
     } else {
-        struct ofp_phy_port opp;
+        struct ofputil_phy_port pp;
 
-        fetch_ofp_phy_port(vconn_name, port_name, &opp);
-        return ntohs(opp.port_no);
+        fetch_ofputil_phy_port(vconn_name, port_name, &pp);
+        return pp.port_no;
     }
 }
 
@@ -923,9 +927,6 @@ ofctl_barrier(struct unixctl_conn *conn, int argc OVS_UNUSED,
     }
 
     msg = ofputil_encode_barrier_request();
-    fprintf(stderr, "send: ");
-    ofp_print(stderr, msg->data, msg->size, verbosity);
-
     error = vconn_send_block(aux->vconn, msg);
     if (error) {
         ofpbuf_delete(msg);
@@ -1003,7 +1004,7 @@ monitor_vconn(struct vconn *vconn)
             ofp_print(stderr, b->data, b->size, verbosity + 2);
             ofpbuf_delete(b);
 
-            if (barrier_aux.conn && msg_type == OFPT_BARRIER_REPLY) {
+            if (barrier_aux.conn && msg_type == OFPT10_BARRIER_REPLY) {
                 unixctl_command_reply(barrier_aux.conn, NULL);
                 barrier_aux.conn = NULL;
             }
@@ -1084,6 +1085,12 @@ do_dump_ports(int argc, char *argv[])
     dump_stats_transaction(argv[1], request);
 }
 
+static void
+do_dump_ports_desc(int argc OVS_UNUSED, char *argv[])
+{
+    dump_trivial_stats_transaction(argv[1], OFPST_PORT_DESC);
+}
+
 static void
 do_probe(int argc OVS_UNUSED, char *argv[])
 {
@@ -1136,46 +1143,46 @@ do_packet_out(int argc, char *argv[])
         ofpbuf_delete(packet);
     }
     vconn_close(vconn);
+    ofpbuf_uninit(&actions);
 }
 
 static void
 do_mod_port(int argc OVS_UNUSED, char *argv[])
 {
-    struct ofp_port_mod *opm;
-    struct ofp_phy_port opp;
-    struct ofpbuf *request;
+    enum ofputil_protocol protocol;
+    struct ofputil_port_mod pm;
+    struct ofputil_phy_port pp;
     struct vconn *vconn;
 
-    fetch_ofp_phy_port(argv[1], argv[2], &opp);
+    fetch_ofputil_phy_port(argv[1], argv[2], &pp);
 
-    opm = make_openflow(sizeof(struct ofp_port_mod), OFPT_PORT_MOD, &request);
-    opm->port_no = opp.port_no;
-    memcpy(opm->hw_addr, opp.hw_addr, sizeof opm->hw_addr);
-    opm->config = htonl(0);
-    opm->mask = htonl(0);
-    opm->advertise = htonl(0);
+    pm.port_no = pp.port_no;
+    memcpy(pm.hw_addr, pp.hw_addr, ETH_ADDR_LEN);
+    pm.config = 0;
+    pm.mask = 0;
+    pm.advertise = 0;
 
     if (!strcasecmp(argv[3], "up")) {
-        opm->mask |= htonl(OFPPC_PORT_DOWN);
+        pm.mask |= OFPUTIL_PC_PORT_DOWN;
     } else if (!strcasecmp(argv[3], "down")) {
-        opm->mask |= htonl(OFPPC_PORT_DOWN);
-        opm->config |= htonl(OFPPC_PORT_DOWN);
+        pm.mask |= OFPUTIL_PC_PORT_DOWN;
+        pm.config |= OFPUTIL_PC_PORT_DOWN;
     } else if (!strcasecmp(argv[3], "flood")) {
-        opm->mask |= htonl(OFPPC_NO_FLOOD);
+        pm.mask |= OFPUTIL_PC_NO_FLOOD;
     } else if (!strcasecmp(argv[3], "noflood")) {
-        opm->mask |= htonl(OFPPC_NO_FLOOD);
-        opm->config |= htonl(OFPPC_NO_FLOOD);
+        pm.mask |= OFPUTIL_PC_NO_FLOOD;
+        pm.config |= OFPUTIL_PC_NO_FLOOD;
     } else if (!strcasecmp(argv[3], "forward")) {
-        opm->mask |= htonl(OFPPC_NO_FWD);
+        pm.mask |= OFPUTIL_PC_NO_FWD;
     } else if (!strcasecmp(argv[3], "noforward")) {
-        opm->mask |= htonl(OFPPC_NO_FWD);
-        opm->config |= htonl(OFPPC_NO_FWD);
+        pm.mask |= OFPUTIL_PC_NO_FWD;
+        pm.config |= OFPUTIL_PC_NO_FWD;
     } else {
         ovs_fatal(0, "unknown mod-port command '%s'", argv[3]);
     }
 
-    open_vconn(argv[1], &vconn);
-    transact_noreply(vconn, request);
+    protocol = open_vconn(argv[1], &vconn);
+    transact_noreply(vconn, ofputil_encode_port_mod(&pm, protocol));
     vconn_close(vconn);
 }
 
@@ -1415,6 +1422,7 @@ fte_free_all(struct classifier *cls)
         classifier_remove(cls, &fte->rule);
         fte_free(fte);
     }
+    classifier_destroy(cls);
 }
 
 /* Searches 'cls' for an FTE matching 'rule', inserting a new one if
@@ -1834,6 +1842,34 @@ do_parse_nx_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     ds_destroy(&in);
 }
 
+/* "print-error ENUM": Prints the type and code of ENUM for every OpenFlow
+ * version. */
+static void
+do_print_error(int argc OVS_UNUSED, char *argv[])
+{
+    enum ofperr error;
+    int version;
+
+    error = ofperr_from_name(argv[1]);
+    if (!error) {
+        ovs_fatal(0, "unknown error \"%s\"", argv[1]);
+    }
+
+    for (version = 0; version <= UINT8_MAX; version++) {
+        const struct ofperr_domain *domain;
+
+        domain = ofperr_domain_from_version(version);
+        if (!domain) {
+            continue;
+        }
+
+        printf("%s: %d,%d\n",
+               ofperr_domain_get_name(domain),
+               ofperr_get_type(error, domain),
+               ofperr_get_code(error, domain));
+    }
+}
+
 /* "ofp-print HEXSTRING [VERBOSITY]": Converts the hex digits in HEXSTRING into
  * binary data, interpreting them as an OpenFlow message, and prints the
  * OpenFlow message on stdout, at VERBOSITY (level 2 by default).  */
@@ -1867,6 +1903,7 @@ static const struct command all_commands[] = {
     { "diff-flows", 2, 2, do_diff_flows },
     { "packet-out", 4, INT_MAX, do_packet_out },
     { "dump-ports", 1, 2, do_dump_ports },
+    { "dump-ports-desc", 1, 1, do_dump_ports_desc },
     { "mod-port", 3, 3, do_mod_port },
     { "get-frags", 1, 1, do_get_frags },
     { "set-frags", 2, 2, do_set_frags },
@@ -1879,6 +1916,7 @@ static const struct command all_commands[] = {
     { "parse-flow", 1, 1, do_parse_flow },
     { "parse-flows", 1, 1, do_parse_flows },
     { "parse-nx-match", 0, 0, do_parse_nx_match },
+    { "print-error", 1, 1, do_print_error },
     { "ofp-print", 1, 2, do_ofp_print },
 
     { NULL, 0, 0, NULL },