V3:
  1. Update names of functions/macros to make them meaningful.
  2. Fix codingstyle.
  3. Remove useless logic/struct/function.
  4. Make printable messages more friendly.
  5. Add OVS_ACTIONS macro to display all action features.

V2:
  Restructure implement of OFPMP_TABLE_FEATURES
  Change decode_*_raw to normalized pull functions

  1. add defines and funcs to decode table features
  2. restructure OFPMP_TABLE_FEATURES decode function
     restructure the function, now them acts like others.
  3. Change big array to defines.
     Change big array to defines.(oxm, table_feature_prop)
     Fix some names, now they're more meaningful.
  4. use macros to restructure implement
  5. Restructure get_* to more effective ones. (table_features, oxm)
  6. remove useless array and prototype

Simon Horman:
  Fix function paras alignment.
  Fix hard coding to marco.
  Fix VLOG calls with rl.
  Fix CodingStyle:
    max chars per line - 79
  Delete useless blank line.
  Restructure implement by macro.

V1:
  ofp-util: Implement the encode/decode Table Features functions

  Implement the encode/decode table features msgs function, and
  NOTE that we implement the decode functions *_raw, maybe we
  should change it the ofpbuf_pull?

Signed-off-by: Alexander Wu <[email protected]>
---
 lib/ofp-util.c |  699 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/ofp-util.h |  211 +++++++++++++++++
 2 files changed, 910 insertions(+), 0 deletions(-)

diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index ede37b0..f537fe3 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -4078,6 +4078,705 @@ ofputil_encode_port_mod(const struct ofputil_port_mod 
*pm,
     return b;
 }
 
