[ovs-dev,patch_v0,2/3] OF1.5-EXT-334: Extensible Flow Entry Statistics Implementation --lib/ofp-util.c lib/ox_stat.c

Submitted by Harivelam Lavanya on April 20, 2017, 12:24 p.m.

Details

Message ID OFBB31332B.6F68E94B-ON65258108.00423C5D-65258108.004433E9@tcs.com
State Deferred
Headers show

Commit Message

Harivelam Lavanya April 20, 2017, 12:24 p.m.
[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<harivelam.lavanya@tcs.com>
Co-authored-by: Satya Valli <satyavalli.rama@tcs.com>


From f2e03a1fdcad61fd9221d6f81ff708b017a119f4 Mon Sep 17 00:00:00 2001
From: Harivelam Lavanya <harivelam.lavanya@tcs.com>
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(-)

Patch hide | download patch | download mbox

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;
+}
+