[ovs-dev] [PATCH v2 02/16] ofp-actions: Add action bitmap abstraction.

Ben Pfaff blp at nicira.com
Thu Aug 7 23:13:48 UTC 2014


Until now, sets of actions have been abstracted separately outside
ofp-actions, as enum ofputil_action_bitmap.  Drawing sets of actions into
ofp-actions, as done in this commit, makes for a better overall
abstraction of actions, with better consistency.

A big part of this commit is shifting from using ofp12_table_stats as if
it were an abstraction for OpenFlow table stats, toward using a new
struct ofputil_table_stats, which is what we generally do with other
OpenFlow structures and fits better with the rest of the code.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 lib/ofp-actions.c          |  156 ++++++++++++++++++++++++
 lib/ofp-actions.h          |  145 ++++++++++++-----------
 lib/ofp-print.c            |  105 ++++-------------
 lib/ofp-util.c             |  280 +++++++++++++++++++++-----------------------
 lib/ofp-util.h             |   66 ++++-------
 ofproto/ofproto-dpif.c     |   23 +---
 ofproto/ofproto-provider.h |   22 ++--
 ofproto/ofproto.c          |   85 ++++++--------
 tests/ofp-print.at         |   26 ++--
 tests/ofproto.at           |   20 ++--
 10 files changed, 495 insertions(+), 433 deletions(-)

diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index e8fd922..3818b2d 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -3091,6 +3091,151 @@ ofpacts_put_openflow_instructions(const struct ofpact ofpacts[],
     }
 }
 
+/* Sets of supported actions. */
+
+struct ofpact_xlate {
+    enum ofpact_type ofpact;
+    int ofpat;
+};
+
+static const struct ofpact_xlate *
+get_ofpact_xlate(enum ofp_version version)
+{
+    /* OpenFlow 1.0 actions. */
+    static const struct ofpact_xlate of10[] = {
+        { OFPACT_OUTPUT, 0 },
+        { OFPACT_SET_VLAN_VID, 1 },
+        { OFPACT_SET_VLAN_PCP, 2 },
+        { OFPACT_STRIP_VLAN, 3 },
+        { OFPACT_SET_ETH_SRC, 4 },
+        { OFPACT_SET_ETH_DST, 5 },
+        { OFPACT_SET_IPV4_SRC, 6 },
+        { OFPACT_SET_IPV4_DST, 7 },
+        { OFPACT_SET_IP_DSCP, 8 },
+        { OFPACT_SET_L4_SRC_PORT, 9 },
+        { OFPACT_SET_L4_DST_PORT, 10 },
+        { OFPACT_ENQUEUE, 11 },
+        { 0, -1 },
+    };
+
+    /* OpenFlow 1.1 actions. */
+    static const struct ofpact_xlate of11[] = {
+        { OFPACT_OUTPUT, 0 },
+        { OFPACT_SET_VLAN_VID, 1 },
+        { OFPACT_SET_VLAN_PCP, 2 },
+        { OFPACT_SET_ETH_SRC, 3 },
+        { OFPACT_SET_ETH_DST, 4 },
+        { OFPACT_SET_IPV4_SRC, 5 },
+        { OFPACT_SET_IPV4_DST, 6 },
+        { OFPACT_SET_IP_DSCP, 7 },
+        { OFPACT_SET_IP_ECN, 8 },
+        { OFPACT_SET_L4_SRC_PORT, 9 },
+        { OFPACT_SET_L4_DST_PORT, 10 },
+        /* OFPAT_COPY_TTL_OUT (11) not supported. */
+        /* OFPAT_COPY_TTL_IN (12) not supported. */
+        { OFPACT_SET_MPLS_LABEL, 13 },
+        { OFPACT_SET_MPLS_TC, 14 },
+        { OFPACT_SET_MPLS_TTL, 15 },
+        { OFPACT_DEC_MPLS_TTL, 16 },
+        { OFPACT_PUSH_VLAN, 17 },
+        { OFPACT_STRIP_VLAN, 18 },
+        { OFPACT_PUSH_MPLS, 19 },
+        { OFPACT_POP_MPLS, 20 },
+        { OFPACT_SET_QUEUE, 21 },
+        { OFPACT_GROUP, 22 },
+        { OFPACT_SET_IP_TTL, 23 },
+        { OFPACT_DEC_TTL, 24 },
+        { 0, -1 },
+    };
+
+    /* OpenFlow 1.2, 1.3, and 1.4 actions. */
+    static const struct ofpact_xlate of12[] = {
+        { OFPACT_OUTPUT, 0 },
+        /* OFPAT_COPY_TTL_OUT (11) not supported. */
+        /* OFPAT_COPY_TTL_IN (12) not supported. */
+        { OFPACT_SET_MPLS_TTL, 15 },
+        { OFPACT_DEC_MPLS_TTL, 16 },
+        { OFPACT_PUSH_VLAN, 17 },
+        { OFPACT_STRIP_VLAN, 18 },
+        { OFPACT_PUSH_MPLS, 19 },
+        { OFPACT_POP_MPLS, 20 },
+        { OFPACT_SET_QUEUE, 21 },
+        { OFPACT_GROUP, 22 },
+        { OFPACT_SET_IP_TTL, 23 },
+        { OFPACT_DEC_TTL, 24 },
+        { OFPACT_SET_FIELD, 25 },
+        /* OF1.3+ OFPAT_PUSH_PBB (26) not supported. */
+        /* OF1.3+ OFPAT_POP_PBB (27) not supported. */
+        { 0, -1 },
+    };
+
+    switch (version) {
+    case OFP10_VERSION:
+        return of10;
+
+    case OFP11_VERSION:
+        return of11;
+
+    case OFP12_VERSION:
+    case OFP13_VERSION:
+    case OFP14_VERSION:
+    case OFP15_VERSION:
+    default:
+        return of12;
+    }
+}
+
+/* Converts 'ofpacts_bitmap', a bitmap whose bits correspond to OFPACT_*
+ * values, into a bitmap of actions suitable for OpenFlow 'version', and
+ * returns the result. */
+ovs_be32
+ofpact_bitmap_to_openflow(uint64_t ofpacts_bitmap, enum ofp_version version)
+{
+    uint32_t openflow_bitmap = 0;
+    const struct ofpact_xlate *x;
+
+    for (x = get_ofpact_xlate(version); x->ofpat >= 0; x++) {
+        if (ofpacts_bitmap & (UINT64_C(1) << x->ofpact)) {
+            openflow_bitmap |= 1u << x->ofpat;
+        }
+    }
+    return htonl(openflow_bitmap);
+}
+
+/* Converts 'ofpat_bitmap', a bitmap of actions from an OpenFlow message with
+ * the given 'version' into a bitmap whose bits correspond to OFPACT_* values,
+ * and returns the result. */
+uint64_t
+ofpact_bitmap_from_openflow(ovs_be32 ofpat_bitmap, enum ofp_version version)
+{
+    uint64_t ofpact_bitmap = 0;
+    const struct ofpact_xlate *x;
+
+    for (x = get_ofpact_xlate(version); x->ofpat >= 0; x++) {
+        if (ofpat_bitmap & htonl(1u << x->ofpat)) {
+            ofpact_bitmap |= UINT64_C(1) << x->ofpact;
+        }
+    }
+    return ofpact_bitmap;
+}
+
+/* Appends to 's' a string representation of the set of OFPACT_* represented
+ * by 'ofpacts_bitmap'. */
+void
+ofpact_bitmap_format(uint64_t ofpacts_bitmap, struct ds *s)
+{
+    if (!ofpacts_bitmap) {
+        ds_put_cstr(s, "<none>");
+    } else {
+        while (ofpacts_bitmap) {
+            ds_put_format(s, "%s ",
+                          ofpact_name(rightmost_1bit_idx(ofpacts_bitmap)));
+            ofpacts_bitmap = zero_rightmost_1bit(ofpacts_bitmap);
+        }
+        ds_chomp(s, ' ');
+    }
+}
+
 /* Returns true if 'action' outputs to 'port', false otherwise. */
 static bool
 ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
@@ -3648,3 +3793,14 @@ ofpact_pad(struct ofpbuf *ofpacts)
         ofpbuf_put_zeros(ofpacts, pad);
     }
 }
+
+const char *
+ofpact_name(enum ofpact_type type)
+{
+    switch (type) {
+#define OFPACT(ENUM, STRUCT, MEMBER, NAME) case OFPACT_##ENUM: return NAME;
+        OFPACTS
+#undef OFPACT
+    }
+    return "<unknown>";
+}
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 8cb8862..5877151 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -31,7 +31,7 @@
  * This macro is used directly only internally by this header, but the list is
  * still of interest to developers.
  *
- * Each DEFINE_OFPACT invocation has the following parameters:
+ * Each OFPACT invocation has the following parameters:
  *
  * 1. <ENUM>, used below in the enum definition of OFPACT_<ENUM>, and
  *    elsewhere.
@@ -49,80 +49,79 @@
  *        - If "struct <STRUCT>" is variable-length, it must be the name of the
  *          flexible array member.
  */
