Replace most uses of assert by ovs_assert.
[sliver-openvswitch.git] / lib / ofp-util.c
index 0b96eb6..c66cd40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -583,7 +583,8 @@ struct proto_abbrev {
 static const struct proto_abbrev proto_abbrevs[] = {
     { OFPUTIL_P_ANY,          "any" },
     { OFPUTIL_P_OF10_STD_ANY, "OpenFlow10" },
-    { OFPUTIL_P_OF10_NXM_ANY,  "NXM" },
+    { OFPUTIL_P_OF10_NXM_ANY, "NXM" },
+    { OFPUTIL_P_ANY_OXM,      "OXM" },
 };
 #define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
 
@@ -595,17 +596,16 @@ enum ofputil_protocol ofputil_flow_dump_protocols[] = {
 };
 size_t ofputil_n_flow_dump_protocols = ARRAY_SIZE(ofputil_flow_dump_protocols);
 
-/* Returns the ofputil_protocol that is initially in effect on an OpenFlow
- * connection that has negotiated the given 'version'.  'version' should
- * normally be an 8-bit OpenFlow version identifier (e.g. 0x01 for OpenFlow
- * 1.0, 0x02 for OpenFlow 1.1).  Returns 0 if 'version' is not supported or
- * outside the valid range.  */
+/* Returns the set of ofputil_protocols that are supported with the given
+ * OpenFlow 'version'.  'version' should normally be an 8-bit OpenFlow version
+ * identifier (e.g. 0x01 for OpenFlow 1.0, 0x02 for OpenFlow 1.1).  Returns 0
+ * if 'version' is not supported or outside the valid range.  */
 enum ofputil_protocol
-ofputil_protocol_from_ofp_version(enum ofp_version version)
+ofputil_protocols_from_ofp_version(enum ofp_version version)
 {
     switch (version) {
     case OFP10_VERSION:
-        return OFPUTIL_P_OF10_STD;
+        return OFPUTIL_P_OF10_STD_ANY | OFPUTIL_P_OF10_NXM_ANY;
     case OFP12_VERSION:
         return OFPUTIL_P_OF12_OXM;
     case OFP13_VERSION:
@@ -616,6 +616,17 @@ ofputil_protocol_from_ofp_version(enum ofp_version version)
     }
 }
 
+/* Returns the ofputil_protocol that is initially in effect on an OpenFlow
+ * connection that has negotiated the given 'version'.  'version' should
+ * normally be an 8-bit OpenFlow version identifier (e.g. 0x01 for OpenFlow
+ * 1.0, 0x02 for OpenFlow 1.1).  Returns 0 if 'version' is not supported or
+ * outside the valid range.  */
+enum ofputil_protocol
+ofputil_protocol_from_ofp_version(enum ofp_version version)
+{
+    return rightmost_1bit(ofputil_protocols_from_ofp_version(version));
+}
+
 /* Returns the OpenFlow protocol version number (e.g. OFP10_VERSION,
  * etc.) that corresponds to 'protocol'. */
 enum ofp_version
@@ -636,6 +647,38 @@ ofputil_protocol_to_ofp_version(enum ofputil_protocol protocol)
     NOT_REACHED();
 }
 
+/* Returns a bitmap of OpenFlow versions that are supported by at
+ * least one of the 'protocols'. */
+uint32_t
+ofputil_protocols_to_version_bitmap(enum ofputil_protocol protocols)
+{
+    uint32_t bitmap = 0;
+
+    for (; protocols; protocols = zero_rightmost_1bit(protocols)) {
+        enum ofputil_protocol protocol = rightmost_1bit(protocols);
+
+        bitmap |= 1u << ofputil_protocol_to_ofp_version(protocol);
+    }
+
+    return bitmap;
+}
+
+/* Returns the set of protocols that are supported on top of the
+ * OpenFlow versions included in 'bitmap'. */
+enum ofputil_protocol
+ofputil_protocols_from_version_bitmap(uint32_t bitmap)
+{
+    enum ofputil_protocol protocols = 0;
+
+    for (; bitmap; bitmap = zero_rightmost_1bit(bitmap)) {
+        enum ofp_version version = rightmost_1bit_idx(bitmap);
+
+        protocols |= ofputil_protocols_from_ofp_version(version);
+    }
+
+    return protocols;
+}
+
 /* Returns true if 'protocol' is a single OFPUTIL_P_* value, false
  * otherwise. */
 bool
