[ovs-dev] [PATCH 2/4] Implement the encode/decode Table Features functions

Alexander Wu alexander.wu at huawei.com
Sat Oct 26 10:14:28 UTC 2013


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 <alexander.wu at huawei.com>
---
  lib/ofp-print.c |  128 +++++++++++-
  lib/ofp-util.c  |  646 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 772 insertions(+), 2 deletions(-)

diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index e4d0303..418f918 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2381,6 +2381,127 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
      ofp_print_group(s, gm.group_id, gm.type, &gm.buckets);
  }

+/* Appends a string representation of 'prop' to 's'. */
+static void
+table_feature_prop_format(const struct ofputil_table_feature_prop_header *prop,
+                                struct ds *s)
+{
+    int i = 0;
+    int n = 0;
+    int element_size = (int)get_prop_length(prop->type);
+    if (!element_size) {
+        /* FIXME LOG SOMETHING */
+        return;
+    } else {
+        n = (prop->length - 4) / element_size;
+    }
+
+    ds_put_format(s, "%s: ", get_prop_name(prop->type));
+
+    switch (prop->type) {
+    case OFPTFPT13_INSTRUCTIONS:
+    case OFPTFPT13_INSTRUCTIONS_MISS: {
+        struct ofp11_instruction *inst = (struct ofp11_instruction *)prop->data;
+
+        /* FIXME ofpacts_format */
+        for (i = 0; i < n; i++) {
+            ds_put_format(s, "%"PRIu16, inst[i].type);
+            if (i != n - 1)
+                ds_put_format(s, ",");
+        }
+        break;
+    }
+    case OFPTFPT13_NEXT_TABLES:
+    case OFPTFPT13_NEXT_TABLES_MISS: {
+        uint8_t *ntables = prop->data;
+        for (i = 0; i < n; i++) {
+            ds_put_format(s, "%"PRIu8, ntables[i]);
+            if (i != n - 1)
+                ds_put_format(s, ",");
+        }
+        break;
+    }
+    case OFPTFPT13_WRITE_ACTIONS:
+    case OFPTFPT13_WRITE_ACTIONS_MISS:
+    case OFPTFPT13_APPLY_ACTIONS:
+    case OFPTFPT13_APPLY_ACTIONS_MISS: {
+        struct ofp_action_header *acts =(struct ofp_action_header *)prop->data;
+
+        /* FIXME ofpacts_format */
+        for (i = 0; i < n; i++) {
+            ds_put_format(s, "%"PRIu16, acts[i].type);
+            if (i != n - 1)
+                ds_put_format(s, ",");
+        }
+        break;
+    }
+    case OFPTFPT13_MATCH:
+    case OFPTFPT13_WILDCARDS:
+    case OFPTFPT13_WRITE_SETFIELD:
+    case OFPTFPT13_WRITE_SETFIELD_MISS:
+    case OFPTFPT13_APPLY_SETFIELD:
+    case OFPTFPT13_APPLY_SETFIELD_MISS: {
+        uint32_t *oxm = (uint32_t *)prop->data;
+
+        for (i = 0; i < n; i++) {
+            ds_put_format(s, "%s", get_oxm_name(oxm[i]));
+            if (i != n - 1)
+                ds_put_format(s, ",");
+        }
+        break;
+    }
+    case OFPTFPT13_EXPERIMENTER:
+    case OFPTFPT13_EXPERIMENTER_MISS:
+        ds_put_format(s, "experimenter");
+        if (i != n - 1)
+            ds_put_format(s, ",");
+        break;
+    default:
+        ds_put_format(s, "unknown(%u)", prop->type);
+        if (i != n - 1)
+            ds_put_format(s, ",");
+        break;
+    }
+}
+
+
+static void
+ofp_print_table_features_stats_single(struct ds *s,
+                        const struct ofputil_table_features *tf)
+{
+    int i;
+    ds_put_format(s, "\n  %"PRIu8":", tf->table_id);
+    ds_put_format(s, " name:%s", tf->name);
+    ds_put_format(s, " metadata_match:%"PRIx64, tf->metadata_match);
+    ds_put_format(s, " metadata_write:%"PRIx64, tf->metadata_write);
+    ds_put_format(s, " config:%"PRIx32, tf->config);
+    ds_put_format(s, " max_entries:%"PRIu32, tf->max_entries);
+
+    ds_put_format(s, "\n    Properties:");
+    for (i = 0; i < tf->n_property; i++) {
+        if (tf->props[i].data == NULL || tf->props[i].length == 0)
+            continue;
+
+        ds_put_format(s, "\n      ");
+        table_feature_prop_format(&tf->props[i], s);
+    }
+    ds_put_format(s, "\n");
+}
+
+static void
+ofp_print_table_features_stats(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofputil_table_features tfs[0xff + 1];
+    int tfs_num;
+    int i;
+
+    ofputil_decode_table_features_reply(oh, &tfs_num, tfs);
+
+    for (i = 0; i < tfs_num; i++) {
+        ofp_print_table_features_stats_single(s, &tfs[i]);
+    }
+}
+
  static void
  ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
                  struct ds *string, int verbosity)