-#define OFPACTS                                                     \
-    /* Output. */                                                   \
-    DEFINE_OFPACT(OUTPUT,          ofpact_output,        ofpact)    \
-    DEFINE_OFPACT(GROUP,           ofpact_group,         ofpact)    \
-    DEFINE_OFPACT(CONTROLLER,      ofpact_controller,    ofpact)    \
-    DEFINE_OFPACT(ENQUEUE,         ofpact_enqueue,       ofpact)    \
-    DEFINE_OFPACT(OUTPUT_REG,      ofpact_output_reg,    ofpact)    \
-    DEFINE_OFPACT(BUNDLE,          ofpact_bundle,        slaves)    \
-                                                                    \
-    /* Header changes. */                                           \
-    DEFINE_OFPACT(SET_FIELD,       ofpact_set_field,     ofpact)    \
-    DEFINE_OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,      ofpact)    \
-    DEFINE_OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,      ofpact)    \
-    DEFINE_OFPACT(STRIP_VLAN,      ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(PUSH_VLAN,       ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(SET_ETH_SRC,     ofpact_mac,           ofpact)    \
-    DEFINE_OFPACT(SET_ETH_DST,     ofpact_mac,           ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_SRC,    ofpact_ipv4,          ofpact)    \
-    DEFINE_OFPACT(SET_IPV4_DST,    ofpact_ipv4,          ofpact)    \
-    DEFINE_OFPACT(SET_IP_DSCP,     ofpact_dscp,          ofpact)    \
-    DEFINE_OFPACT(SET_IP_ECN,      ofpact_ecn,           ofpact)    \
-    DEFINE_OFPACT(SET_IP_TTL,      ofpact_ip_ttl,        ofpact)    \
-    DEFINE_OFPACT(SET_L4_SRC_PORT, ofpact_l4_port,       ofpact)    \
-    DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port,       ofpact)    \
-    DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact)    \
-    DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact)    \
-    DEFINE_OFPACT(STACK_PUSH,      ofpact_stack,         ofpact)    \
-    DEFINE_OFPACT(STACK_POP,       ofpact_stack,         ofpact)    \
-    DEFINE_OFPACT(DEC_TTL,         ofpact_cnt_ids,       cnt_ids)   \
-    DEFINE_OFPACT(SET_MPLS_LABEL,  ofpact_mpls_label,    ofpact)    \
-    DEFINE_OFPACT(SET_MPLS_TC,     ofpact_mpls_tc,       ofpact)    \
-    DEFINE_OFPACT(SET_MPLS_TTL,    ofpact_mpls_ttl,      ofpact)    \
-    DEFINE_OFPACT(DEC_MPLS_TTL,    ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(PUSH_MPLS,       ofpact_push_mpls,     ofpact)    \
-    DEFINE_OFPACT(POP_MPLS,        ofpact_pop_mpls,      ofpact)    \
-                                                                    \
-    /* Metadata. */                                                 \
-    DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
-    DEFINE_OFPACT(SET_QUEUE,       ofpact_queue,         ofpact)    \
-    DEFINE_OFPACT(POP_QUEUE,       ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout,   ofpact)    \
-                                                                    \
-    /* Flow table interaction. */                                   \
-    DEFINE_OFPACT(RESUBMIT,        ofpact_resubmit,      ofpact)    \
-    DEFINE_OFPACT(LEARN,           ofpact_learn,         specs)     \
-                                                                    \
-    /* Arithmetic. */                                               \
-    DEFINE_OFPACT(MULTIPATH,       ofpact_multipath,     ofpact)    \
-                                                                    \
-    /* Other. */                                                    \
-    DEFINE_OFPACT(NOTE,            ofpact_note,          data)      \
-    DEFINE_OFPACT(EXIT,            ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(SAMPLE,          ofpact_sample,        ofpact)    \
-                                                                    \
-    /* Instructions */                                              \
-    DEFINE_OFPACT(METER,           ofpact_meter,         ofpact)    \
-    DEFINE_OFPACT(CLEAR_ACTIONS,   ofpact_null,          ofpact)    \
-    DEFINE_OFPACT(WRITE_ACTIONS,   ofpact_nest,          ofpact)    \
-    DEFINE_OFPACT(WRITE_METADATA,  ofpact_metadata,      ofpact)    \
-    DEFINE_OFPACT(GOTO_TABLE,      ofpact_goto_table,    ofpact)
+#define OFPACTS                                                         \
+    /* Output. */                                                       \
+    OFPACT(OUTPUT,          ofpact_output,      ofpact, "output")       \
+    OFPACT(GROUP,           ofpact_group,       ofpact, "group")        \
+    OFPACT(CONTROLLER,      ofpact_controller,  ofpact, "controller")   \
+    OFPACT(ENQUEUE,         ofpact_enqueue,     ofpact, "enqueue")      \
+    OFPACT(OUTPUT_REG,      ofpact_output_reg,  ofpact, "output_reg")   \
+    OFPACT(BUNDLE,          ofpact_bundle,      slaves, "bundle")       \
+                                                                        \
+    /* Header changes. */                                               \
+    OFPACT(SET_FIELD,       ofpact_set_field,   ofpact, "set_field")    \
+    OFPACT(SET_VLAN_VID,    ofpact_vlan_vid,    ofpact, "set_vlan_vid") \
+    OFPACT(SET_VLAN_PCP,    ofpact_vlan_pcp,    ofpact, "set_vlan_pcp") \
+    OFPACT(STRIP_VLAN,      ofpact_null,        ofpact, "strip_vlan")   \
+    OFPACT(PUSH_VLAN,       ofpact_null,        ofpact, "push_vlan")    \
+    OFPACT(SET_ETH_SRC,     ofpact_mac,         ofpact, "mod_dl_src")   \
+    OFPACT(SET_ETH_DST,     ofpact_mac,         ofpact, "mod_dl_dst")   \
+    OFPACT(SET_IPV4_SRC,    ofpact_ipv4,        ofpact, "mod_nw_src")   \
+    OFPACT(SET_IPV4_DST,    ofpact_ipv4,        ofpact, "mod_nw_dst")   \
+    OFPACT(SET_IP_DSCP,     ofpact_dscp,        ofpact, "mod_nw_tos")   \
+    OFPACT(SET_IP_ECN,      ofpact_ecn,         ofpact, "mod_nw_ecn")   \
+    OFPACT(SET_IP_TTL,      ofpact_ip_ttl,      ofpact, "mod_nw_ttl")   \
+    OFPACT(SET_L4_SRC_PORT, ofpact_l4_port,     ofpact, "mod_tp_src")   \
+    OFPACT(SET_L4_DST_PORT, ofpact_l4_port,     ofpact, "mod_tp_dst")   \
+    OFPACT(REG_MOVE,        ofpact_reg_move,    ofpact, "move")         \
+    OFPACT(REG_LOAD,        ofpact_reg_load,    ofpact, "load")         \
+    OFPACT(STACK_PUSH,      ofpact_stack,       ofpact, "push")         \
+    OFPACT(STACK_POP,       ofpact_stack,       ofpact, "pop")          \
+    OFPACT(DEC_TTL,         ofpact_cnt_ids,     cnt_ids, "dec_ttl")     \
+    OFPACT(SET_MPLS_LABEL,  ofpact_mpls_label,  ofpact, "set_mpls_label") \
+    OFPACT(SET_MPLS_TC,     ofpact_mpls_tc,     ofpact, "set_mpls_tc")  \
+    OFPACT(SET_MPLS_TTL,    ofpact_mpls_ttl,    ofpact, "set_mpls_ttl") \
+    OFPACT(DEC_MPLS_TTL,    ofpact_null,        ofpact, "dec_mpls_ttl") \
+    OFPACT(PUSH_MPLS,       ofpact_push_mpls,   ofpact, "push_mpls")    \
+    OFPACT(POP_MPLS,        ofpact_pop_mpls,    ofpact, "pop_mpls")     \
+                                                                        \
+    /* Metadata. */                                                     \
+    OFPACT(SET_TUNNEL,      ofpact_tunnel,      ofpact, "set_tunnel")   \
+    OFPACT(SET_QUEUE,       ofpact_queue,       ofpact, "set_queue")    \
+    OFPACT(POP_QUEUE,       ofpact_null,        ofpact, "pop_queue")    \
+    OFPACT(FIN_TIMEOUT,     ofpact_fin_timeout, ofpact, "fin_timeout")  \
+                                                                        \
+    /* Flow table interaction. */                                       \
+    OFPACT(RESUBMIT,        ofpact_resubmit,    ofpact, "resubmit")     \
+    OFPACT(LEARN,           ofpact_learn,       specs, "learn")         \
+                                                                        \
+    /* Arithmetic. */                                                   \
+    OFPACT(MULTIPATH,       ofpact_multipath,   ofpact, "multipath")    \
+                                                                        \
+    /* Other. */                                                        \
+    OFPACT(NOTE,            ofpact_note,        data, "note")           \
+    OFPACT(EXIT,            ofpact_null,        ofpact, "exit")         \
+    OFPACT(SAMPLE,          ofpact_sample,      ofpact, "sample")       \
+                                                                        \
+    /* Instructions. */                                                 \
+    OFPACT(METER,           ofpact_meter,       ofpact, "meter")        \
+    OFPACT(CLEAR_ACTIONS,   ofpact_null,        ofpact, "clear_actions") \
+    OFPACT(WRITE_ACTIONS,   ofpact_nest,        ofpact, "write_actions") \
+    OFPACT(WRITE_METADATA,  ofpact_metadata,    ofpact, "write_metadata") \
+    OFPACT(GOTO_TABLE,      ofpact_goto_table,  ofpact, "goto_table")
 
 /* enum ofpact_type, with a member OFPACT_<ENUM> for each action. */
 enum OVS_PACKED_ENUM ofpact_type {
-#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) OFPACT_##ENUM,
+#define OFPACT(ENUM, STRUCT, MEMBER, NAME) OFPACT_##ENUM,
     OFPACTS
-#undef DEFINE_OFPACT
+#undef OFPACT
 };
 
-/* N_OFPACTS, the number of values of "enum ofpact_type". */
+/* Define N_OFPACTS to the number of types of ofpacts. */
 enum {
-    N_OFPACTS =
-#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER) + 1
-    OFPACTS
-#undef DEFINE_OFPACT
+#define OFPACT(ENUM, STRUCT, MEMBER, NAME) + 1
+    N_OFPACTS = OFPACTS
+#undef OFPACT
 };
 
 /* Header for an action.
@@ -611,6 +610,11 @@ void ofpacts_put_openflow_instructions(const struct ofpact[],
                                        struct ofpbuf *openflow,
                                        enum ofp_version ofp_version);
 
+/* Sets of supported actions. */
+ovs_be32 ofpact_bitmap_to_openflow(uint64_t ofpacts_bitmap, enum ofp_version);
+uint64_t ofpact_bitmap_from_openflow(ovs_be32 ofpat_bitmap, enum ofp_version);
+void ofpact_bitmap_format(uint64_t ofpacts_bitmap, struct ds *);
+
 /* Working with ofpacts. */
 bool ofpacts_output_to_port(const struct ofpact[], size_t ofpacts_len,
                             ofp_port_t port);
@@ -624,6 +628,7 @@ uint32_t ofpacts_get_meter(const struct ofpact[], size_t ofpacts_len);
  *
  * (For parsing ofpacts, see ofp-parse.h.) */
 void ofpacts_format(const struct ofpact[], size_t ofpacts_len, struct ds *);
+const char *ofpact_name(enum ofpact_type);
 
 /* Internal use by the helpers below. */
 void ofpact_init(struct ofpact *, enum ofpact_type, size_t len);
@@ -667,7 +672,7 @@ void *ofpact_put(struct ofpbuf *, enum ofpact_type, size_t len);
  *     An integer constant, the value of OFPACT_<ENUM>_RAW_SIZE rounded up to a
  *     multiple of OFPACT_ALIGNTO.
  */
-#define DEFINE_OFPACT(ENUM, STRUCT, MEMBER)                             \
+#define OFPACT(ENUM, STRUCT, MEMBER, NAME)                              \
     BUILD_ASSERT_DECL(offsetof(struct STRUCT, ofpact) == 0);            \
                                                                         \
     enum { OFPACT_##ENUM##_RAW_SIZE                                     \
@@ -699,7 +704,7 @@ void *ofpact_put(struct ofpbuf *, enum ofpact_type, size_t len);
                     OFPACT_##ENUM##_RAW_SIZE);                          \
     }
 OFPACTS
-#undef DEFINE_OFPACT
+#undef OFPACT
 
 /* Functions to use after adding ofpacts to a buffer. */
 void ofpact_update_len(struct ofpbuf *, struct ofpact *);
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 25e0478..2b0b20f 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -467,45 +467,6 @@ ofputil_capabilities_to_name(uint32_t bit)
     return NULL;
 }
 
-static const char *
-ofputil_action_bitmap_to_name(uint32_t bit)
-{
-    enum ofputil_action_bitmap action = bit;
-
-    switch (action) {
-    case OFPUTIL_A_OUTPUT:         return "OUTPUT";
-    case OFPUTIL_A_SET_VLAN_VID:   return "SET_VLAN_VID";
-    case OFPUTIL_A_SET_VLAN_PCP:   return "SET_VLAN_PCP";
-    case OFPUTIL_A_STRIP_VLAN:     return "STRIP_VLAN";
-    case OFPUTIL_A_SET_DL_SRC:     return "SET_DL_SRC";
-    case OFPUTIL_A_SET_DL_DST:     return "SET_DL_DST";
-    case OFPUTIL_A_SET_NW_SRC:     return "SET_NW_SRC";
-    case OFPUTIL_A_SET_NW_DST:     return "SET_NW_DST";
-    case OFPUTIL_A_SET_NW_ECN:     return "SET_NW_ECN";
-    case OFPUTIL_A_SET_NW_TOS:     return "SET_NW_TOS";
-    case OFPUTIL_A_SET_TP_SRC:     return "SET_TP_SRC";
-    case OFPUTIL_A_SET_TP_DST:     return "SET_TP_DST";
-    case OFPUTIL_A_SET_FIELD:      return "SET_FIELD";
-    case OFPUTIL_A_ENQUEUE:        return "ENQUEUE";
-    case OFPUTIL_A_COPY_TTL_OUT:   return "COPY_TTL_OUT";
-    case OFPUTIL_A_COPY_TTL_IN:    return "COPY_TTL_IN";
-    case OFPUTIL_A_SET_MPLS_LABEL: return "SET_MPLS_LABEL";
-    case OFPUTIL_A_SET_MPLS_TC:    return "SET_MPLS_TC";
-    case OFPUTIL_A_SET_MPLS_TTL:   return "SET_MPLS_TTL";
-    case OFPUTIL_A_DEC_MPLS_TTL:   return "DEC_MPLS_TTL";
-    case OFPUTIL_A_PUSH_VLAN:      return "PUSH_VLAN";
-    case OFPUTIL_A_POP_VLAN:       return "POP_VLAN";
-    case OFPUTIL_A_PUSH_MPLS:      return "PUSH_MPLS";
-    case OFPUTIL_A_POP_MPLS:       return "POP_MPLS";
-    case OFPUTIL_A_SET_QUEUE:      return "SET_QUEUE";
-    case OFPUTIL_A_GROUP:          return "GROUP";
-    case OFPUTIL_A_SET_NW_TTL:     return "SET_NW_TTL";
-    case OFPUTIL_A_DEC_NW_TTL:     return "DEC_NW_TTL";
-    }
-
-    return NULL;
-}
-
 static void
 ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
 {
@@ -536,8 +497,7 @@ ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
     switch ((enum ofp_version)oh->version) {
     case OFP10_VERSION:
         ds_put_cstr(string, "actions: ");
-        ofp_print_bit_names(string, features.actions,
-                            ofputil_action_bitmap_to_name, ' ');
+        ofpact_bitmap_format(features.ofpacts, string);
         ds_put_char(string, '\n');
         break;
     case OFP11_VERSION:
@@ -2458,10 +2418,23 @@ ofp_print_group_stats(struct ds *s, const struct ofp_header *oh)
      }
 }
 
+static const char *
+group_type_to_string(enum ofp11_group_type type)
+{
+    switch (type) {
+    case OFPGT11_ALL: return "all";
+    case OFPGT11_SELECT: return "select";
+    case OFPGT11_INDIRECT: return "indirect";
+    case OFPGT11_FF: return "fast failover";
+    default: OVS_NOT_REACHED();
+    }
+}
+
 static void
 ofp_print_group_features(struct ds *string, const struct ofp_header *oh)
 {
     struct ofputil_group_features features;
+    int i;
 
     ofputil_decode_group_features_reply(oh, &features);
 
@@ -2470,32 +2443,15 @@ ofp_print_group_features(struct ds *string, const struct ofp_header *oh)
     ds_put_format(string, "    Capabilities:  0x%"PRIx32"\n",
                   features.capabilities);
 
-    if (features.types & (1u << OFPGT11_ALL)) {
-        ds_put_format(string, "    All group :\n");
-        ds_put_format(string,
-                      "        max_groups = %#"PRIx32" actions=0x%08"PRIx32"\n",
-                      features.max_groups[0], features.actions[0]);
-    }
-
-    if (features.types & (1u << OFPGT11_SELECT)) {
-        ds_put_format(string, "    Select group :\n");
-        ds_put_format(string, "        max_groups = %#"PRIx32" "
-                      "actions=0x%08"PRIx32"\n",
-                      features.max_groups[1], features.actions[1]);
-    }
-
-    if (features.types & (1u << OFPGT11_INDIRECT)) {
-        ds_put_format(string, "    Indirect group :\n");
-        ds_put_format(string, "        max_groups = %#"PRIx32" "
-                      "actions=0x%08"PRIx32"\n",
-                      features.max_groups[2], features.actions[2]);
-    }
-
-    if (features.types & (1u << OFPGT11_FF)) {
-        ds_put_format(string, "    Fast Failover group :\n");
-        ds_put_format(string, "        max_groups = %#"PRIx32" "
-                      "actions=0x%08"PRIx32"\n",
-                      features.max_groups[3], features.actions[3]);
+    for (i = 0; i < 4; i++) {
+        if (features.types & (1u << i)) {
+            ds_put_format(string, "    %s group:\n", group_type_to_string(i));
+            ds_put_format(string, "       max_groups=%#"PRIx32"\n",
+                          features.max_groups[i]);
+            ds_put_format(string, "       actions: ");
+            ofpact_bitmap_format(features.ofpacts[i], string);
+            ds_put_char(string, '\n');
+        }
     }
 }
 
@@ -2535,23 +2491,12 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
     ofp_print_group(s, gm.group_id, gm.type, &gm.buckets);
 }
 
-static const char *
-ofp13_action_to_string(uint32_t bit)
-{
-    switch (bit) {
-#define OFPAT13_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME)  \
-        case 1u << ENUM: return NAME;
-#include "ofp-util.def"
-    }
-    return NULL;
-}
-
 static void
 print_table_action_features(struct ds *s,
                             const struct ofputil_table_action_features *taf)
 {
     ds_put_cstr(s, "        actions: ");
-    ofp_print_bit_names(s, taf->actions, ofp13_action_to_string, ',');
+    ofpact_bitmap_format(taf->ofpacts, s);
     ds_put_char(s, '\n');
 
     ds_put_cstr(s, "        supported on Set-Field: ");
@@ -2572,7 +2517,7 @@ static bool
 table_action_features_equal(const struct ofputil_table_action_features *a,
                             const struct ofputil_table_action_features *b)
 {
-    return (a->actions == b->actions
+    return (a->ofpacts == b->ofpacts
             && bitmap_equal(a->set_fields.bm, b->set_fields.bm, MFF_N_IDS));
 }
 
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index a065169..0ef4070 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -4012,42 +4012,6 @@ BUILD_ASSERT_DECL((int) OFPUTIL_C_IP_REASM == OFPC_IP_REASM);
 BUILD_ASSERT_DECL((int) OFPUTIL_C_QUEUE_STATS == OFPC_QUEUE_STATS);
 BUILD_ASSERT_DECL((int) OFPUTIL_C_ARP_MATCH_IP == OFPC_ARP_MATCH_IP);
 
-struct ofputil_action_bit_translation {
-    enum ofputil_action_bitmap ofputil_bit;
-    int of_bit;
-};
-
-static const struct ofputil_action_bit_translation of10_action_bits[] = {
-    { OFPUTIL_A_OUTPUT,       OFPAT10_OUTPUT },
-    { OFPUTIL_A_SET_VLAN_VID, OFPAT10_SET_VLAN_VID },
-    { OFPUTIL_A_SET_VLAN_PCP, OFPAT10_SET_VLAN_PCP },
-    { OFPUTIL_A_STRIP_VLAN,   OFPAT10_STRIP_VLAN },
-    { OFPUTIL_A_SET_DL_SRC,   OFPAT10_SET_DL_SRC },
-    { OFPUTIL_A_SET_DL_DST,   OFPAT10_SET_DL_DST },
-    { OFPUTIL_A_SET_NW_SRC,   OFPAT10_SET_NW_SRC },
-    { OFPUTIL_A_SET_NW_DST,   OFPAT10_SET_NW_DST },
-    { OFPUTIL_A_SET_NW_TOS,   OFPAT10_SET_NW_TOS },
-    { OFPUTIL_A_SET_TP_SRC,   OFPAT10_SET_TP_SRC },
-    { OFPUTIL_A_SET_TP_DST,   OFPAT10_SET_TP_DST },
-    { OFPUTIL_A_ENQUEUE,      OFPAT10_ENQUEUE },
-    { 0, 0 },
-};
-
-static enum ofputil_action_bitmap
-decode_action_bits(ovs_be32 of_actions,
-                   const struct ofputil_action_bit_translation *x)
-{
-    enum ofputil_action_bitmap ofputil_actions;
-
-    ofputil_actions = 0;
-    for (; x->ofputil_bit; x++) {
-        if (of_actions & htonl(1u << x->of_bit)) {
-            ofputil_actions |= x->ofputil_bit;
-        }
-    }
-    return ofputil_actions;
-}
-
 static uint32_t
 ofputil_capabilities_mask(enum ofp_version ofp_version)
 {
@@ -4096,13 +4060,14 @@ ofputil_decode_switch_features(const struct ofp_header *oh,
         if (osf->capabilities & htonl(OFPC10_STP)) {
             features->capabilities |= OFPUTIL_C_STP;
         }
-        features->actions = decode_action_bits(osf->actions, of10_action_bits);
+        features->ofpacts = ofpact_bitmap_from_openflow(osf->actions,
+                                                        OFP10_VERSION);
     } else if (raw == OFPRAW_OFPT11_FEATURES_REPLY
                || raw == OFPRAW_OFPT13_FEATURES_REPLY) {
         if (osf->capabilities & htonl(OFPC11_GROUP_STATS)) {
             features->capabilities |= OFPUTIL_C_GROUP_STATS;
         }
-        features->actions = 0;
+        features->ofpacts = 0;
         if (raw == OFPRAW_OFPT13_FEATURES_REPLY) {
             features->auxiliary_id = osf->auxiliary_id;
         }
@@ -4153,21 +4118,6 @@ ofputil_switch_features_has_ports(struct ofpbuf *b)
     return false;
 }
 
-static ovs_be32
-encode_action_bits(enum ofputil_action_bitmap ofputil_actions,
-                   const struct ofputil_action_bit_translation *x)
-{
-    uint32_t of_actions;
-
-    of_actions = 0;
-    for (; x->ofputil_bit; x++) {
-        if (ofputil_actions & x->ofputil_bit) {
-            of_actions |= 1 << x->of_bit;
-        }
-    }
-    return htonl(of_actions);
-}
-
 /* Returns a buffer owned by the caller that encodes 'features' in the format
  * required by 'protocol' with the given 'xid'.  The caller should append port
  * information to the buffer with subsequent calls to
@@ -4212,7 +4162,8 @@ ofputil_encode_switch_features(const struct ofputil_switch_features *features,
         if (features->capabilities & OFPUTIL_C_STP) {
             osf->capabilities |= htonl(OFPC10_STP);
         }
-        osf->actions = encode_action_bits(features->actions, of10_action_bits);
+        osf->actions = ofpact_bitmap_to_openflow(features->ofpacts,
+                                                 OFP10_VERSION);
         break;
     case OFP13_VERSION:
     case OFP14_VERSION:
@@ -4504,20 +4455,25 @@ pull_table_feature_property(struct ofpbuf *msg, struct ofpbuf *payload,
 }
 
 static enum ofperr
-parse_table_ids(struct ofpbuf *payload, uint32_t *ids)
+parse_action_bitmap(struct ofpbuf *payload, enum ofp_version ofp_version,
+                    uint64_t *ofpacts)
 {
-    uint16_t type;
+    uint32_t types = 0;
 
-    *ids = 0;
     while (ofpbuf_size(payload) > 0) {
-        enum ofperr error = pull_table_feature_property(payload, NULL, &type);
+        uint16_t type;
+        enum ofperr error;
+
+        error = pull_table_feature_property(payload, NULL, &type);
         if (error) {
             return error;
         }
-        if (type < CHAR_BIT * sizeof *ids) {
-            *ids |= 1u << type;
+        if (type < CHAR_BIT * sizeof types) {
+            types |= 1u << type;
         }
     }
+
+    *ofpacts = ofpact_bitmap_from_openflow(htonl(types), ofp_version);
     return 0;
 }
 
@@ -4646,12 +4602,14 @@ int
 ofputil_decode_table_features(struct ofpbuf *msg,
                               struct ofputil_table_features *tf, bool loose)
 {
+    const struct ofp_header *oh;
     struct ofp13_table_features *otf;
     unsigned int len;
 
     if (!msg->frame) {
         ofpraw_pull_assert(msg);
     }
+    oh = ofpbuf_l2(msg);
 
     if (!ofpbuf_size(msg)) {
         return EOF;
@@ -4708,17 +4666,21 @@ ofputil_decode_table_features(struct ofpbuf *msg,
             break;
 
         case OFPTFPT13_WRITE_ACTIONS:
-            error = parse_table_ids(&payload, &tf->nonmiss.write.actions);
+            error = parse_action_bitmap(&payload, oh->version,
+                                        &tf->nonmiss.write.ofpacts);
             break;
         case OFPTFPT13_WRITE_ACTIONS_MISS:
-            error = parse_table_ids(&payload, &tf->miss.write.actions);
+            error = parse_action_bitmap(&payload, oh->version,
+                                        &tf->miss.write.ofpacts);
             break;
 
         case OFPTFPT13_APPLY_ACTIONS:
-            error = parse_table_ids(&payload, &tf->nonmiss.apply.actions);
+            error = parse_action_bitmap(&payload, oh->version,
+                                        &tf->nonmiss.apply.ofpacts);
             break;
         case OFPTFPT13_APPLY_ACTIONS_MISS:
-            error = parse_table_ids(&payload, &tf->miss.apply.actions);
+            error = parse_action_bitmap(&payload, oh->version,
+                                        &tf->miss.apply.ofpacts);
             break;
 
         case OFPTFPT13_MATCH:
@@ -5030,27 +4992,27 @@ ofputil_decode_role_status(const struct ofp_header *oh,
 /* Table stats. */
 
 static void
-ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in,
+ofputil_put_ofp10_table_stats(const struct ofputil_table_stats *in,
                               struct ofpbuf *buf)
 {
     struct wc_map {
         enum ofp10_flow_wildcards wc10;
-        enum oxm12_ofb_match_fields mf12;
+        enum mf_field_id mf;
     };
 
     static const struct wc_map wc_map[] = {
-        { OFPFW10_IN_PORT,     OFPXMT12_OFB_IN_PORT },
-        { OFPFW10_DL_VLAN,     OFPXMT12_OFB_VLAN_VID },
-        { OFPFW10_DL_SRC,      OFPXMT12_OFB_ETH_SRC },
-        { OFPFW10_DL_DST,      OFPXMT12_OFB_ETH_DST},
-        { OFPFW10_DL_TYPE,     OFPXMT12_OFB_ETH_TYPE },
-        { OFPFW10_NW_PROTO,    OFPXMT12_OFB_IP_PROTO },
-        { OFPFW10_TP_SRC,      OFPXMT12_OFB_TCP_SRC },
-        { OFPFW10_TP_DST,      OFPXMT12_OFB_TCP_DST },
-        { OFPFW10_NW_SRC_MASK, OFPXMT12_OFB_IPV4_SRC },
-        { OFPFW10_NW_DST_MASK, OFPXMT12_OFB_IPV4_DST },
-        { OFPFW10_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP },
-        { OFPFW10_NW_TOS,      OFPXMT12_OFB_IP_DSCP },
+        { OFPFW10_IN_PORT,     MFF_IN_PORT },
+        { OFPFW10_DL_VLAN,     MFF_VLAN_VID },
+        { OFPFW10_DL_SRC,      MFF_ETH_SRC },
+        { OFPFW10_DL_DST,      MFF_ETH_DST},
+        { OFPFW10_DL_TYPE,     MFF_ETH_TYPE },
+        { OFPFW10_NW_PROTO,    MFF_IP_PROTO },
+        { OFPFW10_TP_SRC,      MFF_TCP_SRC },
+        { OFPFW10_TP_DST,      MFF_TCP_DST },
+        { OFPFW10_NW_SRC_MASK, MFF_IPV4_SRC },
+        { OFPFW10_NW_DST_MASK, MFF_IPV4_DST },
+        { OFPFW10_DL_VLAN_PCP, MFF_VLAN_PCP },
+        { OFPFW10_NW_TOS,      MFF_IP_DSCP },
     };
 
     struct ofp10_table_stats *out;
@@ -5061,41 +5023,41 @@ ofputil_put_ofp10_table_stats(const struct ofp12_table_stats *in,
     ovs_strlcpy(out->name, in->name, sizeof out->name);
     out->wildcards = 0;
     for (p = wc_map; p < &wc_map[ARRAY_SIZE(wc_map)]; p++) {
-        if (in->wildcards & htonll(1ULL << p->mf12)) {
+        if (bitmap_is_set(in->wildcards.bm, p->mf)) {
             out->wildcards |= htonl(p->wc10);
         }
     }
-    out->max_entries = in->max_entries;
-    out->active_count = in->active_count;
-    put_32aligned_be64(&out->lookup_count, in->lookup_count);
-    put_32aligned_be64(&out->matched_count, in->matched_count);
+    out->max_entries = htonl(in->max_entries);
+    out->active_count = htonl(in->active_count);
+    put_32aligned_be64(&out->lookup_count, htonll(in->lookup_count));
+    put_32aligned_be64(&out->matched_count, htonll(in->matched_count));
 }
 
 static ovs_be32
-oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12)
+fields_to_ofp11_flow_match_fields(const struct mf_bitmap *fields)
 {
     struct map {
         enum ofp11_flow_match_fields fmf11;
-        enum oxm12_ofb_match_fields mf12;
+        enum mf_field_id mf;
     };
 
     static const struct map map[] = {
-        { OFPFMF11_IN_PORT,     OFPXMT12_OFB_IN_PORT },
-        { OFPFMF11_DL_VLAN,     OFPXMT12_OFB_VLAN_VID },
-        { OFPFMF11_DL_VLAN_PCP, OFPXMT12_OFB_VLAN_PCP },
-        { OFPFMF11_DL_TYPE,     OFPXMT12_OFB_ETH_TYPE },
-        { OFPFMF11_NW_TOS,      OFPXMT12_OFB_IP_DSCP },
-        { OFPFMF11_NW_PROTO,    OFPXMT12_OFB_IP_PROTO },
-        { OFPFMF11_TP_SRC,      OFPXMT12_OFB_TCP_SRC },
-        { OFPFMF11_TP_DST,      OFPXMT12_OFB_TCP_DST },
-        { OFPFMF11_MPLS_LABEL,  OFPXMT12_OFB_MPLS_LABEL },
-        { OFPFMF11_MPLS_TC,     OFPXMT12_OFB_MPLS_TC },
+        { OFPFMF11_IN_PORT,     MFF_IN_PORT },
+        { OFPFMF11_DL_VLAN,     MFF_VLAN_VID },
+        { OFPFMF11_DL_VLAN_PCP, MFF_VLAN_PCP },
+        { OFPFMF11_DL_TYPE,     MFF_ETH_TYPE },
+        { OFPFMF11_NW_TOS,      MFF_IP_DSCP },
+        { OFPFMF11_NW_PROTO,    MFF_IP_PROTO },
+        { OFPFMF11_TP_SRC,      MFF_TCP_SRC },
+        { OFPFMF11_TP_DST,      MFF_TCP_DST },
+        { OFPFMF11_MPLS_LABEL,  MFF_MPLS_LABEL },
+        { OFPFMF11_MPLS_TC,     MFF_MPLS_TC },
         /* I don't know what OFPFMF11_TYPE means. */
-        { OFPFMF11_DL_SRC,      OFPXMT12_OFB_ETH_SRC },
-        { OFPFMF11_DL_DST,      OFPXMT12_OFB_ETH_DST },
-        { OFPFMF11_NW_SRC,      OFPXMT12_OFB_IPV4_SRC },
-        { OFPFMF11_NW_DST,      OFPXMT12_OFB_IPV4_DST },
-        { OFPFMF11_METADATA,    OFPXMT12_OFB_METADATA },
+        { OFPFMF11_DL_SRC,      MFF_ETH_SRC },
+        { OFPFMF11_DL_DST,      MFF_ETH_DST },
+        { OFPFMF11_NW_SRC,      MFF_IPV4_SRC },
+        { OFPFMF11_NW_DST,      MFF_IPV4_DST },
+        { OFPFMF11_METADATA,    MFF_METADATA },
     };
 
     const struct map *p;
@@ -5103,7 +5065,7 @@ oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12)
 
     fmf11 = 0;
     for (p = map; p < &map[ARRAY_SIZE(map)]; p++) {
-        if (oxm12 & htonll(1ULL << p->mf12)) {
+        if (bitmap_is_set(fields->bm, p->mf)) {
             fmf11 |= p->fmf11;
         }
     }
@@ -5111,7 +5073,7 @@ oxm12_to_ofp11_flow_match_fields(ovs_be64 oxm12)
 }
 
 static void
-ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
+ofputil_put_ofp11_table_stats(const struct ofputil_table_stats *in,
                               struct ofpbuf *buf)
 {
     struct ofp11_table_stats *out;
@@ -5119,50 +5081,84 @@ ofputil_put_ofp11_table_stats(const struct ofp12_table_stats *in,
     out = ofpbuf_put_zeros(buf, sizeof *out);
     out->table_id = in->table_id;
     ovs_strlcpy(out->name, in->name, sizeof out->name);
-    out->wildcards = oxm12_to_ofp11_flow_match_fields(in->wildcards);
-    out->match = oxm12_to_ofp11_flow_match_fields(in->match);
-    out->instructions = in->instructions;
-    out->write_actions = in->write_actions;
-    out->apply_actions = in->apply_actions;
-    out->config = in->config;
-    out->max_entries = in->max_entries;
-    out->active_count = in->active_count;
-    out->lookup_count = in->lookup_count;
-    out->matched_count = in->matched_count;
+    out->wildcards = fields_to_ofp11_flow_match_fields(&in->wildcards);
+    out->match = fields_to_ofp11_flow_match_fields(&in->match);
+    out->instructions = htonl(in->instructions);
+    out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts,
+                                                   OFP11_VERSION);
+    out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts,
+                                                   OFP11_VERSION);
+    out->config = htonl(in->config);
+    out->max_entries = htonl(in->max_entries);
+    out->active_count = htonl(in->active_count);
+    out->lookup_count = htonll(in->lookup_count);
+    out->matched_count = htonll(in->matched_count);
+}
+
+static ovs_be64
+mf_bitmap_to_oxm_bitmap(const struct mf_bitmap *fields,
+                        enum ofp_version version)
+{
+    uint64_t oxm_bitmap = 0;
+    int i;
+
+    BITMAP_FOR_EACH_1 (i, MFF_N_IDS, fields->bm) {
+        uint32_t oxm = mf_oxm_header(i, version);
+        uint32_t vendor = NXM_VENDOR(oxm);
+        int field = NXM_FIELD(oxm);
+
+        if (vendor == OFPXMC12_OPENFLOW_BASIC && field < 64) {
+            oxm_bitmap |= UINT64_C(1) << field;
+        }
+    }
+    return htonll(oxm_bitmap);
 }
 
 static void
-ofputil_put_ofp12_table_stats(const struct ofp12_table_stats *in,
+ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *in,
                               struct ofpbuf *buf)
 {
-    struct ofp12_table_stats *out = ofpbuf_put(buf, in, sizeof *in);
+    struct ofp12_table_stats *out;
 
-    /* Trim off OF1.3-only capabilities. */
-    out->match &= htonll(OFPXMT12_MASK);
-    out->wildcards &= htonll(OFPXMT12_MASK);
-    out->write_setfields &= htonll(OFPXMT12_MASK);
-    out->apply_setfields &= htonll(OFPXMT12_MASK);
+    out = ofpbuf_put_zeros(buf, sizeof *out);
+    out->table_id = in->table_id;
+    ovs_strlcpy(out->name, in->name, sizeof out->name);
+    out->match = mf_bitmap_to_oxm_bitmap(&in->match, OFP12_VERSION);
+    out->wildcards = mf_bitmap_to_oxm_bitmap(&in->wildcards, OFP12_VERSION);
+    out->write_actions = ofpact_bitmap_to_openflow(in->write_ofpacts,
+                                                   OFP12_VERSION);
+    out->apply_actions = ofpact_bitmap_to_openflow(in->apply_ofpacts,
+                                                   OFP12_VERSION);
+    out->write_setfields = mf_bitmap_to_oxm_bitmap(&in->write_setfields,
+                                                   OFP12_VERSION);
+    out->apply_setfields = mf_bitmap_to_oxm_bitmap(&in->apply_setfields,
+                                                   OFP12_VERSION);
+    out->metadata_match = in->metadata_match;
+    out->metadata_write = in->metadata_write;
+    out->instructions = htonl(in->instructions & OFPIT11_ALL);
+    out->config = htonl(in->config);
+    out->max_entries = htonl(in->max_entries);
+    out->active_count = htonl(in->active_count);
+    out->lookup_count = htonll(in->lookup_count);
+    out->matched_count = htonll(in->matched_count);
 }
 
 static void
-ofputil_put_ofp13_table_stats(const struct ofp12_table_stats *in,
+ofputil_put_ofp13_table_stats(const struct ofputil_table_stats *in,
                               struct ofpbuf *buf)
 {
     struct ofp13_table_stats *out;
 
-    /* OF 1.3 splits table features off the ofp_table_stats,
-     * so there is not much here. */
-
     out = ofpbuf_put_uninit(buf, sizeof *out);
     out->table_id = in->table_id;
-    out->active_count = in->active_count;
-    out->lookup_count = in->lookup_count;
-    out->matched_count = in->matched_count;
+    out->active_count = htonl(in->active_count);
+    out->lookup_count = htonll(in->lookup_count);
+    out->matched_count = htonll(in->matched_count);
 }
 
 struct ofpbuf *
-ofputil_encode_table_stats_reply(const struct ofp12_table_stats stats[], int n,
-                                 const struct ofp_header *request)
+ofputil_encode_table_stats_reply(const struct ofputil_table_stats stats[],
+                                 int n, const struct ofp_header *request)
 {
     struct ofpbuf *reply;
     int i;
@@ -6796,20 +6792,18 @@ ofputil_encode_group_features_reply(
 {
     struct ofp12_group_features_stats *ogf;
     struct ofpbuf *reply;
+    int i;
 
     reply = ofpraw_alloc_xid(OFPRAW_OFPST12_GROUP_FEATURES_REPLY,
                              request->version, request->xid, 0);
     ogf = ofpbuf_put_zeros(reply, sizeof *ogf);
     ogf->types = htonl(features->types);
     ogf->capabilities = htonl(features->capabilities);
-    ogf->max_groups[0] = htonl(features->max_groups[0]);
-    ogf->max_groups[1] = htonl(features->max_groups[1]);
-    ogf->max_groups[2] = htonl(features->max_groups[2]);
-    ogf->max_groups[3] = htonl(features->max_groups[3]);
-    ogf->actions[0] = htonl(features->actions[0]);
-    ogf->actions[1] = htonl(features->actions[1]);
-    ogf->actions[2] = htonl(features->actions[2]);
-    ogf->actions[3] = htonl(features->actions[3]);
+    for (i = 0; i < 4; i++) {
+        ogf->max_groups[i] = htonl(features->max_groups[i]);
+        ogf->actions[i] = ofpact_bitmap_to_openflow(features->ofpacts[i],
+                                                    request->version);
+    }
 
     return reply;
 }
@@ -6820,17 +6814,15 @@ ofputil_decode_group_features_reply(const struct ofp_header *oh,
                                     struct ofputil_group_features *features)
 {
     const struct ofp12_group_features_stats *ogf = ofpmsg_body(oh);
+    int i;
 
     features->types = ntohl(ogf->types);
     features->capabilities = ntohl(ogf->capabilities);
-    features->max_groups[0] = ntohl(ogf->max_groups[0]);
-    features->max_groups[1] = ntohl(ogf->max_groups[1]);
-    features->max_groups[2] = ntohl(ogf->max_groups[2]);
-    features->max_groups[3] = ntohl(ogf->max_groups[3]);
-    features->actions[0] = ntohl(ogf->actions[0]);
-    features->actions[1] = ntohl(ogf->actions[1]);
-    features->actions[2] = ntohl(ogf->actions[2]);
-    features->actions[3] = ntohl(ogf->actions[3]);
+    for (i = 0; i < 4; i++) {
+        features->max_groups[i] = ntohl(ogf->max_groups[i]);
+        features->ofpacts[i] = ofpact_bitmap_from_openflow(
+            ogf->actions[i], oh->version);
+    }
 }
 
 /* Parse a group status request message into a 32 bit OpenFlow 1.1
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 39e50ed..38e7006 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -528,37 +528,6 @@ enum ofputil_capabilities {
     OFPUTIL_C_PORT_BLOCKED   = 1 << 8,  /* Switch will block looping ports */
 };
 
-enum ofputil_action_bitmap {
-    OFPUTIL_A_OUTPUT         = 1 << 0,
-    OFPUTIL_A_SET_VLAN_VID   = 1 << 1,
-    OFPUTIL_A_SET_VLAN_PCP   = 1 << 2,
-    OFPUTIL_A_STRIP_VLAN     = 1 << 3,
-    OFPUTIL_A_SET_DL_SRC     = 1 << 4,
-    OFPUTIL_A_SET_DL_DST     = 1 << 5,
-    OFPUTIL_A_SET_NW_SRC     = 1 << 6,
-    OFPUTIL_A_SET_NW_DST     = 1 << 7,
-    OFPUTIL_A_SET_NW_ECN     = 1 << 8,
-    OFPUTIL_A_SET_NW_TOS     = 1 << 9,
-    OFPUTIL_A_SET_TP_SRC     = 1 << 10,
-    OFPUTIL_A_SET_TP_DST     = 1 << 11,
-    OFPUTIL_A_ENQUEUE        = 1 << 12,
-    OFPUTIL_A_COPY_TTL_OUT   = 1 << 13,
-    OFPUTIL_A_COPY_TTL_IN    = 1 << 14,
-    OFPUTIL_A_SET_MPLS_LABEL = 1 << 15,
-    OFPUTIL_A_SET_MPLS_TC    = 1 << 16,
-    OFPUTIL_A_SET_MPLS_TTL   = 1 << 17,
-    OFPUTIL_A_DEC_MPLS_TTL   = 1 << 18,
-    OFPUTIL_A_PUSH_VLAN      = 1 << 19,
-    OFPUTIL_A_POP_VLAN       = 1 << 20,
-    OFPUTIL_A_PUSH_MPLS      = 1 << 21,
-    OFPUTIL_A_POP_MPLS       = 1 << 22,
-    OFPUTIL_A_SET_QUEUE      = 1 << 23,
-    OFPUTIL_A_GROUP          = 1 << 24,
-    OFPUTIL_A_SET_NW_TTL     = 1 << 25,
-    OFPUTIL_A_DEC_NW_TTL     = 1 << 26,
-    OFPUTIL_A_SET_FIELD      = 1 << 27,
-};
-
 /* Abstract ofp_switch_features. */
 struct ofputil_switch_features {
     uint64_t datapath_id;       /* Datapath unique ID. */
@@ -566,7 +535,7 @@ struct ofputil_switch_features {
     uint8_t n_tables;           /* Number of tables supported by datapath. */
     uint8_t auxiliary_id;       /* Identify auxiliary connections */
     enum ofputil_capabilities capabilities;
-    enum ofputil_action_bitmap actions;
+    uint64_t ofpacts;           /* Bitmap of OFPACT_* bits. */
 };
 
 enum ofperr ofputil_decode_switch_features(const struct ofp_header *,
@@ -650,7 +619,7 @@ struct ofputil_table_features {
          *    - 'apply' reports features available in an "apply_actions"
          *      instruction. */
         struct ofputil_table_action_features {
-            uint32_t actions;     /* Bitmap of supported OFPAT*. */
+            uint64_t ofpacts;     /* Bitmap of supported OFPACT_*. */
             struct mf_bitmap set_fields; /* Fields for "set-field". */
         } write, apply;
     } nonmiss, miss;
@@ -798,13 +767,30 @@ struct ofpbuf *ofputil_encode_role_status(
 
 enum ofperr ofputil_decode_role_status(const struct ofp_header *oh,
                                        struct ofputil_role_status *rs);
-/* Abstract table stats.
- *
- * For now we use ofp12_table_stats as a superset of the other protocol
- * versions' table stats. */
+/* Abstract table stats. */
+struct ofputil_table_stats {
+    uint8_t table_id;
+    char name[OFP_MAX_TABLE_NAME_LEN];
+    ovs_be64 metadata_match;    /* Bits of metadata table can match. */
+    ovs_be64 metadata_write;    /* Bits of metadata table can write. */
+    uint32_t config;            /* Bitmap of OFPTC_* values */
+    uint32_t max_entries;       /* Max number of entries supported. */
+
+    struct mf_bitmap match;     /* Fields table can match. */
+    struct mf_bitmap wildcards; /* Fields table can wildcard. */
+    uint64_t write_ofpacts;     /* OFPACT_* supported on Write-Actions. */
+    uint64_t apply_ofpacts;     /* OFPACT_* supported on Apply-Actions. */
+    struct mf_bitmap write_setfields; /* Fields that can be set in W-A. */
+    struct mf_bitmap apply_setfields; /* Fields that can be set in A-A. */
+    uint32_t instructions;      /* Bitmap of OFPIT_* values supported. */
+
+    uint32_t active_count;      /* Number of active entries. */
+    uint64_t lookup_count;      /* Number of packets looked up in table. */
+    uint64_t matched_count;     /* Number of packets that hit table. */
+};
 
 struct ofpbuf *ofputil_encode_table_stats_reply(
-    const struct ofp12_table_stats[], int n,
+    const struct ofputil_table_stats[], int n,
     const struct ofp_header *request);
 
 /* Queue configuration request. */
@@ -1099,9 +1085,7 @@ struct ofputil_group_features {
     uint32_t  types;           /* Bitmap of OFPGT_* values supported. */
     uint32_t  capabilities;    /* Bitmap of OFPGFC12_* capability supported. */
     uint32_t  max_groups[4];   /* Maximum number of groups for each type. */
-
-    /* Bitmaps of OFPAT_* that are supported.  OF1.2+ actions only. */
-    uint32_t  actions[4];
+    uint64_t  ofpacts[4];      /* Bitmaps of supported OFPACT_* */
 };
 
 /* Group desc reply, independent of protocol. */
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 48d0b82..92d5718 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1500,37 +1500,26 @@ flush(struct ofproto *ofproto_)
 
 static void
 get_features(struct ofproto *ofproto_ OVS_UNUSED,
-             bool *arp_match_ip, enum ofputil_action_bitmap *actions)
+             bool *arp_match_ip, uint64_t *ofpacts)
 {
     *arp_match_ip = true;
-    *actions = (OFPUTIL_A_OUTPUT |
-                OFPUTIL_A_SET_VLAN_VID |
-                OFPUTIL_A_SET_VLAN_PCP |
-                OFPUTIL_A_STRIP_VLAN |
-                OFPUTIL_A_SET_DL_SRC |
-                OFPUTIL_A_SET_DL_DST |
-                OFPUTIL_A_SET_NW_SRC |
-                OFPUTIL_A_SET_NW_DST |
-                OFPUTIL_A_SET_NW_TOS |
-                OFPUTIL_A_SET_TP_SRC |
-                OFPUTIL_A_SET_TP_DST |
-                OFPUTIL_A_ENQUEUE);
+    *ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
 }
 
 static void
-get_tables(struct ofproto *ofproto, struct ofp12_table_stats *ots)
+get_tables(struct ofproto *ofproto, struct ofputil_table_stats *stats)
 {
     int i;
 
-    strcpy(ots->name, "classifier");
+    strcpy(stats->name, "classifier");
 
     for (i = 0; i < ofproto->n_tables; i++) {
         unsigned long missed, matched;
 
         atomic_read(&ofproto->tables[i].n_matched, &matched);
-        ots[i].matched_count = htonll(matched);
+        stats[i].matched_count = matched;
         atomic_read(&ofproto->tables[i].n_missed, &missed);
-        ots[i].lookup_count = htonll(matched + missed);
+        stats[i].lookup_count = matched + missed;
     }
 }
 
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 7e6e99b..9c0c94e 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -774,30 +774,30 @@ struct ofproto_class {
      * supports matching IP addresses inside ARP requests and replies, false
      * otherwise.
      *
-     * The implementation should store in '*actions' a bitmap of the supported
-     * OpenFlow actions.  Vendor actions are not included in '*actions'. */
+     * The implementation should store in '*ofpacts' a bitmap of the supported
+     * OFPACT_* actions. */
     void (*get_features)(struct ofproto *ofproto,
                          bool *arp_match_ip,
-                         enum ofputil_action_bitmap *actions);
+                         uint64_t *ofpacts);
 
     /* Helper for the OpenFlow OFPST_TABLE statistics request.
      *
-     * The 'ots' array contains 'ofproto->n_tables' elements.  Each element is
+     * The 'stats' array contains 'ofproto->n_tables' elements.  Each element is
      * initialized as:
      *
      *   - 'table_id' to the array index.
      *
      *   - 'name' to "table#" where # is the table ID.
      *
-     *   - 'match' and 'wildcards' to OFPXMT12_MASK.
+     *   - 'match' and 'wildcards' to all fields.
      *
-     *   - 'write_actions' and 'apply_actions' to OFPAT12_OUTPUT.
+     *   - 'write_actions' and 'apply_actions' to all actions.
      *
-     *   - 'write_setfields' and 'apply_setfields' to OFPXMT12_MASK.
+     *   - 'write_setfields' and 'apply_setfields' to all writable fields.
      *
      *   - 'metadata_match' and 'metadata_write' to OVS_BE64_MAX.
      *
-     *   - 'instructions' to OFPIT11_ALL.
+     *   - 'instructions' to all instructions.
      *
      *   - 'config' to OFPTC11_TABLE_MISS_MASK.
      *
@@ -838,11 +838,9 @@ struct ofproto_class {
      *
      *   - 'matched_count' to the number of packets looked up in this flow
      *     table so far that matched one of the flow entries.
-     *
-     * All of the members of struct ofp12_table_stats are in network byte
-     * order.
      */
-    void (*get_tables)(struct ofproto *ofproto, struct ofp12_table_stats *ots);
+    void (*get_tables)(struct ofproto *ofproto,
+                       struct ofputil_table_stats *stats);
 
 /* ## ---------------- ## */
 /* ## ofport Functions ## */
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index fca7d09..78b6773 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -524,28 +524,10 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     ovs_mutex_unlock(&ofproto_mutex);
     ofproto->ogf.capabilities = OFPGFC_CHAINING | OFPGFC_SELECT_LIVENESS |
                                 OFPGFC_SELECT_WEIGHT;
-    ofproto->ogf.max_groups[OFPGT11_ALL] = OFPG_MAX;
-    ofproto->ogf.max_groups[OFPGT11_SELECT] = OFPG_MAX;
-    ofproto->ogf.max_groups[OFPGT11_INDIRECT] = OFPG_MAX;
-    ofproto->ogf.max_groups[OFPGT11_FF] = OFPG_MAX;
-    ofproto->ogf.actions[0] =
-        (1 << OFPAT11_OUTPUT) |
-        (1 << OFPAT11_COPY_TTL_OUT) |
-        (1 << OFPAT11_COPY_TTL_IN) |
-        (1 << OFPAT11_SET_MPLS_TTL) |
-        (1 << OFPAT11_DEC_MPLS_TTL) |
-        (1 << OFPAT11_PUSH_VLAN) |
-        (1 << OFPAT11_POP_VLAN) |
-        (1 << OFPAT11_PUSH_MPLS) |
-        (1 << OFPAT11_POP_MPLS) |
-        (1 << OFPAT11_SET_QUEUE) |
-        (1 << OFPAT11_GROUP) |
-        (1 << OFPAT11_SET_NW_TTL) |
-        (1 << OFPAT11_DEC_NW_TTL) |
-        (1 << OFPAT12_SET_FIELD);
-/* not supported:
- *      (1 << OFPAT13_PUSH_PBB) |
- *      (1 << OFPAT13_POP_PBB) */
+    for (i = 0; i < 4; i++) {
+        ofproto->ogf.max_groups[i] = OFPG_MAX;
+        ofproto->ogf.ofpacts[i] = (UINT64_C(1) << N_OFPACTS) - 1;
+    }
 
     error = ofproto->ofproto_class->construct(ofproto);
     if (error) {
@@ -2805,8 +2787,8 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
     struct ofpbuf *b;
 
     ofproto->ofproto_class->get_features(ofproto, &arp_match_ip,
-                                         &features.actions);
-    ovs_assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */
+                                         &features.ofpacts);
+    ovs_assert(features.ofpacts & (UINT64_C(1) << OFPACT_OUTPUT));
 
     features.datapath_id = ofproto->datapath_id;
     features.n_buffers = pktbuf_capacity();
@@ -3081,37 +3063,44 @@ static enum ofperr
 handle_table_stats_request(struct ofconn *ofconn,
                            const struct ofp_header *request)
 {
+    struct mf_bitmap rw_fields = MF_BITMAP_INITIALIZER;
     struct ofproto *p = ofconn_get_ofproto(ofconn);
-    struct ofp12_table_stats *ots;
+    struct ofputil_table_stats *stats;
     struct ofpbuf *msg;
     int n_tables;
     size_t i;
 
+    for (i = 0; i < MFF_N_IDS; i++) {
+        if (mf_from_id(i)->writable) {
+            bitmap_set1(rw_fields.bm, i);
+        }
+    }
+
     /* Set up default values.
      *
      * ofp12_table_stats is used as a generic structure as
      * it is able to hold all the fields for ofp10_table_stats
      * and ofp11_table_stats (and of course itself).
      */
-    ots = xcalloc(p->n_tables, sizeof *ots);
+    stats = xcalloc(p->n_tables, sizeof *stats);
     for (i = 0; i < p->n_tables; i++) {
-        ots[i].table_id = i;
-        sprintf(ots[i].name, "table%"PRIuSIZE, i);
-        ots[i].match = htonll(OFPXMT13_MASK);
-        ots[i].wildcards = htonll(OFPXMT13_MASK);
-        ots[i].write_actions = htonl(OFPAT11_OUTPUT);
-        ots[i].apply_actions = htonl(OFPAT11_OUTPUT);
-        ots[i].write_setfields = htonll(OFPXMT13_MASK);
-        ots[i].apply_setfields = htonll(OFPXMT13_MASK);
-        ots[i].metadata_match = OVS_BE64_MAX;
-        ots[i].metadata_write = OVS_BE64_MAX;
-        ots[i].instructions = htonl(OFPIT11_ALL);
-        ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK);
-        ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
-        ots[i].active_count = htonl(classifier_count(&p->tables[i].cls));
-    }
-
-    p->ofproto_class->get_tables(p, ots);
+        stats[i].table_id = i;
+        sprintf(stats[i].name, "table%"PRIuSIZE, i);
+        bitmap_set_multiple(stats[i].match.bm, 0, MFF_N_IDS, 1);
+        bitmap_set_multiple(stats[i].wildcards.bm, 0, MFF_N_IDS, 1);
+        stats[i].write_ofpacts = (UINT64_C(1) << N_OFPACTS) - 1;
+        stats[i].apply_ofpacts  = (UINT64_C(1) << N_OFPACTS) - 1;
+        stats[i].write_setfields = rw_fields;
+        stats[i].apply_setfields = rw_fields;
+        stats[i].metadata_match = OVS_BE64_MAX;
+        stats[i].metadata_write = OVS_BE64_MAX;
+        stats[i].instructions = OFPIT13_ALL;
+        stats[i].config = OFPTC11_TABLE_MISS_MASK;
+        stats[i].max_entries = 1000000; /* An arbitrary big number. */
+        stats[i].active_count = classifier_count(&p->tables[i].cls);
+    }
+
+    p->ofproto_class->get_tables(p, stats);
 
     /* Post-process the tables, dropping hidden tables. */
     n_tables = p->n_tables;
@@ -3124,18 +3113,18 @@ handle_table_stats_request(struct ofconn *ofconn,
         }
 
         if (table->name) {
-            ovs_strzcpy(ots[i].name, table->name, sizeof ots[i].name);
+            ovs_strzcpy(stats[i].name, table->name, sizeof stats[i].name);
         }
 
-        if (table->max_flows < ntohl(ots[i].max_entries)) {
-            ots[i].max_entries = htonl(table->max_flows);
+        if (table->max_flows < stats[i].max_entries) {
+            stats[i].max_entries = table->max_flows;
         }
     }
 
-    msg = ofputil_encode_table_stats_reply(ots, n_tables, request);
+    msg = ofputil_encode_table_stats_reply(stats, n_tables, request);
     ofconn_send_reply(ofconn, msg);
 
-    free(ots);
+    free(stats);
 
     return 0;
 }
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 5871930..3e35baa 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -203,7 +203,7 @@ ff fe 50 54 00 00 00 01 62 72 30 00 00 00 00 00 \
 OFPT_FEATURES_REPLY (xid=0x1): dpid:0000505400000001
 n_tables:2, n_buffers:256
 capabilities: FLOW_STATS TABLE_STATS PORT_STATS ARP_MATCH_IP
-actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
+actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
  1(eth1): addr:50:54:00:00:00:02
      config:     0
      state:      0
@@ -1923,20 +1923,24 @@ AT_CHECK([ovs-ofctl ofp-print "\
 03 13 00 38 00 00 00 02 00 08 00 00 00 00 00 00 \
 00 00 00 0f 00 00 00 0f \
 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 \
-00 00 00 01 00 00 00 03 00 00 00 07 00 00 00 0f \
+00 00 00 01 00 02 00 01 00 06 00 01 00 0e 00 01 \
 "], [0], [dnl
 OFPST_GROUP_FEATURES reply (OF1.2) (xid=0x2):
  Group table:
     Types:  0xf
     Capabilities:  0xf
-    All group :
-        max_groups = 0x1 actions=0x00000001
-    Select group :
-        max_groups = 0x2 actions=0x00000003
-    Indirect group :
-        max_groups = 0x3 actions=0x00000007
-    Fast Failover group :
-        max_groups = 0x4 actions=0x0000000f
+    all group:
+       max_groups=0x1
+       actions: output
+    select group:
+       max_groups=0x2
+       actions: output push_vlan
+    indirect group:
+       max_groups=0x3
+       actions: output strip_vlan push_vlan
+    fast failover group:
+       max_groups=0x4
+       actions: output strip_vlan push_vlan push_mpls
 ])
 AT_CLEANUP
 
@@ -2275,7 +2279,7 @@ f5 f6 f7 f8 f9 fa fb fc fd 00 00 00 00 00 00 00 \
       next tables: 1-253
       instructions: apply_actions,clear_actions,write_actions,write_metadata,goto_table
       Write-Actions and Apply-Actions features:
-        actions: output,copy_ttl_out,copy_ttl_in,set_mpls_ttl,dec_mpls_ttl,push_vlan,pop_vlan,push_mpls,pop_mpls,set_queue,group,set_nw_ttl,dec_nw_ttl,set_field,push_pbb,pop_pbb
+        actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
         supported on Set-Field: tun_id,tun_src,tun_dst,metadata,in_port,in_port_oxm,pkt_mark,reg0,reg1,reg2,reg3,reg4,reg5,reg6,reg7,eth_src,eth_dst,vlan_tci,vlan_vid,vlan_pcp,mpls_label,mpls_tc,ip_src,ip_dst,ipv6_src,ipv6_dst,nw_tos,ip_dscp,nw_ecn,nw_ttl,arp_op,arp_spa,arp_tpa,arp_sha,arp_tha,tcp_src,tcp_dst,udp_src,udp_dst,sctp_src,sctp_dst
     matching:
       tun_id: exact match or wildcard
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 3a55ce3..06a7df4 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -36,7 +36,7 @@ AT_CHECK([STRIP_XIDS stdout], [0], [dnl
 OFPT_FEATURES_REPLY: dpid:fedcba9876543210
 n_tables:254, n_buffers:256
 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
-actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
+actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
  LOCAL(br0): addr:aa:55:aa:55:00:00
      config:     PORT_DOWN
      state:      LINK_DOWN
@@ -58,7 +58,7 @@ s/00:0.$/00:0x/' < stdout]],
 OFPT_FEATURES_REPLY: dpid:fedcba9876543210
 n_tables:254, n_buffers:256
 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
-actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
+actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
  1(p1): addr:aa:55:aa:55:00:0x
      config:     PORT_DOWN
      state:      LINK_DOWN
@@ -451,7 +451,7 @@ do
 OFPT_FEATURES_REPLY: dpid:fedcba9876543210
 n_tables:254, n_buffers:256
 capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
-actions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE
+actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
  LOCAL(br0): addr:aa:55:aa:55:00:00
      config:     $config
      state:      $state
@@ -1064,13 +1064,13 @@ AT_CLEANUP
 AT_SETUP([ofproto - flow table configuration (OpenFlow 1.2)])
 OVS_VSWITCHD_START
 # Check the default configuration.
-(mid="wild=0xfffffffff, max=1000000,"
+(mid="wild=0x1ffffffffd, max=1000000,"
  tail="
                lookup=0, matched=0
-               match=0xfffffffff, instructions=0x00000007, config=0x00000003
-               write_actions=0x00000000, apply_actions=0x00000000
-               write_setfields=0x0000000fffffffff
-               apply_setfields=0x0000000fffffffff
+               match=0x1ffffffffd, instructions=0x00000007, config=0x00000003
+               write_actions=0x03ff8001, apply_actions=0x03ff8001
+               write_setfields=0x0000000c0fe7fbdd
+               apply_setfields=0x0000000c0fe7fbdd
                metadata_match=0xffffffffffffffff
                metadata_write=0xffffffffffffffff"
  echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables
@@ -1095,9 +1095,9 @@ AT_CHECK(
 # Check that the configuration was updated.
 mv expout orig-expout
 (echo "OFPST_TABLE reply (OF1.2) (xid=0x2): 254 tables
-  0: main    : wild=0xfffffffff, max=1000000, active=0"
+  0: main    : wild=0x1ffffffffd, max=1000000, active=0"
  tail -n +3 orig-expout | head -7
- echo "  1: table1  : wild=0xfffffffff, max=  1024, active=0"
+ echo "  1: table1  : wild=0x1ffffffffd, max=  1024, active=0"
  tail -n +11 orig-expout) > expout
 AT_CHECK([ovs-ofctl -O OpenFlow12 dump-tables br0], [0], [expout])
 OVS_VSWITCHD_STOP
-- 
1.7.10.4




More information about the dev mailing list