[patch_v0 2/3] OF1.5-EXT-334: Extensible Flow Entry Statistics Implementation --lib/ofp-util.c lib/ox_stat.c
Signed-off-by: Harivelam Lavanya<[email protected]> Co-authored-by: Satya Valli <[email protected]> >From f2e03a1fdcad61fd9221d6f81ff708b017a119f4 Mon Sep 17 00:00:00 2001 From: Harivelam Lavanya <[email protected]> Date: Wed, 19 Apr 2017 19:44:27 +0530 Subject: [PATCH 3/4] OF1.5/EXT-334-OXS Individal Flow Entry Statistics --lib/ofp-util.c lib/ox_stat.c --- lib/ofp-util.c | 125 ++++++++++++++++++++++- lib/ox-stat.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+), 5 deletions(-) diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 1f038c61e..a261d981a 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -50,9 +50,12 @@ #include "unaligned.h" #include "util.h" #include "uuid.h" +#include "ox-stat.h" VLOG_DEFINE_THIS_MODULE(ofp_util); +extern uint8_t oxs_field_set; + /* Rate limit for OpenFlow message parse errors. These always indicate a bug * in the peer and so there's not much point in showing a lot of them. */ static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -2313,6 +2316,39 @@ ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr, return 0; } +ofputil_decode_ofpst15_flow_request(struct ofputil_flow_stats_request *fsr, + struct ofpbuf *b, bool aggregate, + const struct tun_table *tun_table, + const struct vl_mff_map *vl_mff_map) +{ + const struct ofp15_oxs_flow_stats_request *ofsr; + enum ofperr error,stat_error; + uint16_t statlen; + + ofsr = ofpbuf_pull(b, sizeof *ofsr); + fsr->aggregate = aggregate; + fsr->table_id = ofsr->table_id; + + error = ofputil_port_from_ofp11(ofsr->out_port, &fsr->out_port); + if (error) { + return error; + } + + fsr->out_group = ntohl(ofsr->out_group); + fsr->cookie = ofsr->cookie; + fsr->cookie_mask = ofsr->cookie_mask; + + error = ofputil_pull_ofp11_match(b, tun_table, vl_mff_map, &fsr->match, + NULL); + stat_error = oxs_pull_stat(b, NULL, &statlen); + + if (error || stat_error) { + return error; + } + + return 0; +} + static enum ofperr ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr, struct ofpbuf *b, bool aggregate, @@ -2762,6 +2798,10 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr, case OFPRAW_OFPST11_AGGREGATE_REQUEST: return ofputil_decode_ofpst11_flow_request(fsr, &b, true, tun_table, vl_mff_map); + case OFPRAW_OFPST15_OXS_FLOW_REQUEST: + oxs_field_set = 0; + return ofputil_decode_ofpst15_flow_request(fsr, &b, false, tun_table, + vl_mff_map); case OFPRAW_NXST_FLOW_REQUEST: return ofputil_decode_nxst_flow_request(fsr, &b, false, tun_table, @@ -2791,9 +2831,7 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, case OFPUTIL_P_OF11_STD: case OFPUTIL_P_OF12_OXM: case OFPUTIL_P_OF13_OXM: - case OFPUTIL_P_OF14_OXM: - case OFPUTIL_P_OF15_OXM: - case OFPUTIL_P_OF16_OXM: { + case OFPUTIL_P_OF14_OXM: { struct ofp11_flow_stats_request *ofsr; raw = (fsr->aggregate @@ -2811,6 +2849,25 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr, break; } + case OFPUTIL_P_OF15_OXM: + case OFPUTIL_P_OF16_OXM: { + struct ofp15_oxs_flow_stats_request *ofsr; + raw = (fsr->aggregate + ? OFPRAW_OFPST11_AGGREGATE_REQUEST + : OFPRAW_OFPST15_OXS_FLOW_REQUEST); + msg = ofpraw_alloc(raw, ofputil_protocol_to_ofp_version(protocol), + ofputil_match_typical_len(protocol)); + ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr); + ofsr->table_id = fsr->table_id; + ofsr->out_port = ofputil_port_to_ofp11(fsr->out_port); + ofsr->out_group = htonl(fsr->out_group); + ofsr->cookie = fsr->cookie; + ofsr->cookie_mask = fsr->cookie_mask; + ofputil_put_ofp11_match(msg, &fsr->match, protocol); + oxs_put_stat(msg, NULL, ofputil_protocol_to_ofp_version(protocol)); + break; + } + case OFPUTIL_P_OF10_STD: case OFPUTIL_P_OF10_STD_TID: { struct ofp10_flow_stats_request *ofsr; @@ -2893,7 +2950,48 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs, if (!msg->size) { return EOF; - } else if (raw == OFPRAW_OFPST11_FLOW_REPLY + } else if (raw == OFPRAW_OFPST15_OXS_FLOW_REPLY) { + const struct ofp15_oxs_flow_stats_reply *ofs; + size_t length; + uint16_t padded_match_len; + uint16_t stat_len; + + ofs = ofpbuf_try_pull(msg, sizeof *ofs); + if (!ofs) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %"PRIu32 + " leftover " "bytes at end", msg->size); + return EINVAL; + } + + length = ntohs(ofs->length); + if (length < sizeof *ofs) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply claims invalid " + "length %"PRIuSIZE, length); + return EINVAL; + } + + if (ofputil_pull_ofp11_match(msg, NULL, NULL, &fs->match, + &padded_match_len)) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad match"); + return EINVAL; + } + + fs->priority = ntohs(ofs->priority); + fs->table_id = ofs->table_id; + fs->duration_sec = 0; + fs->duration_nsec = 0; + fs->idle_age = 0; + fs->packet_count = 0; + fs->byte_count = 0; + + if(oxs_pull_stat(msg, fs,&stat_len)) { + VLOG_WARN_RL(&bad_ofmsg_rl, "OXS OFPST_FLOW reply bad match"); + return EINVAL; + } + + instructions_len = length - sizeof *ofs - padded_match_len - stat_len; + + } else if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) { const struct ofp11_flow_stats *ofs; size_t length; @@ -3067,7 +3165,22 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs, orig_tun_table = fs->match.flow.tunnel.metadata.tab; fs_->match.flow.tunnel.metadata.tab = tun_table; - if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) { + if (raw == OFPRAW_OFPST15_OXS_FLOW_REPLY) { + struct ofp15_oxs_flow_stats_reply *ofs; + ofpbuf_put_uninit(reply, sizeof *ofs); + oxm_put_match(reply, &fs->match, version); + oxs_put_stat(reply,fs,version); + ofpacts_put_openflow_instructions(fs->ofpacts, fs->ofpacts_len, reply, + version); + + ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs); + ofs->length = htons(reply->size - start_ofs); + ofs->table_id = fs->table_id; + ofs->priority = htons(fs->priority); + ofs->reason = 0; + memset(ofs->pad2, 0, sizeof ofs->pad2); + } else if (raw == OFPRAW_OFPST11_FLOW_REPLY || + raw == OFPRAW_OFPST13_FLOW_REPLY) { struct ofp11_flow_stats *ofs; ofpbuf_put_uninit(reply, sizeof *ofs); @@ -10150,6 +10263,7 @@ ofputil_is_bundlable(enum ofptype type) case OFPTYPE_GET_ASYNC_REQUEST: case OFPTYPE_DESC_STATS_REQUEST: case OFPTYPE_FLOW_STATS_REQUEST: + case OFPTYPE_OXS_FLOW_STATS_REQUEST: case OFPTYPE_AGGREGATE_STATS_REQUEST: case OFPTYPE_TABLE_STATS_REQUEST: case OFPTYPE_TABLE_FEATURES_STATS_REQUEST: @@ -10178,6 +10292,7 @@ ofputil_is_bundlable(enum ofptype type) case OFPTYPE_QUEUE_GET_CONFIG_REPLY: case OFPTYPE_DESC_STATS_REPLY: case OFPTYPE_FLOW_STATS_REPLY: + case OFPTYPE_OXS_FLOW_STATS_REPLY: case OFPTYPE_QUEUE_STATS_REPLY: case OFPTYPE_PORT_STATS_REPLY: case OFPTYPE_TABLE_STATS_REPLY: diff --git a/lib/ox-stat.c b/lib/ox-stat.c index b48ef3aca..14340d7d0 100644 --- a/lib/ox-stat.c +++ b/lib/ox-stat.c @@ -205,6 +205,171 @@ error: return OFPERR_OFPBMC_BAD_LEN; } +static enum ofperr +oxs_pull_entry__(struct ofpbuf *b, uint64_t *header, + const struct oxs_field **field_,struct ofputil_flow_stats *fs) +{ + const struct oxs_field *field; + enum ofperr header_error; + unsigned int payload_len; + const uint8_t *payload; + + header_error = oxs_pull_header__(b, header, &field); + + if (header_error && header_error != OFPERR_OFPBMC_BAD_FIELD) { + return header_error; + } + + payload_len = oxs_payload_len(*header); + payload = ofpbuf_try_pull(b, payload_len); + if (!payload) { + return OFPERR_OFPBMC_BAD_LEN; + } + + if(fs && field){ + switch(field->id) + { + case OFPXST_OFB_DURATION: + { + uint64_t duration=0; + memcpy(&duration,payload,sizeof(duration)); + duration = ntohll(duration); + fs->duration_sec = ((uint32_t)((duration & + 0xFFFFFFFF00000000) >> 32)); + fs->duration_nsec = ((uint32_t)(duration & 0xFFFFFFFF)); + } + break; + case OFPXST_OFB_IDLE_TIME: + { + uint64_t idle_time=0; + memcpy(&idle_time,payload,sizeof(idle_time)); + idle_time = ntohll(idle_time); + fs->idle_age = ((idle_time & 0xFFFFFFFF00000000) >> 32); + } + break; + case OFPXST_OFB_PACKET_COUNT: + { + uint64_t packet_count; + memcpy(&packet_count,payload,sizeof(packet_count)); + fs->packet_count = ntohll(packet_count); + } + break; + case OFPXST_OFB_BYTE_COUNT: + { + uint64_t byte_count; + memcpy(&byte_count,payload,sizeof(byte_count)); + fs->byte_count = ntohll(byte_count); + } + break; + } + } + + if (field_) { + *field_ = field; + return header_error; + } + + return 0; +} + +static enum ofperr +oxs_pull_match_entry(struct ofpbuf *b, + const struct oxs_field **field, + struct ofputil_flow_stats *fs) +{ + enum ofperr error; + uint64_t header; + + error = oxs_pull_entry__(b, &header, field,fs); + if (error) { + return error; + } + return 0; +} + +static enum ofperr +oxs_pull_raw(const uint8_t *p, unsigned int stat_len, + struct ofputil_flow_stats *fs, + ovs_be64 *cookie, ovs_be64 *cookie_mask) +{ + ovs_assert((cookie != NULL) == (cookie_mask != NULL)); + if (cookie) { + *cookie = *cookie_mask = htonll(0); + } + + struct ofpbuf b = ofpbuf_const_initializer(p, stat_len); + + while (b.size) { + const uint8_t *pos = b.data; + const struct oxs_field *field; + union mf_value value; + union mf_value mask; + enum ofperr error; + error = oxs_pull_match_entry(&b, &field,fs); + if (error) { + if (error == OFPERR_OFPBMC_BAD_FIELD && !false) { + continue; + } + } + else if (!field) { + if (!cookie) { + error = OFPERR_OFPBMC_BAD_FIELD; + } else if (*cookie_mask) { + error = OFPERR_OFPBMC_DUP_FIELD; + } else { + *cookie = value.be64; + *cookie_mask = mask.be64; + } + } + else { + if(field->id == OFPXST_OFB_DURATION) { + oxs_field_set |= 1<<0; + } else if(field->id == OFPXST_OFB_IDLE_TIME) { + oxs_field_set |= 1<<1; + } else if(field->id == OFPXST_OFB_FLOW_COUNT) { + oxs_field_set |= 1<<2; + } else if(field->id == OFPXST_OFB_PACKET_COUNT) { + oxs_field_set |= 1<<3; + } else if(field->id == OFPXST_OFB_BYTE_COUNT) { + oxs_field_set |= 1<<4; + } + } + if (error) { + VLOG_DBG_RL(&rl, "error parsing OXS at offset %"PRIdPTR" " + "within match (%s)", pos - + p, ofperr_to_string(error)); + return error; + } + } + return 0; +} + +int oxs_pull_stat(struct ofpbuf *b,struct ofputil_flow_stats *fs, + uint16_t *statlen) +{ + struct ofp_oxs_stat *oxs = b->data; + uint8_t *p; + uint16_t stat_len; + stat_len = ntohs(oxs->length); + if (stat_len < sizeof *oxs) { + return OFPERR_OFPBMC_BAD_LEN; + } + + p = ofpbuf_try_pull(b, ROUND_UP(stat_len, 8)); + if (!p) { + VLOG_DBG_RL(&rl, "oxs length %u, rounded up to a " + "multiple of 8, is longer than space in message (max " + "length %"PRIu32")", stat_len, b->size); + return OFPERR_OFPBMC_BAD_LEN; + } + *statlen = ROUND_UP(stat_len, 8); + return oxs_pull_raw(p + sizeof *oxs, stat_len - sizeof *oxs,fs, + NULL, NULL); +} + +static struct hmap oxs_header_map; +static struct hmap oxs_name_map; + static void oxs_init(void) { @@ -227,3 +392,148 @@ oxs_init(void) } } +static const struct oxs_field * +oxs_field_by_header(uint32_t header) +{ + const struct oxs_field_index *oxfs; + uint32_t header_no_len; + + oxs_init(); + + header_no_len = oxs_header_no_len(header); + HMAP_FOR_EACH_IN_BUCKET (oxfs, header_node, hash_int(header_no_len,0), + &oxs_header_map) { + if (header_no_len == oxs_header_no_len(oxfs->fs.header)) { + if (OXS_LENGTH(header) == OXS_LENGTH(oxfs->fs.header)) { + return &oxfs->fs; + } else { + return NULL; + } + } + } + return NULL; +} + +static const struct oxs_field * +oxs_field_by_id(enum oxs_ofb_stat_fields id, enum ofp_version version) +{ + const struct oxs_field_index *oxfs; + const struct oxs_field *fs; + + oxs_init(); + + LIST_FOR_EACH (oxfs, ox_node, &oxs_ox_map[id]) { + if (!fs || version >= oxfs->fs.version) { + fs = &oxfs->fs; + } + } + return fs; +} + +static void +oxs_put_header__(struct ofpbuf *b, uint64_t header) +{ + ovs_be32 network_header = htonl(header); + ofpbuf_put(b, &network_header, oxs_header_len(header)); +} + + +static void +oxs_put_header_len(struct ofpbuf *b, enum oxs_ofb_stat_fields field, + enum ofp_version version) +{ + uint32_t header = oxs_header_get(field, version); + header = OXS_HEADER(OXS_CLASS(header), + OXS_FIELD(header), + OXS_LENGTH(header)); + oxs_put_header__(b, header); +} + +void oxs_put__(struct ofpbuf *b, enum oxs_ofb_stat_fields field, + enum ofp_version version, + const void *value, const void *mask, size_t n_bytes) +{ + oxs_put_header_len(b, field, version); + ofpbuf_put(b, value, n_bytes); + if (mask) { + ofpbuf_put(b, mask, n_bytes); + } + +} + +static int +ox_put_raw(struct ofpbuf *b, enum ofp_version oxs, + struct ofputil_flow_stats *fs, + ovs_be64 cookie, ovs_be64 cookie_mask) +{ + const size_t start_len = b->size; + int stat_len; + if (oxs_field_set & 1<<0) { + uint64_t duration = 0; + if(fs){ + duration = (uint64_t) fs->duration_sec << 32 | + fs->duration_nsec; + duration = htonll(duration); + } + oxs_put__(b, OFPXST_OFB_DURATION, oxs, &duration, NULL, + OXS_STATS_DURATION_LEN); + } + if (oxs_field_set & 1<<1) { + uint64_t idl_time = 0; + if(fs){ + idl_time = (uint64_t)fs->idle_age <<32 ; + idl_time = htonll(idl_time); + } + oxs_put__(b, OFPXST_OFB_IDLE_TIME, oxs, &idl_time, NULL, + OXS_STATS_IDLE_TIME_LEN); + } + if (oxs_field_set & 1<<2) { + uint32_t flow_count = 0; + oxs_put__(b, OFPXST_OFB_FLOW_COUNT, oxs, &flow_count, NULL, + OXS_STATS_FLOW_COUNT_LEN); + } + if (oxs_field_set & 1<<3) { + uint64_t pkt_count = 0; + if(fs){ + pkt_count = fs->packet_count; + pkt_count = htonll(pkt_count); + } + oxs_put__(b, OFPXST_OFB_PACKET_COUNT, oxs, &pkt_count, NULL, + OXS_STATS_PACKET_COUNT_LEN); + } + if (oxs_field_set & 1<<4) { + uint64_t byte_count = 0; + if(fs){ + byte_count = fs->byte_count; + byte_count = htonll(byte_count); + } + oxs_put__(b, OFPXST_OFB_BYTE_COUNT, oxs, &byte_count, NULL, + OXS_STATS_BYTE_COUNT_LEN); + } + if (cookie_mask) { + cookie &= cookie_mask; + oxs_put_header__(b, OXS_OX_COOKIE); + ofpbuf_put(b, &cookie, sizeof cookie); + } + stat_len = b->size - start_len; + return stat_len; +} + +int +oxs_put_stat(struct ofpbuf *b, struct ofputil_flow_stats *fs, + enum ofp_version version) +{ + int stat_len; + struct ofp_oxs_stat *oxs; + size_t start_len = b->size; + ovs_be64 cookie = htonll(0), cookie_mask = htonll(0); + ofpbuf_put_uninit(b, sizeof *oxs); + stat_len = (ox_put_raw(b, version, fs, cookie, cookie_mask) + + sizeof *oxs); + ofpbuf_put_zeros(b, PAD_SIZE(stat_len, 8)); + oxs = ofpbuf_at(b, start_len, sizeof *oxs); + oxs->reserved = htons(0); + oxs->length = htons(stat_len); + return stat_len; +} + -- 2.11.0 =====-----=====-----===== Notice: The information contained in this e-mail message and/or attachments to it may contain confidential or privileged information. If you are not the intended recipient, any dissemination, use, review, distribution, printing or copying of the information contained in this e-mail message and/or attachments to it are strictly prohibited. If you have received this communication in error, please notify us by reply e-mail or telephone and immediately and permanently delete the message and any attachments. Thank you _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
