ofp-actions: Add decoding and encoding OF1.1 instructions and actions.
authorBen Pfaff <blp@nicira.com>
Wed, 4 Jul 2012 05:14:29 +0000 (22:14 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 4 Jul 2012 05:21:12 +0000 (22:21 -0700)
So far, only the Apply-Actions instruction is supported, and only
actions that have identical semantics to OpenFlow 1.0 actions.

Co-authored-by: Simon Horman <horms@verge.net.au>
Co-authored-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Ben Pfaff <blp@nicira.com>
15 files changed:
DESIGN
build-aux/extract-ofp-errors
include/openflow/openflow-1.0.h
include/openflow/openflow-1.1.h
include/openflow/openflow-common.h
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-errors.h
lib/ofp-parse.c
lib/ofp-util.c
lib/ofp-util.def
lib/ofp-util.h
ofproto/connmgr.c
tests/ofp-actions.at
utilities/ovs-ofctl.c

diff --git a/DESIGN b/DESIGN
index 7dd6efa..b06751f 100644 (file)
--- a/DESIGN
+++ b/DESIGN
@@ -628,6 +628,19 @@ against desired actions in a bytewise fashion:
         - Open vSwitch zeros padding bytes in action structures,
           regardless of their values when the flows were added.
 
         - Open vSwitch zeros padding bytes in action structures,
           regardless of their values when the flows were added.
 
+        - Open vSwitch "normalizes" the instructions in OpenFlow 1.1
+          (and later) in the following way:
+
+              * OVS sorts the instructions into the following order:
+                Apply-Actions, Clear-Actions, Write-Actions,
+                Write-Metadata, Goto-Table.
+
+              * OVS drops Apply-Actions instructions that have empty
+                action lists.
+
+              * OVS drops Write-Actions instructions that have empty
+                action sets.
+
 Please report other discrepancies, if you notice any, so that we can
 fix or document them.
 
 Please report other discrepancies, if you notice any, so that we can
 fix or document them.
 
index efaf103..1ec5ba4 100755 (executable)
@@ -234,6 +234,7 @@ def extract_ofp_errors(filenames):
                               "NX1.0+": ("OF1.0", "OF1.1", "OF1.2"),
                               "NX1.0":  ("OF1.0",),
                               "NX1.1":  ("OF1.1",),
                               "NX1.0+": ("OF1.0", "OF1.1", "OF1.2"),
                               "NX1.0":  ("OF1.0",),
                               "NX1.1":  ("OF1.1",),
+                              "NX1.1+": ("OF1.1",),
                               "NX1.2":  ("OF1.2",)}
                 if targets not in target_map:
                     fatal("%s: unknown error domain" % targets)
                               "NX1.2":  ("OF1.2",)}
                 if targets not in target_map:
                     fatal("%s: unknown error domain" % targets)
