The next patch will introduce nested actions with special restrictions.
Refactor the action verification to allow ofpacts_verify() to identify
nesting so that these retrictions may be applied.

Signed-off-by: Joe Stringer <joestrin...@nicira.com>
---
 lib/ofp-actions.c      | 104 +++++++++++++++++++++++++++++++++++--------------
 lib/ofp-actions.h      |   3 +-
 lib/ofp-parse.c        |   2 +-
 ofproto/ofproto-dpif.c |   2 +-
 utilities/ovs-ofctl.c  |   2 +-
 5 files changed, 80 insertions(+), 33 deletions(-)

diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index c46ce97..c1e46b5 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -332,7 +332,8 @@ static void ofpacts_update_instruction_actions(struct 
ofpbuf *openflow,
 static void pad_ofpat(struct ofpbuf *openflow, size_t start_ofs);
 
 static enum ofperr ofpacts_verify(const struct ofpact[], size_t ofpacts_len,
-                                  uint32_t allowed_ovsinsts);
+                                  uint32_t allowed_ovsinsts,
+                                  enum ofpact_type outer_action);
 
 static void ofpact_put_set_field(struct ofpbuf *openflow, enum ofp_version,
                                  enum mf_field_id, uint64_t value);
@@ -344,7 +345,21 @@ static void *ofpact_put_raw(struct ofpbuf *, enum 
ofp_version,
 
 static char *OVS_WARN_UNUSED_RESULT ofpacts_parse(
     char *str, struct ofpbuf *ofpacts, enum ofputil_protocol *usable_protocols,
-    bool allow_instructions);
+    bool allow_instructions, enum ofpact_type outer_action);
+
+/* Pull off existing actions or instructions. Used by nesting actions to keep
+ * ofpacts_parse() oblivious of actions nesting. */
+static size_t
+ofpacts_pull(struct ofpbuf *ofpacts)
+{
+    size_t ofs;
+
+    ofpact_pad(ofpacts);
+    ofs = ofpacts->size;
+    ofpbuf_pull(ofpacts, ofs);
+
+    return ofs;
+}
 
 #include "ofp-actions.inc1"
 
@@ -4506,14 +4521,9 @@ static char * OVS_WARN_UNUSED_RESULT
 parse_WRITE_ACTIONS(char *arg, struct ofpbuf *ofpacts,
                     enum ofputil_protocol *usable_protocols)
 {
+    size_t ofs = ofpacts_pull(ofpacts);
     struct ofpact_nest *on;
     char *error;
-    size_t ofs;
-
-    /* Pull off existing actions or instructions. */
-    ofpact_pad(ofpacts);
-    ofs = ofpacts->size;
-    ofpbuf_pull(ofpacts, ofs);
 
     /* Add a Write-Actions instruction and then pull it off. */
     ofpact_put(ofpacts, OFPACT_WRITE_ACTIONS, sizeof *on);
@@ -4526,7 +4536,8 @@ parse_WRITE_ACTIONS(char *arg, struct ofpbuf *ofpacts,
      * that it doesn't actually include the nested actions.  That means that
      * ofpacts_parse() would reject them as being part of an Apply-Actions that
      * follows a Write-Actions, which is an invalid order.  */
-    error = ofpacts_parse(arg, ofpacts, usable_protocols, false);
+    error = ofpacts_parse(arg, ofpacts, usable_protocols, false,
+                          OFPACT_WRITE_ACTIONS);
 
     /* Put the Write-Actions back on and update its length. */
     on = ofpbuf_push_uninit(ofpacts, sizeof *on);
@@ -4718,12 +4729,15 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow,
                                 unsigned int actions_len,
                                 enum ofp_version version,
                                 uint32_t allowed_ovsinsts,
-                                struct ofpbuf *ofpacts)
+                                struct ofpbuf *ofpacts,
+                                enum ofpact_type outer_action)
 {
     const struct ofp_action_header *actions;
     enum ofperr error;
 
-    ofpbuf_clear(ofpacts);
+    if (!outer_action) {
+        ofpbuf_clear(ofpacts);
+    }
 
     if (actions_len % OFP_ACTION_ALIGN != 0) {
         VLOG_WARN_RL(&rl, "OpenFlow message actions length %u is not a "
@@ -4745,8 +4759,8 @@ ofpacts_pull_openflow_actions__(struct ofpbuf *openflow,
         return error;
     }
 
-    error = ofpacts_verify(ofpacts->data, ofpacts->size,
-                           allowed_ovsinsts);
+    error = ofpacts_verify(ofpacts->data, ofpacts->size, allowed_ovsinsts,
+                           outer_action);
     if (error) {
         ofpbuf_clear(ofpacts);
     }
@@ -4778,7 +4792,7 @@ ofpacts_pull_openflow_actions(struct ofpbuf *openflow,
 {
     return ofpacts_pull_openflow_actions__(openflow, actions_len, version,
                                            1u << OVSINST_OFPIT11_APPLY_ACTIONS,
-                                           ofpacts);
+                                           ofpacts, 0);
 }
 
 /* OpenFlow 1.1 actions. */
@@ -5315,7 +5329,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf 
*openflow,
         return ofpacts_pull_openflow_actions__(openflow, instructions_len,
                                                version,
                                                (1u << N_OVS_INSTRUCTIONS) - 1,
-                                               ofpacts);
+                                               ofpacts, 0);
     }
 
     ofpbuf_clear(ofpacts);
@@ -5412,7 +5426,7 @@ ofpacts_pull_openflow_instructions(struct ofpbuf 
*openflow,
     }
 
     error = ofpacts_verify(ofpacts->data, ofpacts->size,
-                           (1u << N_OVS_INSTRUCTIONS) - 1);
+                           (1u << N_OVS_INSTRUCTIONS) - 1, 0);
 exit:
     if (error) {
         ofpbuf_clear(ofpacts);
@@ -5776,15 +5790,30 @@ ofpacts_check_consistency(struct ofpact ofpacts[], 
size_t ofpacts_len,
             : 0);
 }
 
