ofp-print: Fix misaligned data access in ofp_print_error_msg().
[cascardo/ovs.git] / lib / ofp-print.c
index 9a84645..e14bd6e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -77,7 +77,7 @@ ofp_packet_to_string(const void *data, size_t len)
         } else if (flow.nw_proto == IPPROTO_SCTP) {
             struct sctp_header *sh = buf.l4;
             ds_put_format(&ds, " sctp_csum:%"PRIx32,
-                          ntohl(sh->sctp_csum));
+                          ntohl(get_16aligned_be32(&sh->sctp_csum)));
         }
     }
 
@@ -105,11 +105,11 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
         ds_put_format(string, " table_id=%"PRIu8, pin.table_id);
     }
 
-    if (pin.cookie) {
+    if (pin.cookie != OVS_BE64_MAX) {
         ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie));
     }
 
-    ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len);
+    ds_put_format(string, " total_len=%"PRIuSIZE" in_port=", pin.total_len);
     ofputil_format_port(pin.fmd.in_port, string);
 
     if (pin.fmd.tun_id != htonll(0)) {
@@ -142,7 +142,7 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
                   ofputil_packet_in_reason_to_string(pin.reason, reasonbuf,
                                                      sizeof reasonbuf));
 
-    ds_put_format(string, " data_len=%zu", pin.packet_len);
+    ds_put_format(string, " data_len=%"PRIuSIZE, pin.packet_len);
     if (pin.buffer_id == UINT32_MAX) {
         ds_put_format(string, " (unbuffered)");
         if (pin.total_len != pin.packet_len) {
@@ -189,7 +189,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
     ofpacts_format(po.ofpacts, po.ofpacts_len, string);
 
     if (po.buffer_id == UINT32_MAX) {
-        ds_put_format(string, " data_len=%zu", po.packet_len);
+        ds_put_format(string, " data_len=%"PRIuSIZE, po.packet_len);
         if (verbosity > 0 && po.packet_len > 0) {
             char *packet = ofp_packet_to_string(po.packet, po.packet_len);
             ds_put_char(string, '\n');
@@ -540,7 +540,7 @@ ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
     case OFP13_VERSION:
         return; /* no ports in ofp13_switch_features */
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
     ofp_print_phy_ports(string, oh->version, &b);
@@ -757,7 +757,8 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
     protocol = ofputil_protocol_set_tid(protocol, true);
 
     ofpbuf_init(&ofpacts, 64);
-    error = ofputil_decode_flow_mod(&fm, oh, protocol, &ofpacts);
+    error = ofputil_decode_flow_mod(&fm, oh, protocol, &ofpacts,
+                                    OFPP_MAX, 255);
     if (error) {
         ofpbuf_uninit(&ofpacts);
         ofp_print_error(s, error);
@@ -859,10 +860,26 @@ static void
 ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
 {
     ds_put_format(string, "%u", sec);
+
+    /* If there are no fractional seconds, don't print any decimals.
+     *
+     * If the fractional seconds can be expressed exactly as milliseconds,
+     * print 3 decimals.  Open vSwitch provides millisecond precision for most
+     * time measurements, so printing 3 decimals every time makes it easier to
+     * spot real changes in flow dumps that refresh themselves quickly.
+     *
+     * If the fractional seconds are more precise than milliseconds, print the
+     * number of decimals needed to express them exactly.
+     */
     if (nsec > 0) {
-        ds_put_format(string, ".%09u", nsec);
-        while (string->string[string->length - 1] == '0') {
-            string->length--;
+        unsigned int msec = nsec / 1000000;
+        if (msec * 1000000 == nsec) {
+            ds_put_format(string, ".%03u", msec);
+        } else {
+            ds_put_format(string, ".%09u", nsec);
+            while (string->string[string->length - 1] == '0') {
+                string->length--;
+            }
         }
     }
     ds_put_char(string, 's');
@@ -1008,6 +1025,71 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
     ofp_print_table_miss_config(string, pm.config);
 }
 
+static void
+ofp_print_queue_get_config_request(struct ds *string,
+                                   const struct ofp_header *oh)
+{
+    enum ofperr error;
+    ofp_port_t port;
+
+    error = ofputil_decode_queue_get_config_request(oh, &port);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ds_put_cstr(string, " port=");
+    ofputil_format_port(port, string);
+}
+
+static void
+print_queue_rate(struct ds *string, const char *name, unsigned int rate)
+{
+    if (rate <= 1000) {
+        ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
+    } else if (rate < UINT16_MAX) {
+        ds_put_format(string, " %s:(disabled)", name);
+    }
+}
+
+static void
+ofp_print_queue_get_config_reply(struct ds *string,
+                                 const struct ofp_header *oh)
+{
+    enum ofperr error;
+    struct ofpbuf b;
+    ofp_port_t port;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    error = ofputil_decode_queue_get_config_reply(&b, &port);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ds_put_cstr(string, " port=");
+    ofputil_format_port(port, string);
+    ds_put_char(string, '\n');
+
+    for (;;) {
+        struct ofputil_queue_config queue;
+        int retval;
+
+        retval = ofputil_pull_queue_get_config_reply(&b, &queue);
+        if (retval) {
+            if (retval != EOF) {
+                ofp_print_error(string, retval);
+            }
+            break;
+        }
+
+        ds_put_format(string, "queue %"PRIu32":", queue.queue_id);
+        print_queue_rate(string, "min_rate", queue.min_rate);
+        print_queue_rate(string, "max_rate", queue.max_rate);
+        ds_put_char(string, '\n');
+    }
+}
+
 static void
 ofp_print_meter_flags(struct ds *s, uint16_t flags)
 {
@@ -1284,6 +1366,7 @@ ofp_print_error_msg(struct ds *string, const struct ofp_header *oh)
         ds_put_cstr(string, s);
         free(s);
     }
+    ofpbuf_uninit(&payload);
 }
 
 static void
@@ -1467,7 +1550,7 @@ ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
 {
     struct ofpbuf b;
 
-    ds_put_format(string, " %zu ports\n", ofputil_count_port_stats(oh));
+    ds_put_format(string, " %"PRIuSIZE" ports\n", ofputil_count_port_stats(oh));
     if (verbosity < 1) {
         return;
     }
@@ -1581,7 +1664,7 @@ ofp_print_ofpst_table_reply13(struct ds *string, const struct ofp_header *oh,
     ofpraw_pull_assert(&b);
 
     n = b.size / sizeof *ts;
-    ds_put_format(string, " %zu tables\n", n);
+    ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
     }
@@ -1611,7 +1694,7 @@ ofp_print_ofpst_table_reply12(struct ds *string, const struct ofp_header *oh,
     ofpraw_pull_assert(&b);
 
     n = b.size / sizeof *ts;
-    ds_put_format(string, " %zu tables\n", n);
+    ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
     }
@@ -1638,7 +1721,7 @@ ofp_print_ofpst_table_reply11(struct ds *string, const struct ofp_header *oh,
     ofpraw_pull_assert(&b);
 
     n = b.size / sizeof *ts;
-    ds_put_format(string, " %zu tables\n", n);
+    ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
     }
@@ -1678,7 +1761,7 @@ ofp_print_ofpst_table_reply10(struct ds *string, const struct ofp_header *oh,
     ofpraw_pull_assert(&b);
 
     n = b.size / sizeof *ts;
-    ds_put_format(string, " %zu tables\n", n);
+    ds_put_format(string, " %"PRIuSIZE" tables\n", n);
     if (verbosity < 1) {
         return;
     }
@@ -1723,7 +1806,7 @@ ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
         break;
 
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1762,7 +1845,7 @@ ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
 {
     struct ofpbuf b;
 
-    ds_put_format(string, " %zu queues\n", ofputil_count_queue_stats(oh));
+    ds_put_format(string, " %"PRIuSIZE" queues\n", ofputil_count_queue_stats(oh));
     if (verbosity < 1) {
         return;
     }
@@ -1845,27 +1928,19 @@ ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
 {
     size_t len = ntohs(oh->length);
 
-    ds_put_format(string, " %zu bytes of payload\n", len - sizeof *oh);
+    ds_put_format(string, " %"PRIuSIZE" bytes of payload\n", len - sizeof *oh);
     if (verbosity > 1) {
         ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
     }
 }
 
 static void
-ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
+ofp_print_role_generic(struct ds *string, enum ofp12_controller_role role,
+                       uint64_t generation_id)
 {
-    struct ofputil_role_request rr;
-    enum ofperr error;
-
-    error = ofputil_decode_role_message(oh, &rr);
-    if (error) {
-        ofp_print_error(string, error);
-        return;
-    }
-
     ds_put_cstr(string, " role=");
 
-    switch (rr.role) {
+    switch (role) {
     case OFPCR12_ROLE_NOCHANGE:
         ds_put_cstr(string, "nochange");
         break;
@@ -1879,11 +1954,57 @@ ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
         ds_put_cstr(string, "slave");
         break;
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 
-    if (rr.have_generation_id) {
-        ds_put_format(string, " generation_id=%"PRIu64, rr.generation_id);
+    if (generation_id != UINT64_MAX) {
+        ds_put_format(string, " generation_id=%"PRIu64, generation_id);
+    }
+}
+
+static void
+ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
+{
+    struct ofputil_role_request rr;
+    enum ofperr error;
+
+    error = ofputil_decode_role_message(oh, &rr);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ofp_print_role_generic(string, rr.role, rr.have_generation_id ? rr.generation_id : UINT64_MAX);
+}
+
+static void
+ofp_print_role_status_message(struct ds *string, const struct ofp_header *oh)
+{
+    struct ofputil_role_status rs;
+    enum ofperr error;
+
+    error = ofputil_decode_role_status(oh, &rs);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ofp_print_role_generic(string, rs.role, rs.generation_id);
+
+    ds_put_cstr(string, " reason=");
+
+    switch (rs.reason) {
+    case OFPCRR_MASTER_REQUEST:
+        ds_put_cstr(string, "master_request");
+        break;
+    case OFPCRR_CONFIG:
+        ds_put_cstr(string, "configuration_changed");
+        break;
+    case OFPCRR_EXPERIMENTER:
+        ds_put_cstr(string, "experimenter_data_changed");
+        break;
+    default:
+        OVS_NOT_REACHED();
     }
 }
 
@@ -2419,8 +2540,6 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
         ofp_print_group_mod(string, oh);
         break;
 
-    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
-    case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
     case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
     case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
         ofp_print_not_implemented(string);
@@ -2490,10 +2609,21 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
     case OFPTYPE_BARRIER_REPLY:
         break;
 
+    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
+        ofp_print_queue_get_config_request(string, oh);
+        break;
+
+    case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
+        ofp_print_queue_get_config_reply(string, oh);
+        break;
+
     case OFPTYPE_ROLE_REQUEST:
     case OFPTYPE_ROLE_REPLY:
         ofp_print_role_message(string, oh);
         break;
+    case OFPTYPE_ROLE_STATUS:
+        ofp_print_role_status_message(string, oh);
+        break;
 
     case OFPTYPE_METER_STATS_REQUEST:
     case OFPTYPE_METER_CONFIG_STATS_REQUEST:
@@ -2633,7 +2763,7 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
     if (!len) {
         ds_put_cstr(&string, "OpenFlow message is empty\n");
     } else if (len < sizeof(struct ofp_header)) {
-        ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
+        ds_put_format(&string, "OpenFlow packet too short (only %"PRIuSIZE" bytes):\n",
                       len);
     } else if (ntohs(oh->length) > len) {
         enum ofperr error;
@@ -2646,11 +2776,11 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
         }
 
         ds_put_format(&string,
-                      "(***truncated to %zu bytes from %"PRIu16"***)\n",
+                      "(***truncated to %"PRIuSIZE" bytes from %"PRIu16"***)\n",
                       len, ntohs(oh->length));
     } else if (ntohs(oh->length) < len) {
         ds_put_format(&string,
-                      "(***only uses %"PRIu16" bytes out of %zu***)\n",
+                      "(***only uses %"PRIu16" bytes out of %"PRIuSIZE"***)\n",
                       ntohs(oh->length), len);
     } else {
         enum ofperr error;