@@ -738,10 +781,10 @@ ofputil_protocol_to_string(enum ofputil_protocol protocol)
         return "OpenFlow10+table_id";
 
     case OFPUTIL_P_OF12_OXM:
-        return "OXM";
+        return "OXM-OpenFlow12";
 
     case OFPUTIL_P_OF13_OXM:
-        return "OpenFlow13";
+        return "OXM-OpenFlow13";
     }
 
     /* Check abbreviations. */
@@ -764,7 +807,7 @@ ofputil_protocols_to_string(enum ofputil_protocol protocols)
 {
     struct ds s;
 
-    assert(!(protocols & ~OFPUTIL_P_ANY));
+    ovs_assert(!(protocols & ~OFPUTIL_P_ANY));
     if (protocols == 0) {
         return xstrdup("none");
     }
@@ -1024,6 +1067,11 @@ ofputil_usable_protocols(const struct match *match)
         return OFPUTIL_P_NONE;
     }
 
+    /* skb_mark and skb_priority can't be sent in a flow_mod */
+    if (wc->masks.skb_mark || wc->masks.skb_priority) {
+        return OFPUTIL_P_NONE;
+    }
+
     /* NXM, OXM, and OF1.1 support bitwise matching on ethernet addresses. */
     if (!eth_mask_is_exact(wc->masks.dl_src)
         && !eth_addr_is_zero(wc->masks.dl_src)) {
@@ -1319,7 +1367,7 @@ ofputil_encode_set_protocol(enum ofputil_protocol current,
         return ofputil_make_flow_mod_table_id(want_tid);
     }
 
-    assert(current == want);
+    ovs_assert(current == want);
 
     *next = current;
     return NULL;
@@ -1333,7 +1381,7 @@ ofputil_encode_nx_set_flow_format(enum nx_flow_format nxff)
     struct nx_set_flow_format *sff;
     struct ofpbuf *msg;
 
-    assert(ofputil_nx_flow_format_is_valid(nxff));
+    ovs_assert(ofputil_nx_flow_format_is_valid(nxff));
 
     msg = ofpraw_alloc(OFPRAW_NXT_SET_FLOW_FORMAT, OFP10_VERSION, 0);
     sff = ofpbuf_put_zeros(msg, sizeof *sff);
@@ -1547,11 +1595,13 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         if (fm->flags & OFPFF10_EMERG) {
             /* We do not support the OpenFlow 1.0 emergency flow cache, which
              * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
-             * There is no good error code, so just state that the flow table
-             * is full.
-             * Moreover, OFPFF10_EMERG overlaps with OFPFF12_RESET_COUNTS,
-             * so this check must be here */
-            return OFPERR_OFPFMFC_TABLE_FULL;
+             *
+             * OpenFlow 1.0 specifies the error code to use when idle_timeout
+             * or hard_timeout is nonzero.  Otherwise, there is no good error
+             * code, so just state that the flow table is full. */
+            return (fm->hard_timeout || fm->idle_timeout
+                    ? OFPERR_OFPFMFC_BAD_EMERG_TIMEOUT
+                    : OFPERR_OFPFMFC_TABLE_FULL);
         }
 
         if (protocol & OFPUTIL_P_TID) {
@@ -2245,7 +2295,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->packet_count = ntohll(ofr->packet_count);
         fr->byte_count = ntohll(ofr->byte_count);
     } else if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
-        const struct ofp_flow_removed *ofr;
+        const struct ofp10_flow_removed *ofr;
 
         ofr = ofpbuf_pull(&b, sizeof *ofr);
 
@@ -2325,7 +2375,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
 
     case OFPUTIL_P_OF10_STD:
     case OFPUTIL_P_OF10_STD_TID: {
-        struct ofp_flow_removed *ofr;
+        struct ofp10_flow_removed *ofr;
 
         msg = ofpraw_alloc_xid(OFPRAW_OFPT10_FLOW_REMOVED, OFP10_VERSION,
                                htonl(0), 0);
@@ -2429,9 +2479,9 @@ ofputil_decode_packet_in(struct ofputil_packet_in *pin,
 
         ofputil_decode_packet_in_finish(pin, &match, &b);
     } else if (raw == OFPRAW_OFPT10_PACKET_IN) {
-        const struct ofp_packet_in *opi;
+        const struct ofp10_packet_in *opi;
 
-        opi = ofpbuf_pull(&b, offsetof(struct ofp_packet_in, data));
+        opi = ofpbuf_pull(&b, offsetof(struct ofp10_packet_in, data));
 
         pin->packet = opi->data;
         pin->packet_len = b.size;
@@ -2542,11 +2592,11 @@ ofputil_encode_packet_in(const struct ofputil_packet_in *pin,
             opi->cookie = pin->cookie;
         }
     } else if (packet_in_format == NXPIF_OPENFLOW10) {
-        struct ofp_packet_in *opi;
+        struct ofp10_packet_in *opi;
 
         packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
                                   htonl(0), send_len);
-        opi = ofpbuf_put_zeros(packet, offsetof(struct ofp_packet_in, data));
+        opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
         opi->total_len = htons(pin->total_len);
         opi->in_port = htons(pin->fmd.in_port);
         opi->reason = pin->reason;
@@ -2655,7 +2705,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
         }
     } else if (raw == OFPRAW_OFPT10_PACKET_OUT) {
         enum ofperr error;
-        const struct ofp_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
+        const struct ofp10_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
 
         po->buffer_id = ntohl(opo->buffer_id);
         po->in_port = ntohs(opo->in_port);
@@ -3147,7 +3197,9 @@ ofputil_put_switch_features_port(const struct ofputil_phy_port *pp,
 {
     const struct ofp_header *oh = b->data;
 
-    ofputil_put_phy_port(oh->version, pp, b);
+    if (oh->version < OFP13_VERSION) {
+        ofputil_put_phy_port(oh->version, pp, b);
+    }
 }
 \f
 /* ofputil_port_status */
@@ -3174,7 +3226,7 @@ ofputil_decode_port_status(const struct ofp_header *oh,
     ps->reason = ops->reason;
 
     retval = ofputil_pull_phy_port(oh->version, &b, &ps->desc);
-    assert(retval != EOF);
+    ovs_assert(retval != EOF);
     return retval;
 }
 
@@ -3303,6 +3355,104 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
     return b;
 }
 \f
+/* ofputil_role_request */
+
+/* Decodes the OpenFlow "role request" or "role reply" message in '*oh' into
+ * an abstract form in '*rr'.  Returns 0 if successful, otherwise an
+ * OFPERR_* value. */
+enum ofperr
+ofputil_decode_role_message(const struct ofp_header *oh,
+                            struct ofputil_role_request *rr)
+{
+    const struct ofp12_role_request *orr = ofpmsg_body(oh);
+    uint32_t role = ntohl(orr->role);
+    struct ofpbuf b;
+    enum ofpraw raw;
+
+    memset(rr, 0, sizeof *rr);
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&b);
+
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST
+        || raw == OFPRAW_OFPT12_ROLE_REPLY) {
+
+        if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+            if (role == OFPCR12_ROLE_NOCHANGE) {
+                rr->request_current_role_only = true;
+                return 0;
+            }
+            if (role == OFPCR12_ROLE_MASTER || role == OFPCR12_ROLE_SLAVE) {
+                rr->generation_id = ntohll(orr->generation_id);
+                rr->have_generation_id = true;
+            }
+        }
+
+        /* Map to enum nx_role */
+        role -= 1; /* OFPCR12_ROLE_MASTER -> NX_ROLE_MASTER etc. */
+    } else if (raw != OFPRAW_NXT_ROLE_REQUEST
+               && raw != OFPRAW_NXT_ROLE_REPLY) {
+        return OFPERR_OFPBRC_BAD_TYPE;
+    }
+
+    if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
+        && role != NX_ROLE_SLAVE) {
+        return OFPERR_OFPRRFC_BAD_ROLE;
+    }
+
+    rr->role = role;
+    return 0;
+}
+
+/* Returns an encoded form of a role reply suitable for the "request" in a
+ * buffer owned by the caller. */
+struct ofpbuf *
+ofputil_encode_role_reply(const struct ofp_header *request,
+                          enum nx_role role)
+{
+    struct ofp12_role_request *reply;
+    struct ofpbuf *buf;
+    size_t reply_size;
+
+    struct ofpbuf b;
+    enum ofpraw raw;
+
+    ofpbuf_use_const(&b, request, ntohs(request->length));
+    raw = ofpraw_pull_assert(&b);
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
+        reply_size = sizeof (struct ofp12_role_request);
+        raw = OFPRAW_OFPT12_ROLE_REPLY;
+    }
+    else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
+        reply_size = sizeof (struct nx_role_request);
+        raw = OFPRAW_NXT_ROLE_REPLY;
+    } else {
+        NOT_REACHED();
+    }
+
+    buf = ofpraw_alloc_reply(raw, request, 0);
+    reply = ofpbuf_put_zeros(buf, reply_size);
+
+    if (raw == OFPRAW_OFPT12_ROLE_REPLY) {
+        /* Map to OpenFlow enum ofp12_controller_role */
+        role += 1; /* NX_ROLE_MASTER -> OFPCR12_ROLE_MASTER etc. */
+        /*
+         * OpenFlow specification does not specify use of generation_id field
+         * on reply messages.  Intuitively, it would seem a good idea to return
+         * the current value.  However, the current value is undefined
+         * initially, and there is no way to insert an undefined value in the
+         * message.  Therefore we leave the generation_id zeroed on reply
+         * messages.
+         *
+         * A request for clarification has been filed with the Open Networking
+         * Foundation as EXT-272.
+         */
+    }
+    reply->role = htonl(role);
+
+    return buf;
+}
+\f
 /* Table stats. */
 
 static void