+static enum ofperr
+ofpacts_verify_nested(const struct ofpact *a, enum ofpact_type outer_action)
+{
+    if (outer_action != OFPACT_WRITE_ACTIONS) {
+        VLOG_WARN("\"%s\" action doesn't support nested action \"%s\"",
+                  ofpact_name(outer_action), ofpact_name(a->type));
+        return OFPERR_OFPBAC_BAD_ARGUMENT;
+    }
+
+    return 0;
+}
+
 /* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are in the
  * appropriate order as defined by the OpenFlow spec and as required by Open
  * vSwitch.
  *
  * 'allowed_ovsinsts' is a bitmap of OVSINST_* values, in which 1-bits indicate
- * instructions that are allowed within 'ofpacts[]'. */
+ * instructions that are allowed within 'ofpacts[]'.
+ *
+ * If 'outer_action' is not zero, it specifies that the actions are nested
+ * within another action of type 'outer_action'. */
 static enum ofperr
 ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len,
-               uint32_t allowed_ovsinsts)
+               uint32_t allowed_ovsinsts, enum ofpact_type outer_action)
 {
     const struct ofpact *a;
     enum ovs_instruction_type inst;
@@ -5806,6 +5835,14 @@ ofpacts_verify(const struct ofpact ofpacts[], size_t 
ofpacts_len,
             return 0;
         }
 
+        if (outer_action) {
+               enum ofperr error = ofpacts_verify_nested(a, outer_action);
+
+               if (error) {
+                   return error;
+               }
+        }
+
         next = ovs_instruction_type_from_ofpact_type(a->type);
         if (a > ofpacts
             && (inst == OVSINST_OFPIT11_APPLY_ACTIONS
@@ -6318,11 +6355,14 @@ ofpact_type_from_name(const char *name, enum 
ofpact_type *type)
 /* Parses 'str' as a series of instructions, and appends them to 'ofpacts'.
  *
  * Returns NULL if successful, otherwise a malloc()'d string describing the
- * error.  The caller is responsible for freeing the returned string. */
+ * error.  The caller is responsible for freeing the returned string.
+ *
+ * If 'outer_action' is specified, indicates that the actions being parsed
+ * are nested within another action of the type specified in 'outer_action'. */
 static char * OVS_WARN_UNUSED_RESULT
 ofpacts_parse__(char *str, struct ofpbuf *ofpacts,
                 enum ofputil_protocol *usable_protocols,
-                bool allow_instructions)
+                bool allow_instructions, enum ofpact_type outer_action)
 {
     int prev_inst = -1;
     enum ofperr retval;
@@ -6396,7 +6436,8 @@ ofpacts_parse__(char *str, struct ofpbuf *ofpacts,
     retval = ofpacts_verify(ofpacts->data, ofpacts->size,
                             (allow_instructions
                              ? (1u << N_OVS_INSTRUCTIONS) - 1
-                             : 1u << OVSINST_OFPIT11_APPLY_ACTIONS));
+                             : 1u << OVSINST_OFPIT11_APPLY_ACTIONS),
+                            outer_action);
     if (retval) {
         return xstrdup("Incorrect instruction ordering");
     }
@@ -6406,11 +6447,12 @@ ofpacts_parse__(char *str, struct ofpbuf *ofpacts,
 
 static char * OVS_WARN_UNUSED_RESULT
 ofpacts_parse(char *str, struct ofpbuf *ofpacts,
-              enum ofputil_protocol *usable_protocols, bool allow_instructions)
+              enum ofputil_protocol *usable_protocols, bool allow_instructions,
+              enum ofpact_type outer_action)
 {
     uint32_t orig_size = ofpacts->size;
     char *error = ofpacts_parse__(str, ofpacts, usable_protocols,
-                                  allow_instructions);
+                                  allow_instructions, outer_action);
     if (error) {
         ofpacts->size = orig_size;
     }
@@ -6420,29 +6462,33 @@ ofpacts_parse(char *str, struct ofpbuf *ofpacts,
 static char * OVS_WARN_UNUSED_RESULT
 ofpacts_parse_copy(const char *s_, struct ofpbuf *ofpacts,
                    enum ofputil_protocol *usable_protocols,
-                   bool allow_instructions)
+                   bool allow_instructions, enum ofpact_type outer_action)
 {
     char *error, *s;
 
     *usable_protocols = OFPUTIL_P_ANY;
 
     s = xstrdup(s_);
-    error = ofpacts_parse(s, ofpacts, usable_protocols, allow_instructions);
+    error = ofpacts_parse(s, ofpacts, usable_protocols, allow_instructions,
+                          outer_action);
     free(s);
 
     return error;
 }
 
 /* Parses 's' as a set of OpenFlow actions and appends the actions to
- * 'ofpacts'.
+ * 'ofpacts'. 'outer_action', if nonzero, specifies that 's' contains actions
+ * that are nested within the action of type 'outer_action'.
  *
  * Returns NULL if successful, otherwise a malloc()'d string describing the
  * error.  The caller is responsible for freeing the returned string. */
 char * OVS_WARN_UNUSED_RESULT
 ofpacts_parse_actions(const char *s, struct ofpbuf *ofpacts,
-                      enum ofputil_protocol *usable_protocols)
+                      enum ofputil_protocol *usable_protocols,
+                      enum ofpact_type outer_action)
 {
-    return ofpacts_parse_copy(s, ofpacts, usable_protocols, false);
+    return ofpacts_parse_copy(s, ofpacts, usable_protocols, false,
+                              outer_action);
 }
 
 /* Parses 's' as a set of OpenFlow instructions and appends the instructions to
@@ -6454,7 +6500,7 @@ char * OVS_WARN_UNUSED_RESULT
 ofpacts_parse_instructions(const char *s, struct ofpbuf *ofpacts,
                            enum ofputil_protocol *usable_protocols)
 {
-    return ofpacts_parse_copy(s, ofpacts, usable_protocols, true);
+    return ofpacts_parse_copy(s, ofpacts, usable_protocols, true, 0);
 }
 
 const char *
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 51b2963..818f5c8 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -777,7 +777,8 @@ uint32_t ofpacts_get_meter(const struct ofpact[], size_t 
ofpacts_len);
 /* Formatting and parsing ofpacts. */
 void ofpacts_format(const struct ofpact[], size_t ofpacts_len, struct ds *);
 char *ofpacts_parse_actions(const char *, struct ofpbuf *ofpacts,
-                            enum ofputil_protocol *usable_protocols)
+                            enum ofputil_protocol *usable_protocols,
+                            enum ofpact_type outer_action)
     OVS_WARN_UNUSED_RESULT;
 char *ofpacts_parse_instructions(const char *, struct ofpbuf *ofpacts,
                                  enum ofputil_protocol *usable_protocols)
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 5950f06..75762b8 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -1197,7 +1197,7 @@ parse_bucket_str(struct ofputil_bucket *bucket, char 
*str_, uint8_t group_type,
 
     ofpbuf_init(&ofpacts, 0);
     error = ofpacts_parse_actions(ds_cstr(&actions), &ofpacts,
-                                  usable_protocols);
+                                  usable_protocols, 0);
     ds_destroy(&actions);
     if (error) {
         ofpbuf_uninit(&ofpacts);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 1279907..e39a959 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4787,7 +4787,7 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, 
int argc,
     ofpbuf_init(&ofpacts, 0);
 
     /* Parse actions. */
-    error = ofpacts_parse_actions(argv[--argc], &ofpacts, &usable_protocols);
+    error = ofpacts_parse_actions(argv[--argc], &ofpacts, &usable_protocols, 
0);
     if (error) {
         unixctl_command_reply_error(conn, error);
         free(error);
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 75e84e2..cc440dd 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1838,7 +1838,7 @@ ofctl_packet_out(struct ovs_cmdl_context *ctx)
     enum ofputil_protocol usable_protocols; /* XXX: Use in proto selection */
 
     ofpbuf_init(&ofpacts, 64);
-    error = ofpacts_parse_actions(ctx->argv[3], &ofpacts, &usable_protocols);
+    error = ofpacts_parse_actions(ctx->argv[3], &ofpacts, &usable_protocols, 
0);
     if (error) {
         ovs_fatal(0, "%s", error);
     }
-- 
2.1.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to