ofp-util: Work on decoding OF1.1 flow_mods.
[openvswitch] / lib / ofp-util.c
index 7875cbf86a41167ffd8f0aa057c2f5b60f7ced0c..8d0f99384c58d421eaae315b428f7ed60beb1141 100644 (file)
@@ -265,6 +265,31 @@ ofputil_cls_rule_to_ofp10_match(const struct cls_rule *rule,
     memset(match->pad2, '\0', sizeof match->pad2);
 }
 
+enum ofperr
+ofputil_pull_ofp11_match(struct ofpbuf *buf, unsigned int priority,
+                         struct cls_rule *rule)
+{
+    struct ofp11_match_header *omh;
+    struct ofp11_match *om;
+
+    if (buf->size < sizeof(struct ofp11_match_header)) {
+        return OFPERR_OFPBMC_BAD_LEN;
+    }
+
+    omh = buf->data;
+    switch (ntohs(omh->type)) {
+    case OFPMT_STANDARD:
+        if (omh->length != htons(sizeof *om) || buf->size < sizeof *om) {
+            return OFPERR_OFPBMC_BAD_LEN;
+        }
+        om = ofpbuf_pull(buf, sizeof *om);
+        return ofputil_cls_rule_from_ofp11_match(om, priority, rule);
+
+    default:
+        return OFPERR_OFPBMC_BAD_TYPE;
+    }
+}
+
 /* Converts the ofp11_match in 'match' into a cls_rule in 'rule', with the
  * given 'priority'.  Returns 0 if successful, otherwise an OFPERR_* value. */
 enum ofperr
