lib/ofpbuf: Compact
[sliver-openvswitch.git] / lib / ofp-actions.c
index 4558669..23d89d3 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.
@@ -248,8 +248,8 @@ dec_ttl_cnt_ids_from_openflow(const struct nx_action_cnt_ids *nac_ids,
     }
 
     if (ids_size < ids->n_controllers * sizeof(ovs_be16)) {
-        VLOG_WARN_RL(&rl, "Nicira action dec_ttl_cnt_ids only has %zu bytes "
-                     "allocated for controller ids.  %zu bytes are required for "
+        VLOG_WARN_RL(&rl, "Nicira action dec_ttl_cnt_ids only has %"PRIuSIZE" bytes "
+                     "allocated for controller ids.  %"PRIuSIZE" bytes are required for "
                      "%"PRIu16" controllers.", ids_size,
                      ids->n_controllers * sizeof(ovs_be16), ids->n_controllers);
         return OFPERR_OFPBAC_BAD_LEN;
@@ -286,8 +286,7 @@ sample_from_openflow(const struct nx_action_sample *nas,
 }
 
 static enum ofperr
-push_mpls_from_openflow(ovs_be16 ethertype, enum ofpact_mpls_position position,
-                        struct ofpbuf *out)
+push_mpls_from_openflow(ovs_be16 ethertype, struct ofpbuf *out)
 {
     struct ofpact_push_mpls *oam;
 
@@ -296,7 +295,6 @@ push_mpls_from_openflow(ovs_be16 ethertype, enum ofpact_mpls_position position,
     }
     oam = ofpact_put_PUSH_MPLS(out);
     oam->ethertype = ethertype;
-    oam->position = position;
 
     return 0;
 }
@@ -324,7 +322,7 @@ decode_nxast_action(const union ofp_action *a, enum ofputil_action_code *code)
             } else {                                    \
                 return OFPERR_OFPBAC_BAD_LEN;           \
             }                                           \
-            NOT_REACHED();
+            OVS_NOT_REACHED();
 #include "ofp-util.def"
 
     case CONSTANT_HTONS(NXAST_SNAT__OBSOLETE):
@@ -379,8 +377,9 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
 #define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OFPUTIL_NXAST_RESUBMIT:
         resubmit_from_openflow(&a->resubmit, out);
@@ -473,8 +472,7 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         break;
 
     case OFPUTIL_NXAST_PUSH_MPLS:
-        error = push_mpls_from_openflow(a->push_mpls.ethertype,
-                                        OFPACT_MPLS_AFTER_VLAN, out);
+        error = push_mpls_from_openflow(a->push_mpls.ethertype, out);
         break;
 
     case OFPUTIL_NXAST_SET_MPLS_LABEL:
@@ -526,8 +524,9 @@ ofpact_from_openflow10(const union ofp_action *a,
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OFPUTIL_OFPAT10_OUTPUT:
         return output_from_openflow10(&a->output10, out);
@@ -638,7 +637,7 @@ log_bad_action(const union ofp_action *actions, size_t max_actions,
 
         ds_init(&s);
         ds_put_hex_dump(&s, actions, max_actions * OFP_ACTION_ALIGN, 0, false);
-        VLOG_WARN("bad action at offset %#tx (%s):\n%s",
+        VLOG_WARN("bad action at offset %#"PRIxPTR" (%s):\n%s",
                   (char *)bad_action - (char *)actions,
                   ofperr_get_name(error), ds_cstr(&s));
         ds_destroy(&s);
@@ -711,7 +710,7 @@ ofpacts_pull_openflow_actions(struct ofpbuf *openflow,
     actions = ofpbuf_try_pull(openflow, actions_len);
     if (actions == NULL) {
         VLOG_WARN_RL(&rl, "OpenFlow message actions length %u exceeds "
-                     "remaining message length (%zu)",
+                     "remaining message length (%"PRIu32")",
                      actions_len, openflow->size);
         return OFPERR_OFPBRC_BAD_LEN;
     }
@@ -764,7 +763,7 @@ decode_openflow11_action(const union ofp_action *a,
             } else {                                    \
                 return OFPERR_OFPBAC_BAD_LEN;           \
             }                                           \
-            NOT_REACHED();
+            OVS_NOT_REACHED();
 #include "ofp-util.def"
 
     default:
@@ -1087,7 +1086,7 @@ set_field_to_openflow(const struct ofpact_set_field *sf,
     } else if (oh->version == OFP10_VERSION) {
         set_field_to_openflow10(sf, openflow);
     } else {
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1144,8 +1143,9 @@ ofpact_from_openflow11(const union ofp_action *a, enum ofp_version version,
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OFPUTIL_OFPAT11_OUTPUT:
         return output_from_openflow11(&a->ofp11_output, out);
@@ -1255,11 +1255,7 @@ ofpact_from_openflow11(const union ofp_action *a, enum ofp_version version,
         break;
 
     case OFPUTIL_OFPAT11_PUSH_MPLS:
-        /* OpenFlow 1.3 has different semantics. */
-        error = push_mpls_from_openflow(a->push.ethertype,
-                                        version >= OFP13_VERSION ?
-                                        OFPACT_MPLS_BEFORE_VLAN :
-                                        OFPACT_MPLS_AFTER_VLAN, out);
+        error = push_mpls_from_openflow(a->push.ethertype, out);
         break;
 
     case OFPUTIL_OFPAT11_POP_MPLS:
@@ -1337,7 +1333,7 @@ ofpact_is_set_action(const struct ofpact *a)
     case OFPACT_WRITE_METADATA:
         return false;
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1404,7 +1400,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
     case OFPACT_WRITE_METADATA:
         return false;
     default:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 
@@ -1637,6 +1633,24 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
     }
 }
 
+enum ofperr
+ovs_instruction_type_from_inst_type(enum ovs_instruction_type *instruction_type,
+                                    const uint16_t inst_type)
+{
+    switch (inst_type) {
+
+#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) \
+    case ENUM:                                      \
+        *instruction_type = OVSINST_##ENUM;         \
+        return 0;
+OVS_INSTRUCTIONS
+#undef DEFINE_INST
+
+    default:
+        return OFPERR_OFPBIC_UNKNOWN_INST;
+    }
+}
+
 static inline struct ofp11_instruction *
 instruction_next(const struct ofp11_instruction *inst)
 {
@@ -1715,7 +1729,7 @@ decode_openflow11_instructions(const struct ofp11_instruction insts[],
     }
 
     if (left) {
-        VLOG_WARN_RL(&rl, "bad instruction format at offset %zu",
+        VLOG_WARN_RL(&rl, "bad instruction format at offset %"PRIuSIZE,
                      (n_insts - left) * sizeof *inst);
         return OFPERR_OFPBIC_BAD_LEN;
     }
@@ -1754,7 +1768,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
     instructions = ofpbuf_try_pull(openflow, instructions_len);
     if (instructions == NULL) {
         VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds "
-                     "remaining message length (%zu)",
+                     "remaining message length (%"PRIu32")",
                      instructions_len, openflow->size);
         error = OFPERR_OFPBIC_BAD_LEN;
         goto exit;
@@ -1867,14 +1881,26 @@ ofpact_check_output_port(ofp_port_t port, ofp_port_t max_ports)
     }
 }
 
+/* Removes the protocols that require consistency between match and actions
+ * (that's everything but OpenFlow 1.0) from '*usable_protocols'.
+ *
+ * (An example of an inconsistency between match and actions is a flow that
+ * does not match on an MPLS Ethertype but has an action that pops an MPLS
+ * label.) */
+static void
+inconsistent_match(enum ofputil_protocol *usable_protocols)
+{
+    *usable_protocols &= OFPUTIL_P_OF10_ANY;
+}
+
 /* May modify flow->dl_type, flow->nw_proto and flow->vlan_tci,
  * caller must restore them.
  *
  * Modifies some actions, filling in fields that could not be properly set
  * without context. */
 static enum ofperr
-ofpact_check__(struct ofpact *a, struct flow *flow,
-               bool enforce_consistency, ofp_port_t max_ports,
+ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
+               struct flow *flow, ofp_port_t max_ports,
                uint8_t table_id, uint8_t n_tables)
 {
     const struct ofpact_enqueue *enqueue;
@@ -1910,7 +1936,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
             (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
         if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
             !ofpact_get_SET_VLAN_VID(a)->push_vlan_if_needed) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Temporary mark that we have a vlan tag. */
         flow->vlan_tci |= htons(VLAN_CFI);
@@ -1923,7 +1949,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
             (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
         if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
             !ofpact_get_SET_VLAN_PCP(a)->push_vlan_if_needed) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Temporary mark that we have a vlan tag. */
         flow->vlan_tci |= htons(VLAN_CFI);
@@ -1931,7 +1957,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
 
     case OFPACT_STRIP_VLAN:
         if (!(flow->vlan_tci & htons(VLAN_CFI))) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Temporary mark that we have no vlan tag. */
         flow->vlan_tci = htons(0);
@@ -1953,7 +1979,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     case OFPACT_SET_IPV4_SRC:
     case OFPACT_SET_IPV4_DST:
         if (flow->dl_type != htons(ETH_TYPE_IP)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -1962,7 +1988,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     case OFPACT_SET_IP_TTL:
     case OFPACT_DEC_TTL:
         if (!is_ip_any(flow)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -1970,7 +1996,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         if (!is_ip_any(flow) ||
             (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP
              && flow->nw_proto != IPPROTO_SCTP)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Note on which transport protocol the port numbers are set.
          * This allows this set action to be converted to an OF1.2 set field
@@ -1982,7 +2008,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         if (!is_ip_any(flow) ||
             (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP
              && flow->nw_proto != IPPROTO_SCTP)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Note on which transport protocol the port numbers are set.
          * This allows this set action to be converted to an OF1.2 set field
@@ -2027,7 +2053,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     case OFPACT_SET_MPLS_TTL:
     case OFPACT_DEC_MPLS_TTL:
         if (!eth_type_mpls(flow->dl_type)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -2039,7 +2065,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
 
     case OFPACT_FIN_TIMEOUT:
         if (flow->nw_proto != IPPROTO_TCP) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -2062,10 +2088,10 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         return 0;
 
     case OFPACT_POP_MPLS:
-        flow->dl_type = ofpact_get_POP_MPLS(a)->ethertype;
         if (!eth_type_mpls(flow->dl_type)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
+        flow->dl_type = ofpact_get_POP_MPLS(a)->ethertype;
         return 0;
 
     case OFPACT_SAMPLE:
@@ -2075,9 +2101,12 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         return 0;
 
     case OFPACT_WRITE_ACTIONS: {
+        /* Use a temporary copy of 'usable_protocols' because we can't check
+         * consistency of an action set. */
         struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a);
+        enum ofputil_protocol p = *usable_protocols;
         return ofpacts_check(on->actions, ofpact_nest_get_action_len(on),
-                             flow, false, max_ports, table_id, n_tables);
+                             flow, max_ports, table_id, n_tables, &p);
     }
 
     case OFPACT_WRITE_METADATA:
@@ -2104,28 +2133,27 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         return 0;
 
     default:
-        NOT_REACHED();
-    }
-
- inconsistent:
-    if (enforce_consistency) {
-        return OFPERR_OFPBAC_MATCH_INCONSISTENT;
+        OVS_NOT_REACHED();
     }
-    return 0;
 }
 
 /* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are
  * appropriate for a packet with the prerequisites satisfied by 'flow' in a
  * switch with no more than 'max_ports' ports.
  *
+ * If 'ofpacts' and 'flow' are inconsistent with one another, un-sets in
+ * '*usable_protocols' the protocols that forbid the inconsistency.  (An
+ * example of an inconsistency between match and actions is a flow that does
+ * not match on an MPLS Ethertype but has an action that pops an MPLS label.)
+ *
  * May annotate ofpacts with information gathered from the 'flow'.
  *
  * May temporarily modify 'flow', but restores the changes before returning. */
 enum ofperr
 ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len,
-              struct flow *flow, bool enforce_consistency,
-              ofp_port_t max_ports,
-              uint8_t table_id, uint8_t n_tables)
+              struct flow *flow, ofp_port_t max_ports,
+              uint8_t table_id, uint8_t n_tables,
+              enum ofputil_protocol *usable_protocols)
 {
     struct ofpact *a;
     ovs_be16 dl_type = flow->dl_type;
@@ -2134,7 +2162,7 @@ ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len,
     enum ofperr error = 0;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        error = ofpact_check__(a, flow, enforce_consistency,
+        error = ofpact_check__(usable_protocols, a, flow,
                                max_ports, table_id, n_tables);
         if (error) {
             break;
@@ -2147,6 +2175,24 @@ ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len,
     return error;
 }
 
+/* Like ofpacts_check(), but reports inconsistencies as
+ * OFPERR_OFPBAC_MATCH_INCONSISTENT rather than clearing bits. */
+enum ofperr
+ofpacts_check_consistency(struct ofpact ofpacts[], size_t ofpacts_len,
+                          struct flow *flow, ofp_port_t max_ports,
+                          uint8_t table_id, uint8_t n_tables,
+                          enum ofputil_protocol usable_protocols)
+{
+    enum ofputil_protocol p = usable_protocols;
+    enum ofperr error;
+
+    error = ofpacts_check(ofpacts, ofpacts_len, flow, max_ports,
+                          table_id, n_tables, &p);
+    return (error ? error
+            : p != usable_protocols ? OFPERR_OFPBAC_MATCH_INCONSISTENT
+            : 0);
+}
+
 /* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
  * in the appropriate order as defined by the OpenFlow spec. */
 enum ofperr
@@ -2449,7 +2495,7 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_GOTO_TABLE:
     case OFPACT_METER:
     case OFPACT_SET_FIELD:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
     }
 }
 \f
@@ -2750,7 +2796,7 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_WRITE_ACTIONS:
     case OFPACT_GOTO_TABLE:
     case OFPACT_METER:
-        NOT_REACHED();
+        OVS_NOT_REACHED();
 
     case OFPACT_GROUP:
         ofputil_put_OFPAT11_GROUP(out)->group_id =
@@ -3602,8 +3648,8 @@ ofpact_update_len(struct ofpbuf *ofpacts, struct ofpact *ofpact)
 void
 ofpact_pad(struct ofpbuf *ofpacts)
 {
-    unsigned int rem = ofpacts->size % OFPACT_ALIGNTO;
-    if (rem) {
-        ofpbuf_put_zeros(ofpacts, OFPACT_ALIGNTO - rem);
+    unsigned int pad = PAD_SIZE(ofpacts->size, OFPACT_ALIGNTO);
+    if (pad) {
+        ofpbuf_put_zeros(ofpacts, pad);
     }
 }