@@ -2419,10 +2540,13 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
          ofp_print_group_mod(string, oh);
          break;

-    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
-    case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
      case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
      case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+        ofp_print_table_features_stats(string, oh);
+        break;
+
+    case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
+    case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
          ofp_print_not_implemented(string);
          break;

diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 8c200ce..090e0a4 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -3752,6 +3752,652 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
      return b;
  }

+static enum ofperr table_features_move_data(uint8_t *dst, uint8_t **src,
+                        uint32_t *length, uint32_t data_len)
+{
+    memcpy(dst, *src, data_len);
+    if (*length < data_len)
+        return OFPERR_OFPTFFC_BAD_LEN;
+    *length -= data_len;
+    *src += data_len;
+    return 0;
+}
+
+static enum ofperr
+decode_table_features_prop_header(uint8_t **p, uint32_t *length,
+            struct ofputil_table_feature_prop_header *prop)
+{
+    struct ofp13_table_feature_prop_header oprop;
+
+    table_features_move_data((uint8_t*)&oprop, p, length, sizeof(oprop));
+
+    prop->type = ntohs(oprop.type);
+    prop->length = ntohs(oprop.length);
+
+    if (prop->length < sizeof(oprop)) {
+        VLOG_DBG("decode table feature property err: prop length %u < "
+            "min header length %zu \n", prop->length, sizeof(oprop));
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+    return 0;
+}
+
+static int prop_get_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;
+}
+
+static void ntoh_instruction_array(uint8_t *array, uint16_t n_elem)
+{
+    int i;
+    struct ofp11_instruction *oi = (struct ofp11_instruction *)array;
+    for (i = 0; i < n_elem; i++) {
+        oi[i].len = ntohs(oi[i].len);
+        oi[i].type = ntohs(oi[i].type);
+    }
+}
+
+static void ntoh_action_array(uint8_t *array, uint16_t n_elem)
+{
+    int i;
+    struct ofp_action_header *oa = (struct ofp_action_header *)array;
+    for (i = 0; i < n_elem; i++) {
+        oa[i].len = ntohs(oa[i].len);
+        oa[i].type = ntohs(oa[i].type);
+    }
+}
+
+static void ntoh_be32_array(uint8_t *array, uint16_t n_elem)
+{
+    int i;
+    ovs_be32 *be32 = (ovs_be32 *)array;
+    for (i = 0; i < n_elem; i++) {
+        be32[i] = ntohl(be32[i]);
+    }
+}
+
+static void hton_instruction_array(uint8_t *array, uint16_t n_elem)
+{
+    int i;
+    struct ofp11_instruction *oi = (struct ofp11_instruction *)array;
+    for (i = 0; i < n_elem; i++) {
+        oi[i].len = htons(oi[i].len);
+        oi[i].type = htons(oi[i].type);
+    }
+}
+
+static void hton_action_array(uint8_t *array, uint16_t n_elem)
+{
+    int i;
+    struct ofp_action_header *oa = (struct ofp_action_header *)array;
+    for (i = 0; i < n_elem; i++) {
+        oa[i].len = htons(oa[i].len);
+        oa[i].type = htons(oa[i].type);
+    }
+}
+
+static void hton_be32_array(uint8_t *array, uint16_t n_elem)
+{
+    int i;
+    ovs_be32 *be32 = (ovs_be32 *)array;
+    for (i = 0; i < n_elem; i++) {
+        be32[i] = htonl(be32[i]);
+    }
+}
+
+struct oxm_variable oxm_variables[] = {
+    {OXM_OF_IN_PORT, "IN_PORT"},
+    {OXM_OF_IN_PHY_PORT, "IN_PHY_PORT"},
+    {OXM_OF_METADATA, "METADATA"},
+    {OXM_OF_ETH_DST, "ETH_DST"},
+    {OXM_OF_ETH_SRC, "ETH_SRC"},
+    {OXM_OF_ETH_TYPE, "ETH_TYPE"},
+    {OXM_OF_VLAN_VID, "VLAN_VID"},
+    {OXM_OF_VLAN_PCP, "VLAN_PCP"},
+    {OXM_OF_IP_DSCP, "IP_DSCP"},
+    {OXM_OF_IP_ECN, "IP_ECN"},
+    {OXM_OF_IP_PROTO, "IP_PROTO"},
+    {OXM_OF_IPV4_SRC, "IPV4_SRC"},
+    {OXM_OF_IPV4_DST, "IPV4_DST"},
+    {OXM_OF_TCP_SRC, "TCP_SRC"},
+    {OXM_OF_TCP_DST, "TCP_DST"},
+    {OXM_OF_UDP_SRC, "UDP_SRC"},
+    {OXM_OF_UDP_DST, "UDP_DST"},
+    {OXM_OF_SCTP_SRC, "SCTP_SRC"},
+    {OXM_OF_SCTP_DST, "SCTP_DST"},
+    {OXM_OF_ICMPV4_TYPE, "ICMPV4_TYPE"},
+    {OXM_OF_ICMPV4_CODE, "ICMPV4_CODE"},
+    {OXM_OF_ARP_OP, "ARP_OP"},
+    {OXM_OF_ARP_SPA, "ARP_SPA"},
+    {OXM_OF_ARP_TPA, "ARP_TPA"},
+    {OXM_OF_ARP_SHA, "ARP_SHA"},
+    {OXM_OF_ARP_THA, "ARP_THA"},
+    {OXM_OF_IPV6_SRC, "IPV6_SRC"},
+    {OXM_OF_IPV6_DST, "IPV6_DST"},
+    {OXM_OF_IPV6_FLABEL, "IPV6_FLABEL"},
+    {OXM_OF_ICMPV6_TYPE, "ICMPV6_TYPE"},
+    {OXM_OF_ICMPV6_CODE, "ICMPV6_CODE"},
+    {OXM_OF_IPV6_ND_TARGET, "IPV6_ND_TARGET"},
+    {OXM_OF_IPV6_ND_SLL, "IPV6_ND_SLL"},
+    {OXM_OF_IPV6_ND_TLL, "IPV6_ND_TLL"},
+    {OXM_OF_MPLS_LABEL, "MPLS_LABEL"},
+    {OXM_OF_MPLS_TC, "MPLS_TC"},
+    {OXM_OF_MPLS_BOS, "MPLS_BOS"},
+    {OXM_OF_TUNNEL_ID, "TUNNEL_ID"},
+    {OXM_OF_IPV6_EXTHDR, "IPV6_EXTHDR"},
+};
+
+int get_oxm_num(void)
+{
+    return ARRAY_SIZE(oxm_variables);
+}
+
+char *get_oxm_name(uint32_t type)
+{
+    int i;
+    int n = ARRAY_SIZE(oxm_variables);
+    for (i = 0; i < n; i++) {
+        if (type == oxm_variables[i].data)
+            return oxm_variables[i].name;
+    }
+    return NULL;
+}
+
+struct table_feature_prop {
+    uint16_t type;
+    uint16_t length;
+    void (*array_ntoh)(uint8_t*, uint16_t);
+    void (*array_hton)(uint8_t*, uint16_t);
+    char *name;
+};
+
+static struct table_feature_prop static_props[] = {
+    {OFPTFPT13_INSTRUCTIONS, sizeof(struct ofp11_instruction),
+       ntoh_instruction_array, hton_instruction_array, "OFPTFPT13_INSTRUCTIONS"},
+    {OFPTFPT13_INSTRUCTIONS_MISS, sizeof(struct ofp11_instruction),
+       ntoh_instruction_array, hton_instruction_array, "OFPTFPT13_INSTRUCTIONS_MISS"},
+    {OFPTFPT13_NEXT_TABLES, sizeof(uint8_t), NULL, NULL, "OFPTFPT13_NEXT_TABLES"},
+    {OFPTFPT13_NEXT_TABLES_MISS, sizeof(uint8_t), NULL, NULL, "OFPTFPT13_NEXT_TABLES_MISS"},
+    {OFPTFPT13_WRITE_ACTIONS, sizeof(struct ofp_action_header),
+       ntoh_action_array, hton_action_array, "OFPTFPT13_WRITE_ACTIONS"},
+    {OFPTFPT13_WRITE_ACTIONS_MISS, sizeof(struct ofp_action_header),
+       ntoh_action_array, hton_action_array, "OFPTFPT13_WRITE_ACTIONS_MISS"},
+    {OFPTFPT13_APPLY_ACTIONS, sizeof(struct ofp_action_header),
+       ntoh_action_array, hton_action_array, "OFPTFPT13_APPLY_ACTIONS"},
+    {OFPTFPT13_APPLY_ACTIONS_MISS, sizeof(struct ofp_action_header),
+       ntoh_action_array, hton_action_array, "OFPTFPT13_APPLY_ACTIONS_MISS"},
+    {OFPTFPT13_MATCH, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_MATCH"},
+    {OFPTFPT13_WILDCARDS, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_WILDCARDS"},
+    {OFPTFPT13_WRITE_SETFIELD, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_WRITE_SETFIELD"},
+    {OFPTFPT13_WRITE_SETFIELD_MISS, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_WRITE_SETFIELD_MISS"},
+    {OFPTFPT13_APPLY_SETFIELD, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_APPLY_SETFIELD"},
+    {OFPTFPT13_APPLY_SETFIELD_MISS, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_APPLY_SETFIELD_MISS"},
+    {OFPTFPT13_EXPERIMENTER, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_EXPERIMENTER"},
+    {OFPTFPT13_EXPERIMENTER_MISS, sizeof(ovs_be32),
+       ntoh_be32_array, hton_be32_array, "OFPTFPT13_EXPERIMENTER_MISS"},
+};
+
+/* CHECK to REPLACE if necessary */
+char *get_prop_name(uint16_t type)
+{
+    int i;
+    int n = ARRAY_SIZE(static_props);
+    for (i = 0; i < n; i++) {
+        if (static_props[i].type == type) {
+            return static_props[i].name;
+        }
+    }
+    return NULL;
+}
+
+/* CHECK to REPLACE if necessary */
+uint16_t get_prop_length(uint16_t type)
+{
+    int i;
+    int n = ARRAY_SIZE(static_props);
+    for (i = 0; i < n; i++) {
+        if (static_props[i].type == type) {
+            return static_props[i].length;
+        }
+    }
+    return 0;
+}
+
+/* CHECK to REPLACE if necessary */
+static void *get_prop_array_ntoh_func(uint16_t type)
+{
+    int i;
+    int n = ARRAY_SIZE(static_props);
+    for (i = 0; i < n; i++) {
+        if (static_props[i].type == type) {
+            return static_props[i].array_ntoh;
+        }
+    }
+    return NULL;
+}
+
+/* CHECK to REPLACE if necessary */
+static void *get_prop_array_hton_func(uint16_t type)
+{
+    int i;
+    int n = ARRAY_SIZE(static_props);
+    for (i = 0; i < n; i++) {
+        if (static_props[i].type == type) {
+            return static_props[i].array_hton;
+        }
+    }
+    return NULL;
+}
+
+static enum ofperr prop_data_trans(uint16_t type, uint32_t length, uint8_t *data, bool ntoh)
+{
+    enum ofperr error = 0;
+    uint32_t data_len = 0;
+    uint32_t element_size = 0;
+    uint32_t n_elem = 0;
+
+    void (*trans_array)(uint8_t *, uint16_t);
+
+    data_len = length - sizeof(struct ofp13_table_feature_prop_header);
+    element_size = get_prop_length(type);
+    if (0 == element_size) {
+        return OFPERR_OFPTFFC_BAD_TYPE;
+    } else if (data_len % element_size) {
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+    error = prop_get_n_elem(&n_elem, data_len, element_size);
+    if (error)
+        return error;
+
+    if (ntoh)
+        trans_array = get_prop_array_ntoh_func(type);
+    else
+        trans_array = get_prop_array_hton_func(type);
+
+    if (trans_array)
+        trans_array(data, n_elem);
+
+    return 0;
+}
+
+static enum ofperr prop_data_ntoh(uint16_t type, uint32_t length, uint8_t *data)
+{
+    return prop_data_trans(type, length, data, true);
+}
+
+static enum ofperr prop_data_hton(uint16_t type, uint32_t length, uint8_t *data)
+{
+    return prop_data_trans(type, length, data, false);
+}
+
+static enum ofperr
+decode_table_feature_prop(uint8_t **p, uint32_t *length,
+                            struct ofputil_table_feature_prop_header *prop)
+{
+    enum ofperr error = 0;
+    uint32_t data_len = 0;
+    uint32_t padding_len = 0;
+
+    error = decode_table_features_prop_header(p, length, prop);
+    if (error)
+        return error;
+
+    data_len = prop->length - sizeof(struct ofp13_table_feature_prop_header);
+
+    /* NOTE SPECIAL XMALLOC HERE FIXME */
+    prop->data = xmalloc(data_len);
+    table_features_move_data(prop->data, p, length, data_len);
+
+    padding_len = ROUND_UP(prop->length, 8) - prop->length;
+    if (padding_len) {
+        *p += padding_len;
+        *length -= padding_len;
+    }
+
+    if ((error = prop_data_ntoh(prop->type, prop->length, prop->data)))
+        return error;
+
+    return 0;
+}
+
+static enum ofperr
+decode_table_feature_props(uint8_t **p, uint32_t length,
+                            struct ofputil_table_features *tf)
+{
+    enum ofperr error = 0;
+    int i = 0;
+
+    while (length > 0) {
+        error = decode_table_feature_prop(p, &length, &tf->props[i]);
+        if (error)
+            return error;
+        ++i;
+    }
+
+    tf->n_property = i;
+    return 0;
+}
+
+
+static enum ofperr
+decode_table_feature_raw(uint8_t **p, uint32_t *length,
+                         struct ofputil_table_features *tf)
+{
+    struct ofp13_table_features otf;
+    uint32_t props_len;
+    int error = 0;
+
+    if (*length == 0) {
+        /* do nothing if there is no body */
+        goto out;
+    } else if (*length < sizeof(otf)) {
+        VLOG_DBG("Table features decode bad length, "
+            "length(%u) < min size(%zu).\n", *length, sizeof(otf));
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+    /* update props' header len */
+    table_features_move_data((uint8_t*)&otf, p, length, sizeof(otf));
+
+    /* length -> n array */
+    tf->length = ntohs(otf.length); /* now we get length of this tf */
+    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_len = tf->length - sizeof(otf);
+    if ((error = decode_table_feature_props(p, props_len, tf)))
+        goto out;
+
+    /* if succeed, update length after decode props */
+    if (*length > props_len)
+        *length -= props_len;
+    else {
+        VLOG_DBG("Table features decode bad length, "
+            "length left(%u), properties length(%u).\n", *length, props_len);
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+out:
+    return error;
+}
+
+static enum ofperr
+ofputil_pull_table_features_raw(uint8_t *p, uint32_t length,
+                         struct ofputil_table_features tfs[],
+                         int *tfs_num)
+{
+    enum ofperr error = 0;
+    int i = 0;
+
+    /* FIXME the 0xff is hard coding */
+    while (length > 0 && i <= 0xff) {
+        struct ofputil_table_features *tf = &tfs[i];
+
+        if ((error = decode_table_feature_raw(&p, &length, tf))) {
+            goto out;
+        }
+        ++i;
+    }
+out:
+    *tfs_num = i;
+    return error;
+}
+
+enum ofperr
+ofputil_decode_table_features_reply(const struct ofp_header *oh, int *tfs_num,
+                         struct ofputil_table_features tfs[])
+{
+    struct ofpbuf msg;
+    enum ofpraw raw;
+    uint8_t *p;
+    int features_len = 0;
+    int error = 0;
+
+    ofpbuf_use_const(&msg, oh, ntohs(oh->length));
+    raw = ofpraw_pull_assert(&msg);
+    if (raw != OFPRAW_OFPST13_TABLE_FEATURES_REPLY) {
+        VLOG_DBG("bad msg type(%u)\n", raw);
+        return OFPERR_OFPBRC_BAD_TYPE;
+    }
+
+    /* 8 is multipart-header's len */
+    features_len = ntohs(oh->length) - sizeof(*oh) - 8;
+    p = ofpbuf_try_pull(&msg, features_len);
+    if (!p) {
+        VLOG_WARN("table features length %u is longer than space "
+            "in message length %zu", features_len, msg.size);
+        return OFPERR_OFPTFFC_BAD_LEN;
+    }
+
+    ofputil_pull_table_features_raw(p, (uint16_t)features_len, tfs, tfs_num);
+
+    return error;
+}
+
+
+enum ofperr
+ofputil_decode_table_features_request(const struct ofp_header *oh, int *tfs_num,
+                         struct ofputil_table_features tfs[],
+                         uint32_t *flag)
+{
+    struct ofpbuf msg;
+    enum ofpraw raw;
+    uint8_t *p;
+    uint32_t features_len;
+    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("bad msg type(%u)\n", raw);
+        return OFPERR_OFPBRC_BAD_TYPE;
+    }
+
+    if (msg.size == 0) /* stands for GET table_features request */ {
+        *flag = OTF_GET;
+    } else {
+        *flag = OTF_SET;
+
+        /* 8 is multipart-header's len */
+        features_len = ntohs(oh->length) - sizeof *oh - 8;
+        p = ofpbuf_try_pull(&msg, features_len);
+        if (!p) {
+            VLOG_WARN("table features length %u is longer than space "
+                "in message length %zu", features_len, msg.size);
+            return OFPERR_OFPTFFC_BAD_LEN;
+        }
+
+        ofputil_pull_table_features_raw(p, features_len, tfs, tfs_num);
+    }
+    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;
+    int error = 0;
+    uint8_t *data;
+    int data_len;
+    int padding_len;
+
+    for (i = 0; i < prop_num; i++) {
+        struct ofp13_table_feature_prop_header *oprop;
+        const struct ofputil_table_feature_prop_header *prop = &props[i];
+        if (!prop->data || !prop->length) {
+            continue;
+        }
+
+        oprop = ofpbuf_put_zeros(reply, sizeof *oprop);
+        data_len = prop->length - sizeof *oprop;
+        padding_len = ROUND_UP(prop->length, 8) - prop->length;
+
+        oprop->type = htons(prop->type);
+        oprop->length = htons(prop->length);
+
+        data = ofpbuf_put_uninit(reply, data_len + padding_len);
+        memcpy(data, prop->data, data_len);
+        memset(data + data_len, 0, padding_len);
+
+        if (error != prop_data_hton(prop->type, prop->length, data))
+            return error;
+    }
+
+    return 0;
+}
+
+/* use it when encode */
+
+static uint32_t
+table_feature_prop_calculate_len(
+                    const struct ofputil_table_feature_prop_header *prop)
+{
+    /* NOTE, ofputil prop should padding now, FIXME later */
+    return ROUND_UP(prop->length, 8);
+}
+
+static uint32_t
+table_feature_props_calculate_len(
+                        const struct ofputil_table_feature_prop_header *props,
+                        uint16_t n_property)
+{
+    int i;
+    uint32_t len = 0;
+
+    for (i = 0; i < n_property; i++) {
+        len += table_feature_prop_calculate_len(&props[i]);
+    }
+
+    return len;
+}
+
+static uint32_t
+table_feature_calculate_len(const struct ofputil_table_features *tf)
+{
+    /* 64 is the header length */
+    uint32_t len = sizeof(struct ofp13_table_features);
+
+    len += table_feature_props_calculate_len(tf->props, tf->n_property);
+
+    return len;
+}
+
+static void
+ofputil_put_table_feature(const struct ofputil_table_features *tf, struct ofpbuf *reply)
+{
+    struct ofp13_table_features *otf;
+    uint32_t feature_len = table_feature_calculate_len(tf);
+    otf = ofpbuf_put_zeros(reply, 64); //feature_len
+
+    /* if it's a get request, length is 64 bits. */
+    otf->length = htons(feature_len);
+    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);
+
+    /* encode props */
+    if (tf->n_property > 0) {
+        ofputil_encode_table_features_props(reply, tf->props, tf->n_property);
+    }
+}
+
+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);
+
+    }
+    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;
+}
+
+struct ofpbuf *
+ofputil_encode_table_features(const struct ofputil_table_features tfs[], int n,
+                                    const struct ofp_header *request)
+{
+    struct ofpbuf *reply;
+    int i;
+
+    /* should we replace the func to alloc_features? */
+    reply = ofpraw_alloc_stats_reply(request, 0);
+
+    for (i = 0; i < n; i++) {
+        /* TODO encode body inside the func */
+        ofputil_put_table_feature(&tfs[i], reply);
+    }
+
+    return reply;
+}
+
  /* ofputil_table_mod */

  /* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
-- 
1.7.3.1.msysgit.0





More information about the dev mailing list