@@ -1102,87 +1127,131 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
 
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
-    if (raw == OFPRAW_OFPT10_FLOW_MOD) {
+    if (raw == OFPRAW_OFPT11_FLOW_MOD) {
         /* Standard OpenFlow 1.1 flow_mod. */
-        const struct ofp_flow_mod *ofm;
-        uint16_t priority;
+        const struct ofp11_flow_mod *ofm;
         enum ofperr error;
 
-        /* Get the ofp_flow_mod. */
         ofm = ofpbuf_pull(&b, sizeof *ofm);
 
-        /* Set priority based on original wildcards.  Normally we'd allow
-         * ofputil_cls_rule_from_match() to do this for us, but
-         * ofputil_normalize_rule() can put wildcards where the original flow
-         * didn't have them. */
-        priority = ntohs(ofm->priority);
-        if (!(ofm->match.wildcards & htonl(OFPFW10_ALL))) {
-            priority = UINT16_MAX;
+        error = ofputil_pull_ofp11_match(&b, ntohs(ofm->priority), &fm->cr);
+        if (error) {
+            return error;
         }
 
-        /* Translate the rule. */
-        ofputil_cls_rule_from_ofp10_match(&ofm->match, priority, &fm->cr);
-        ofputil_normalize_rule(&fm->cr);
-
-        /* Now get the actions. */
-        error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+        error = ofpacts_pull_openflow11_instructions(&b, b.size, ofpacts);
         if (error) {
             return error;
         }
 
         /* Translate the message. */
-        command = ntohs(ofm->command);
-        fm->cookie = htonll(0);
-        fm->cookie_mask = htonll(0);
-        fm->new_cookie = ofm->cookie;
+        if (ofm->command == OFPFC_ADD) {
+            fm->cookie = htonll(0);
+            fm->cookie_mask = htonll(0);
+            fm->new_cookie = ofm->cookie;
+        } else {
+            /* XXX */
+            fm->cookie = ofm->cookie;
+            fm->cookie_mask = ofm->cookie_mask;
+            fm->new_cookie = htonll(UINT64_MAX);
+        }
+        fm->command = ofm->command;
+        fm->table_id = ofm->table_id;
         fm->idle_timeout = ntohs(ofm->idle_timeout);
         fm->hard_timeout = ntohs(ofm->hard_timeout);
         fm->buffer_id = ntohl(ofm->buffer_id);
-        fm->out_port = ntohs(ofm->out_port);
-        fm->flags = ntohs(ofm->flags);
-    } else if (raw == OFPRAW_NXT_FLOW_MOD) {
-        /* Nicira extended flow_mod. */
-        const struct nx_flow_mod *nfm;
-        enum ofperr error;
-
-        /* Dissect the message. */
-        nfm = ofpbuf_pull(&b, sizeof *nfm);
-        error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
-                              &fm->cr, &fm->cookie, &fm->cookie_mask);
+        error = ofputil_port_from_ofp11(ofm->out_port, &fm->out_port);
         if (error) {
             return error;
         }
-        error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
-        if (error) {
-            return error;
+        if (ofm->out_group != htonl(OFPG_ANY)) {
+            return OFPERR_NXFMFC_GROUPS_NOT_SUPPORTED;
         }
-
-        /* Translate the message. */
-        command = ntohs(nfm->command);
-        if ((command & 0xff) == OFPFC_ADD && fm->cookie_mask) {
-            /* Flow additions may only set a new cookie, not match an
-             * existing cookie. */
-            return OFPERR_NXBRC_NXM_INVALID;
-        }
-        fm->new_cookie = nfm->cookie;
-        fm->idle_timeout = ntohs(nfm->idle_timeout);
-        fm->hard_timeout = ntohs(nfm->hard_timeout);
-        fm->buffer_id = ntohl(nfm->buffer_id);
-        fm->out_port = ntohs(nfm->out_port);
-        fm->flags = ntohs(nfm->flags);
+        fm->flags = ntohs(ofm->flags);
     } else {
-        NOT_REACHED();
+        if (raw == OFPRAW_OFPT10_FLOW_MOD) {
+            /* Standard OpenFlow 1.0 flow_mod. */
+            const struct ofp10_flow_mod *ofm;
+            uint16_t priority;
+            enum ofperr error;
+
+            /* Get the ofp10_flow_mod. */
+            ofm = ofpbuf_pull(&b, sizeof *ofm);
+
+            /* Set priority based on original wildcards.  Normally we'd allow
+             * ofputil_cls_rule_from_match() to do this for us, but
+             * ofputil_normalize_rule() can put wildcards where the original
+             * flow didn't have them. */
+            priority = ntohs(ofm->priority);
+            if (!(ofm->match.wildcards & htonl(OFPFW10_ALL))) {
+                priority = UINT16_MAX;
+            }
+
+            /* Translate the rule. */
+            ofputil_cls_rule_from_ofp10_match(&ofm->match, priority, &fm->cr);
+            ofputil_normalize_rule(&fm->cr);
+
+            /* Now get the actions. */
+            error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+            if (error) {
+                return error;
+            }
+
+            /* Translate the message. */
+            command = ntohs(ofm->command);
+            fm->cookie = htonll(0);
+            fm->cookie_mask = htonll(0);
+            fm->new_cookie = ofm->cookie;
+            fm->idle_timeout = ntohs(ofm->idle_timeout);
+            fm->hard_timeout = ntohs(ofm->hard_timeout);
+            fm->buffer_id = ntohl(ofm->buffer_id);
+            fm->out_port = ntohs(ofm->out_port);
+            fm->flags = ntohs(ofm->flags);
+        } else if (raw == OFPRAW_NXT_FLOW_MOD) {
+            /* Nicira extended flow_mod. */
+            const struct nx_flow_mod *nfm;
+            enum ofperr error;
+
+            /* Dissect the message. */
+            nfm = ofpbuf_pull(&b, sizeof *nfm);
+            error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
+                                  &fm->cr, &fm->cookie, &fm->cookie_mask);
+            if (error) {
+                return error;
+            }
+            error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+            if (error) {
+                return error;
+            }
+
+            /* Translate the message. */
+            command = ntohs(nfm->command);
+            if ((command & 0xff) == OFPFC_ADD && fm->cookie_mask) {
+                /* Flow additions may only set a new cookie, not match an
+                 * existing cookie. */
+                return OFPERR_NXBRC_NXM_INVALID;
+            }
+            fm->new_cookie = nfm->cookie;
+            fm->idle_timeout = ntohs(nfm->idle_timeout);
+            fm->hard_timeout = ntohs(nfm->hard_timeout);
+            fm->buffer_id = ntohl(nfm->buffer_id);
+            fm->out_port = ntohs(nfm->out_port);
+            fm->flags = ntohs(nfm->flags);
+        } else {
+            NOT_REACHED();
+        }
+
+        if (protocol & OFPUTIL_P_TID) {
+            fm->command = command & 0xff;
+            fm->table_id = command >> 8;
+        } else {
+            fm->command = command;
+            fm->table_id = 0xff;
+        }
     }
 
     fm->ofpacts = ofpacts->data;
     fm->ofpacts_len = ofpacts->size;
-    if (protocol & OFPUTIL_P_TID) {
-        fm->command = command & 0xff;
-        fm->table_id = command >> 8;
-    } else {
-        fm->command = command;
-        fm->table_id = 0xff;
-    }
 
     return 0;
 }
