diff mbox

[ovs-dev,6/6] OF1.5/EXT-334 OXS/Flow Removal -2

Message ID 1495041893-25723-1-git-send-email-harivelam.lavanya@tcs.com
State Changes Requested
Headers show

Commit Message

SatyaValli May 17, 2017, 5:24 p.m. UTC
From: Harivelam Lavanya <harivelam.lavanya@tcs.com>

Since FLOW_REMOVED is not supported in OF1.5 version,
testing has been done by adding test case in ofproto.at.
While doing make check after adding test case we are able to see
OFPT_FLOW_REMOVED (OF1.5) message has sent successfully.

But make check is failing because of Signal 15 termination,
so we've removed that test case from the patch.

Signed-off-by: Harivelam Lavanya <harivelam.lavanya@tcs.com> 
Co-authored-by: Satya Valli <satyavalli.rama@tcs.com> 

---
 lib/ofp-util.c |  41 ++++++++++-
 lib/ox-stat.c  | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 262 insertions(+), 4 deletions(-)
diff mbox

Patch

diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index f0c96db..a63c643 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -3346,7 +3346,23 @@  ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
 {
     struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
     enum ofpraw raw = ofpraw_pull_assert(&b);
-    if (raw == OFPRAW_OFPT11_FLOW_REMOVED) {
+    if (raw == OFPRAW_OFPT15_FLOW_REMOVED) {
+        const struct ofp15_flow_removed *ofr;
+        enum ofperr error;
+
+        ofr = ofpbuf_pull(&b, sizeof *ofr);
+
+        error = ofputil_pull_ofp11_match(&b, NULL, NULL,  &fr->match, NULL);
+        if (error) {
+            return error;
+        }
+        oxs_flow_removed_stat_pull(&b,fr);
+
+        fr->priority = ntohs(ofr->priority);
+        fr->cookie = ofr->cookie;
+        fr->reason = ofr->reason;
+        fr->table_id = ofr->table_id;
+    } else if (raw == OFPRAW_OFPT11_FLOW_REMOVED) {
         const struct ofp12_flow_removed *ofr;
         enum ofperr error;
 
@@ -3429,12 +3445,29 @@  ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     }
 
     switch (protocol) {
+    case OFPUTIL_P_OF15_OXM:
+    case OFPUTIL_P_OF16_OXM: {
+        struct ofp15_flow_removed *ofr;
+
+        msg = ofpraw_alloc_xid(OFPRAW_OFPT15_FLOW_REMOVED,
+                               ofputil_protocol_to_ofp_version(protocol),
+                               htonl(0),
+                               ofputil_match_typical_len(protocol));
+        ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
+        ofr->cookie = fr->cookie;
+        ofr->priority = htons(fr->priority);
+        ofr->reason = reason;
+        ofr->table_id = fr->table_id;
+        ofputil_put_ofp11_match(msg, &fr->match, protocol);
+        /*Stats encoding in OXS TLV Format*/
+        oxs_flow_removed_stat_put(msg,fr,protocol);
+        break;
+    }
+
     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 ofp12_flow_removed *ofr;
 
         msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
diff --git a/lib/ox-stat.c b/lib/ox-stat.c
index 4cfcff7..d83ba00 100644
--- a/lib/ox-stat.c
+++ b/lib/ox-stat.c
@@ -150,6 +150,11 @@  static enum ofperr oxs_pull_raw(const uint8_t *, unsigned int ,
                                 ovs_be64 * cookie, ovs_be64 * cookie_mask);
 static enum ofperr oxs_pull_agg_raw(const uint8_t * p, unsigned int stat_len,
                                     struct ofputil_aggregate_stats *fs);
+static int oxs_flow_rem_stat_fields_pull(const uint8_t *p,
+                                         unsigned int stat_len,
+                                         struct ofputil_flow_removed *fr);
+static int oxs_pull_flow_rem_stat_entry(struct ofpbuf *b,
+                                        struct ofputil_flow_removed *fr);
 static void oxs_init(void);
 static void oxs_put_header__(struct ofpbuf *b, uint64_t header);
 static void oxs_put_header_len(struct ofpbuf *b,
@@ -157,6 +162,18 @@  static void oxs_put_header_len(struct ofpbuf *b,
                                enum ofp_version version);
 static int ox_put_agg_raw(struct ofpbuf *b, enum ofp_version oxs,
                           const struct ofputil_aggregate_stats *fs);
+static void oxs_put_duration(struct ofpbuf *b,
+                             const struct ofputil_flow_removed *fr,
+                             enum ofp_version version);
+static void oxs_put_packet_count(struct ofpbuf *b,
+                                 const struct ofputil_flow_removed *fr,
+                                 enum ofp_version version);
+static void oxs_put_byte_count(struct ofpbuf *b,
+                               const struct ofputil_flow_removed *fr,
+                               enum ofp_version version);
+static int oxs_flow_rem_stat_fields_put(struct ofpbuf *b,
+                                        const struct ofputil_flow_removed *fr,
+                                        enum ofp_version version);
 
 static bool
 is_experimenter_oxs(uint64_t header)
@@ -765,3 +782,211 @@  oxs_put_agg_stat(struct ofpbuf *b, const struct ofputil_aggregate_stats *fs,
    return stat_len;
 }
 
+static void
+oxs_put_duration(struct ofpbuf *b,
+                 const struct ofputil_flow_removed *fr,
+                 enum ofp_version version)
+{
+    uint64_t duration = 0;
+
+    if (fr) {
+        duration = (uint64_t) fr->duration_sec << 32 | fr->duration_nsec;
+        duration = htonll(duration);
+    }
+    oxs_put__(b, OFPXST_OFB_DURATION, version, &duration, NULL,
+              OXS_STATS_DURATION_LEN);
+    return;
+}
+
+static void
+oxs_put_packet_count(struct ofpbuf *b,
+                     const struct ofputil_flow_removed *fr,
+                     enum ofp_version version)
+{
+    uint64_t pkt_count = 0;
+
+    if (fr) {
+        pkt_count = fr->packet_count;
+        pkt_count = htonll(pkt_count);
+    }
+    oxs_put__(b, OFPXST_OFB_PACKET_COUNT, version, &pkt_count, NULL,
+              OXS_STATS_PACKET_COUNT_LEN);
+    return;
+}
+
+static void
+oxs_put_byte_count(struct ofpbuf *b,
+                   const struct ofputil_flow_removed *fr,
+                   enum ofp_version version)
+{
+    uint64_t byte_count = 0;
+
+    if (fr) {
+        byte_count = fr->byte_count;
+        byte_count = htonll(byte_count);
+    }
+    oxs_put__(b, OFPXST_OFB_BYTE_COUNT, version, &byte_count, NULL,
+              OXS_STATS_BYTE_COUNT_LEN);
+    return;
+}
+
+static int
+oxs_flow_rem_stat_fields_put(struct ofpbuf *b,
+                             const struct ofputil_flow_removed *fr,
+                             enum ofp_version version)
+{
+    int stat_len;
+    size_t start_len = b->size;
+
+    oxs_put_duration(b, fr, version);
+    oxs_put_packet_count(b, fr, version);
+    oxs_put_byte_count(b, fr, version);
+
+    stat_len = (b->size - start_len);
+    return stat_len;
+}
+
+/* Encode Flow entry statistics in FLOW_REMOVED message
+ *
+ * Appends to 'b' the flow entry statistics in a flexible encoding ,OXS
+ * format.
+ *
+ * OXS is a TLV format to express flow entry statistics.  Specify the OpenFlow
+ * version in use as 'version'.
+ *
+ * Returns the number of bytes appended to 'b'.
+ *
+ * This function can cause 'b''s data to be reallocated.
+ *
+ * Returns zero or the number of bytes appended to 'b'. */
+int
+oxs_flow_removed_stat_put(struct ofpbuf *b,
+                          const struct ofputil_flow_removed *fr,
+                          enum ofp_version version)
+{
+    int stat_len;
+    struct ofp_oxs_stat *oxs;
+    size_t start_len = b->size;
+
+    ofpbuf_put_uninit(b, sizeof *oxs);
+    stat_len = oxs_flow_rem_stat_fields_put(b, fr, version) + 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;
+}
+
+static int
+oxs_flow_rem_stat_fields_pull(const uint8_t * p, unsigned int stat_len,
+                              struct ofputil_flow_removed *fr)
+{
+    struct ofpbuf b = ofpbuf_const_initializer(p, stat_len);
+
+    while (b.size) {
+
+        const uint8_t *pos = b.data;
+        enum ofperr error;
+
+        error = oxs_pull_flow_rem_stat_entry(&b, fr);
+        if (error) {
+            if (error == OFPERR_OFPBMC_BAD_FIELD && !false) {
+                continue;
+            }
+        }
+        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;
+}
+
+static int
+oxs_pull_flow_rem_stat_entry(struct ofpbuf *b, struct ofputil_flow_removed *fr)
+{
+    const struct oxs_field *field;
+    uint64_t header;
+    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 (fr && field) {
+
+        switch (field->id) {
+        case OFPXST_OFB_DURATION:
+            {
+                uint64_t duration;
+
+                memcpy(&duration, payload, sizeof (duration));
+                fr->duration_nsec = ntohl((duration & 0xffffffff));
+                fr->duration_sec = ntohl((uint32_t) (duration >> 32));
+            }
+            break;
+        case OFPXST_OFB_PACKET_COUNT:
+            {
+                uint64_t packet_count;
+
+                memcpy(&packet_count, payload, sizeof (packet_count));
+                fr->packet_count = ntohll(packet_count);
+
+            }
+            break;
+        case OFPXST_OFB_BYTE_COUNT:
+            {
+                uint64_t byte_count;
+
+                memcpy(&byte_count, payload, sizeof (byte_count));
+                fr->byte_count = ntohll(byte_count);
+            }
+            break;
+        case OFPXST_OFB_IDLE_TIME:
+        case OFPXST_OFB_FLOW_COUNT:
+        default:
+            break;
+
+        }
+    }
+    return 0;
+}
+
+/* Retrieve struct ofp_oxs_stat from 'b', followed by the flow entry
+ * statistics in OXS format.
+ *
+ * Returns error if message parsing fails, otherwise returns zero . */
+int
+oxs_flow_removed_stat_pull(struct ofpbuf *b,
+                           struct ofputil_flow_removed *ofr) {
+    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;
+    }
+
+    return oxs_flow_rem_stat_fields_pull(p + sizeof (*oxs),
+                                         stat_len - sizeof (*oxs), ofr);
+
+}
+