index 2ee356d..039eb6b 100644 (file)
@@ -232,72 +232,19 @@ enum ofp10_action_type {
  * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
  * number of bytes to send.  A 'max_len' of zero means no bytes of the
  * packet should be sent. */
  * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
  * number of bytes to send.  A 'max_len' of zero means no bytes of the
  * packet should be sent. */
-struct ofp_action_output {
+struct ofp10_action_output {
     ovs_be16 type;                  /* OFPAT10_OUTPUT. */
     ovs_be16 len;                   /* Length is 8. */
     ovs_be16 port;                  /* Output port. */
     ovs_be16 max_len;               /* Max length to send to controller. */
 };
     ovs_be16 type;                  /* OFPAT10_OUTPUT. */
     ovs_be16 len;                   /* Length is 8. */
     ovs_be16 port;                  /* Output port. */
     ovs_be16 max_len;               /* Max length to send to controller. */
 };
-OFP_ASSERT(sizeof(struct ofp_action_output) == 8);
+OFP_ASSERT(sizeof(struct ofp10_action_output) == 8);
 
 /* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate
  * special conditions.  All ones is used to match that no VLAN id was
  * set. */
 #define OFP_VLAN_NONE      0xffff
 
 
 /* The VLAN id is 12 bits, so we can use the entire 16 bits to indicate
  * special conditions.  All ones is used to match that no VLAN id was
  * set. */
 #define OFP_VLAN_NONE      0xffff
 
-/* Action structure for OFPAT10_SET_VLAN_VID. */
-struct ofp_action_vlan_vid {
-    ovs_be16 type;                  /* OFPAT10_SET_VLAN_VID. */
-    ovs_be16 len;                   /* Length is 8. */
-    ovs_be16 vlan_vid;              /* VLAN id. */
-    uint8_t pad[2];
-};
-OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8);
-
-/* Action structure for OFPAT10_SET_VLAN_PCP. */
-struct ofp_action_vlan_pcp {
-    ovs_be16 type;                  /* OFPAT10_SET_VLAN_PCP. */
-    ovs_be16 len;                   /* Length is 8. */
-    uint8_t vlan_pcp;               /* VLAN priority. */
-    uint8_t pad[3];
-};
-OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8);
-
-/* Action structure for OFPAT10_SET_DL_SRC/DST. */
-struct ofp_action_dl_addr {
-    ovs_be16 type;                  /* OFPAT10_SET_DL_SRC/DST. */
-    ovs_be16 len;                   /* Length is 16. */
-    uint8_t dl_addr[OFP_ETH_ALEN];  /* Ethernet address. */
-    uint8_t pad[6];
-};
-OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16);
-
-/* Action structure for OFPAT10_SET_NW_SRC/DST. */
-struct ofp_action_nw_addr {
-    ovs_be16 type;                  /* OFPAT10_SET_TW_SRC/DST. */
-    ovs_be16 len;                   /* Length is 8. */
-    ovs_be32 nw_addr;               /* IP address. */
-};
-OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
-
-/* Action structure for OFPAT10_SET_NW_TOS. */
-struct ofp_action_nw_tos {
-    ovs_be16 type;                  /* OFPAT10_SET_TW_TOS. */
-    ovs_be16 len;                   /* Length is 8. */
-    uint8_t nw_tos;                 /* DSCP in high 6 bits, rest ignored. */
-    uint8_t pad[3];
-};
-OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
-
-/* Action structure for OFPAT10_SET_TP_SRC/DST. */
-struct ofp_action_tp_port {
-    ovs_be16 type;                  /* OFPAT10_SET_TP_SRC/DST. */
-    ovs_be16 len;                   /* Length is 8. */
-    ovs_be16 tp_port;               /* TCP/UDP port. */
-    uint8_t pad[2];
-};
-OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8);
-
 /* Action header for OFPAT10_VENDOR. The rest of the body is vendor-defined. */
 struct ofp_action_vendor_header {
     ovs_be16 type;                  /* OFPAT10_VENDOR. */
 /* Action header for OFPAT10_VENDOR. The rest of the body is vendor-defined. */
 struct ofp_action_vendor_header {
     ovs_be16 type;                  /* OFPAT10_VENDOR. */
@@ -336,7 +283,7 @@ union ofp_action {
     ovs_be16 type;
     struct ofp_action_header header;
     struct ofp_action_vendor_header vendor;
     ovs_be16 type;
     struct ofp_action_header header;
     struct ofp_action_vendor_header vendor;
-    struct ofp_action_output output;
+    struct ofp10_action_output output10;
     struct ofp_action_vlan_vid vlan_vid;
     struct ofp_action_vlan_pcp vlan_pcp;
     struct ofp_action_nw_addr nw_addr;
     struct ofp_action_vlan_vid vlan_vid;
     struct ofp_action_vlan_pcp vlan_pcp;
     struct ofp_action_nw_addr nw_addr;
index f0c063b..f0f3793 100644 (file)
@@ -305,6 +305,16 @@ enum ofp11_instruction_type {
     OFPIT11_EXPERIMENTER = 0xFFFF  /* Experimenter instruction */
 };
 
     OFPIT11_EXPERIMENTER = 0xFFFF  /* Experimenter instruction */
 };
 
+#define OFP11_INSTRUCTION_ALIGN 8
+
+/* Generic ofp_instruction structure. */
+struct ofp11_instruction {
+    ovs_be16 type;              /* Instruction type */
+    ovs_be16 len;               /* Length of this struct in bytes. */
+    uint8_t pad[4];             /* Align to 64-bits */
+};
+OFP_ASSERT(sizeof(struct ofp11_instruction) == 8);
+
 /* Instruction structure for OFPIT_GOTO_TABLE */
 struct ofp11_instruction_goto_table {
     ovs_be16 type;                 /* OFPIT_GOTO_TABLE */
 /* Instruction structure for OFPIT_GOTO_TABLE */
 struct ofp11_instruction_goto_table {
     ovs_be16 type;                 /* OFPIT_GOTO_TABLE */
@@ -335,6 +345,16 @@ struct ofp11_instruction_actions {
 };
 OFP_ASSERT(sizeof(struct ofp11_instruction_actions) == 8);
 
 };
 OFP_ASSERT(sizeof(struct ofp11_instruction_actions) == 8);
 
+/* Instruction structure for experimental instructions */
+struct ofp11_instruction_experimenter {
+    ovs_be16 type;              /* OFPIT11_EXPERIMENTER */
+    ovs_be16 len;               /* Length of this struct in bytes */
+    ovs_be32 experimenter;      /* Experimenter ID which takes the same form
+                                   as in struct ofp_vendor_header. */
+    /* Experimenter-defined arbitrary additional data. */
+};
+OFP_ASSERT(sizeof(struct ofp11_instruction_experimenter) == 8);
+
 /* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
    * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
    * number of bytes to send. A 'max_len' of zero means no bytes of the
 /* Action structure for OFPAT_OUTPUT, which sends packets out 'port'.
    * When the 'port' is the OFPP_CONTROLLER, 'max_len' indicates the max
    * number of bytes to send. A 'max_len' of zero means no bytes of the
index 9788af1..bb4de0b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2011 The Board of Trustees of The Leland Stanford
+/* Copyright (c) 2008, 2011, 2012 The Board of Trustees of The Leland Stanford
  * Junior University
  *
  * We are making the OpenFlow specification and associated documentation
  * Junior University
  *
  * We are making the OpenFlow specification and associated documentation
@@ -222,6 +222,59 @@ enum ofp_packet_in_reason {
     OFPR_N_REASONS
 };
 
     OFPR_N_REASONS
 };
 
+/* Action structure for OFPAT10_SET_VLAN_VID and OFPAT11_SET_VLAN_VID. */
+struct ofp_action_vlan_vid {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be16 vlan_vid;              /* VLAN id. */
+    uint8_t pad[2];
+};
+OFP_ASSERT(sizeof(struct ofp_action_vlan_vid) == 8);
+
+/* Action structure for OFPAT10_SET_VLAN_PCP and OFPAT11_SET_VLAN_PCP. */
+struct ofp_action_vlan_pcp {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    uint8_t vlan_pcp;               /* VLAN priority. */
+    uint8_t pad[3];
+};
+OFP_ASSERT(sizeof(struct ofp_action_vlan_pcp) == 8);
+
+/* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */
+struct ofp_action_dl_addr {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 16. */
+    uint8_t dl_addr[OFP_ETH_ALEN];  /* Ethernet address. */
+    uint8_t pad[6];
+};
+OFP_ASSERT(sizeof(struct ofp_action_dl_addr) == 16);
+
+/* Action structure for OFPAT10_SET_NW_SRC/DST and OFPAT11_SET_NW_SRC/DST. */
+struct ofp_action_nw_addr {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be32 nw_addr;               /* IP address. */
+};
+OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
+
+/* Action structure for OFPAT10_SET_NW_TOS and OFPAT11_SET_NW_TOS. */
+struct ofp_action_nw_tos {
+    ovs_be16 type;                  /* Type.. */
+    ovs_be16 len;                   /* Length is 8. */
+    uint8_t nw_tos;                 /* DSCP in high 6 bits, rest ignored. */
+    uint8_t pad[3];
+};
+OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
+
+/* Action structure for OFPAT10_SET_TP_SRC/DST and OFPAT11_SET_TP_SRC/DST. */
+struct ofp_action_tp_port {
+    ovs_be16 type;                  /* Type. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be16 tp_port;               /* TCP/UDP port. */
+    uint8_t pad[2];
+};
+OFP_ASSERT(sizeof(struct ofp_action_tp_port) == 8);
+
 /* Why was this flow removed? */
 enum ofp_flow_removed_reason {
     OFPRR_IDLE_TIMEOUT,         /* Flow idle time exceeded idle_timeout. */
 /* Why was this flow removed? */
 enum ofp_flow_removed_reason {
     OFPRR_IDLE_TIMEOUT,         /* Flow idle time exceeded idle_timeout. */
index 12cc0b0..2254f53 100644 (file)
@@ -36,7 +36,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 /* Converting OpenFlow 1.0 to ofpacts. */
 
 static enum ofperr
 /* Converting OpenFlow 1.0 to ofpacts. */
 
 static enum ofperr
-output_from_openflow10(const struct ofp_action_output *oao,
+output_from_openflow10(const struct ofp10_action_output *oao,
                        struct ofpbuf *out)
 {
     struct ofpact_output *output;
                        struct ofpbuf *out)
 {
     struct ofpact_output *output;
@@ -216,7 +216,8 @@ decode_openflow10_action(const union ofp_action *a,
 }
 
 static enum ofperr
 }
 
 static enum ofperr
-ofpact_from_openflow10__(const union ofp_action *a, struct ofpbuf *out)
+ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
+                  struct ofpbuf *out)
 {
     const struct nx_action_resubmit *nar;
     const struct nx_action_set_tunnel *nast;
 {
     const struct nx_action_resubmit *nar;
     const struct nx_action_set_tunnel *nast;
@@ -224,79 +225,15 @@ ofpact_from_openflow10__(const union ofp_action *a, struct ofpbuf *out)
     const struct nx_action_note *nan;
     const struct nx_action_set_tunnel64 *nast64;
     struct ofpact_tunnel *tunnel;
     const struct nx_action_note *nan;
     const struct nx_action_set_tunnel64 *nast64;
     struct ofpact_tunnel *tunnel;
-    enum ofputil_action_code code;
-    enum ofperr error;
-
-    error = decode_openflow10_action(a, &code);
-    if (error) {
-        return error;
-    }
+    enum ofperr error = 0;
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
 
     switch (code) {
     case OFPUTIL_ACTION_INVALID:
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
         NOT_REACHED();
 
         NOT_REACHED();
 
-    case OFPUTIL_OFPAT10_OUTPUT:
-        return output_from_openflow10((const struct ofp_action_output *) a,
-                                      out);
-
-    case OFPUTIL_OFPAT10_SET_VLAN_VID:
-        if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
-            return OFPERR_OFPBAC_BAD_ARGUMENT;
-        }
-        ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_VLAN_PCP:
-        if (a->vlan_pcp.vlan_pcp & ~7) {
-            return OFPERR_OFPBAC_BAD_ARGUMENT;
-        }
-        ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
-        break;
-
-    case OFPUTIL_OFPAT10_STRIP_VLAN:
-        ofpact_put_STRIP_VLAN(out);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_DL_SRC:
-        memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
-               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_DL_DST:
-        memcpy(ofpact_put_SET_ETH_DST(out)->mac,
-               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_NW_SRC:
-        ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
-        break;
-
-    case OFPUTIL_OFPAT10_SET_NW_DST:
-        ofpact_put_SET_IPV4_DST(out)->ipv4 = a->nw_addr.nw_addr;
-        break;
-
-    case OFPUTIL_OFPAT10_SET_NW_TOS:
-        if (a->nw_tos.nw_tos & ~IP_DSCP_MASK) {
-            return OFPERR_OFPBAC_BAD_ARGUMENT;
-        }
-        ofpact_put_SET_IPV4_DSCP(out)->dscp = a->nw_tos.nw_tos;
-        break;
-
-    case OFPUTIL_OFPAT10_SET_TP_SRC:
-        ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(a->tp_port.tp_port);
-        break;
-
-    case OFPUTIL_OFPAT10_SET_TP_DST:
-        ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
-
-        break;
-
-    case OFPUTIL_OFPAT10_ENQUEUE:
-        error = enqueue_from_openflow10((const struct ofp_action_enqueue *) a,
-                                        out);
-        break;
-
     case OFPUTIL_NXAST_RESUBMIT:
         resubmit_from_openflow((const struct nx_action_resubmit *) a, out);
         break;
     case OFPUTIL_NXAST_RESUBMIT:
         resubmit_from_openflow((const struct nx_action_resubmit *) a, out);
         break;
@@ -389,6 +326,91 @@ ofpact_from_openflow10__(const union ofp_action *a, struct ofpbuf *out)
     return error;
 }
 
     return error;
 }
 
+static enum ofperr
+ofpact_from_openflow10(const union ofp_action *a, struct ofpbuf *out)
+{
+    enum ofputil_action_code code;
+    enum ofperr error;
+
+    error = decode_openflow10_action(a, &code);
+    if (error) {
+        return error;
+    }
+
+    switch (code) {
+    case OFPUTIL_ACTION_INVALID:
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
+        NOT_REACHED();
+
+    case OFPUTIL_OFPAT10_OUTPUT:
+        return output_from_openflow10(&a->output10, out);
+
+    case OFPUTIL_OFPAT10_SET_VLAN_VID:
+        if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_VLAN_PCP:
+        if (a->vlan_pcp.vlan_pcp & ~7) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
+        break;
+
+    case OFPUTIL_OFPAT10_STRIP_VLAN:
+        ofpact_put_STRIP_VLAN(out);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_DL_SRC:
+        memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
+               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_DL_DST:
+        memcpy(ofpact_put_SET_ETH_DST(out)->mac,
+               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_NW_SRC:
+        ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT10_SET_NW_DST:
+        ofpact_put_SET_IPV4_DST(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT10_SET_NW_TOS:
+        if (a->nw_tos.nw_tos & ~IP_DSCP_MASK) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_IPV4_DSCP(out)->dscp = a->nw_tos.nw_tos;
+        break;
+
+    case OFPUTIL_OFPAT10_SET_TP_SRC:
+        ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(a->tp_port.tp_port);
+        break;
+
+    case OFPUTIL_OFPAT10_SET_TP_DST:
+        ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
+
+        break;
+
+    case OFPUTIL_OFPAT10_ENQUEUE:
+        error = enqueue_from_openflow10((const struct ofp_action_enqueue *) a,
+                                        out);
+        break;
+
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
+       return ofpact_from_nxast(a, code, out);
+    }
+
+    return error;
+}
+
 static inline union ofp_action *
 action_next(const union ofp_action *a)
 {
 static inline union ofp_action *
 action_next(const union ofp_action *a)
 {
@@ -413,14 +435,14 @@ action_is_valid(const union ofp_action *a, size_t n_actions)
           (ITER) = action_next(ITER)))
 
 static enum ofperr
           (ITER) = action_next(ITER)))
 
 static enum ofperr
-ofpact_from_openflow10(const union ofp_action *in, size_t n_in,
-                       struct ofpbuf *out)
+ofpacts_from_openflow10(const union ofp_action *in, size_t n_in,
+                        struct ofpbuf *out)
 {
     const union ofp_action *a;
     size_t left;
 
     ACTION_FOR_EACH (a, left, in, n_in) {
 {
     const union ofp_action *a;
     size_t left;
 
     ACTION_FOR_EACH (a, left, in, n_in) {
-        enum ofperr error = ofpact_from_openflow10__(a, out);
+        enum ofperr error = ofpact_from_openflow10(a, out);
         if (error) {
             VLOG_WARN_RL(&rl, "bad action at offset %td (%s)",
                          (a - in) * sizeof *a, ofperr_get_name(error));
         if (error) {
             VLOG_WARN_RL(&rl, "bad action at offset %td (%s)",
                          (a - in) * sizeof *a, ofperr_get_name(error));
@@ -437,16 +459,12 @@ ofpact_from_openflow10(const union ofp_action *in, size_t n_in,
     return 0;
 }
 
     return 0;
 }
 
-/* Attempts to convert 'actions_len' bytes of OpenFlow actions from the front
- * of 'openflow' into ofpacts.  On success, replaces any existing content in
- * 'ofpacts' by the converted ofpacts; on failure, clears 'ofpacts'.  Returns 0
- * if successful, otherwise an OpenFlow error.
- *
- * This function does not check that the actions are valid in a given context.
- * The caller should do so, with ofpacts_check(). */
-enum ofperr
-ofpacts_pull_openflow(struct ofpbuf *openflow, unsigned int actions_len,
-                      struct ofpbuf *ofpacts)
+static enum ofperr
+ofpacts_pull_actions(struct ofpbuf *openflow, unsigned int actions_len,
+                     struct ofpbuf *ofpacts,
+                     enum ofperr (*translate)(const union ofp_action *actions,
+                                              size_t n_actions,
+                                              struct ofpbuf *ofpacts))
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     const union ofp_action *actions;
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     const union ofp_action *actions;
@@ -468,13 +486,420 @@ ofpacts_pull_openflow(struct ofpbuf *openflow, unsigned int actions_len,
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
         return OFPERR_OFPBRC_BAD_LEN;
     }
 
-    error = ofpact_from_openflow10(actions, actions_len / OFP_ACTION_ALIGN,
-                                   ofpacts);
+    error = translate(actions, actions_len / OFP_ACTION_ALIGN, ofpacts);
     if (error) {
         ofpbuf_clear(ofpacts);
     }
     if (error) {
         ofpbuf_clear(ofpacts);
     }
+    return error;
+}
+
+/* Attempts to convert 'actions_len' bytes of OpenFlow 1.0 actions from the
+ * front of 'openflow' into ofpacts.  On success, replaces any existing content
+ * in 'ofpacts' by the converted ofpacts; on failure, clears 'ofpacts'.
+ * Returns 0 if successful, otherwise an OpenFlow error.
+ *
+ * This function does not check that the actions are valid in a given context.
+ * The caller should do so, with ofpacts_check(). */
+enum ofperr
+ofpacts_pull_openflow10(struct ofpbuf *openflow, unsigned int actions_len,
+                        struct ofpbuf *ofpacts)
+{
+    return ofpacts_pull_actions(openflow, actions_len, ofpacts,
+                                ofpacts_from_openflow10);
+}
+\f
+/* OpenFlow 1.1 actions. */
+
+/* Parses 'a' to determine its type.  On success stores the correct type into
+ * '*code' and returns 0.  On failure returns an OFPERR_* error code and
+ * '*code' is indeterminate.
+ *
+ * The caller must have already verified that 'a''s length is potentially
+ * correct (that is, a->header.len is nonzero and a multiple of sizeof(union
+ * ofp_action) and no longer than the amount of space allocated to 'a').
+ *
+ * This function verifies that 'a''s length is correct for the type of action
+ * that it represents. */
+static enum ofperr
+decode_openflow11_action(const union ofp_action *a,
+                         enum ofputil_action_code *code)
+{
+    switch (a->type) {
+    case CONSTANT_HTONS(OFPAT11_EXPERIMENTER):
+        return decode_nxast_action(a, code);
+
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)                          \
+        case CONSTANT_HTONS(ENUM):                                  \
+            if (a->header.len == htons(sizeof(struct STRUCT))) {    \
+                *code = OFPUTIL_##ENUM;                             \
+                return 0;                                           \
+            } else {                                                \
+                return OFPERR_OFPBAC_BAD_LEN;                       \
+            }                                                       \
+            break;
+#include "ofp-util.def"
+
+    default:
+        return OFPERR_OFPBAC_BAD_TYPE;
+    }
+}
+
+static enum ofperr
+output_from_openflow11(const struct ofp11_action_output *oao,
+                       struct ofpbuf *out)
+{
+    struct ofpact_output *output;
+    enum ofperr error;
+
+    output = ofpact_put_OUTPUT(out);
+    output->max_len = ntohs(oao->max_len);
+
+    error = ofputil_port_from_ofp11(oao->port, &output->port);
+    if (error) {
+        return error;
+    }
+
+    return ofputil_check_output_port(output->port, OFPP_MAX);
+}
+
+static enum ofperr
+ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
+{
+    enum ofputil_action_code code;
+    enum ofperr error;
+
+    error = decode_openflow11_action(a, &code);
+    if (error) {
+        return error;
+    }
+
+    switch (code) {
+    case OFPUTIL_ACTION_INVALID:
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
+        NOT_REACHED();
+
+    case OFPUTIL_OFPAT11_OUTPUT:
+        return output_from_openflow11((const struct ofp11_action_output *) a,
+                                      out);
+
+    case OFPUTIL_OFPAT11_SET_VLAN_VID:
+        if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_VID(out)->vlan_vid = ntohs(a->vlan_vid.vlan_vid);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_VLAN_PCP:
+        if (a->vlan_pcp.vlan_pcp & ~7) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_VLAN_PCP(out)->vlan_pcp = a->vlan_pcp.vlan_pcp;
+        break;
+
+    case OFPUTIL_OFPAT11_SET_DL_SRC:
+        memcpy(ofpact_put_SET_ETH_SRC(out)->mac,
+               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_DL_DST:
+        memcpy(ofpact_put_SET_ETH_DST(out)->mac,
+               ((const struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_NW_SRC:
+        ofpact_put_SET_IPV4_SRC(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT11_SET_NW_DST:
+        ofpact_put_SET_IPV4_DST(out)->ipv4 = a->nw_addr.nw_addr;
+        break;
+
+    case OFPUTIL_OFPAT11_SET_NW_TOS:
+        if (a->nw_tos.nw_tos & ~IP_DSCP_MASK) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_SET_IPV4_DSCP(out)->dscp = a->nw_tos.nw_tos;
+        break;
+
+    case OFPUTIL_OFPAT11_SET_TP_SRC:
+        ofpact_put_SET_L4_SRC_PORT(out)->port = ntohs(a->tp_port.tp_port);
+        break;
+
+    case OFPUTIL_OFPAT11_SET_TP_DST:
+        ofpact_put_SET_L4_DST_PORT(out)->port = ntohs(a->tp_port.tp_port);
+        break;
+
+#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
+#include "ofp-util.def"
+        return ofpact_from_nxast(a, code, out);
+    }
+
+    return error;
+}
+
+static enum ofperr
+ofpacts_from_openflow11(const union ofp_action *in, size_t n_in,
+                        struct ofpbuf *out)
+{
+    const union ofp_action *a;
+    size_t left;
+
+    ACTION_FOR_EACH (a, left, in, n_in) {
+        enum ofperr error = ofpact_from_openflow11(a, out);
+        if (error) {
+            VLOG_WARN_RL(&rl, "bad action at offset %td (%s)",
+                         (a - in) * sizeof *a, ofperr_get_name(error));
+            return error;
+        }
+    }
+    if (left) {
+        VLOG_WARN_RL(&rl, "bad action format at offset %zu",
+                     (n_in - left) * sizeof *a);
+        return OFPERR_OFPBAC_BAD_LEN;
+    }
+
+    return 0;
+}
+\f
+/* OpenFlow 1.1 instructions. */
+
+#define OVS_INSTRUCTIONS                                    \
+    DEFINE_INST(OFPIT11_GOTO_TABLE,                         \
+                ofp11_instruction_goto_table,     false,    \
+                "goto_table")                               \
+                                                            \
+    DEFINE_INST(OFPIT11_WRITE_METADATA,                     \
+                ofp11_instruction_write_metadata, false,    \
+                "write_metadata")                           \
+                                                            \
+    DEFINE_INST(OFPIT11_WRITE_ACTIONS,                      \
+                ofp11_instruction_actions,        true,     \
+                "write_actions")                            \
+                                                            \
+    DEFINE_INST(OFPIT11_APPLY_ACTIONS,                      \
+                ofp11_instruction_actions,        true,     \
+                "apply_actions")                            \
+                                                            \
+    DEFINE_INST(OFPIT11_CLEAR_ACTIONS,                      \
+                ofp11_instruction,                false,    \
+                "clear_actions")
+
+enum ovs_instruction_type {
+#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) OVSINST_##ENUM,
+    OVS_INSTRUCTIONS
+#undef DEFINE_INST
+};
+
+enum {
+#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
+    N_OVS_INSTRUCTIONS = OVS_INSTRUCTIONS
+#undef DEFINE_INST
+};
+
+#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME)             \
+    static inline void                                          \
+    instruction_init_##ENUM(struct STRUCT *s)                   \
+    {                                                           \
+        memset(s, 0, sizeof *s);                                \
+        s->type = htons(ENUM);                                  \
+        s->len = htons(sizeof *s);                              \
+    }                                                           \
+                                                                \
+    static inline struct STRUCT *                               \
+    instruction_put_##ENUM(struct ofpbuf *buf)                  \
+    {                                                           \
+        struct STRUCT *s = ofpbuf_put_uninit(buf, sizeof *s);   \
+        instruction_init_##ENUM(s);                             \
+        return s;                                               \
+    }
+OVS_INSTRUCTIONS
+#undef DEFINE_INST
+
+static inline struct ofp11_instruction *
+instruction_next(const struct ofp11_instruction *inst)
+{
+    return ((struct ofp11_instruction *) (void *)
+            ((uint8_t *) inst + ntohs(inst->len)));
+}
+
+static inline bool
+instruction_is_valid(const struct ofp11_instruction *inst,
+                     size_t n_instructions)
+{
+    uint16_t len = ntohs(inst->len);
+    return (!(len % OFP11_INSTRUCTION_ALIGN)
+            && len >= sizeof *inst
+            && len / sizeof *inst <= n_instructions);
+}
+
+/* This macro is careful to check for instructions with bad lengths. */
+#define INSTRUCTION_FOR_EACH(ITER, LEFT, INSTRUCTIONS, N_INSTRUCTIONS)  \
+    for ((ITER) = (INSTRUCTIONS), (LEFT) = (N_INSTRUCTIONS);            \
+         (LEFT) > 0 && instruction_is_valid(ITER, LEFT);                \
+         ((LEFT) -= (ntohs((ITER)->len)                                 \
+                     / sizeof(struct ofp11_instruction)),               \
+          (ITER) = instruction_next(ITER)))
+
+static enum ofperr
+decode_openflow11_instruction(const struct ofp11_instruction *inst,
+                              enum ovs_instruction_type *type)
+{
+    uint16_t len = ntohs(inst->len);
+
+    switch (inst->type) {
+    case CONSTANT_HTONS(OFPIT11_EXPERIMENTER):
+        return OFPERR_OFPBIC_BAD_EXPERIMENTER;
+
+#define DEFINE_INST(ENUM, STRUCT, EXTENSIBLE, NAME)     \
+        case CONSTANT_HTONS(ENUM):                      \
+            if (EXTENSIBLE                              \
+                ? len >= sizeof(struct STRUCT)          \
+                : len == sizeof(struct STRUCT)) {       \
+                *type = OVSINST_##ENUM;                 \
+                return 0;                               \
+            } else {                                    \
+                return OFPERR_OFPBIC_BAD_LEN;           \
+            }
+OVS_INSTRUCTIONS
+#undef DEFINE_INST
+
+    default:
+        return OFPERR_OFPBIC_UNKNOWN_INST;
+    }
+}
+
+static enum ofperr
+decode_openflow11_instructions(const struct ofp11_instruction insts[],
+                               size_t n_insts,
+                               const struct ofp11_instruction *out[])
+{
+    const struct ofp11_instruction *inst;
+    size_t left;
+
+    memset(out, 0, N_OVS_INSTRUCTIONS * sizeof *out);
+    INSTRUCTION_FOR_EACH (inst, left, insts, n_insts) {
+        enum ovs_instruction_type type;
+        enum ofperr error;
+
+        error = decode_openflow11_instruction(inst, &type);
+        if (error) {
+            return error;
+        }
+
+        if (out[type]) {
+            return OFPERR_NXBIC_DUP_TYPE;
+        }
+        out[type] = inst;
+    }
+
+    if (left) {
+        VLOG_WARN_RL(&rl, "bad instruction format at offset %zu",
+                     (n_insts - left) * sizeof *inst);
+        return OFPERR_OFPBIC_BAD_LEN;
+    }
     return 0;
 }
     return 0;
 }
+
+static void
+get_actions_from_instruction(const struct ofp11_instruction *inst,
+                         const union ofp_action **actions,
+                         size_t *n_actions)
+{
+    *actions = (const union ofp_action *) (inst + 1);
+    *n_actions = (ntohs(inst->len) - sizeof *inst) / OFP11_INSTRUCTION_ALIGN;
+}
+
+/* Attempts to convert 'actions_len' bytes of OpenFlow 1.1 actions from the
+ * front of 'openflow' into ofpacts.  On success, replaces any existing content
+ * in 'ofpacts' by the converted ofpacts; on failure, clears 'ofpacts'.
+ * Returns 0 if successful, otherwise an OpenFlow error.
+ *
+ * In most places in OpenFlow 1.1 and 1.2, actions appear encapsulated in
+ * instructions, so you should call ofpacts_pull_openflow11_instructions()
+ * instead of this function.
+ *
+ * This function does not check that the actions are valid in a given context.
+ * The caller should do so, with ofpacts_check(). */
+enum ofperr
+ofpacts_pull_openflow11_actions(struct ofpbuf *openflow,
+                                unsigned int actions_len,
+                                struct ofpbuf *ofpacts)
+{
+    enum ofperr error;
+
+    error = ofpacts_pull_actions(openflow, actions_len, ofpacts,
+                                 ofpacts_from_openflow11);
+    if (!error) {
+        ofpact_pad(ofpacts);
+    }
+    return error;
+}
+
+enum ofperr
+ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
+                                     unsigned int instructions_len,
+                                     struct ofpbuf *ofpacts)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+    const struct ofp11_instruction *instructions;
+    const struct ofp11_instruction *insts[N_OVS_INSTRUCTIONS];
+    enum ofperr error;
+
+    ofpbuf_clear(ofpacts);
+
+    if (instructions_len % OFP11_INSTRUCTION_ALIGN != 0) {
+        VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u is not a "
+                     "multiple of %d",
+                     instructions_len, OFP11_INSTRUCTION_ALIGN);
+        error = OFPERR_OFPBIC_BAD_LEN;
+        goto exit;
+    }
+
+    instructions = ofpbuf_try_pull(openflow, instructions_len);
+    if (instructions == NULL) {
+        VLOG_WARN_RL(&rl, "OpenFlow message instructions length %u exceeds "
+                     "remaining message length (%zu)",
+                     instructions_len, openflow->size);
+        error = OFPERR_OFPBIC_BAD_LEN;
+        goto exit;
+    }
+
+    error = decode_openflow11_instructions(
+        instructions, instructions_len / OFP11_INSTRUCTION_ALIGN,
+        insts);
+    if (error) {
+        goto exit;
+    }
+
+    if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) {
+        const union ofp_action *actions;
+        size_t n_actions;
+
+        get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS],
+                                     &actions, &n_actions);
+        error = ofpacts_from_openflow11(actions, n_actions, ofpacts);
+        if (error) {
+            goto exit;
+        }
+    }
+
+    ofpact_pad(ofpacts);
+
+    if (insts[OVSINST_OFPIT11_GOTO_TABLE] ||
+        insts[OVSINST_OFPIT11_WRITE_METADATA] ||
+        insts[OVSINST_OFPIT11_WRITE_ACTIONS] ||
+        insts[OVSINST_OFPIT11_CLEAR_ACTIONS]) {
+        error = OFPERR_OFPBIC_UNSUP_INST;
+        goto exit;
+    }
+
+exit:
+    if (error) {
+        ofpbuf_clear(ofpacts);
+    }
+    return error;
+}
 \f
 static enum ofperr
 ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
 \f
 static enum ofperr
 ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
@@ -744,7 +1169,7 @@ static void
 ofpact_output_to_openflow10(const struct ofpact_output *output,
                             struct ofpbuf *out)
 {
 ofpact_output_to_openflow10(const struct ofpact_output *output,
                             struct ofpbuf *out)
 {
-    struct ofp_action_output *oao;
+    struct ofp10_action_output *oao;
 
     oao = ofputil_put_OFPAT10_OUTPUT(out);
     oao->port = htons(output->port);
 
     oao = ofputil_put_OFPAT10_OUTPUT(out);
     oao->port = htons(output->port);
@@ -844,12 +1269,12 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     }
 }
 
     }
 }
 
-/* Converts the 'ofpacts_len' bytes of ofpacts in 'ofpacts' into OpenFlow
+/* Converts the 'ofpacts_len' bytes of ofpacts in 'ofpacts' into OpenFlow 1.0
  * actions in 'openflow', appending the actions to any existing data in
  * 'openflow'. */
 void
  * actions in 'openflow', appending the actions to any existing data in
  * 'openflow'. */
 void
-ofpacts_to_openflow(const struct ofpact ofpacts[], size_t ofpacts_len,
-                    struct ofpbuf *openflow)
+ofpacts_put_openflow10(const struct ofpact ofpacts[], size_t ofpacts_len,
+                       struct ofpbuf *openflow)
 {
     const struct ofpact *a;
 
 {
     const struct ofpact *a;
 
@@ -858,6 +1283,136 @@ ofpacts_to_openflow(const struct ofpact ofpacts[], size_t ofpacts_len,
     }
 }
 \f
     }
 }
 \f
+/* Converting ofpacts to OpenFlow 1.1. */
+
+static void
+ofpact_output_to_openflow11(const struct ofpact_output *output,
+                            struct ofpbuf *out)
+{
+    struct ofp11_action_output *oao;
+
+    oao = ofputil_put_OFPAT11_OUTPUT(out);
+    oao->port = ofputil_port_to_ofp11(output->port);
+    oao->max_len = htons(output->max_len);
+}
+
+static void
+ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
+{
+    switch (a->type) {
+    case OFPACT_OUTPUT:
+        return ofpact_output_to_openflow11(ofpact_get_OUTPUT(a), out);
+
+    case OFPACT_ENQUEUE:
+        /* XXX */
+        break;
+
+    case OFPACT_SET_VLAN_VID:
+        ofputil_put_OFPAT11_SET_VLAN_VID(out)->vlan_vid
+            = htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid);
+        break;
+
+    case OFPACT_SET_VLAN_PCP:
+        ofputil_put_OFPAT11_SET_VLAN_PCP(out)->vlan_pcp
+            = ofpact_get_SET_VLAN_PCP(a)->vlan_pcp;
+        break;
+
+    case OFPACT_STRIP_VLAN:
+        /* XXX */
+        break;
+
+    case OFPACT_SET_ETH_SRC:
+        memcpy(ofputil_put_OFPAT11_SET_DL_SRC(out)->dl_addr,
+               ofpact_get_SET_ETH_SRC(a)->mac, ETH_ADDR_LEN);
+        break;
+
+    case OFPACT_SET_ETH_DST:
+        memcpy(ofputil_put_OFPAT11_SET_DL_DST(out)->dl_addr,
+               ofpact_get_SET_ETH_DST(a)->mac, ETH_ADDR_LEN);
+        break;
+
+    case OFPACT_SET_IPV4_SRC:
+        ofputil_put_OFPAT11_SET_NW_SRC(out)->nw_addr
+            = ofpact_get_SET_IPV4_SRC(a)->ipv4;
+        break;
+
+    case OFPACT_SET_IPV4_DST:
+        ofputil_put_OFPAT11_SET_NW_DST(out)->nw_addr
+            = ofpact_get_SET_IPV4_DST(a)->ipv4;
+        break;
+
+    case OFPACT_SET_IPV4_DSCP:
+        ofputil_put_OFPAT11_SET_NW_TOS(out)->nw_tos
+            = ofpact_get_SET_IPV4_DSCP(a)->dscp;
+        break;
+
+    case OFPACT_SET_L4_SRC_PORT:
+        ofputil_put_OFPAT11_SET_TP_SRC(out)->tp_port
+            = htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
+        break;
+
+    case OFPACT_SET_L4_DST_PORT:
+        ofputil_put_OFPAT11_SET_TP_DST(out)->tp_port
+            = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
+        break;
+
+    case OFPACT_CONTROLLER:
+    case OFPACT_OUTPUT_REG:
+    case OFPACT_BUNDLE:
+    case OFPACT_REG_MOVE:
+    case OFPACT_REG_LOAD:
+    case OFPACT_DEC_TTL:
+    case OFPACT_SET_TUNNEL:
+    case OFPACT_SET_QUEUE:
+    case OFPACT_POP_QUEUE:
+    case OFPACT_FIN_TIMEOUT:
+    case OFPACT_RESUBMIT:
+    case OFPACT_LEARN:
+    case OFPACT_MULTIPATH:
+    case OFPACT_AUTOPATH:
+    case OFPACT_NOTE:
+    case OFPACT_EXIT:
+        ofpact_to_nxast(a, out);
+        break;
+    }
+}
+
+/* Converts the ofpacts in 'ofpacts' (terminated by OFPACT_END) into OpenFlow
+ * 1.1 actions in 'openflow', appending the actions to any existing data in
+ * 'openflow'. */
+void
+ofpacts_put_openflow11_actions(const struct ofpact ofpacts[],
+                               size_t ofpacts_len, struct ofpbuf *openflow)
+{
+    const struct ofpact *a;
+
+    OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+        ofpact_to_openflow11(a, openflow);
+    }
+}
+
+void
+ofpacts_put_openflow11_instructions(const struct ofpact ofpacts[],
+                                    size_t ofpacts_len,
+                                    struct ofpbuf *openflow)
+{
+    struct ofp11_instruction_actions *oia;
+    size_t ofs;
+
+    /* Put an OFPIT11_APPLY_ACTIONS instruction and fill it in. */
+    ofs = openflow->size;
+    instruction_put_OFPIT11_APPLY_ACTIONS(openflow);
+    ofpacts_put_openflow11_actions(ofpacts, ofpacts_len, openflow);
+
+    /* Update the instruction's length (or, if it's empty, delete it). */
+    oia = ofpbuf_at_assert(openflow, ofs, sizeof *oia);
+    if (openflow->size > ofs + sizeof *oia) {
+        oia->len = htons(openflow->size - ofs);
+    } else {
+        openflow->size = ofs;
+    }
+}
+\f
 /* Returns true if 'action' outputs to 'port', false otherwise. */
 static bool
 ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
 /* Returns true if 'action' outputs to 'port', false otherwise. */
 static bool
 ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
index 59b9846..7c9cb05 100644 (file)
@@ -381,15 +381,26 @@ struct ofpact_note {
 };
 
 /* Converting OpenFlow to ofpacts. */
 };
 
 /* Converting OpenFlow to ofpacts. */
-enum ofperr ofpacts_pull_openflow(struct ofpbuf *openflow,
-                                  unsigned int actions_len,
-                                  struct ofpbuf *ofpacts);
+enum ofperr ofpacts_pull_openflow10(struct ofpbuf *openflow,
+                                    unsigned int actions_len,
+                                    struct ofpbuf *ofpacts);
+enum ofperr ofpacts_pull_openflow11_actions(struct ofpbuf *openflow,
+                                            unsigned int actions_len,
+                                            struct ofpbuf *ofpacts);
+enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
+                                                 unsigned int instructions_len,
+                                                 struct ofpbuf *ofpacts);
 enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len,
                           const struct flow *, int max_ports);
 
 /* Converting ofpacts to OpenFlow. */
 enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len,
                           const struct flow *, int max_ports);
 
 /* Converting ofpacts to OpenFlow. */
