[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