+static enum ofperr
+tfprop_count_n_elem(uint32_t *n_elem, uint16_t length, uint16_t elem_size)
+{
+    int n = 0;
+    if (length % elem_size)
+        return OFPERR_OFPTFFC_BAD_LEN;
+
+    n = length / elem_size;
+    *n_elem = n;
+    return 0;
+}
+
+#define OVS_ACTIONS                                         \
+    DEFINE_ACTION(OFPAT11_OUTPUT         , "output")        \
+    DEFINE_ACTION(OFPAT11_COPY_TTL_OUT   , "copy_ttl_out")  \
+    DEFINE_ACTION(OFPAT11_COPY_TTL_IN    , "copy_ttl_in")   \
+    DEFINE_ACTION(OFPAT11_SET_MPLS_TTL   , "set_mpls_ttl")  \
+    DEFINE_ACTION(OFPAT11_DEC_MPLS_TTL   , "dec_mpls_ttl")  \
+    DEFINE_ACTION(OFPAT11_PUSH_VLAN      , "push_vlan")     \
+    DEFINE_ACTION(OFPAT11_POP_VLAN       , "pop_vlan")      \
+    DEFINE_ACTION(OFPAT11_PUSH_MPLS      , "push_mpls")     \
+    DEFINE_ACTION(OFPAT11_POP_MPLS       , "pop_mpls")      \
+    DEFINE_ACTION(OFPAT11_SET_QUEUE      , "set_queue")     \
+    DEFINE_ACTION(OFPAT11_GROUP          , "group")         \
+    DEFINE_ACTION(OFPAT11_SET_NW_TTL     , "set_nw_ttl")    \
+    DEFINE_ACTION(OFPAT11_DEC_NW_TTL     , "dec_nw_ttl")    \
+    DEFINE_ACTION(OFPAT12_SET_FIELD      , "set_field")     \
+    DEFINE_ACTION(OFPAT13_PUSH_PBB       , "push_pbb")      \
+    DEFINE_ACTION(OFPAT13_POP_PBB        , "pop_pbb")       \
+    DEFINE_ACTION(OFPAT11_EXPERIMENTER   , "experimenter")
+
+enum {
+#define DEFINE_ACTION(ENUM, NAME) + 1
+    N_OVS_ACTION = OVS_ACTIONS
+#undef DEFINE_ACTION
+};
+
+struct action_info action_info[] = {
+#define DEFINE_ACTION(ENUM, NAME)    {ENUM, NAME},
+OVS_ACTIONS
+#undef DEFINE_ACTION
+};
+
+int get_action_num(void)
+{
+    return N_OVS_ACTION;
+}
+
+char *get_action_name(uint16_t type)
+{
+    switch (type) {
+
+#define DEFINE_ACTION(ENUM, NAME)  \
+    case ENUM:                     \
+        return NAME;
+OVS_ACTIONS
+#undef DEFINE_ACTION
+
+    default:
+        return NULL;
+    }
+}
+
+#define OVS_OXMS                                        \
+    DEFINE_OXM(OXM_OF_IN_PORT       , "in_port")        \
+    DEFINE_OXM(OXM_OF_IN_PHY_PORT   , "in_phy_port")    \
+    DEFINE_OXM(OXM_OF_METADATA      , "metadata")       \
+    DEFINE_OXM(OXM_OF_ETH_DST_W     , "eth_dst")        \
+    DEFINE_OXM(OXM_OF_ETH_SRC_W     , "eth_src")        \
+    DEFINE_OXM(OXM_OF_ETH_TYPE      , "eth_type")       \
+    DEFINE_OXM(OXM_OF_VLAN_VID_W    , "vlan_vid")       \
+    DEFINE_OXM(OXM_OF_VLAN_PCP      , "vlan_pcp")       \
+    DEFINE_OXM(OXM_OF_IP_DSCP       , "ip_dscp")        \
+    DEFINE_OXM(OXM_OF_IP_ECN        , "ip_ecn")         \
+    DEFINE_OXM(OXM_OF_IP_PROTO      , "ip_proto")       \
+    DEFINE_OXM(OXM_OF_IPV4_SRC_W    , "ipv4_src")       \
+    DEFINE_OXM(OXM_OF_IPV4_DST_W    , "ipv4_dst")       \
+    DEFINE_OXM(OXM_OF_TCP_SRC       , "tcp_src")        \
+    DEFINE_OXM(OXM_OF_TCP_DST       , "tcp_dst")        \
+    DEFINE_OXM(OXM_OF_UDP_SRC       , "udp_src")        \
+    DEFINE_OXM(OXM_OF_UDP_DST       , "udp_dst")        \
+    DEFINE_OXM(OXM_OF_SCTP_SRC      , "sctp_src")       \
+    DEFINE_OXM(OXM_OF_SCTP_DST      , "sctp_dst")       \
+    DEFINE_OXM(OXM_OF_ICMPV4_TYPE   , "icmpv4_type")    \
+    DEFINE_OXM(OXM_OF_ICMPV4_CODE   , "icmpv4_code")    \
+    DEFINE_OXM(OXM_OF_ARP_OP        , "arp_op")         \
+    DEFINE_OXM(OXM_OF_ARP_SPA_W     , "arp_spa")        \
+    DEFINE_OXM(OXM_OF_ARP_TPA_W     , "arp_tpa")        \
+    DEFINE_OXM(OXM_OF_ARP_SHA_W     , "arp_sha")        \
+    DEFINE_OXM(OXM_OF_ARP_THA_W     , "arp_tha")        \
+    DEFINE_OXM(OXM_OF_IPV6_SRC_W    , "ipv6_src")       \
+    DEFINE_OXM(OXM_OF_IPV6_DST_W    , "ipv6_dst")       \
+    DEFINE_OXM(OXM_OF_IPV6_FLABEL_W , "ipv6_flabel")    \
+    DEFINE_OXM(OXM_OF_ICMPV6_TYPE   , "icmpv6_type")    \
+    DEFINE_OXM(OXM_OF_ICMPV6_CODE   , "icmpv6_code")    \
+    DEFINE_OXM(OXM_OF_IPV6_ND_TARGET, "ipv6_nd_target") \
+    DEFINE_OXM(OXM_OF_IPV6_ND_SLL   , "ipv6_nd_sll")    \
+    DEFINE_OXM(OXM_OF_IPV6_ND_TLL   , "ipv6_nd_tll")    \
+    DEFINE_OXM(OXM_OF_MPLS_LABEL    , "mpls_label")     \
+    DEFINE_OXM(OXM_OF_MPLS_TC       , "mpls_tc")        \
+    DEFINE_OXM(OXM_OF_MPLS_BOS      , "mpls_bos")       \
+    DEFINE_OXM(OXM_OF_TUNNEL_ID_W   , "tunnel_id")      \
+    DEFINE_OXM(OXM_OF_IPV6_EXTHDR_W , "ipv6_exthdr")
+
+enum {
+#define DEFINE_OXM(ENUM, NAME) + 1
+    N_OVS_OXM = OVS_OXMS
+#undef DEFINE_OXM
+};
+
+struct oxm_info oxm_info[] = {
+#define DEFINE_OXM(ENUM, NAME)    {ENUM, NAME},
+OVS_OXMS
+#undef DEFINE_OXM
+};
+
+int get_oxm_num(void)
+{
+    return N_OVS_OXM;
+}
+
+char *get_oxm_name(uint32_t type)
+{
+    switch (type) {
+
+#define DEFINE_OXM(ENUM, NAME)  \
+    case ENUM:                  \
+        return NAME;
+OVS_OXMS
+#undef DEFINE_OXM
+
+    default:
+        return NULL;
+    }
+}
+
+char *table_feature_prop_get_name(enum ofp13_table_feature_prop_type type)
+{
+    switch (type) {
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME)  \
+    case ENUM:                                  \
+        return NAME;
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+    case OFPTFPT13_EXPERIMENTER:
+    case OFPTFPT13_EXPERIMENTER_MISS:
+    default:
+        return NULL;
+    }
+}
+
+uint16_t table_feature_prop_get_length(enum ofp13_table_feature_prop_type type)
+{
+    switch (type) {
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME)  \
+    case ENUM:                                  \
+        return sizeof(STRUCT);
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+    case OFPTFPT13_EXPERIMENTER:
+    case OFPTFPT13_EXPERIMENTER_MISS:
+    default:
+        return 0;
+    }
+}
+
+#define TFPROP_ALIGN 8
+#define MULTIPART_HDR_LEN 8 /* TYPE:2 FLAG:2 PADDING:4 */
+#define MULTIPART_ALIGN 8
+
+static int
+tfprop_is_valid(const struct ofp13_table_feature_prop_header *prop,
+                size_t n_prop)
+{
+    uint16_t len = ntohs(prop->length);
+    return (len >= sizeof *prop
+            && (ROUND_UP(len, TFPROP_ALIGN) / TFPROP_ALIGN) <= n_prop);
+}
+
+static inline struct ofp13_table_feature_prop_header *
+tfprop_next(const struct ofp13_table_feature_prop_header *prop)
+{
+    return ((struct ofp13_table_feature_prop_header *) (void *)
+            ((uint8_t *) prop + ROUND_UP(ntohs(prop->length), TFPROP_ALIGN)));
+}
+
+/* This macro is careful to check for props with bad lengths. */
+#define TFPROP_FOR_EACH(ITER, LEFT, PROPS, N_PROPS)                     \
+    for ((ITER) = (PROPS), (LEFT) = (N_PROPS);                          \
+         (LEFT) > 0 && tfprop_is_valid(ITER, LEFT);                     \
+         ((LEFT) -= ROUND_UP(ntohs((ITER)->length), TFPROP_ALIGN)       \
+                     / TFPROP_ALIGN,                                    \
+          (ITER) = tfprop_next(ITER)))
+
+enum ovs_tfprop_type {
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) OVSTFPROP_##ENUM,
+    OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+};
+
+struct tfprop_type_info {
+    enum ovs_tfprop_type type;
+    const char *name;
+};
+
+static const struct tfprop_type_info prop_info[] = {
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) {OVSTFPROP_##ENUM, NAME},
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+};
+
+#define TF_OPROP_DATA(OPROP) ((void *)(OPROP + 1))
+static enum ofperr
+trans_openflow13_tfprop(const struct ofp13_table_feature_prop_header *oprop,
+                        struct ofputil_table_feature_prop_header *prop)
+{
+    uint32_t data_len;
+    uint32_t padding_len;
+
+    enum ofperr error = 0;
+    uint32_t element_size = 0;
+    uint32_t n_elem = 0;
+    int i;
+
+    prop->type = ntohs(oprop->type);
+    prop->length = ntohs(oprop->length);
+    data_len = prop->length - sizeof *oprop;
+
+    /* NOTE we xmalloc data here, and use it to get/set table-features */
+    prop->data = xmalloc(data_len);
+    memcpy(prop->data, TF_OPROP_DATA(oprop), data_len);
+    padding_len = ROUND_UP(prop->length, TFPROP_ALIGN) - prop->length;
+
+    element_size = table_feature_prop_get_length(prop->type);
+    if (element_size == 0) {
+        return OFPERR_OFPTFFC_BAD_TYPE;
+    } else if (data_len % element_size) {
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+    error = tfprop_count_n_elem(&n_elem, data_len, element_size);
+    if (error) {
+        return error;
+    }
+
+    switch (prop->type) {
+    case OFPUTIL_INSTRUCTIONS:
+    case OFPUTIL_INSTRUCTIONS_MISS: {
+        struct ofp11_instruction *oinst = TF_OPROP_DATA(oprop);
+        struct ofputil_instruction *inst = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            inst[i].len = ntohs(oinst[i].len);
+            inst[i].type = ntohs(oinst[i].type);
+        }
+        break;
+    }
+    case OFPUTIL_NEXT_TABLES:
+    case OFPUTIL_NEXT_TABLES_MISS: {
+        uint8_t *ontable = TF_OPROP_DATA(oprop);
+        uint8_t *ntable = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            ntable[i] = ontable[i];
+        }
+        break;
+    }
+    case OFPUTIL_WRITE_ACTIONS:
+    case OFPUTIL_WRITE_ACTIONS_MISS:
+    case OFPUTIL_APPLY_ACTIONS:
+    case OFPUTIL_APPLY_ACTIONS_MISS: {
+        const struct ofp_action_header *oact = TF_OPROP_DATA(oprop);
+        struct ofp_action_header *act = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            act[i].len = ntohs(oact[i].len);
+            act[i].type = ntohs(oact[i].type);
+        }
+        break;
+    }
+    case OFPUTIL_MATCH:
+    case OFPUTIL_WILDCARDS:
+    case OFPUTIL_WRITE_SETFIELD:
+    case OFPUTIL_WRITE_SETFIELD_MISS:
+    case OFPUTIL_APPLY_SETFIELD:
+    case OFPUTIL_APPLY_SETFIELD_MISS: {
+        const ovs_be32 *be32 = TF_OPROP_DATA(oprop);
+        uint32_t *u32 = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            u32[i] = ntohl(be32[i]);
+        }
+        break;
+    }
+    case OFPUTIL_EXPERIMENTER:
+    case OFPUTIL_EXPERIMENTER_MISS:
+    default:
+        return OFPERR_OFPTFFC_BAD_TYPE;
+    }
+    return 0;
+}
+
+static enum ofperr
+encode_openflow13_tfprop(struct ofpbuf *reply,
+                         const struct ofputil_table_feature_prop_header *prop)
+{
+    uint32_t data_len;
+    uint32_t padding_len;
+    void *data;
+
+    uint32_t n_elem;
+    uint16_t element_size;
+    enum ofperr error;
+    int i;
+    struct ofp13_table_feature_prop_header *oprop;
+
+    oprop = ofpbuf_put_zeros(reply, sizeof *oprop);
+    data_len = prop->length - sizeof *oprop;
+    padding_len = ROUND_UP(prop->length, TFPROP_ALIGN) - prop->length;
+
+    element_size = table_feature_prop_get_length(prop->type);
+    if (0 == element_size) {
+        return OFPERR_OFPTFFC_BAD_TYPE;
+    } else if (data_len % element_size) {
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+    error = tfprop_count_n_elem(&n_elem, data_len, element_size);
+    if (error) {
+        return error;
+    }
+
+    oprop->type = htons(prop->type);
+    oprop->length = htons(prop->length);
+
+    data = ofpbuf_put_zeros(reply, data_len + padding_len);
+
+    switch (prop->type) {
+    case OFPUTIL_INSTRUCTIONS:
+    case OFPUTIL_INSTRUCTIONS_MISS: {
+        struct ofp11_instruction *oinst = data;
+        struct ofputil_instruction *inst = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            oinst[i].len = htons(inst[i].len);
+            oinst[i].type = htons(inst[i].type);
+        }
+        break;
+    }
+    case OFPUTIL_NEXT_TABLES:
+    case OFPUTIL_NEXT_TABLES_MISS: {
+        uint8_t *ontable = data;
+        uint8_t *ntable = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            ontable[i] = ntable[i];
+        }
+        break;
+    }
+    case OFPUTIL_WRITE_ACTIONS:
+    case OFPUTIL_WRITE_ACTIONS_MISS:
+    case OFPUTIL_APPLY_ACTIONS:
+    case OFPUTIL_APPLY_ACTIONS_MISS: {
+        struct ofp_action_header *oact = data;
+        struct ofp_action_header *act = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            oact[i].len = htons(act[i].len);
+            oact[i].type = htons(act[i].type);
+        }
+        break;
+    }
+    case OFPUTIL_MATCH:
+    case OFPUTIL_WILDCARDS:
+    case OFPUTIL_WRITE_SETFIELD:
+    case OFPUTIL_WRITE_SETFIELD_MISS:
+    case OFPUTIL_APPLY_SETFIELD:
+    case OFPUTIL_APPLY_SETFIELD_MISS: {
+        ovs_be32 *be32 = data;
+        uint32_t *u32 = prop->data;
+        for (i = 0; i < n_elem; i++) {
+            be32[i] = htonl(u32[i]);
+        }
+        break;
+    }
+    case OFPUTIL_EXPERIMENTER:
+    case OFPUTIL_EXPERIMENTER_MISS:
+    default:
+        return OFPERR_OFPTFFC_BAD_TYPE;
+    }
+    return 0;
+}
+
+static enum ofperr
+decode_openflow13_tfprop(const struct ofp13_table_feature_prop_header *prop,
+                         enum ofp13_table_feature_prop_type *type)
+{
+    uint16_t len = ntohs(prop->length);
+
+    switch (prop->type) {
+    case CONSTANT_HTONS(OFPTFPT13_EXPERIMENTER):
+    case CONSTANT_HTONS(OFPTFPT13_EXPERIMENTER_MISS):
+        return OFPERR_OFPTFFC_BAD_ARGUMENT;
+
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME)      \
+    case CONSTANT_HTONS(ENUM):                      \
+        if (len - sizeof *prop / sizeof(STRUCT)) {  \
+            *type = OVSTFPROP_##ENUM;               \
+            return 0;                               \
+        } else {                                    \
+            return OFPERR_OFPBIC_BAD_LEN;           \
+        }
+OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+
+    default:
+        return OFPERR_OFPTFFC_BAD_TYPE;
+    }
+}
+
+static enum ofperr
+table_feature_check_len(const struct ofp13_table_features *feature)
+{
+    uint16_t len = ntohs(feature->length);
+
+    if (len < sizeof *feature || len % 8) {
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+    return 0;
+}
+
+static void
+table_feature_get_id(const struct ofp13_table_features *feature,
+                     uint8_t *table_id)
+{
+    *table_id = feature->table_id;
+}
+
+static int
+table_feature_is_valid(const struct ofp13_table_features *feature,
+                       size_t n_feature)
+{
+    uint16_t len = ntohs(feature->length);
+    return (!(len % 8)
+            && len >= (sizeof *feature)
+            && (len / sizeof *feature) <= n_feature);
+}
+
+static inline struct ofp13_table_features *
+table_feature_next(const struct ofp13_table_features *feature)
+{
+    return ((struct ofp13_table_features *) (void *)
+            ((uint8_t *) feature + ntohs(feature->length)));
+}
+
+/* This macro is careful to check for props with bad lengths. */
+#define TABLE_FEATURE_FOR_EACH(ITER, LEFT, FEATURES, N_FEATURES)        \
+    for ((ITER) = (FEATURES), (LEFT) = (N_FEATURES);                    \
+         (LEFT) > 0 && table_feature_is_valid(ITER, LEFT);              \
+         ((LEFT) -= (ntohs((ITER)->length)                              \
+                     / MULTIPART_ALIGN),                                \
+          (ITER) = table_feature_next(ITER)))
+
+static enum ofperr
+decode_openflow13_table_features(const struct ofp13_table_features features[],
+                                 size_t n_features,
+                                 const struct ofp13_table_features *out[])
+{
+    const struct ofp13_table_features *feature;
+    size_t left;
+
+    memset(out, 0, OFTABLE_NUM * sizeof *out);
+    TABLE_FEATURE_FOR_EACH (feature, left, features, n_features) {
+        uint8_t table_id;
+        enum ofperr error;
+
+        error = table_feature_check_len(feature);
+        if (error) {
+            return error;
+        }
+
+        table_feature_get_id(feature, &table_id);
+
+        if (out[table_id]) {
+            /* CHECK if we could return a more meaningful type */
+            return OFPERR_OFPTFFC_BAD_TABLE;
+        }
+        out[table_id] = feature;
+    }
+
+    if (left) {
+        VLOG_WARN( "Bad table features format at offset %zu.",
+                     (n_features - left) * sizeof *feature);
+        return OFPERR_OFPBIC_BAD_LEN;
+    }
+    return 0;
+}
+
+static enum ofperr
+decode_openflow13_tfprops(const struct ofp13_table_feature_prop_header props[],
+                          size_t n_props,
+                          const struct ofp13_table_feature_prop_header *out[])
+{
+    const struct ofp13_table_feature_prop_header *prop;
+    size_t left;
+
+    memset(out, 0, N_OVS_TFPROPS * sizeof *out);
+    TFPROP_FOR_EACH (prop, left, props, n_props) {
+        enum ofp13_table_feature_prop_type type;
+        enum ofperr error;
+
+        error = decode_openflow13_tfprop(prop, &type);
+        if (error) {
+            return error;
+        }
+
+        if (out[type]) {
+            return OFPERR_OFPTFFC_BAD_TYPE;
+        }
+        out[type] = prop;
+    }
+
+    if (left) {
+        VLOG_WARN( "Bad table features property format at offset %zu.",
+                     (n_props - left) * TFPROP_ALIGN);
+        return OFPERR_OFPBIC_BAD_LEN;
+    }
+    return 0;
+}
+
+static enum ofperr
+translate_table_features(struct ofputil_table_features *tf,
+                         const struct ofp13_table_features *otf)
+{
+    enum ofperr error;
+    const struct ofp13_table_feature_prop_header *props;
+    uint16_t props_len;
+    const struct ofp13_table_feature_prop_header *ps[N_OVS_TFPROPS];
+    int i;
+
+    tf->length = ntohs(otf->length);
+    tf->table_id = otf->table_id;
+    ovs_strlcpy(tf->name, otf->name, OFP_MAX_TABLE_NAME_LEN);
+    tf->metadata_match = ntohll(otf->metadata_match);
+    tf->metadata_write = ntohll(otf->metadata_write);
+    tf->config = ntohl(otf->config);
+    tf->max_entries = ntohl(otf->max_entries);
+
+    props = (const struct ofp13_table_feature_prop_header *)(otf + 1);
+    props_len = ntohs(otf->length) - sizeof(*otf);
+    error = decode_openflow13_tfprops(props, props_len / TFPROP_ALIGN, ps);
+    if (error) {
+        return error;
+    }
+
+    for (i = 0; i < N_OVS_TFPROPS; i++) {
+        if (ps[i] == NULL) {
+            continue;
+        }
+        trans_openflow13_tfprop(ps[i], &tf->props[i]);
+        ++tf->n_property;
+    }
+
+    return 0;
+}
+
+enum ofperr
+ofputil_pull_table_features(const struct ofp_header *oh, int *tfs_num,
+                            struct ofputil_table_features tfs[],
+                            uint32_t *flag)
+{
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+    struct ofpbuf msg;
+    enum ofpraw raw;
+
+    const struct ofp13_table_features *features;
+    const struct ofp13_table_features *fs[OFTABLE_NUM];
+
+    uint32_t features_len;
+    int i;
+    int tfs_cursor = 0;
+    int error = 0;
+
+    ofpbuf_use_const(&msg, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&msg);
+    if (raw != OFPRAW_OFPST13_TABLE_FEATURES_REQUEST
+        && raw != OFPRAW_OFPST13_TABLE_FEATURES_REPLY) {
+        VLOG_DBG_RL(&rl, "Bad openflow msg type(%u).\n", raw);
+        return OFPERR_OFPBRC_BAD_TYPE;
+    }
+
+    if (msg.size == 0) /* stands for GET table_features request */ {
+        *flag = OVS_TF_GET;
+        return 0;
+    }
+
+    /* Else if request contains body, then it's a SET table_features request */
+    *flag = OVS_TF_SET;
+
+    features_len = (ntohs(oh->length) - sizeof(*oh) - MULTIPART_HDR_LEN);
+    features = ofpbuf_try_pull(&msg, features_len);
+    if (features == NULL) {
+        VLOG_WARN_RL(&rl, "Table features length %u is longer than space "
+            "in message length %zu.", features_len, msg.size);
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+    error = decode_openflow13_table_features(
+        features, features_len / MULTIPART_ALIGN, fs);
+    if (error) {
+        return error;
+    }
+
+    for (i = 0; i < OFTABLE_NUM; i++) {
+        if (fs[i] == NULL) {
+            continue;
+        }
+
+        translate_table_features(&tfs[tfs_cursor++], fs[i]);
+    }
+
+    *tfs_num = tfs_cursor;
+    return error;
+}
+
+static enum ofperr
+ofputil_encode_table_features_props(struct ofpbuf *reply,
+                          const struct ofputil_table_feature_prop_header 
*props,
+                          int prop_num)
+{
+    int i;
+    enum ofperr error;
+
+    for (i = 0; i < prop_num; i++) {
+        const struct ofputil_table_feature_prop_header *prop = &props[i];
+        if (!prop->data || !prop->length) {
+            continue;
+        }
+
+        error = encode_openflow13_tfprop(reply, prop);
+        if (error) {
+            return error;
+        }
+    }
+
+    return 0;
+}
+
+void
+ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
+                                    struct list *replies)
+{
+    struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
+    size_t start_otf = reply->size;
+    enum ofpraw raw;
+
+    ofpraw_decode_partial(&raw, reply->data, reply->size);
+    if (raw == OFPRAW_OFPST13_TABLE_FEATURES_REPLY) {
+        struct ofp13_table_features *otf;
+
+        ofpbuf_put_zeros(reply, sizeof *otf);
+        ofputil_encode_table_features_props(reply, tf->props, tf->n_property);
+
+        otf = ofpbuf_at_assert(reply, start_otf, sizeof *otf);
+        otf->length = htons(reply->size - start_otf);
+        otf->table_id = tf->table_id;
+        ovs_strlcpy(otf->name, tf->name, OFP_MAX_TABLE_NAME_LEN);
+        otf->metadata_match = htonll(tf->metadata_match);
+        otf->metadata_write = htonll(tf->metadata_write);
+        otf->config = htonl(tf->config);
+        otf->max_entries = htonl(tf->max_entries);
+    } else {
+        NOT_REACHED();
+    }
+    ofpmp_postappend(replies, start_otf);
+}
+
+/* Returns an OpenFlow group features request for OpenFlow version
+ * 'ofp_version'. */
+struct ofpbuf *
+ofputil_encode_table_features_request(enum ofp_version ofp_version)
+{
+    struct ofpbuf *request = NULL;
+
+    switch (ofp_version) {
+    case OFP10_VERSION:
+    case OFP11_VERSION:
+        ovs_fatal(0, "dump-table-features needs OpenFlow 1.2 or later "
+                     "(\'-O OpenFlow12\')");
+    case OFP12_VERSION:
+    case OFP13_VERSION: {
+        request = ofpraw_alloc(OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
+                               ofp_version, 0);
+        break;
+    }
+    default:
+        NOT_REACHED();
+    }
+
+    return request;
+}
+
 /* ofputil_table_mod */
 
 /* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index fef85e0..881e092 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -599,6 +599,217 @@ enum ofperr ofputil_decode_table_mod(const struct 
ofp_header *,
 struct ofpbuf *ofputil_encode_table_mod(const struct ofputil_table_mod *,
                                        enum ofputil_protocol);
 
+struct ofputil_table_feature_prop_header {
+    uint16_t type;   /* One of OFPTFPT_*. */
+    uint16_t length; /* Length in bytes of this property. */
+    void *data;
+};
+
+enum ovs_table_features_flag {
+    OVS_TF_GET = (1 << 0),
+    OVS_TF_SET = (1 << 1)
+};
+
+#define OFTABLE_NUM 0xff
+
+/* Abstract ofp13_table_features */
+struct ofputil_table_features {
+    uint16_t length;          /* Length is padded to 64 bits. */
+    uint8_t table_id;         /* Identifier of table. Lower numbered tables
+                                 are consulted first. */
+    char name[OFP_MAX_TABLE_NAME_LEN];
+    uint64_t metadata_match;  /* Bits of metadata table can match. */
+    uint64_t 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 ofputil_table_feature_prop_header props[0xff];
+    uint16_t n_property;
+};
+
+struct action_info {
+    uint32_t type;
+    char *name;
+};
+
+extern struct action_info action_info[];
+int get_action_num(void);
+char *get_action_name(uint16_t type);
+
+struct oxm_info {
+    uint32_t type;
+    char *name;
+};
+
+extern struct oxm_info oxm_info[];
+int get_oxm_num(void);
+char *get_oxm_name(uint32_t type);
+
+#define OVS_TABLE_FEATURE_PROPS                         \
+    DEFINE_TFPROP(OFPTFPT13_INSTRUCTIONS,               \
+         struct ofp11_instruction, instruction_array,   \
+         "Instruction")                                 \
+    DEFINE_TFPROP(OFPTFPT13_INSTRUCTIONS_MISS,          \
+         struct ofp11_instruction, instruction_array,   \
+         "Instruction miss")                            \
+    DEFINE_TFPROP(OFPTFPT13_NEXT_TABLES,                \
+         uint8_t, next_table_array,                     \
+         "Next tables")                                 \
+    DEFINE_TFPROP(OFPTFPT13_NEXT_TABLES_MISS,           \
+         uint8_t, next_table_array,                     \
+         "Next tables miss")                            \
+    DEFINE_TFPROP(OFPTFPT13_WRITE_ACTIONS,              \
+         struct ofp_action_header, action_array,        \
+         "Write actions")                               \
+    DEFINE_TFPROP(OFPTFPT13_WRITE_ACTIONS_MISS,         \
+         struct ofp_action_header, action_array,        \
+         "Write actions miss")                          \
+    DEFINE_TFPROP(OFPTFPT13_APPLY_ACTIONS,              \
+         struct ofp_action_header, action_array,        \
+         "Apply actions")                               \
+    DEFINE_TFPROP(OFPTFPT13_APPLY_ACTIONS_MISS,         \
+         struct ofp_action_header, action_array,        \
+         "Apply actions miss")                          \
+    DEFINE_TFPROP(OFPTFPT13_MATCH,                      \
+         ovs_be32, oxm_array,                           \
+         "Match")                                       \
+    DEFINE_TFPROP(OFPTFPT13_WILDCARDS,                  \
+         ovs_be32, oxm_array,                           \
+         "Wildcards")                                   \
+    DEFINE_TFPROP(OFPTFPT13_WRITE_SETFIELD,             \
+         ovs_be32, oxm_array,                           \
+         "Write setfield")                              \
+    DEFINE_TFPROP(OFPTFPT13_WRITE_SETFIELD_MISS,        \
+         ovs_be32, oxm_array,                           \
+         "Write setfield miss")                         \
+    DEFINE_TFPROP(OFPTFPT13_APPLY_SETFIELD,             \
+         ovs_be32, oxm_array,                           \
+         "Apply setfield")                              \
+    DEFINE_TFPROP(OFPTFPT13_APPLY_SETFIELD_MISS,        \
+         ovs_be32, oxm_array,                           \
+         "Apply setfield miss")
+
+enum {
+#define DEFINE_TFPROP(ENUM, STRUCT, TAG, NAME) + 1
+    N_OVS_TFPROPS = OVS_TABLE_FEATURE_PROPS
+#undef DEFINE_TFPROP
+};
+
+/* Table Feature property types.
+ * Low order bit cleared indicates a property for a regular Flow Entry.
+ * Low order bit set indicates a property for the Table-Miss Flow Entry. */
+enum ofputil_table_feature_prop_type {
+    OFPUTIL_INSTRUCTIONS         = 0, /* Instructions property. */
+    OFPUTIL_INSTRUCTIONS_MISS    = 1, /* Instructions for table-miss. */
+    OFPUTIL_NEXT_TABLES          = 2, /* Next Table property. */
+    OFPUTIL_NEXT_TABLES_MISS     = 3, /* Next Table for table-miss. */
+    OFPUTIL_WRITE_ACTIONS        = 4, /* Write Actions property. */
+    OFPUTIL_WRITE_ACTIONS_MISS   = 5, /* Write Actions for table-miss. */
+    OFPUTIL_APPLY_ACTIONS        = 6, /* Apply Actions property. */
+    OFPUTIL_APPLY_ACTIONS_MISS   = 7, /* Apply Actions for table-miss. */
+    OFPUTIL_MATCH                = 8, /* Match property. */
+    OFPUTIL_WILDCARDS            = 10, /* Wildcards property. */
+    OFPUTIL_WRITE_SETFIELD       = 12, /* Write Set-Field property. */
+    OFPUTIL_WRITE_SETFIELD_MISS  = 13, /* Write Set-Field for table-miss. */
+    OFPUTIL_APPLY_SETFIELD       = 14, /* Apply Set-Field property. */
+    OFPUTIL_APPLY_SETFIELD_MISS  = 15, /* Apply Set-Field for table-miss. */
+    OFPUTIL_EXPERIMENTER         = 0xFFFE, /* Experimenter property. */
+    OFPUTIL_EXPERIMENTER_MISS    = 0xFFFF, /* Experimenter for table-miss. */
+};
+
+struct ofputil_instruction {
+    uint16_t type;              /* Instruction type */
+    uint16_t len;               /* Length of this struct in bytes. */
+    uint8_t pad[4];
+};
+
+/* Instructions property */
+struct ofputil_table_feature_prop_instructions {
+    uint16_t    type;    /* One of OFPUTIL_INSTRUCTIONS,
+                            OFPUTIL_INSTRUCTIONS_MISS. */
+    uint16_t    length;  /* Length in bytes of this property. */
+    uint8_t     table_id;
+    uint8_t     n_instructions;
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the instruction ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    struct ofputil_instruction *instruction_ids;
+};
+
+#define NEXT_TABLE_NUM  0xff
+
+struct ofputil_table_feature_prop_next_tables {
+    uint16_t    type;   /* One of OFPUTIL_NEXT_TABLES,
+                           OFPUTIL_NEXT_TABLES_MISS. */
+    uint16_t    length; /* Length in bytes of this property. */
+    uint8_t     n_next_table;
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the table_ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    uint8_t     next_table_ids[NEXT_TABLE_NUM]; /* List of table ids. */
+};
+
+struct ofputil_table_feature_prop_actions {
+    uint16_t    type;   /* One of OFPUTIL_WRITE_ACTIONS,
+                           OFPUTIL_WRITE_ACTIONS_MISS,
+                           OFPUTIL_APPLY_ACTIONS,
+                           OFPUTIL_APPLY_ACTIONS_MISS. */
+    uint16_t    length; /* Length in bytes of this property. */
+    uint8_t     n_actions;
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the action_ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+     struct ofp_action_header *action_ids;    /* List of actions
+                                                   without any data */
+};
+
+/* Match, Wildcard or Set-Field property */
+struct ofputil_table_feature_prop_oxm {
+    uint16_t    type;   /* One of OFPTFPT13_MATCH, OFPTFPT13_WILDCARDS,
+                           OFPTFPT13_WRITE_SETFIELD,
+                           OFPTFPT13_WRITE_SETFIELD_MISS,
+                           OFPTFPT13_APPLY_SETFIELD,
+                           OFPTFPT13_APPLY_SETFIELD_MISS. */
+    uint16_t    length; /* Length in bytes of this property. */
+    uint8_t     n_oxm;
+    /* Followed by:
+     *   - Exactly (length - 4) bytes containing the oxm_ids, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    /* enum   ofputil_match_bitmap  oxm_bits; */  /*  Array of OXM headers */
+};
+
+/* Experimenter table feature property */
+struct ofputil_table_feature_prop_experimenter {
+    uint16_t    type;     /* One of OFPTFPT13_EXPERIMENTER,
+                             OFPTFPT13_EXPERIMENTER_MISS. */
+    uint16_t    length;   /* Length in bytes of this property. */
+    uint32_t    experimenter; /* Experimenter ID which takes the same form
+                                 as in struct ofp_experimenter_header. */
+    uint32_t    exp_type;     /* Experimenter defined. */
+    /* Followed by:
+     *   - Exactly (length - 12) bytes containing the experimenter data, then
+     *   - Exactly (length + 7)/8*8 - (length) (between 0 and 7)
+     *     bytes of all-zero bytes */
+    /*uint32_t    experimenter_data[10]; */
+};
+
+enum ofperr
+ofputil_pull_table_features(const struct ofp_header *oh, int *n,
+                            struct ofputil_table_features tfs[],
+                            uint32_t *flag);
+struct ofpbuf *
+ofputil_encode_table_features_request(enum ofp_version ofp_version);
+void
+ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
+                                    struct list *replies);
+
+uint16_t table_feature_prop_get_length(enum ofp13_table_feature_prop_type 
type);
+char *table_feature_prop_get_name(enum ofp13_table_feature_prop_type type);
+
 /* Meter band configuration for all supported band types. */
 struct ofputil_meter_band {
     uint16_t type;
-- 
1.7.3.1.msysgit.0


_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev

Reply via email to