-void ofpacts_to_openflow(const struct ofpact[], size_t ofpacts_len,
-                         struct ofpbuf *openflow);
+void ofpacts_put_openflow10(const struct ofpact[], size_t ofpacts_len,
+                            struct ofpbuf *openflow);
+void ofpacts_put_openflow11_actions(const struct ofpact[], size_t ofpacts_len,
+                                    struct ofpbuf *openflow);
+void ofpacts_put_openflow11_instructions(const struct ofpact[],
+                                         size_t ofpacts_len,
+                                         struct ofpbuf *openflow);
 
 /* Working with ofpacts. */
 bool ofpacts_output_to_port(const struct ofpact[], size_t ofpacts_len,
 
 /* Working with ofpacts. */
 bool ofpacts_output_to_port(const struct ofpact[], size_t ofpacts_len,
index 5f908db..61cef41 100644 (file)
@@ -193,7 +193,7 @@ enum ofperr {
 /* ## --------------------- ## */
 
     /* OF1.1+(3).  Error in instruction list. */
 /* ## --------------------- ## */
 
     /* OF1.1+(3).  Error in instruction list. */
-    OFPERR_OFPET_BAD_INSTRUCTION,
+    OFPERR_OFPIT_BAD_INSTRUCTION,
 
     /* OF1.1+(3,0).  Unknown instruction. */
     OFPERR_OFPBIC_UNKNOWN_INST,
 
     /* OF1.1+(3,0).  Unknown instruction. */
     OFPERR_OFPBIC_UNKNOWN_INST,
@@ -222,6 +222,9 @@ enum ofperr {
     /* OF1.2+(3,8).  Permissions error. */
     OFPERR_OFPBIC_EPERM,
 
     /* OF1.2+(3,8).  Permissions error. */
     OFPERR_OFPBIC_EPERM,
 
+    /* NX1.1+(3,256).  Duplicate instruction type in set of instructions. */
+    OFPERR_NXBIC_DUP_TYPE,
+
 /* ## --------------- ## */
 /* ## OFPET_BAD_MATCH ## */
 /* ## --------------- ## */
 /* ## --------------- ## */
 /* ## OFPET_BAD_MATCH ## */
 /* ## --------------- ## */
index 6236e50..922e296 100644 (file)
@@ -293,10 +293,12 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         NOT_REACHED();
 
     case OFPUTIL_OFPAT10_OUTPUT:
         NOT_REACHED();
 
     case OFPUTIL_OFPAT10_OUTPUT:
+    case OFPUTIL_OFPAT11_OUTPUT:
         parse_output(arg, ofpacts);
         break;
 
     case OFPUTIL_OFPAT10_SET_VLAN_VID:
         parse_output(arg, ofpacts);
         break;
 
     case OFPUTIL_OFPAT10_SET_VLAN_VID:
+    case OFPUTIL_OFPAT11_SET_VLAN_VID:
         vid = str_to_u32(arg);
         if (vid & ~VLAN_VID_MASK) {
             ovs_fatal(0, "%s: not a valid VLAN VID", arg);
         vid = str_to_u32(arg);
         if (vid & ~VLAN_VID_MASK) {
             ovs_fatal(0, "%s: not a valid VLAN VID", arg);
@@ -305,6 +307,7 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT10_SET_VLAN_PCP:
         break;
 
     case OFPUTIL_OFPAT10_SET_VLAN_PCP:
+    case OFPUTIL_OFPAT11_SET_VLAN_PCP:
         pcp = str_to_u32(arg);
         if (pcp & ~7) {
             ovs_fatal(0, "%s: not a valid VLAN PCP", arg);
         pcp = str_to_u32(arg);
         if (pcp & ~7) {
             ovs_fatal(0, "%s: not a valid VLAN PCP", arg);
@@ -317,24 +320,29 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT10_SET_DL_SRC:
         break;
 
     case OFPUTIL_OFPAT10_SET_DL_SRC:
+    case OFPUTIL_OFPAT11_SET_DL_SRC:
         str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
         break;
 
     case OFPUTIL_OFPAT10_SET_DL_DST:
         str_to_mac(arg, ofpact_put_SET_ETH_SRC(ofpacts)->mac);
         break;
 
     case OFPUTIL_OFPAT10_SET_DL_DST:
+    case OFPUTIL_OFPAT11_SET_DL_DST:
         str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac);
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_SRC:
         str_to_mac(arg, ofpact_put_SET_ETH_DST(ofpacts)->mac);
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_SRC:
+    case OFPUTIL_OFPAT11_SET_NW_SRC:
         str_to_ip(arg, &ip);
         ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip;
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_DST:
         str_to_ip(arg, &ip);
         ofpact_put_SET_IPV4_SRC(ofpacts)->ipv4 = ip;
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_DST:
+    case OFPUTIL_OFPAT11_SET_NW_DST:
         str_to_ip(arg, &ip);
         ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip;
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_TOS:
         str_to_ip(arg, &ip);
         ofpact_put_SET_IPV4_DST(ofpacts)->ipv4 = ip;
         break;
 
     case OFPUTIL_OFPAT10_SET_NW_TOS:
+    case OFPUTIL_OFPAT11_SET_NW_TOS:
         tos = str_to_u32(arg);
         if (tos & ~IP_DSCP_MASK) {
             ovs_fatal(0, "%s: not a valid TOS", arg);
         tos = str_to_u32(arg);
         if (tos & ~IP_DSCP_MASK) {
             ovs_fatal(0, "%s: not a valid TOS", arg);
@@ -343,10 +351,12 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         break;
 
     case OFPUTIL_OFPAT10_SET_TP_SRC:
         break;
 
     case OFPUTIL_OFPAT10_SET_TP_SRC:
+    case OFPUTIL_OFPAT11_SET_TP_SRC:
         ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg);
         break;
 
     case OFPUTIL_OFPAT10_SET_TP_DST:
         ofpact_put_SET_L4_SRC_PORT(ofpacts)->port = str_to_u32(arg);
         break;
 
     case OFPUTIL_OFPAT10_SET_TP_DST:
+    case OFPUTIL_OFPAT11_SET_TP_DST:
         ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg);
         break;
 
         ofpact_put_SET_L4_DST_PORT(ofpacts)->port = str_to_u32(arg);
         break;
 
index 4864815..834bb62 100644 (file)
@@ -1687,7 +1687,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         ofputil_normalize_rule(&fm->cr);
 
         /* Now get the actions. */
         ofputil_normalize_rule(&fm->cr);
 
         /* Now get the actions. */
-        error = ofpacts_pull_openflow(&b, b.size, ofpacts);
+        error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
         if (error) {
             return error;
         }
         if (error) {
             return error;
         }
@@ -1714,7 +1714,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
         if (error) {
             return error;
         }
         if (error) {
             return error;
         }
-        error = ofpacts_pull_openflow(&b, b.size, ofpacts);
+        error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
         if (error) {
             return error;
         }
         if (error) {
             return error;
         }
@@ -1805,7 +1805,7 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
     }
 
     if (fm->ofpacts) {
     }
 
     if (fm->ofpacts) {
-        ofpacts_to_openflow(fm->ofpacts, fm->ofpacts_len, msg);
+        ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
     }
     update_openflow_length(msg);
     return msg;
     }
     update_openflow_length(msg);
     return msg;
@@ -2048,7 +2048,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
             return EINVAL;
         }
 
             return EINVAL;
         }
 
-        if (ofpacts_pull_openflow(msg, length - sizeof *ofs, ofpacts)) {
+        if (ofpacts_pull_openflow10(msg, length - sizeof *ofs, ofpacts)) {
             return EINVAL;
         }
 
             return EINVAL;
         }
 
@@ -2088,7 +2088,7 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
         }
 
         actions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);
         }
 
         actions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);
-        if (ofpacts_pull_openflow(msg, actions_len, ofpacts)) {
+        if (ofpacts_pull_openflow10(msg, actions_len, ofpacts)) {
             return EINVAL;
         }
 
             return EINVAL;
         }
 
@@ -2159,7 +2159,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
                            htonll(unknown_to_zero(fs->packet_count)));
         put_32aligned_be64(&ofs->byte_count,
                            htonll(unknown_to_zero(fs->byte_count)));
                            htonll(unknown_to_zero(fs->packet_count)));
         put_32aligned_be64(&ofs->byte_count,
                            htonll(unknown_to_zero(fs->byte_count)));
-        ofpacts_to_openflow(fs->ofpacts, fs->ofpacts_len, reply);
+        ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply);
 
         ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
         ofs->length = htons(reply->size - start_ofs);
 
         ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
         ofs->length = htons(reply->size - start_ofs);
@@ -2184,7 +2184,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
         nfs->cookie = fs->cookie;
         nfs->packet_count = htonll(fs->packet_count);
         nfs->byte_count = htonll(fs->byte_count);
         nfs->cookie = fs->cookie;
         nfs->packet_count = htonll(fs->packet_count);
         nfs->byte_count = htonll(fs->byte_count);
-        ofpacts_to_openflow(fs->ofpacts, fs->ofpacts_len, reply);
+        ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply);
 
         nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
         nfs->length = htons(reply->size - start_ofs);
 
         nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
         nfs->length = htons(reply->size - start_ofs);
@@ -2546,7 +2546,7 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
     ofpbuf_use_const(&b, opo, ntohs(opo->header.length));
     ofpbuf_pull(&b, sizeof *opo);
 
     ofpbuf_use_const(&b, opo, ntohs(opo->header.length));
     ofpbuf_pull(&b, sizeof *opo);
 
-    error = ofpacts_pull_openflow(&b, ntohs(opo->actions_len), ofpacts);
+    error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
     if (error) {
         return error;
     }
     if (error) {
         return error;
     }
@@ -3107,7 +3107,7 @@ ofputil_encode_packet_out(const struct ofputil_packet_out *po)
 
     msg = ofpbuf_new(size);
     put_openflow(sizeof *opo, OFPT_PACKET_OUT, msg);
 
     msg = ofpbuf_new(size);
     put_openflow(sizeof *opo, OFPT_PACKET_OUT, msg);
-    ofpacts_to_openflow(po->ofpacts, po->ofpacts_len, msg);
+    ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg);
 
     opo = msg->data;
     opo->buffer_id = htonl(po->buffer_id);
 
     opo = msg->data;
     opo->buffer_id = htonl(po->buffer_id);
@@ -3662,7 +3662,8 @@ ofputil_action_code_from_name(const char *name)
 {
     static const char *names[OFPUTIL_N_ACTIONS] = {
         NULL,
 {
     static const char *names[OFPUTIL_N_ACTIONS] = {
         NULL,
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             NAME,
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           NAME,
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           NAME,
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
 #include "ofp-util.def"
     };
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
 #include "ofp-util.def"
     };
@@ -3691,6 +3692,7 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
 
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)                    \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
 
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)                    \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
+#define OFPAT11_ACTION OFPAT10_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)        \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
 #include "ofp-util.def"
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)        \
     case OFPUTIL_##ENUM: return ofputil_put_##ENUM(buf);
 #include "ofp-util.def"
@@ -3714,6 +3716,7 @@ ofputil_put_action(enum ofputil_action_code code, struct ofpbuf *buf)
         ofputil_init_##ENUM(s);                                 \
         return s;                                               \
     }
         ofputil_init_##ENUM(s);                                 \
         return s;                                               \
     }
+#define OFPAT11_ACTION OFPAT10_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)            \
     void                                                        \
     ofputil_init_##ENUM(struct STRUCT *s)                       \
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)            \
     void                                                        \
     ofputil_init_##ENUM(struct STRUCT *s)                       \
index 8739ac0..974cd8f 100644 (file)
@@ -3,7 +3,7 @@
 #ifndef OFPAT10_ACTION
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)
 #endif
 #ifndef OFPAT10_ACTION
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)
 #endif
-OFPAT10_ACTION(OFPAT10_OUTPUT,       ofp_action_output,   "output")
+OFPAT10_ACTION(OFPAT10_OUTPUT,       ofp10_action_output, "output")
 OFPAT10_ACTION(OFPAT10_SET_VLAN_VID, ofp_action_vlan_vid, "mod_vlan_vid")
 OFPAT10_ACTION(OFPAT10_SET_VLAN_PCP, ofp_action_vlan_pcp, "mod_vlan_pcp")
 OFPAT10_ACTION(OFPAT10_STRIP_VLAN,   ofp_action_header,   "strip_vlan")
 OFPAT10_ACTION(OFPAT10_SET_VLAN_VID, ofp_action_vlan_vid, "mod_vlan_vid")
 OFPAT10_ACTION(OFPAT10_SET_VLAN_PCP, ofp_action_vlan_pcp, "mod_vlan_pcp")
 OFPAT10_ACTION(OFPAT10_STRIP_VLAN,   ofp_action_header,   "strip_vlan")
@@ -15,7 +15,26 @@ OFPAT10_ACTION(OFPAT10_SET_NW_TOS,   ofp_action_nw_tos,   "mod_nw_tos")
 OFPAT10_ACTION(OFPAT10_SET_TP_SRC,   ofp_action_tp_port,  "mod_tp_src")
 OFPAT10_ACTION(OFPAT10_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
 OFPAT10_ACTION(OFPAT10_ENQUEUE,      ofp_action_enqueue,  "enqueue")
 OFPAT10_ACTION(OFPAT10_SET_TP_SRC,   ofp_action_tp_port,  "mod_tp_src")
 OFPAT10_ACTION(OFPAT10_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
 OFPAT10_ACTION(OFPAT10_ENQUEUE,      ofp_action_enqueue,  "enqueue")
-#undef OFPAT10_ACTION
+
+#ifndef OFPAT11_ACTION
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)
+#endif
+OFPAT11_ACTION(OFPAT11_OUTPUT,       ofp11_action_output, "output")
+OFPAT11_ACTION(OFPAT11_SET_VLAN_VID, ofp_action_vlan_vid, "mod_vlan_vid")
+OFPAT11_ACTION(OFPAT11_SET_VLAN_PCP, ofp_action_vlan_pcp, "mod_vlan_pcp")
+OFPAT11_ACTION(OFPAT11_SET_DL_SRC,   ofp_action_dl_addr,  "mod_dl_src")
+OFPAT11_ACTION(OFPAT11_SET_DL_DST,   ofp_action_dl_addr,  "mod_dl_dst")
+OFPAT11_ACTION(OFPAT11_SET_NW_SRC,   ofp_action_nw_addr,  "mod_nw_src")
+OFPAT11_ACTION(OFPAT11_SET_NW_DST,   ofp_action_nw_addr,  "mod_nw_dst")
+OFPAT11_ACTION(OFPAT11_SET_NW_TOS,   ofp_action_nw_tos,   "mod_nw_tos")
+//OFPAT11_ACTION(OFPAT11_SET_NW_ECN,   ofp11_action_nw_ecn, "mod_nw_ecn")
+OFPAT11_ACTION(OFPAT11_SET_TP_SRC,   ofp_action_tp_port,  "mod_tp_src")
+OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  "mod_tp_dst")
+//OFPAT11_ACTION(OFPAT11_PUSH_VLAN,    ofp11_action_push,   "push_vlan")
+//OFPAT11_ACTION(OFPAT11_POP_VLAN,     ofp_action_header,   "pop_vlan")
+//OFPAT11_ACTION(OFPAT11_SET_QUEUE,    ofp11_action_set_queue, "set_queue")
+//OFPAT11_ACTION(OFPAT11_SET_NW_TTL,   ofp11_action_nw_ttl, "set_nw_ttl")
+//OFPAT11_ACTION(OFPAT11_DEC_NW_TTL,   ofp_action_header,   "dec_ttl")
 
 #ifndef NXAST_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
 
 #ifndef NXAST_ACTION
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)
@@ -39,4 +58,7 @@ NXAST_ACTION(NXAST_EXIT,           nx_action_header,       0, "exit")
 NXAST_ACTION(NXAST_DEC_TTL,        nx_action_header,       0, "dec_ttl")
 NXAST_ACTION(NXAST_FIN_TIMEOUT,    nx_action_fin_timeout,  0, "fin_timeout")
 NXAST_ACTION(NXAST_CONTROLLER,     nx_action_controller,   0, "controller")
 NXAST_ACTION(NXAST_DEC_TTL,        nx_action_header,       0, "dec_ttl")
 NXAST_ACTION(NXAST_FIN_TIMEOUT,    nx_action_fin_timeout,  0, "fin_timeout")
 NXAST_ACTION(NXAST_CONTROLLER,     nx_action_controller,   0, "controller")
+
+#undef OFPAT10_ACTION
+#undef OFPAT11_ACTION
 #undef NXAST_ACTION
 #undef NXAST_ACTION
index 30e04c4..703de50 100644 (file)
@@ -598,14 +598,16 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *);
  */
 enum OVS_PACKED_ENUM ofputil_action_code {
     OFPUTIL_ACTION_INVALID,
  */
 enum OVS_PACKED_ENUM ofputil_action_code {
     OFPUTIL_ACTION_INVALID,
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             OFPUTIL_##ENUM,
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           OFPUTIL_##ENUM,
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           OFPUTIL_##ENUM,
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
 #include "ofp-util.def"
 };
 
 /* The number of values of "enum ofputil_action_code". */
 enum {
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) OFPUTIL_##ENUM,
 #include "ofp-util.def"
 };
 
 /* The number of values of "enum ofputil_action_code". */
 enum {
-#define OFPAT10_ACTION(ENUM, STRUCT, NAME)             + 1
+#define OFPAT10_ACTION(ENUM, STRUCT, NAME)           + 1
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)           + 1
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
     OFPUTIL_N_ACTIONS = 1
 #include "ofp-util.def"
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) + 1
     OFPUTIL_N_ACTIONS = 1
 #include "ofp-util.def"
@@ -632,6 +634,9 @@ void *ofputil_put_action(enum ofputil_action_code, struct ofpbuf *buf);
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)              \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
 #define OFPAT10_ACTION(ENUM, STRUCT, NAME)              \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
+#define OFPAT11_ACTION(ENUM, STRUCT, NAME)              \
+    void ofputil_init_##ENUM(struct STRUCT *);          \
+    struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)    \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)    \
     void ofputil_init_##ENUM(struct STRUCT *);          \
     struct STRUCT *ofputil_put_##ENUM(struct ofpbuf *);
index 87dc2ad..18b80b8 100644 (file)
@@ -1372,7 +1372,7 @@ schedule_packet_in(struct ofconn *ofconn, struct ofputil_packet_in pin)
         pin.send_len = pin.packet_len;
     } else {
         /* Caller should have initialized 'send_len' to 'max_len' specified in
         pin.send_len = pin.packet_len;
     } else {
         /* Caller should have initialized 'send_len' to 'max_len' specified in
-         * struct ofp_action_output. */
+         * output action. */
     }
     if (pin.buffer_id != UINT32_MAX) {
         pin.send_len = MIN(pin.send_len, ofconn->miss_send_len);
     }
     if (pin.buffer_id != UINT32_MAX) {
         pin.send_len = MIN(pin.send_len, ofconn->miss_send_len);
index 6f70213..ba8d309 100644 (file)
@@ -119,3 +119,192 @@ AT_CHECK(
   [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-ofp10-actions < input.txt],
   [0], [expout], [experr])
 AT_CLEANUP
   [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-ofp10-actions < input.txt],
   [0], [expout], [experr])
 AT_CLEANUP
+
+AT_SETUP([OpenFlow 1.1 action translation])
+AT_KEYWORDS([OF1.1])
+AT_DATA([test-data], [dnl
+# actions=LOCAL
+0000 0010 fffffffe 04d2 000000000000
+
+# actions=CONTROLLER:1234
+0000 0010 fffffffd 04d2 000000000000
+
+# actions=mod_vlan_vid:9
+0001 0008 0009 0000
+
+# actions=mod_vlan_pcp:6
+0002 0008 06 000000
+
+# actions=mod_dl_src:00:11:22:33:44:55
+0003 0010 001122334455 000000000000
+
+# actions=mod_dl_dst:10:20:30:40:50:60
+0004 0010 102030405060 000000000000
+
+# actions=mod_nw_src:1.2.3.4
+0005 0008 01020304
+
+# actions=mod_nw_dst:192.168.0.1
+0006 0008 c0a80001
+
+# actions=mod_nw_tos:48
+0007 0008 30 000000
+
+# actions=mod_tp_src:80
+0009 0008 0050 0000
+
+# actions=mod_tp_dst:443
+000a 0008 01bb 0000
+
+# actions=resubmit:5
+ffff 0010 00002320 0001 0005 00000000
+
+# actions=set_tunnel:0x12345678
+ffff 0010 00002320 0002 0000 12345678
+
+# actions=set_queue:2309737729
+ffff 0010 00002320 0004 0000 89abcd01
+
+# actions=pop_queue
+ffff 0010 00002320 0005 000000000000
+
+# actions=move:NXM_OF_IN_PORT[]->NXM_OF_VLAN_TCI[]
+ffff 0018 00002320 0006 0010 0000 0000 00000002 00000802
+
+# actions=load:0xf009->NXM_OF_VLAN_TCI[]
+ffff 0018 00002320 0007 000f 00000802 000000000000f009
+
+# actions=note:11.e9.9a.ad.67.f3
+ffff 0010 00002320 0008 11e99aad67f3
+
+# actions=set_tunnel64:0xc426384d49c53d60
+ffff 0018 00002320 0009 000000000000 c426384d49c53d60
+
+# actions=set_tunnel64:0x885f3298
+ffff 0018 00002320 0009 000000000000 00000000885f3298
+
+# actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
+ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
+
+# actions=autopath(2,NXM_NX_REG0[2..30])
+ffff 0018 00002320 000b 009c 00010004 00000002 00000000
+
+# actions=bundle(eth_src,0,hrw,ofport,slaves:4,8)
+ffff 0028 00002320 000c 0001 0000 0000 00000002 0002 0000 00000000 00000000 dnl
+0004 0008 00000000
+
+# actions=bundle_load(eth_src,0,hrw,ofport,NXM_NX_REG0[],slaves:4,8)
+ffff 0028 00002320 000d 0001 0000 0000 00000002 0002 001f 00010004 00000000 dnl
+0004 0008 00000000
+
+# actions=resubmit(10,5)
+ffff 0010 00002320 000e 000a 05 000000
+
+# actions=output:NXM_NX_REG1[5..10]
+ffff 0018 00002320 000f 0145 00010204 ffff 000000000000
+
+# actions=learn(table=2,idle_timeout=10,hard_timeout=20,fin_idle_timeout=2,fin_hard_timeout=4,priority=80,cookie=0x123456789abcdef0,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[])
+ffff 0048 00002320 0010 000a 0014 0050 123456789abcdef0 0000 02 00 0002 0004 dnl
+000c 00000802 0000 00000802 0000 dnl
+0030 00000406 0000 00000206 0000 dnl
+1010 00000002 0000 dnl
+00000000
+
+# actions=exit
+ffff 0010 00002320 0011 000000000000
+
+# actions=dec_ttl
+ffff 0010 00002320 0012 000000000000
+
+# actions=fin_timeout(idle_timeout=10,hard_timeout=20)
+ffff 0010 00002320 0013 000a 0014 0000
+
+# actions=controller(reason=invalid_ttl,max_len=1234,id=5678)
+ffff 0010 00002320 0014 04d2 162e 02 00
+
+])
+sed '/^[[#&]]/d' < test-data > input.txt
+sed -n 's/^# //p; /^$/p' < test-data > expout
+sed -n 's/^& //p' < test-data > experr
+AT_CAPTURE_FILE([input.txt])
+AT_CAPTURE_FILE([expout])
+AT_CAPTURE_FILE([experr])
+AT_CHECK(
+  [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-ofp11-actions < input.txt],
+  [0], [expout], [experr])
+AT_CLEANUP
+
+AT_SETUP([OpenFlow 1.1 instruction translation])
+AT_KEYWORDS([OF1.1])
+AT_DATA([test-data], [dnl
+# actions=LOCAL
+0004 0018 00000000 dnl
+0000 0010 fffffffe 04d2 000000000000
+
+dnl Check that an empty Apply-Actions instruction gets dropped.
+# actions=drop
+#  0: 00 -> (none)
+#  1: 04 -> (none)
+#  2: 00 -> (none)
+#  3: 08 -> (none)
+#  4: 00 -> (none)
+#  5: 00 -> (none)
+#  6: 00 -> (none)
+#  7: 00 -> (none)
+0004 0008 00000000
+
+# bad OF1.1 instructions: NXBIC_DUP_TYPE
+0004 0008 00000000 0004 0008 00000000
+
+dnl Instructions not multiple of 8 in length.
+& ofp_actions|WARN|OpenFlow message instructions length 9 is not a multiple of 8
+# bad OF1.1 instructions: OFPBIC_BAD_LEN
+0004 0009 01 00000000
+
+dnl Goto-Table instruction too long.
+# bad OF1.1 instructions: OFPBIC_BAD_LEN
+0001 0010 01 000000 0000000000000000
+
+dnl Goto-Table not supported yet.
+# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+0001 0008 01 000000
+
+dnl Write-Metadata not supported yet.
+# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+0002 0018 00000000 fedcba9876543210 ffffffffffffffff
+
+dnl Write-Metadata too short.
+# bad OF1.1 instructions: OFPBIC_BAD_LEN
+0002 0010 00000000 fedcba9876543210
+
+dnl Write-Metadata too long.
+# bad OF1.1 instructions: OFPBIC_BAD_LEN
+0002 0020 00000000 fedcba9876543210 ffffffffffffffff 0000000000000000
+
+dnl Write-Actions not supported yet.
+# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+0003 0008 01 000000
+
+dnl Clear-Actions not supported yet.
+# bad OF1.1 instructions: OFPBIC_UNSUP_INST
+0005 0008 01 000000
+
+dnl Experimenter actions not supported yet.
+# bad OF1.1 instructions: OFPBIC_BAD_EXPERIMENTER
+ffff 0008 01 000000
+
+dnl Bad instruction number (0 not assigned).
+# bad OF1.1 instructions: OFPBIC_UNKNOWN_INST
+0000 0008 01 000000
+
+])
+sed '/^[[#&]]/d' < test-data > input.txt
+sed -n 's/^# //p; /^$/p' < test-data > expout
+sed -n 's/^& //p' < test-data > experr
+AT_CAPTURE_FILE([input.txt])
+AT_CAPTURE_FILE([expout])
+AT_CAPTURE_FILE([experr])
+AT_CHECK(
+  [ovs-ofctl '-vPATTERN:console:%c|%p|%m' parse-ofp11-instructions < input.txt],
+  [0], [expout], [experr])
+AT_CLEANUP
index b95f5da..7b0b220 100644 (file)
@@ -2046,7 +2046,7 @@ do_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         /* Convert to ofpacts. */
         ofpbuf_init(&ofpacts, 0);
         size = of10_in.size;
         /* Convert to ofpacts. */
         ofpbuf_init(&ofpacts, 0);
         size = of10_in.size;
