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...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev