ofp-actions: Support mixing "conjunction" and "note" actions.
[cascardo/ovs.git] / lib / ofp-actions.c
index 260d854..eef3389 100644 (file)
@@ -3660,7 +3660,24 @@ format_RESUBMIT(const struct ofpact_resubmit *a, struct ds *s)
  * address.  This is not usually the intent in MAC learning; instead, we want
  * the MAC learn entry to expire when no traffic has been sent *from* the
  * learned address.  Use a hard timeout for that.
- */
+ *
+ *
+ * Visibility of Changes
+ * ---------------------
+ *
+ * Prior to Open vSwitch 2.4, any changes made by a "learn" action in a given
+ * flow translation are visible to flow table lookups made later in the flow
+ * translation.  This means that, in the example above, a MAC learned by the
+ * learn action in table 0 would be found in table 1 (if the packet being
+ * processed had the same source and destination MAC address).
+ *
+ * In Open vSwitch 2.4 and later, changes to a flow table (whether to add or
+ * modify a flow) by a "learn" action are visible only for later flow
+ * translations, not for later lookups within the same flow translation.  In
+ * the MAC learning example, a MAC learned by the learn action in table 0 would
+ * not be found in table 1 if the flow translation would resubmit to table 1
+ * after the processing of the learn action, meaning that if this MAC had not
+ * been learned before then the packet would be flooded. */
 struct nx_action_learn {
     ovs_be16 type;              /* OFPAT_VENDOR. */
     ovs_be16 len;               /* At least 24. */
@@ -4237,6 +4254,31 @@ format_EXIT(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
     ds_put_cstr(s, "exit");
 }
 \f
+/* Unroll xlate action. */
+
+static void
+encode_UNROLL_XLATE(const struct ofpact_unroll_xlate *unroll OVS_UNUSED,
+                    enum ofp_version ofp_version OVS_UNUSED,
+                    struct ofpbuf *out OVS_UNUSED)
+{
+    OVS_NOT_REACHED();
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_UNROLL_XLATE(char *arg OVS_UNUSED, struct ofpbuf *ofpacts OVS_UNUSED,
+                   enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+    OVS_NOT_REACHED();
+    return NULL;
+}
+
+static void
+format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a OVS_UNUSED,
+                    struct ds *s)
+{
+    ds_put_cstr(s, "unroll_xlate");
+}
+\f
 /* Action structure for NXAST_SAMPLE.
  *
  * Samples matching packets with the given probability and sends them
@@ -4726,6 +4768,7 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
     case OFPACT_DEC_TTL:
     case OFPACT_ENQUEUE:
     case OFPACT_EXIT:
+    case OFPACT_UNROLL_XLATE:
     case OFPACT_FIN_TIMEOUT:
     case OFPACT_GOTO_TABLE:
     case OFPACT_GROUP:
@@ -4795,6 +4838,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
     case OFPACT_CONTROLLER:
     case OFPACT_ENQUEUE:
     case OFPACT_EXIT:
+    case OFPACT_UNROLL_XLATE:
     case OFPACT_FIN_TIMEOUT:
     case OFPACT_LEARN:
     case OFPACT_CONJUNCTION:
@@ -4868,7 +4912,7 @@ ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in,
  * "Action Set" and "Action List" terms used in OpenFlow 1.1+.)
  *
  * In general this involves appending the last instance of each action that is
- * adimissible in the action set in the order described in the OpenFlow
+ * admissible in the action set in the order described in the OpenFlow
  * specification.
  *
  * Exceptions:
@@ -5017,6 +5061,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
     case OFPACT_MULTIPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_UNROLL_XLATE:
     case OFPACT_SAMPLE:
     default:
         return OVSINST_OFPIT11_APPLY_ACTIONS;
@@ -5280,8 +5325,8 @@ ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
 
         ofpact_pad(ofpacts);
         start = ofpacts->size;
-        on = ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS,
-                        offsetof(struct ofpact_nest, actions));
+        ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS,
+                   offsetof(struct ofpact_nest, actions));
         get_actions_from_instruction(insts[OVSINST_OFPIT11_WRITE_ACTIONS],
                                      &actions, &actions_len);
         error = ofpacts_decode_for_action_set(actions, actions_len,
@@ -5607,6 +5652,11 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
     case OFPACT_GROUP:
         return 0;
 
+    case OFPACT_UNROLL_XLATE:
+        /* UNROLL is an internal action that should never be seen via
+         * OpenFlow. */
+        return OFPERR_OFPBAC_BAD_TYPE;
+
     default:
         OVS_NOT_REACHED();
     }
@@ -5687,9 +5737,11 @@ ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len,
 
         if (a->type == OFPACT_CONJUNCTION) {
             OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-                if (a->type != OFPACT_CONJUNCTION) {
-                    VLOG_WARN("when %s action is present, it must be the only "
-                              "kind of action used", ofpact_name(a->type));
+                if (a->type != OFPACT_CONJUNCTION && a->type != OFPACT_NOTE) {
+                    VLOG_WARN("\"conjunction\" actions may be used along with "
+                              "\"note\" but not any other kind of action "
+                              "(such as the \"%s\" action used here)",
+                              ofpact_name(a->type));
                     return OFPERR_NXBAC_BAD_CONJUNCTION;
                 }
             }
@@ -5998,6 +6050,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
     case OFPACT_MULTIPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_UNROLL_XLATE:
     case OFPACT_PUSH_MPLS:
     case OFPACT_POP_MPLS:
     case OFPACT_SAMPLE: