datapath: Replace "struct odp_action" by Netlink attributes.
[sliver-openvswitch.git] / lib / ofp-util.c
index f37b644..cdbbb0d 100644 (file)
@@ -25,6 +25,7 @@
 #include "ofpbuf.h"
 #include "packets.h"
 #include "random.h"
+#include "type-props.h"
 #include "vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(ofp_util);
@@ -105,7 +106,7 @@ void
 ofputil_cls_rule_from_match(const struct ofp_match *match,
                             unsigned int priority,
                             enum nx_flow_format flow_format,
-                            uint64_t cookie, struct cls_rule *rule)
+                            ovs_be64 cookie, struct cls_rule *rule)
 {
     struct flow_wildcards *wc = &rule->wc;
     unsigned int ofpfw;
@@ -129,7 +130,7 @@ ofputil_cls_rule_from_match(const struct ofp_match *match,
         rule->flow.tun_id = htonl(ntohll(cookie) >> 32);
     } else {
         wc->wildcards |= FWW_TUN_ID;
-        rule->flow.tun_id = 0;
+        rule->flow.tun_id = htonl(0);
     }
 
     if (ofpfw & OFPFW_DL_DST) {
@@ -887,8 +888,7 @@ ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh,
     const struct ofputil_msg_type *type;
     struct ofpbuf b;
 
-    b.data = (void *) oh;
-    b.size = ntohs(oh->length);
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
 
     ofputil_decode_msg_type(oh, &type);
     if (ofputil_msg_type_code(type) == OFPUTIL_OFPT_FLOW_MOD) {
@@ -898,10 +898,7 @@ ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh,
         int error;
 
         /* Dissect the message. */
-        ofm = ofpbuf_try_pull(&b, sizeof *ofm);
-        if (!ofm) {
-            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
-        }
+        ofm = ofpbuf_pull(&b, sizeof *ofm);
         error = ofputil_pull_actions(&b, b.size, &fm->actions, &fm->n_actions);
         if (error) {
             return error;
@@ -941,10 +938,7 @@ ofputil_decode_flow_mod(struct flow_mod *fm, const struct ofp_header *oh,
         int error;
 
         /* Dissect the message. */
-        nfm = ofpbuf_try_pull(&b, sizeof *nfm);
-        if (!nfm) {
-            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
-        }
+        nfm = ofpbuf_pull(&b, sizeof *nfm);
         error = nx_pull_match(&b, ntohs(nfm->match_len), ntohs(nfm->priority),
                               &fm->cr);
         if (error) {
@@ -1053,13 +1047,9 @@ ofputil_decode_nxst_flow_request(struct flow_stats_request *fsr,
     struct ofpbuf b;
     int error;
 
-    b.data = (void *) oh;
-    b.size = ntohs(oh->length);
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
 
-    nfsr = ofpbuf_try_pull(&b, sizeof *nfsr);
-    if (!nfsr) {
-        return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
-    }
+    nfsr = ofpbuf_pull(&b, sizeof *nfsr);
     error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &fsr->match);
     if (error) {
         return error;
@@ -1078,7 +1068,11 @@ ofputil_decode_nxst_flow_request(struct flow_stats_request *fsr,
 /* Converts an OFPST_FLOW, OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE
  * message 'oh', received when the current flow format was 'flow_format', into
  * an abstract flow_stats_request in 'fsr'.  Returns 0 if successful, otherwise
- * an OpenFlow error code. */
+ * an OpenFlow error code.
+ *
+ * For OFPST_FLOW and OFPST_AGGREGATE messages, 'flow_format' should be the
+ * current flow format at the time when the message was received.  Otherwise
+ * 'flow_format' is ignored. */
 int
 ofputil_decode_flow_stats_request(struct flow_stats_request *fsr,
                                   const struct ofp_header *oh,
@@ -1088,8 +1082,7 @@ ofputil_decode_flow_stats_request(struct flow_stats_request *fsr,
     struct ofpbuf b;
     int code;
 
-    b.data = (void *) oh;
-    b.size = ntohs(oh->length);
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
 
     ofputil_decode_msg_type(oh, &type);
     code = ofputil_msg_type_code(type);
@@ -1152,6 +1145,68 @@ ofputil_encode_flow_stats_request(const struct flow_stats_request *fsr,
     return msg;
 }
 
+/* Converts an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message 'oh', received
+ * when the current flow format was 'flow_format', into an abstract
+ * ofputil_flow_removed in 'fr'.  Returns 0 if successful, otherwise an
+ * OpenFlow error code.
+ *
+ * For OFPT_FLOW_REMOVED messages, 'flow_format' should be the current flow
+ * format at the time when the message was received.  Otherwise 'flow_format'
+ * is ignored. */
+int
+ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
+                            const struct ofp_header *oh,
+                            enum nx_flow_format flow_format)
+{
+    const struct ofputil_msg_type *type;
+    enum ofputil_msg_code code;
+
+    ofputil_decode_msg_type(oh, &type);
+    code = ofputil_msg_type_code(type);
+    if (code == OFPUTIL_OFPT_FLOW_REMOVED) {
+        const struct ofp_flow_removed *ofr;
+
+        ofr = (const struct ofp_flow_removed *) oh;
+        ofputil_cls_rule_from_match(&ofr->match, ntohs(ofr->priority),
+                                    flow_format, ofr->cookie, &fr->rule);
+        fr->cookie = ofr->cookie;
+        fr->reason = ofr->reason;
+        fr->duration_sec = ntohl(ofr->duration_sec);
+        fr->duration_nsec = ntohl(ofr->duration_nsec);
+        fr->idle_timeout = ntohs(ofr->idle_timeout);
+        fr->packet_count = ntohll(ofr->packet_count);
+        fr->byte_count = ntohll(ofr->byte_count);
+    } else if (code == OFPUTIL_NXT_FLOW_REMOVED) {
+        struct nx_flow_removed *nfr;
+        struct ofpbuf b;
+        int error;
+
+        ofpbuf_use_const(&b, oh, ntohs(oh->length));
+
+        nfr = ofpbuf_pull(&b, sizeof *nfr);
+        error = nx_pull_match(&b, ntohs(nfr->match_len), ntohs(nfr->priority),
+                              &fr->rule);
+        if (error) {
+            return error;
+        }
+        if (b.size) {
+            return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+        }
+
+        fr->cookie = nfr->cookie;
+        fr->reason = nfr->reason;
+        fr->duration_sec = ntohl(nfr->duration_sec);
+        fr->duration_nsec = ntohl(nfr->duration_nsec);
+        fr->idle_timeout = ntohs(nfr->idle_timeout);
+        fr->packet_count = ntohll(nfr->packet_count);
+        fr->byte_count = ntohll(nfr->byte_count);
+    } else {
+        NOT_REACHED();
+    }
+
+    return 0;
+}
+
 /* Returns a string representing the message type of 'type'.  The string is the
  * enumeration constant for the type, e.g. "OFPT_HELLO".  For statistics
  * messages, the constant is followed by "request" or "reply",
@@ -1343,6 +1398,22 @@ ofputil_stats_body_len(const struct ofp_header *oh)
     return ntohs(oh->length) - sizeof(struct ofp_stats_request);
 }
 
+/* Returns the first byte of the body of the nicira_stats_msg in 'oh'. */
+const void *
+ofputil_nxstats_body(const struct ofp_header *oh)
+{
+    assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+    return ((const struct nicira_stats_msg *) oh) + 1;
+}
+
+/* Returns the length of the body of the nicira_stats_msg in 'oh'. */
+size_t
+ofputil_nxstats_body_len(const struct ofp_header *oh)
+{
+    assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+    return ntohs(oh->length) - sizeof(struct nicira_stats_msg);
+}
+
 struct ofpbuf *
 make_flow_mod(uint16_t command, const struct cls_rule *rule,
               size_t actions_len)
@@ -1616,6 +1687,7 @@ check_nicira_action(const union ofp_action *a, unsigned int len,
                     const struct flow *flow)
 {
     const struct nx_action_header *nah;
+    uint16_t subtype;
     int error;
 
     if (len < 16) {
@@ -1625,7 +1697,14 @@ check_nicira_action(const union ofp_action *a, unsigned int len,
     }
     nah = (const struct nx_action_header *) a;
 
-    switch (ntohs(nah->subtype)) {
+    subtype = ntohs(nah->subtype);
+    if (subtype > TYPE_MAXIMUM(enum nx_action_subtype)) {
+        /* This is necessary because enum nx_action_subtype is probably an
+         * 8-bit type, so the cast below throws away the top 8 bits. */
+        return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
+    }
+
+    switch ((enum nx_action_subtype) subtype) {
     case NXAST_RESUBMIT:
     case NXAST_SET_TUNNEL:
     case NXAST_DROP_SPOOFED_ARP:
@@ -1652,6 +1731,7 @@ check_nicira_action(const union ofp_action *a, unsigned int len,
     case NXAST_NOTE:
         return 0;
 
+    case NXAST_SNAT__OBSOLETE:
     default:
         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
     }
@@ -1661,9 +1741,10 @@ static int
 check_action(const union ofp_action *a, unsigned int len,
              const struct flow *flow, int max_ports)
 {
+    enum ofp_action_type type = ntohs(a->type);
     int error;
 
-    switch (ntohs(a->type)) {
+    switch (type) {
     case OFPAT_OUTPUT:
         error = check_action_exact_len(a, len, 8);
         if (error) {
@@ -1712,8 +1793,7 @@ check_action(const union ofp_action *a, unsigned int len,
         return check_enqueue_action(a, len, max_ports);
 
     default:
-        VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %"PRIu16,
-                ntohs(a->type));
+        VLOG_WARN_RL(&bad_ofmsg_rl, "unknown action type %d", (int) type);
         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE);
     }
 }
@@ -1995,6 +2075,7 @@ make_ofp_error_msg(int error, const struct ofp_header *oh)
     }
 
     if (len) {
+        buf->size -= len;
         ofpbuf_put(buf, data, len);
     }