@@ -1193,7 +1262,7 @@ struct ofpbuf *
 ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
                         enum ofputil_protocol protocol)
 {
-    struct ofp_flow_mod *ofm;
+    struct ofp10_flow_mod *ofm;
     struct nx_flow_mod *nfm;
     struct ofpbuf *msg;
     uint16_t command;
@@ -1284,7 +1353,7 @@ ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
 
 static enum ofperr
 ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
-                                  const struct ofp_flow_stats_request *ofsr,
+                                  const struct ofp10_flow_stats_request *ofsr,
                                   bool aggregate)
 {
     fsr->aggregate = aggregate;
@@ -1364,7 +1433,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
     switch (protocol) {
     case OFPUTIL_P_OF10:
     case OFPUTIL_P_OF10_TID: {
-        struct ofp_flow_stats_request *ofsr;
+        struct ofp10_flow_stats_request *ofsr;
 
         raw = (fsr->aggregate
                ? OFPRAW_OFPST_AGGREGATE_REQUEST
@@ -1461,7 +1530,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
     if (!msg->size) {
         return EOF;
     } else if (raw == OFPRAW_OFPST_FLOW_REPLY) {
-        const struct ofp_flow_stats *ofs;
+        const struct ofp10_flow_stats *ofs;
         size_t length;
 
         ofs = ofpbuf_try_pull(msg, sizeof *ofs);
@@ -1573,7 +1642,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
 
     ofpraw_decode_partial(&raw, reply->data, reply->size);
     if (raw == OFPRAW_OFPST_FLOW_REPLY) {
-        struct ofp_flow_stats *ofs;
+        struct ofp10_flow_stats *ofs;
 
         ofpbuf_put_uninit(reply, sizeof *ofs);
         ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply);
@@ -1629,38 +1698,33 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
 }
 
 /* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or
- * NXST_AGGREGATE reply according to 'protocol', and returns the message. */
+ * NXST_AGGREGATE reply matching 'request', and returns the message. */
 struct ofpbuf *
 ofputil_encode_aggregate_stats_reply(
     const struct ofputil_aggregate_stats *stats,
     const struct ofp_header *request)
 {
+    struct ofp_aggregate_stats_reply *asr;
+    uint64_t packet_count;
+    uint64_t byte_count;
     struct ofpbuf *msg;
     enum ofpraw raw;
 
     ofpraw_decode(&raw, request);
     if (raw == OFPRAW_OFPST_AGGREGATE_REQUEST) {
-        struct ofp_aggregate_stats_reply *asr;
-
-        msg = ofpraw_alloc_reply(OFPRAW_OFPST_AGGREGATE_REPLY, request, 0);
-        asr = ofpbuf_put_zeros(msg, sizeof *asr);
-        put_32aligned_be64(&asr->packet_count,
-                           htonll(unknown_to_zero(stats->packet_count)));
-        put_32aligned_be64(&asr->byte_count,
-                           htonll(unknown_to_zero(stats->byte_count)));
-        asr->flow_count = htonl(stats->flow_count);
-    } else if (raw == OFPRAW_NXST_AGGREGATE_REQUEST) {
-        struct nx_aggregate_stats_reply *nasr;
-
-        msg = ofpraw_alloc_reply(OFPRAW_NXST_AGGREGATE_REPLY, request, 0);
-        nasr = ofpbuf_put_zeros(msg, sizeof *nasr);
-        nasr->packet_count = htonll(stats->packet_count);
-        nasr->byte_count = htonll(stats->byte_count);
-        nasr->flow_count = htonl(stats->flow_count);
+        packet_count = unknown_to_zero(stats->packet_count);
+        byte_count = unknown_to_zero(stats->byte_count);
     } else {
-        NOT_REACHED();
+        packet_count = stats->packet_count;
+        byte_count = stats->byte_count;
     }
 
+    msg = ofpraw_alloc_stats_reply(request, 0);
+    asr = ofpbuf_put_zeros(msg, sizeof *asr);
+    put_32aligned_be64(&asr->packet_count, htonll(packet_count));
+    put_32aligned_be64(&asr->byte_count, htonll(byte_count));
+    asr->flow_count = htonl(stats->flow_count);
+
     return msg;
 }
 
@@ -1668,26 +1732,16 @@ enum ofperr
 ofputil_decode_aggregate_stats_reply(struct ofputil_aggregate_stats *stats,
                                      const struct ofp_header *reply)
 {
+    struct ofp_aggregate_stats_reply *asr;
     struct ofpbuf msg;
-    enum ofpraw raw;
 
     ofpbuf_use_const(&msg, reply, ntohs(reply->length));
-    raw = ofpraw_pull_assert(&msg);
-    if (raw == OFPRAW_OFPST_AGGREGATE_REPLY) {
-        struct ofp_aggregate_stats_reply *asr = msg.l3;
-
-        stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count));
-        stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count));
-        stats->flow_count = ntohl(asr->flow_count);
-    } else if (raw == OFPRAW_NXST_AGGREGATE_REPLY) {
-        struct nx_aggregate_stats_reply *nasr = msg.l3;
-
-        stats->packet_count = ntohll(nasr->packet_count);
-        stats->byte_count = ntohll(nasr->byte_count);
-        stats->flow_count = ntohl(nasr->flow_count);
-    } else {
-        NOT_REACHED();
-    }
+    ofpraw_pull_assert(&msg);
+
+    asr = msg.l3;
+    stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count));
+    stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count));
+    stats->flow_count = ntohl(asr->flow_count);
 
     return 0;
 }