-        error = ofpacts_pull_openflow(&of10_in, of10_in.size, &ofpacts);
+        error = ofpacts_pull_openflow10(&of10_in, of10_in.size, &ofpacts);
         if (error) {
             printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error));
             ofpbuf_uninit(&ofpacts);
         if (error) {
             printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error));
             ofpbuf_uninit(&ofpacts);
@@ -2063,7 +2063,7 @@ do_parse_ofp10_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
 
         /* Convert back to ofp10 actions and print differences from input. */
         ofpbuf_init(&of10_out, 0);
 
         /* Convert back to ofp10 actions and print differences from input. */
         ofpbuf_init(&of10_out, 0);
-        ofpacts_to_openflow(ofpacts.data, ofpacts.size, &of10_out);
+        ofpacts_put_openflow10(ofpacts.data, ofpacts.size, &of10_out);
 
         print_differences(of10_in.data, of10_in.size,
                           of10_out.data, of10_out.size);
 
         print_differences(of10_in.data, of10_in.size,
                           of10_out.data, of10_out.size);
@@ -2091,7 +2091,6 @@ do_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         struct ofp11_match match_out;
         struct cls_rule rule;
         enum ofperr error;
         struct ofp11_match match_out;
         struct cls_rule rule;
         enum ofperr error;
-        int i;
 
         /* Parse hex bytes. */
         ofpbuf_init(&match_in, 0);
 
         /* Parse hex bytes. */
         ofpbuf_init(&match_in, 0);
@@ -2118,17 +2117,129 @@ do_parse_ofp11_match(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
         /* Convert back to ofp11_match and print differences from input. */
         ofputil_cls_rule_to_ofp11_match(&rule, &match_out);
 
         /* Convert back to ofp11_match and print differences from input. */
         ofputil_cls_rule_to_ofp11_match(&rule, &match_out);
 
-        for (i = 0; i < sizeof match_out; i++) {
-            uint8_t in = ((const uint8_t *) match_in.data)[i];
-            uint8_t out = ((const uint8_t *) &match_out)[i];
+        print_differences(match_in.data, match_in.size,
+                          &match_out, sizeof match_out);
+        putchar('\n');
 
 
-            if (in != out) {
-                printf("%2d: %02"PRIx8" -> %02"PRIx8"\n", i, in, out);
-            }
+        ofpbuf_uninit(&match_in);
+    }
+    ds_destroy(&in);
+}
+
+/* "parse-ofp11-actions": reads a series of OpenFlow 1.1 action specifications
+ * as hex bytes from stdin, converts them to ofpacts, prints them as strings
+ * on stdout, and then converts them back to hex bytes and prints any
+ * differences from the input. */
+static void
+do_parse_ofp11_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+    struct ds in;
+
+    ds_init(&in);
+    while (!ds_get_preprocessed_line(&in, stdin)) {
+        struct ofpbuf of11_out;
+        struct ofpbuf of11_in;
+        struct ofpbuf ofpacts;
+        enum ofperr error;
+        size_t size;
+        struct ds s;
+
+        /* Parse hex bytes. */
+        ofpbuf_init(&of11_in, 0);
+        if (ofpbuf_put_hex(&of11_in, ds_cstr(&in), NULL)[0] != '\0') {
+            ovs_fatal(0, "Trailing garbage in hex data");
         }
         }
+
+        /* Convert to ofpacts. */
+        ofpbuf_init(&ofpacts, 0);
+        size = of11_in.size;
+        error = ofpacts_pull_openflow11_actions(&of11_in, of11_in.size,
+                                                &ofpacts);
+        if (error) {
+            printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error));
+            ofpbuf_uninit(&ofpacts);
+            ofpbuf_uninit(&of11_in);
+            continue;
+        }
+        ofpbuf_push_uninit(&of11_in, size);
+
+        /* Print cls_rule. */
+        ds_init(&s);
+        ofpacts_format(ofpacts.data, ofpacts.size, &s);
+        puts(ds_cstr(&s));
+        ds_destroy(&s);
+
+        /* Convert back to ofp11 actions and print differences from input. */
+        ofpbuf_init(&of11_out, 0);
+        ofpacts_put_openflow11_actions(ofpacts.data, ofpacts.size, &of11_out);
+
+        print_differences(of11_in.data, of11_in.size,
+                          of11_out.data, of11_out.size);
         putchar('\n');
 
         putchar('\n');
 
-        ofpbuf_uninit(&match_in);
+        ofpbuf_uninit(&ofpacts);
+        ofpbuf_uninit(&of11_in);
+        ofpbuf_uninit(&of11_out);
+    }
+    ds_destroy(&in);
+}
+
+/* "parse-ofp11-instructions": reads a series of OpenFlow 1.1 instruction
+ * specifications as hex bytes from stdin, converts them to ofpacts, prints
+ * them as strings on stdout, and then converts them back to hex bytes and
+ * prints any differences from the input. */
+static void
+do_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+    struct ds in;
+
+    ds_init(&in);
+    while (!ds_get_preprocessed_line(&in, stdin)) {
+        struct ofpbuf of11_out;
+        struct ofpbuf of11_in;
+        struct ofpbuf ofpacts;
+        enum ofperr error;
+        size_t size;
+        struct ds s;
+
+        /* Parse hex bytes. */
+        ofpbuf_init(&of11_in, 0);
+        if (ofpbuf_put_hex(&of11_in, ds_cstr(&in), NULL)[0] != '\0') {
+            ovs_fatal(0, "Trailing garbage in hex data");
+        }
+
+        /* Convert to ofpacts. */
+        ofpbuf_init(&ofpacts, 0);
+        size = of11_in.size;
+        error = ofpacts_pull_openflow11_instructions(&of11_in, of11_in.size,
+                                                     &ofpacts);
+        if (error) {
+            printf("bad OF1.1 instructions: %s\n\n", ofperr_get_name(error));
+            ofpbuf_uninit(&ofpacts);
+            ofpbuf_uninit(&of11_in);
+            continue;
+        }
+        ofpbuf_push_uninit(&of11_in, size);
+
+        /* Print cls_rule. */
+        ds_init(&s);
+        ofpacts_format(ofpacts.data, ofpacts.size, &s);
+        puts(ds_cstr(&s));
+        ds_destroy(&s);
+
+        /* Convert back to ofp11 instructions and print differences from
+         * input. */
+        ofpbuf_init(&of11_out, 0);
+        ofpacts_put_openflow11_instructions(ofpacts.data, ofpacts.size,
+                                            &of11_out);
+
+        print_differences(of11_in.data, of11_in.size,
+                          of11_out.data, of11_out.size);
+        putchar('\n');
+
+        ofpbuf_uninit(&ofpacts);
+        ofpbuf_uninit(&of11_in);
+        ofpbuf_uninit(&of11_out);
     }
     ds_destroy(&in);
 }
     }
     ds_destroy(&in);
 }
@@ -2211,6 +2322,8 @@ static const struct command all_commands[] = {
     { "parse-oxm", 0, 0, do_parse_oxm },
     { "parse-ofp10-actions", 0, 0, do_parse_ofp10_actions },
     { "parse-ofp11-match", 0, 0, do_parse_ofp11_match },
     { "parse-oxm", 0, 0, do_parse_oxm },
     { "parse-ofp10-actions", 0, 0, do_parse_ofp10_actions },
     { "parse-ofp11-match", 0, 0, do_parse_ofp11_match },
+    { "parse-ofp11-actions", 0, 0, do_parse_ofp11_actions },
+    { "parse-ofp11-instructions", 0, 0, do_parse_ofp11_instructions },
     { "print-error", 1, 1, do_print_error },
     { "ofp-print", 1, 2, do_ofp_print },
 
     { "print-error", 1, 1, do_print_error },
     { "ofp-print", 1, 2, do_ofp_print },