@@ -3310,7 +3460,7 @@ ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in,
                               struct ofpbuf *buf)
 {
     struct wc_map {
-        enum ofp_flow_wildcards wc10;
+        enum ofp10_flow_wildcards wc10;
         enum oxm12_ofb_match_fields mf12;
     };
 
@@ -3332,9 +3482,9 @@ ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in,
     struct ofp10_table_stats *out;
     const struct wc_map *p;
 
-    out = ofpbuf_put_uninit(buf, sizeof *out);
+    out = ofpbuf_put_zeros(buf, sizeof *out);
     out->table_id = in->table_id;
-    strcpy(out->name, in->name);
+    ovs_strlcpy(out->name, in->name, sizeof out->name);
     out->wildcards = 0;
     for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) {
         if (in->wildcards & htonll(1ULL << p->mf12)) {
@@ -3392,9 +3542,9 @@ ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
 {
     struct ofp11_table_stats *out;
 
-    out = ofpbuf_put_uninit(buf, sizeof *out);
+    out = ofpbuf_put_zeros(buf, sizeof *out);
     out->table_id = in->table_id;
-    strcpy(out->name, in->name);
+    ovs_strlcpy(out->name, in->name, sizeof out->name);
     out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards);
     out->match = oxm12_to_ofp11_flow_match_fields(in->match);
     out->instructions = in->instructions;
@@ -3638,7 +3788,7 @@ ofputil_decode_flow_update(struct ofputil_flow_update *update,
         VLOG_WARN_RL(&bad_ofmsg_rl,
                      "NXST_FLOW_MONITOR reply has bad event %"PRIu16,
                      ntohs(nfuh->event));
-        return OFPERR_OFPET_BAD_REQUEST;
+        return OFPERR_NXBRC_FM_BAD_EVENT;
     }
 
 bad_len:
@@ -3735,7 +3885,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po,
 
     switch (ofp_version) {
     case OFP10_VERSION: {
-        struct ofp_packet_out *opo;
+        struct ofp10_packet_out *opo;
         size_t actions_ofs;
 
         msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
@@ -3978,7 +4128,7 @@ ofputil_port_from_string(const char *s, uint16_t *portp)
             return true;
         } else if (port32 < OFPP11_MAX) {
             VLOG_WARN("port %u is outside the supported range 0 through "
-                      "%"PRIx16"or 0x%x through 0x%"PRIx32, port32,
+                      "%"PRIx16" or 0x%x through 0x%"PRIx32, port32,
                       UINT16_MAX, (unsigned int) OFPP11_MAX, UINT32_MAX);
             return false;
         } else {