diff --git a/NEWS b/NEWS
index 4230189..0704960 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,13 @@ Post-v2.9.0
        "table#".  These are not helpful names for the purpose of accepting
        and displaying table names, so now tables by default have no names.
    - ovs-ofctl:
+     * Existing flow entry statistics are redefined as standard OXS(OpenFlow
+       Extensible Statistics) fields for displaying the arbitrary flow stats.
+     * The existing flow statistics are renamed as Flow Description.
+     * Now "ovs-ofctl dump-flows" and "ovs-ofctl dump-aggregate" accepts a new
+       option --oxs-stats provided with the arbitrary OXS fields i.e
+       flow duration, flow count, packet count, byte count for displaying
+       the desired flow stats. See ovs-ofctl(8) for details.
      * ovs-ofctl now accepts and display table names in place of numbers.  By
        default it always accepts names and in interactive use it displays them;
        use --names or --no-names to override.  See ovs-ofctl(8) for details.
diff --git a/include/openflow/openflow-1.5.h b/include/openflow/openflow-1.5.h
index 73b76d8..d1870ce 100644
--- a/include/openflow/openflow-1.5.h
+++ b/include/openflow/openflow-1.5.h
@@ -163,4 +163,85 @@ struct ofp15_packet_out {
 };
 OFP_ASSERT(sizeof(struct ofp15_packet_out) == 8);
 
+struct ofp_oxs_stat {
+    ovs_be16 reserved;          /* Reserved for future use,
+                                 * currently zeroed. */
+    ovs_be16 length;            /* Stats Length */
+};
+
+OFP_ASSERT(sizeof(struct ofp_oxs_stat) == 4);
+
+/* Body for ofp_multipart_request of type
+ * OFPMP_FLOW_DESC & OFPMP_FLOW_STATS. */
+struct ofp15_flow_stats_request {
+    uint8_t table_id;           /* ID of table to read (from ofp_table_desc),
+                                 * OFPTT_ALL for all tables. */
+    uint8_t pad[3];             /* Align to 32 bits. */
+    ovs_be32 out_port;          /* Require matching entries to include this as
+                                 * an output port. A value of OFP_ANY
+                                 * indicates no restriction. */
+    ovs_be32 out_group;         /* Require matching entries to include this as
+                                 * an output group. A value of OFPG_ANY
+                                 * indicates no restriction. */
+    uint8_t pad2[4];            /* Align to 64 bits. */
+    ovs_be64 cookie;            /* Require matching entries to contain this
+                                 * cookie value */
+    ovs_be64 cookie_mask;       /* Mask used to restrict the cookie bits that
+                                 * must match. A value of 0 indicates no
+                                 * restriction. */
+};
+
+OFP_ASSERT(sizeof(struct ofp15_flow_stats_request) == 32);
+
+/* Body of reply to OFPMP_FLOW_DESC request. */
+struct ofp15_flow_desc {
+    ovs_be16 length;          /* Length of this entry. */
+    uint8_t pad2[2];          /* Align to 64 bits. */
+    uint8_t table_id;         /* ID of table flow came from. */
+    uint8_t pad;
+    ovs_be16 priority;        /* Priority of the entry. */
+    ovs_be16 idle_timeout;    /* Number of seconds
+                                 idle before expiration. */
+    ovs_be16 hard_timeout;    /* Number of seconds
+                                 before expiration. */
+    ovs_be16 flags;           /* Bitmap of OFPFF_*. flags. */
+    ovs_be16 importance;      /* Eviction precedence. */
+    ovs_be64 cookie;          /* Opaque controller issued identifier. */
+};
+
+OFP_ASSERT(sizeof(struct ofp15_flow_desc) == 24);
+
+/* Body of reply to OFPMP_FLOW_STATS request
+ * and body for OFPIT_STAT_TRIGGER generated status. */
+struct ofp15_flow_stats_reply {
+    ovs_be16 length;            /* Length of this entry.  */
+    uint8_t pad2[2];            /* Align to 64 bits.  */
+    uint8_t table_id;           /* ID of table flow came from. */
+    uint8_t reason;             /* One of OFPFSR_*.  */
+    ovs_be16 priority;          /* Priority of the entry.  */
+};
+
+OFP_ASSERT(sizeof(struct ofp15_flow_stats_reply) == 8);
+
+/* OXS flow stat field types for OpenFlow basic class. */
+enum oxs_ofb_stat_fields {
+    OFPXST_OFB_DURATION = 0,     /* Time flow entry has been alive.  */
+    OFPXST_OFB_IDLE_TIME = 1,    /* Time flow entry has been idle.  */
+    OFPXST_OFB_FLOW_COUNT = 3,   /* Number of aggregated flow entries. */
+    OFPXST_OFB_PACKET_COUNT = 4, /* Number of packets in flow entry.  */
+    OFPXST_OFB_BYTE_COUNT = 5,   /* Number of bytes in flow entry.  */
+};
+
+/* Flow removed (datapath -> controller). */
+struct ofp15_flow_removed {
+    uint8_t table_id;           /* ID of the table */
+    uint8_t reason;             /* One of OFPRR_*. */
+    ovs_be16 priority;          /* Priority level of flow entry. */
+    ovs_be16 idle_timeout;      /* Idle timeout from original flow mod. */
+    ovs_be16 hard_timeout;      /* Hard timeout from original flow mod. */
+    ovs_be64 cookie;            /* Opaque controller issued identifier. */
+};
+
+OFP_ASSERT(sizeof (struct ofp15_flow_removed) == 16);
+
 #endif /* openflow/openflow-1.5.h */
diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h
index 3f92f2a..b7e3a09 100644
--- a/include/openvswitch/ofp-msgs.h
+++ b/include/openvswitch/ofp-msgs.h
@@ -165,8 +165,10 @@ enum ofpraw {
 
     /* OFPT 1.0 (11): struct ofp10_flow_removed. */
     OFPRAW_OFPT10_FLOW_REMOVED,
-    /* OFPT 1.1+ (11): struct ofp11_flow_removed, uint8_t[8][]. */
+    /* OFPT 1.1-1.4 (11): struct ofp11_flow_removed, uint8_t[8][]. */
     OFPRAW_OFPT11_FLOW_REMOVED,
+    /* OFPT 1.5+ (11): struct ofp15_flow_removed, uint8_t[8][]. */
+    OFPRAW_OFPT15_FLOW_REMOVED,
     /* NXT 1.0+ (14): struct nx_flow_removed, uint8_t[8][]. */
     OFPRAW_NXT_FLOW_REMOVED,
 
@@ -293,8 +295,12 @@ enum ofpraw {
 
     /* OFPST 1.0 (1): struct ofp10_flow_stats_request. */
     OFPRAW_OFPST10_FLOW_REQUEST,
-    /* OFPST 1.1+ (1): struct ofp11_flow_stats_request, uint8_t[8][]. */
+    /* OFPST 1.1-1.4 (1): struct ofp11_flow_stats_request, uint8_t[8][]. */
     OFPRAW_OFPST11_FLOW_REQUEST,
+    /* OFPST 1.5+ (1): struct ofp15_flow_stats_request, uint8_t[8][]. */
+    OFPRAW_OFPST15_FLOW_REQUEST,
+    /* OFPST 1.5+ (17): struct ofp15_flow_stats_request, uint8_t[8][]. */
+    OFPRAW_OFPST15_FLOW_DESC_REQUEST,
     /* NXST 1.0 (0): struct nx_flow_stats_request, uint8_t[8][]. */
     OFPRAW_NXST_FLOW_REQUEST,
 
@@ -302,20 +308,28 @@ enum ofpraw {
     OFPRAW_OFPST10_FLOW_REPLY,
     /* OFPST 1.1-1.2 (1): uint8_t[]. */
     OFPRAW_OFPST11_FLOW_REPLY,
-    /* OFPST 1.3+ (1): uint8_t[]. */
+    /* OFPST 1.3-1.4 (1): uint8_t[]. */
     OFPRAW_OFPST13_FLOW_REPLY,
+    /* OFPST 1.5+ (1): uint8_t[]. */
+    OFPRAW_OFPST15_FLOW_REPLY,
+    /* OFPST 1.5+ (17): uint8_t[]. */
+    OFPRAW_OFPST15_FLOW_DESC_REPLY,
     /* NXST 1.0 (0): uint8_t[]. */
     OFPRAW_NXST_FLOW_REPLY,
 
     /* OFPST 1.0 (2): struct ofp10_flow_stats_request. */
     OFPRAW_OFPST10_AGGREGATE_REQUEST,
-    /* OFPST 1.1+ (2): struct ofp11_flow_stats_request, uint8_t[8][]. */
+    /* OFPST 1.1-1.4 (2): struct ofp11_flow_stats_request, uint8_t[8][]. */
     OFPRAW_OFPST11_AGGREGATE_REQUEST,
+    /* OFPST 1.5+ (2): struct ofp15_flow_stats_request, uint8_t[8][]. */
+    OFPRAW_OFPST15_AGGREGATE_REQUEST,
     /* NXST 1.0 (1): struct nx_flow_stats_request, uint8_t[8][]. */
     OFPRAW_NXST_AGGREGATE_REQUEST,
 
-    /* OFPST 1.0+ (2): struct ofp_aggregate_stats_reply. */
+    /* OFPST 1.0-1.4 (2): struct ofp_aggregate_stats_reply. */
     OFPRAW_OFPST_AGGREGATE_REPLY,
+    /* OFPST 1.5+ (2): uint8_t[] . */
+    OFPRAW_OFPST15_AGGREGATE_REPLY,
     /* NXST 1.0 (1): struct ofp_aggregate_stats_reply. */
     OFPRAW_NXST_AGGREGATE_REPLY,
 
@@ -561,6 +575,7 @@ enum ofptype {
                                   * OFPRAW_NXT_PACKET_IN. */
     OFPTYPE_FLOW_REMOVED,        /* OFPRAW_OFPT10_FLOW_REMOVED.
                                   * OFPRAW_OFPT11_FLOW_REMOVED.
+                                  * OFPRAW_OFPT15_FLOW_REMOVED.
                                   * OFPRAW_NXT_FLOW_REMOVED. */
     OFPTYPE_PORT_STATUS,         /* OFPRAW_OFPT10_PORT_STATUS.
                                   * OFPRAW_OFPT11_PORT_STATUS.
@@ -637,16 +652,22 @@ enum ofptype {
     OFPTYPE_DESC_STATS_REPLY,        /* OFPRAW_OFPST_DESC_REPLY. */
     OFPTYPE_FLOW_STATS_REQUEST,      /* OFPRAW_OFPST10_FLOW_REQUEST.
                                       * OFPRAW_OFPST11_FLOW_REQUEST.
+                                      * OFPRAW_OFPST15_FLOW_REQUEST.
                                       * OFPRAW_NXST_FLOW_REQUEST. */
     OFPTYPE_FLOW_STATS_REPLY,        /* OFPRAW_OFPST10_FLOW_REPLY.
                                       * OFPRAW_OFPST11_FLOW_REPLY.
                                       * OFPRAW_OFPST13_FLOW_REPLY.
+                                      * OFPRAW_OFPST15_FLOW_REPLY.
                                       * OFPRAW_NXST_FLOW_REPLY. */
     OFPTYPE_AGGREGATE_STATS_REQUEST, /* OFPRAW_OFPST10_AGGREGATE_REQUEST.
                                       * OFPRAW_OFPST11_AGGREGATE_REQUEST.
+                                      * OFPRAW_OFPST15_AGGREGATE_REQUEST.
                                       * OFPRAW_NXST_AGGREGATE_REQUEST. */
     OFPTYPE_AGGREGATE_STATS_REPLY,   /* OFPRAW_OFPST_AGGREGATE_REPLY.
+                                      * OFPRAW_OFPST15_AGGREGATE_REPLY.
                                       * OFPRAW_NXST_AGGREGATE_REPLY. */
+    OFPTYPE_FLOW_DESC_REQUEST,   /* OFPRAW_OFPST15_FLOW_DESC_REQUEST. */
+    OFPTYPE_FLOW_DESC_REPLY,     /* OFPRAW_OFPST15_FLOW_DESC_REPLY. */
     OFPTYPE_TABLE_STATS_REQUEST,     /* OFPRAW_OFPST_TABLE_REQUEST. */
     OFPTYPE_TABLE_STATS_REPLY,       /* OFPRAW_OFPST10_TABLE_REPLY.
                                       * OFPRAW_OFPST11_TABLE_REPLY.
diff --git a/include/openvswitch/ofp-print.h b/include/openvswitch/ofp-print.h
index ed11378..f7eea44 100644
--- a/include/openvswitch/ofp-print.h
+++ b/include/openvswitch/ofp-print.h
@@ -34,6 +34,7 @@ struct ofputil_table_features;
 struct ofputil_table_map;
 struct ofputil_table_stats;
 struct dp_packet;
+struct ofputil_aggregate_stats;
 
 #ifdef  __cplusplus
 extern "C" {
@@ -62,12 +63,16 @@ void ofp_print_table_features(
     const struct ofputil_table_stats *stats,
     const struct ofputil_table_stats *prev_stats,
     const struct ofputil_table_map *table_map);
-
 void ofp_print_flow_stats(struct ds *, const struct ofputil_flow_stats *,
                           const struct ofputil_port_map *,
                           const struct ofputil_table_map *,
                           bool show_stats);
-
+void ofp_print_flow_oxs_stats(struct ds *string,
+                         const struct ofputil_flow_stats *fs,
+                         bool stats, uint8_t oxs_field_set);
+void ofp_print_flow_oxs_agg_stats(struct ds *,
+                         const struct ofputil_aggregate_stats ,
+                         bool , uint8_t );
 #ifdef  __cplusplus
 }
 #endif
diff --git a/lib/automake.mk b/lib/automake.mk
index 5c26e0f..7ecf647 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -216,6 +216,8 @@ lib_libopenvswitch_la_SOURCES = \
 	lib/ovsdb-parser.h \
 	lib/ovsdb-types.c \
 	lib/ovsdb-types.h \
+	lib/ox-stat.c \
+	lib/ox-stat.h \
 	lib/packets.c \
 	lib/packets.h \
 	lib/pcap-file.c \
diff --git a/lib/ofp-bundle.c b/lib/ofp-bundle.c
index 0921c81..a54e2fd 100644
--- a/lib/ofp-bundle.c
+++ b/lib/ofp-bundle.c
@@ -183,6 +183,7 @@ ofputil_is_bundlable(enum ofptype type)
     case OFPTYPE_GET_ASYNC_REQUEST:
     case OFPTYPE_DESC_STATS_REQUEST:
     case OFPTYPE_FLOW_STATS_REQUEST:
+    case OFPTYPE_FLOW_DESC_REQUEST:
     case OFPTYPE_AGGREGATE_STATS_REQUEST:
     case OFPTYPE_TABLE_STATS_REQUEST:
     case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
@@ -211,6 +212,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_FLOW_DESC_REPLY:
     case OFPTYPE_QUEUE_STATS_REPLY:
     case OFPTYPE_PORT_STATS_REPLY:
     case OFPTYPE_TABLE_STATS_REPLY:
diff --git a/lib/ofp-flow.c b/lib/ofp-flow.c
index c29f5b7..3d2d979 100644
--- a/lib/ofp-flow.c
+++ b/lib/ofp-flow.c
@@ -30,6 +30,7 @@
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 #include "util.h"
+#include "ox-stat.h"
 
 VLOG_DEFINE_THIS_MODULE(ofp_flow);
 
@@ -552,6 +553,37 @@ ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr,
 }
 
 static enum ofperr
+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_flow_stats_request *ofsr;
+    enum ofperr error;
+
+    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);
+    if (error) {
+        return error;
+    }
+
+    return 0;
+}
+
+static enum ofperr
 ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
                                  struct ofpbuf *b, bool aggregate,
                                  const struct tun_table *tun_table,
@@ -605,10 +637,18 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
         return ofputil_decode_ofpst11_flow_request(fsr, &b, false, tun_table,
                                                    vl_mff_map);
 
+    case OFPRAW_OFPST15_FLOW_DESC_REQUEST:
+        return ofputil_decode_ofpst15_flow_request(fsr, &b, false,
+                                                   tun_table, vl_mff_map);
+
     case OFPRAW_OFPST11_AGGREGATE_REQUEST:
         return ofputil_decode_ofpst11_flow_request(fsr, &b, true, tun_table,
                                                    vl_mff_map);
 
+    case OFPRAW_OFPST15_AGGREGATE_REQUEST:
+       return ofputil_decode_ofpst15_flow_request(fsr, &b, true,
+                                                  tun_table, vl_mff_map);
+
     case OFPRAW_NXST_FLOW_REQUEST:
         return ofputil_decode_nxst_flow_request(fsr, &b, false, tun_table,
                                                 vl_mff_map);
@@ -637,9 +677,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
@@ -657,6 +695,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_flow_stats_request *ofsr;
+
+        raw = (fsr->aggregate
+               ? OFPRAW_OFPST15_AGGREGATE_REQUEST
+               : OFPRAW_OFPST15_FLOW_DESC_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);
+        break;
+    }
+
     case OFPUTIL_P_OF10_STD:
     case OFPUTIL_P_OF10_STD_TID: {
         struct ofp10_flow_stats_request *ofsr;
@@ -773,6 +830,58 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
 
     if (!msg->size) {
         return EOF;
+    } else if (raw == OFPRAW_OFPST15_FLOW_DESC_REPLY) {
+       const struct ofp15_flow_desc *ofd;
+       size_t length;
+       uint16_t padded_match_len;
+       uint16_t stat_len;
+       uint8_t oxs_field_set;
+
+       ofd = ofpbuf_try_pull(msg, sizeof *ofd);
+      if (!ofd) {
+           VLOG_WARN_RL(&rl, "OFPST_FLOW_DESC reply has %" PRIu32
+                        " leftover " "bytes at end", msg->size);
+           return EINVAL;
+       }
+
+       length = ntohs(ofd->length);
+       if (length < sizeof *ofd) {
+           VLOG_WARN_RL(&rl, "OFPST_FLOW_DESC reply claims invalid "
+                        "length %" PRIuSIZE, length);
+           return EINVAL;
+       }
+
+       if (ofputil_pull_ofp11_match
+          (msg, NULL, NULL, &fs->match, &padded_match_len)) {
+           VLOG_WARN_RL(&rl, "OFPST_FLOW_DESC reply bad match");
+           return EINVAL;
+       }
+
+       fs->priority = ntohs(ofd->priority);
+       fs->table_id = ofd->table_id;
+       fs->duration_sec = 0;
+       fs->duration_nsec = 0;
+       fs->idle_age = 0;
+       fs->hard_age = -1;
+       fs->packet_count = 0;
+       fs->byte_count = 0;
+       fs->cookie = ofd->cookie;
+       fs->idle_timeout = ntohs(ofd->idle_timeout);
+       fs->hard_timeout = ntohs(ofd->hard_timeout);
+       fs->importance = ntohs(ofd->importance);
+
+      error = ofputil_decode_flow_mod_flags(ofd->flags, -1, oh->version,
+                                                &fs->flags);
+           if (error) {
+               return error;
+           }
+
+       if (oxs_pull_stat(msg, fs, &stat_len, &oxs_field_set)) {
+           VLOG_WARN_RL(&rl, "OXS OFPST_FLOW_DESC reply bad match");
+           return EINVAL;
+       }
+       instructions_len = length - sizeof *ofd - padded_match_len - stat_len;
+
     } else if (raw == OFPRAW_OFPST11_FLOW_REPLY
                || raw == OFPRAW_OFPST13_FLOW_REPLY) {
         const struct ofp11_flow_stats *ofs;
@@ -951,7 +1060,31 @@ 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_FLOW_DESC_REPLY) {
+        struct ofp15_flow_desc *ofd;
+        /* oxs_field_set is used to encode/decode OXS fields in TLV format*/
+        uint8_t oxs_field_set;
+
+        oxs_bitmap_set_all(&oxs_field_set);
+        ofpbuf_put_uninit(reply, sizeof *ofd);
+        oxm_put_match(reply, &fs->match, version);
+        oxs_put_stat(reply, fs, version, oxs_field_set);
+        ofpacts_put_openflow_instructions(fs->ofpacts, fs->ofpacts_len, reply,
+                                      version);
+
+        ofd = ofpbuf_at_assert(reply, start_ofs, sizeof *ofd);
+        ofd->length = htons(reply->size - start_ofs);
+        ofd->table_id = fs->table_id;
+        ofd->priority = htons(fs->priority);
+        ofd->idle_timeout = htons(fs->idle_timeout);
+        ofd->hard_timeout = htons(fs->hard_timeout);
+        ofd->cookie = fs->cookie;
+        memset(ofd->pad2, 0, sizeof ofd->pad2);
+        ofd->pad = 0;
+        ofd->importance = htons(fs->importance);
+        ofd->flags = ofputil_encode_flow_mod_flags(fs->flags, version);
+    } else if (raw == OFPRAW_OFPST11_FLOW_REPLY ||
+               raw == OFPRAW_OFPST13_FLOW_REPLY) {
         struct ofp11_flow_stats *ofs;
 
         ofpbuf_put_uninit(reply, sizeof *ofs);
@@ -1053,20 +1186,29 @@ ofputil_encode_aggregate_stats_reply(
     enum ofpraw raw;
 
     ofpraw_decode(&raw, request);
-    if (raw == OFPRAW_OFPST10_AGGREGATE_REQUEST) {
-        packet_count = unknown_to_zero(stats->packet_count);
-        byte_count = unknown_to_zero(stats->byte_count);
+    if (raw == OFPRAW_OFPST15_AGGREGATE_REQUEST) {
+        enum ofp_version version = request->version;
+        /* oxs_field_set is used to encode/decode OXS fields in TLV format*/
+        uint8_t oxs_set_field;
+
+        oxs_bitmap_set_all(&oxs_set_field);
+        msg = ofpraw_alloc_stats_reply(request, 0);
+        oxs_put_agg_stat(msg, stats, version, oxs_set_field);
     } else {
-        packet_count = stats->packet_count;
-        byte_count = stats->byte_count;
-    }
-
-    msg = ofpraw_alloc_stats_reply(request, 0);
-    asr = ofpbuf_put_zeros(msg, sizeof *asr);
-    put_32aligned_be64(&asr->packet_count, htonll(packet_count));
-    put_32aligned_be64(&asr->byte_count, htonll(byte_count));
-    asr->flow_count = htonl(stats->flow_count);
+        if (raw == OFPRAW_OFPST10_AGGREGATE_REQUEST) {
+            packet_count = unknown_to_zero(stats->packet_count);
+            byte_count = unknown_to_zero(stats->byte_count);
+        } else {
+            packet_count = stats->packet_count;
+            byte_count = stats->byte_count;
+        }
 
+        msg = ofpraw_alloc_stats_reply(request, 0);
+        asr = ofpbuf_put_zeros(msg, sizeof *asr);
+        put_32aligned_be64(&asr->packet_count, htonll(packet_count));
+        put_32aligned_be64(&asr->byte_count, htonll(byte_count));
+        asr->flow_count = htonl(stats->flow_count);
+    }
     return msg;
 }
 
@@ -1075,12 +1217,22 @@ ofputil_decode_aggregate_stats_reply(struct ofputil_aggregate_stats *stats,
                                      const struct ofp_header *reply)
 {
     struct ofpbuf msg = ofpbuf_const_initializer(reply, ntohs(reply->length));
-    ofpraw_pull_assert(&msg);
+    enum ofperr error;
+    enum ofpraw raw;
 
-    struct ofp_aggregate_stats_reply *asr = msg.msg;
-    stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count));
-    stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count));
-    stats->flow_count = ntohl(asr->flow_count);
+    raw = ofpraw_pull_assert(&msg);
+    if (raw == OFPRAW_OFPST15_AGGREGATE_REPLY) {
+        memset(stats, 0, sizeof (*stats));
+        error = oxs_pull_agg_stat(msg, stats);
+        if (error) {
+            return error;
+        }
+    } else {
+        struct ofp_aggregate_stats_reply *asr = msg.msg;
+        stats->packet_count = ntohll(get_32aligned_be64(&asr->packet_count));
+        stats->byte_count = ntohll(get_32aligned_be64(&asr->byte_count));
+        stats->flow_count = ntohl(asr->flow_count);
+    }
 
     return 0;
 }
@@ -1436,8 +1588,8 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
     char *string = xstrdup(str_);
     char *error;
 
-    error = parse_ofp_str__(fm, command, string, port_map, table_map,
-                            usable_protocols);
+    error = parse_ofp_str__(fm, command, string, port_map,
+                            table_map, usable_protocols);
     if (error) {
         fm->ofpacts = NULL;
         fm->ofpacts_len = 0;
diff --git a/lib/ofp-monitor.c b/lib/ofp-monitor.c
index 49d623c..c65c629 100644
--- a/lib/ofp-monitor.c
+++ b/lib/ofp-monitor.c
@@ -28,6 +28,7 @@
 #include "openvswitch/ofp-parse.h"
 #include "openvswitch/ofp-table.h"
 #include "openvswitch/vlog.h"
+#include "ox-stat.h"
 
 VLOG_DEFINE_THIS_MODULE(ofp_monitor);
 
@@ -42,7 +43,26 @@ 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;
+        fr->idle_timeout = ntohs(ofr->idle_timeout);
+        fr->hard_timeout = ntohs(ofr->hard_timeout);
+    } else if (raw == OFPRAW_OFPT11_FLOW_REMOVED) {
+
         const struct ofp12_flow_removed *ofr;
         enum ofperr error;
 
@@ -138,9 +158,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
     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,
@@ -161,7 +179,27 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         ofputil_put_ofp11_match(msg, &fr->match, protocol);
         break;
     }
+    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;
+        ofr->idle_timeout = htons(fr->idle_timeout);
+        ofr->hard_timeout = htons(fr->hard_timeout);
+        ofputil_put_ofp11_match(msg, &fr->match, protocol);
+        /*Stats encoding in OXS TLV Format*/
+        oxs_flow_removed_stat_put(msg, fr,
+                                  ofputil_protocol_to_ofp_version(protocol));
+        break;
+    }
     case OFPUTIL_P_OF10_STD:
     case OFPUTIL_P_OF10_STD_TID: {
         struct ofp10_flow_removed *ofr;
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 4feb82e..f98cbdc 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -27,6 +27,7 @@
 #include "packets.h"
 #include "socket-util.h"
 #include "util.h"
+#include "ox-stat.h"
 
 /* Parses 'str' as an 8-bit unsigned integer into '*valuep'.
  *
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 2f96b18..9c70ad0 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -63,6 +63,7 @@
 #include "unaligned.h"
 #include "util.h"
 #include "uuid.h"
+#include "ox-stat.h"
 
 static void ofp_print_queue_name(struct ds *string, uint32_t port);
 static void ofp_print_error(struct ds *, enum ofperr);
@@ -1805,6 +1806,55 @@ ofp_print_flow_stats(struct ds *string, const struct ofputil_flow_stats *fs,
     ofpacts_format(fs->ofpacts, fs->ofpacts_len, &fp);
 }
 
+void
+ofp_print_flow_oxs_stats(struct ds *string,
+                         const struct ofputil_flow_stats *fs,
+                         bool oxs, uint8_t oxs_field_set)
+{
+    if (!oxs && oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_DURATION)) {
+        ds_put_format(string, "%sduration=%s", colors.param, colors.end);
+        ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
+        ds_put_cstr(string, "  ");
+    }
+    if (!oxs) {
+        if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_PACKET_COUNT)) {
+            ds_put_format(string, "%sn_packets=%s%"PRIu64"  ",
+                      colors.param, colors.end, fs->packet_count);
+        }
+        if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_BYTE_COUNT)) {
+            ds_put_format(string, "%sn_bytes=%s%"PRIu64"  ",
+                      colors.param, colors.end, fs->byte_count);
+        }
+    }
+    if (!oxs && fs->idle_age >= 0 &&
+        oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_IDLE_TIME)) {
+        ds_put_format(string, "%sidle_age=%s%d  ",
+                      colors.param, colors.end, fs->idle_age);
+    }
+
+}
+
+void
+ofp_print_flow_oxs_agg_stats(struct ds *string,
+                             const struct ofputil_aggregate_stats fs,
+                             bool stats, uint8_t oxs_field_set)
+{
+    if (!stats) {
+        if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_PACKET_COUNT)) {
+            ds_put_format(string, "%sn_packets=%s%"PRIu64"  ",
+                      colors.param, colors.end, fs.packet_count);
+        }
+        if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_BYTE_COUNT)) {
+            ds_put_format(string, "%sn_bytes=%s%"PRIu64"  ",
+                      colors.param, colors.end, fs.byte_count);
+        }
+        if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_FLOW_COUNT)) {
+            ds_put_format(string, "%sflow_count=%s%"PRIu32"  ",
+                      colors.param, colors.end, fs.flow_count);
+        }
+    }
+}
+
 static enum ofperr
 ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh,
                            const struct ofputil_port_map *port_map,
@@ -3684,6 +3734,7 @@ ofp_to_string__(const struct ofp_header *oh,
 
     case OFPTYPE_FLOW_STATS_REQUEST:
     case OFPTYPE_AGGREGATE_STATS_REQUEST:
+    case OFPTYPE_FLOW_DESC_REQUEST:
         ofp_print_stats(string, oh);
         return ofp_print_flow_stats_request(string, oh, port_map, table_map);
 
@@ -3704,6 +3755,7 @@ ofp_to_string__(const struct ofp_header *oh,
         return ofp_print_ofpst_desc_reply(string, oh);
 
     case OFPTYPE_FLOW_STATS_REPLY:
+    case OFPTYPE_FLOW_DESC_REPLY:
         ofp_print_stats(string, oh);
         return ofp_print_flow_stats_reply(string, oh, port_map, table_map);
 
diff --git a/lib/ox-stat.c b/lib/ox-stat.c
new file mode 100644
index 0000000..29917b7
--- /dev/null
+++ b/lib/ox-stat.c
@@ -0,0 +1,1040 @@
+/*
+ * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "nx-match.h"
+#include <netinet/icmp6.h>
+#include "classifier.h"
+#include "colors.h"
+#include "openvswitch/hmap.h"
+#include "openflow/nicira-ext.h"
+#include "openvswitch/dynamic-string.h"
+#include "openvswitch/meta-flow.h"
+#include "openvswitch/ofp-actions.h"
+#include "openvswitch/ofp-errors.h"
+#include "openvswitch/ofp-util.h"
+#include "openvswitch/ofpbuf.h"
+#include "openvswitch/vlog.h"
+#include "packets.h"
+#include "openvswitch/shash.h"
+#include "tun-metadata.h"
+#include "unaligned.h"
+#include "util.h"
+#include "ox-stat.h"
+
+VLOG_DEFINE_THIS_MODULE(ox_stat);
+
+/* ## -------------------------- ## */
+/* ## OpenFlow Extensible Stats. ## */
+/* ## -------------------------- ## */
+
+/* Components of a OXS TLV header. */
+
+static struct ovs_list oxs_ox_map[OFPXST_OFB_BYTE_COUNT + 1];
+static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+static uint32_t
+oxs_header_no_len(uint32_t header)
+{
+    return header & 0xffffff80;
+}
+
+#define OXS_CLASS(HEADER) ((HEADER) >> 16)
+#define OXS_FIELD(HEADER) (((HEADER) >> 9) & 0x7f)
+#define OXS_TYPE(HEADER) (((HEADER) >> 9) & 0x7fffff)
+#define OXS_RESERVED(HEADER) (((HEADER) >> 8) & 1)
+#define OXS_LENGTH(HEADER) ((HEADER) & 0xff)
+
+/* Components of a OXS TLV header. */
+#define OXS_HEADER__(CLASS, FIELD, RESERVED, LENGTH) \
+(((CLASS) << 16) | ((FIELD) << 9) | ((RESERVED) << 8) | (LENGTH))
+
+#define OXS_HEADER(CLASS, FIELD, LENGTH) \
+        OXS_HEADER__(CLASS, FIELD, 0, LENGTH)
+
+/*  OXS Class IDs.
+ *  The high order bit differentiate reserved classes from member classes.
+ *  Classes 0x0000 to 0x7FFF are member classes, allocated by ONF.
+ *  Classes 0x8000 to 0xFFFE are reserved classes, reserved for
+ *  standardisation.
+ */
+
+enum ofp_oxs_class {
+    OFPXSC_OPENFLOW_BASIC = 0x8002,     /* Basic stats class for OpenFlow */
+    OFPXSC_EXPERIMENTER = 0xFFFF,       /* Experimenter class */
+};
+
+#define OFPXST_OFB_ALL ((UINT64_C(1) << 6) - 1)
+#define OXS_OX_COOKIE    OXS_HEADER  (0x8002, 5 , 8)
+
+struct oxs_field {
+    uint32_t header;
+    enum ofp_version version;
+    const char *name;
+    enum oxs_ofb_stat_fields id;
+};
+
+struct oxs_field_index {
+    struct hmap_node header_node;
+    struct hmap_node name_node;
+    struct ovs_list ox_node;
+    const struct oxs_field fs;
+};
+
+#define OXS_STATS_DURATION_LEN     8
+#define OXS_STATS_IDLE_TIME_LEN    8
+#define OXS_STATS_FLOW_COUNT_LEN   4
+#define OXS_STATS_PACKET_COUNT_LEN 8
+#define OXS_STATS_BYTE_COUNT_LEN   8
+
+#define OXS_OF_DURATION     OXS_HEADER (0x8002, OFPXST_OFB_DURATION, \
+                                        OXS_STATS_DURATION_LEN)
+#define OXS_OF_IDLE_TIME    OXS_HEADER (0x8002, OFPXST_OFB_IDLE_TIME, \
+                                        OXS_STATS_IDLE_TIME_LEN)
+#define OXS_OF_FLOW_COUNT   OXS_HEADER (0x8002, OFPXST_OFB_FLOW_COUNT, \
+                                        OXS_STATS_FLOW_COUNT_LEN)
+#define OXS_OF_PACKET_COUNT OXS_HEADER (0x8002, OFPXST_OFB_PACKET_COUNT, \
+                                        OXS_STATS_PACKET_COUNT_LEN)
+#define OXS_OF_BYTE_COUNT   OXS_HEADER (0x8002, OFPXST_OFB_BYTE_COUNT, \
+                                        OXS_STATS_BYTE_COUNT_LEN)
+
+static struct oxs_field_index all_oxs_fields[] = {
+    {.fs = {OXS_OF_DURATION, OFP15_VERSION, "OFPXST_OFB_DURATION",
+            OFPXST_OFB_DURATION}},
+    {.fs = {OXS_OF_IDLE_TIME, OFP15_VERSION, "OFPXST_OFB_IDLE_TIME",
+            OFPXST_OFB_IDLE_TIME}},
+    {.fs = {OXS_OF_FLOW_COUNT, OFP15_VERSION, "OFPXST_OFB_FLOW_COUNT",
+            OFPXST_OFB_FLOW_COUNT}},
+    {.fs = {OXS_OF_PACKET_COUNT, OFP15_VERSION, "OFPXST_OFB_PACKET_COUNT",
+            OFPXST_OFB_PACKET_COUNT}},
+    {.fs = {OXS_OF_BYTE_COUNT, OFP15_VERSION, "OFPXST_OFB_BYTE_COUNT",
+            OFPXST_OFB_BYTE_COUNT}},
+};
+
+static const struct oxs_field *oxs_field_by_header(uint32_t header);
+static const struct oxs_field *oxs_field_by_id(enum oxs_ofb_stat_fields,
+                                               enum ofp_version);
+static bool is_experimenter_oxs(uint64_t header);
+static int oxs_experimenter_len(uint64_t header);
+static int oxs_payload_len (uint64_t header);
+static int oxs_header_len (uint64_t header);
+static uint64_t oxs_header_get(enum oxs_ofb_stat_fields id,
+                                enum ofp_version version);
+static int oxs_pull_header__(struct ofpbuf *b, uint64_t * header,
+                              const struct oxs_field **field);
+static enum ofperr oxs_pull_entry__(struct ofpbuf *b, uint64_t * header,
+                                    const struct oxs_field **field_,
+                                    struct ofputil_flow_stats *fs);
+static enum ofperr oxs_pull_match_entry(struct ofpbuf *b,
+                                        const struct oxs_field **field,
+                                        struct ofputil_flow_stats *fs);
+static enum ofperr oxs_pull_raw(const uint8_t *, unsigned int ,
+                                struct ofputil_flow_stats *fs,
+                                ovs_be64 * cookie, ovs_be64 * cookie_mask,
+                                uint8_t *oxs_field_set);
+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,
+                               enum oxs_ofb_stat_fields field,
+                               enum ofp_version version);
+static int ox_put_agg_raw(struct ofpbuf *b, enum ofp_version oxs,
+                          const struct ofputil_aggregate_stats *fs,
+                          uint8_t oxs_field_set);
+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);
+
+bool
+parse_oxs_key(char **stringp, char **keyp)
+{
+    /* Skip white space and delimiters. If that brings us to the end of the
+     * input string, we are done. */
+    *stringp += strspn(*stringp, ", \t\r\n");
+    if (*(*stringp) == '\0') {
+        *keyp = NULL;
+        return false;
+    }
+
+    /* Extract the key and the delimiter that ends the key.
+     * Advance the input position past the key and delimiter. */
+    char *key = *stringp;
+    size_t key_len = strcspn(key, ":=(, \t\r\n");
+    char key_delim = key[key_len];
+    key[key_len] = '\0';
+    *stringp += key_len + (key_delim != '\0');
+
+        *keyp = key;
+        return true;
+}
+
+bool
+parse_oxs_field(const char *name, const struct ox_field **f_out)
+{
+    static const struct ox_field fields[] = {
+        {"duration", OFPXST_OFB_DURATION},
+        {"idle_time", OFPXST_OFB_IDLE_TIME},
+        {"flow_count", OFPXST_OFB_FLOW_COUNT},
+        {"packet_count", OFPXST_OFB_PACKET_COUNT},
+        {"byte_count", OFPXST_OFB_BYTE_COUNT},
+    };
+
+    const struct ox_field *oxfs;
+
+    for (oxfs = fields; oxfs < &fields[ARRAY_SIZE(fields)]; oxfs++) {
+        if (!strcmp(oxfs->name, name)) {
+            *f_out = oxfs;
+            return true;
+        }
+    }
+    *f_out = NULL;
+    return false;
+}
+
+void
+oxs_bitmap_set_all(uint8_t *oxs_field_set)
+{
+    enum  oxs_ofb_stat_fields i;
+
+    for (i = OFPXST_OFB_DURATION; i <= OFPXST_OFB_BYTE_COUNT; i++) {
+        *oxs_field_set |= 1 << i;
+    }
+}
+
+void
+oxs_bitmap_set(uint8_t *oxs_field_set, enum  oxs_ofb_stat_fields i)
+{
+    *oxs_field_set |= 1 << i;
+
+}
+
+bool
+oxs_bitmap_is_set(uint8_t oxs_field_set, enum  oxs_ofb_stat_fields i)
+{
+    if (oxs_field_set & 1 << i) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static bool
+is_experimenter_oxs(uint64_t header)
+{
+    return OXS_CLASS(header) == OFPXSC_EXPERIMENTER;
+}
+
+static int
+oxs_experimenter_len(uint64_t header)
+{
+    return is_experimenter_oxs(header) ? 4 : 0;
+}
+
+static int
+oxs_payload_len(uint64_t header)
+{
+    return OXS_LENGTH(header) - oxs_experimenter_len(header);
+}
+
+static int
+oxs_header_len(uint64_t header)
+{
+    return 4 + oxs_experimenter_len(header);
+}
+
+static uint64_t
+oxs_header_get(enum oxs_ofb_stat_fields id, enum ofp_version version)
+{
+    const struct oxs_field *f = oxs_field_by_id(id, version);
+
+    return f ? f->header : 0;
+}
+
+static int
+oxs_pull_header__(struct ofpbuf *b, uint64_t * header,
+                  const struct oxs_field **field)
+{
+    if (b->size < 4) {
+        goto bad_len;
+    }
+
+    *header = ((uint32_t) ntohl(get_unaligned_be32(b->data)));
+    if (is_experimenter_oxs(*header)) {
+        if (b->size < 8) {
+            goto bad_len;
+        }
+
+        *header = ntohll(get_unaligned_be64(b->data));
+    }
+
+    if (OXS_LENGTH(*header) < oxs_experimenter_len(*header)) {
+        goto error;
+    }
+
+    ofpbuf_pull(b, oxs_header_len(*header));
+
+    if (field) {
+        *field = oxs_field_by_header(*header);
+        if (!*field || (*field == NULL)) {
+            return OFPERR_OFPBMC_BAD_FIELD;
+        }
+    }
+    return 0;
+
+bad_len:
+    VLOG_DBG_RL(&rl, "encountered partial (%" PRIu32 "-byte) OXS entry",
+                b->size);
+error:
+    *header = 0;
+    if (field) {
+        *field = NULL;
+    }
+    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: {
+            ovs_be64 duration = 0;
+
+            memcpy(&duration, payload, sizeof (duration));
+            uint64_t duration_ = ntohll(duration);
+            fs->duration_sec = ((uint32_t) ((duration_ &
+                                            0xFFFFFFFF00000000LL) >> 32));
+            fs->duration_nsec = ((uint32_t) (duration_ & 0xFFFFFFFFLL));
+        }
+        break;
+        case OFPXST_OFB_IDLE_TIME: {
+            ovs_be64 idle_time = 0;
+
+            memcpy(&idle_time, payload, sizeof (idle_time));
+            uint64_t idle_time_ = ntohll(idle_time);
+            fs->idle_age = ((idle_time_ & 0xFFFFFFFF00000000LL) >> 32);
+        }
+        break;
+        case OFPXST_OFB_PACKET_COUNT: {
+            ovs_be64 packet_count;
+
+            memcpy(&packet_count, payload, sizeof (packet_count));
+            fs->packet_count = ntohll(packet_count);
+        }
+        break;
+        case OFPXST_OFB_BYTE_COUNT: {
+            ovs_be64 byte_count;
+
+            memcpy(&byte_count, payload, sizeof (byte_count));
+            fs->byte_count = ntohll(byte_count);
+        }
+        break;
+        case OFPXST_OFB_FLOW_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, uint8_t *oxs_field_set)
+{
+    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 {
+           oxs_bitmap_set(oxs_field_set,field->id);
+        }
+        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;
+}
+
+/* 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_pull_stat(struct ofpbuf *b, struct ofputil_flow_stats *fs,
+              uint16_t * statlen, uint8_t *oxs_field_set)
+{
+    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, oxs_field_set);
+}
+
+static enum ofperr
+oxs_pull_agg_raw(const uint8_t * p, unsigned int stat_len,
+                 struct ofputil_aggregate_stats *fs)
+{
+    struct ofpbuf b = ofpbuf_const_initializer(p, stat_len);
+
+    while (b.size) {
+
+        uint64_t header;
+        unsigned int payload_len;
+        const struct oxs_field *field;
+        const uint8_t *payload;
+
+        oxs_pull_header__(&b, &header, &field);
+        payload_len = oxs_payload_len(header);
+        payload = ofpbuf_try_pull(&b, payload_len);
+
+        if (fs && field) {
+            switch (field->id) {
+            case OFPXST_OFB_FLOW_COUNT: {
+                ovs_be32 flow_count;
+
+                memcpy(&flow_count, payload, sizeof (flow_count));
+                fs->flow_count = ntohl(flow_count);
+            }
+            break;
+            case OFPXST_OFB_PACKET_COUNT: {
+                ovs_be64 packet_count;
+
+                memcpy(&packet_count, payload, sizeof (packet_count));
+                fs->packet_count = ntohll(packet_count);
+            }
+            break;
+            case OFPXST_OFB_BYTE_COUNT: {
+                ovs_be64 byte_count;
+
+                memcpy(&byte_count, payload, sizeof (byte_count));
+                fs->byte_count = ntohll(byte_count);
+            }
+            break;
+            case OFPXST_OFB_DURATION:
+            case OFPXST_OFB_IDLE_TIME:
+                break;
+            }
+
+        }
+
+    }
+    return 0;
+}
+
+/* Retrieve struct ofp_oxs_stat from 'b', followed by the aggregate flow entry
+ * statistics in OXS format.
+ *
+ * Returns error if message parsing fails, otherwise returns zero . */
+int
+oxs_pull_agg_stat(struct ofpbuf b, struct ofputil_aggregate_stats *fs)
+{
+    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_pull_agg_raw(p + sizeof *oxs, stat_len - sizeof *oxs, fs);
+}
+
+static struct hmap oxs_header_map;
+static struct hmap oxs_name_map;
+
+static void
+oxs_init(void)
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+
+    if (ovsthread_once_start(&once)) {
+        hmap_init(&oxs_header_map);
+        hmap_init(&oxs_name_map);
+        for (int i = 0; i < OFPXST_OFB_BYTE_COUNT + 1; i++) {
+            ovs_list_init(&oxs_ox_map[i]);
+        }
+        for (struct oxs_field_index * oxfs = all_oxs_fields;
+             oxfs < &all_oxs_fields[ARRAY_SIZE(all_oxs_fields)]; oxfs++) {
+            hmap_insert(&oxs_header_map, &oxfs->header_node,
+                        hash_int(oxs_header_no_len(oxfs->fs.header), 0));
+            hmap_insert(&oxs_name_map, &oxfs->name_node,
+                        hash_string(oxfs->fs.name, 0));
+            ovs_list_push_back(&oxs_ox_map[oxfs->fs.id], &oxfs->ox_node);
+        }
+        ovsthread_once_done(&once);
+    }
+}
+
+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 = NULL;
+
+    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);
+    }
+
+}
+
+/* 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'. */
+static int
+ox_put_raw(struct ofpbuf *b, enum ofp_version oxs,
+           const struct ofputil_flow_stats *fs,
+           ovs_be64 cookie, ovs_be64 cookie_mask, uint8_t oxs_field_set)
+{
+    const size_t start_len = b->size;
+    int stat_len;
+
+    if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_DURATION)) {
+        ovs_be64 duration = 0;
+
+        if (fs) {
+            uint64_t 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_bitmap_is_set(oxs_field_set, OFPXST_OFB_IDLE_TIME)) {
+        ovs_be64 idl_time = 0;
+
+        if (fs) {
+            uint64_t idl_time_n = (uint64_t) fs->idle_age << 32;
+            idl_time = htonll(idl_time_n);
+        }
+        oxs_put__(b, OFPXST_OFB_IDLE_TIME, oxs, &idl_time, NULL,
+                  OXS_STATS_IDLE_TIME_LEN);
+    }
+    if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_FLOW_COUNT)) {
+        ovs_be32 flow_count = 0;
+
+        oxs_put__(b, OFPXST_OFB_FLOW_COUNT, oxs, &flow_count, NULL,
+                  OXS_STATS_FLOW_COUNT_LEN);
+    }
+    if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_PACKET_COUNT)) {
+        ovs_be64 pkt_count = 0;
+
+        if (fs) {
+            pkt_count = htonll(fs->packet_count);
+        }
+        oxs_put__(b, OFPXST_OFB_PACKET_COUNT, oxs, &pkt_count, NULL,
+                  OXS_STATS_PACKET_COUNT_LEN);
+    }
+    if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_BYTE_COUNT)) {
+        ovs_be64 byte_count = 0;
+
+        if (fs) {
+            byte_count = htonll(fs->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;
+}
+
+/* Appends to 'b' an struct ofp_oxs_stat followed by the flow entry statistics
+ * in OXS format , plus enough zero bytes to pad the data appended out to a
+ * multiple of 8.
+ *
+ * Specify the OpenFlow version in use as 'version'.
+ *
+ * This function can cause 'b''s data to be reallocated.
+ *
+ * Returns the number of bytes appended to 'b', excluding the padding.Never
+ * returns zero. */
+int
+oxs_put_stat(struct ofpbuf *b, const struct ofputil_flow_stats *fs,
+             enum ofp_version version, uint8_t oxs_field_set)
+{
+    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, oxs_field_set)
+                + 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;
+}
+
+/* Appends to 'b' the aggregate 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'. */
+static int
+ox_put_agg_raw(struct ofpbuf *b, enum ofp_version oxs,
+               const struct ofputil_aggregate_stats *fs, uint8_t oxs_field_set)
+{
+   const size_t start_len = b->size;
+   int stat_len;
+
+   if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_FLOW_COUNT)) {
+       ovs_be32 flow_count = 0;
+
+       if (fs) {
+           flow_count = htonl(fs->flow_count);
+       }
+       oxs_put__(b, OFPXST_OFB_FLOW_COUNT, oxs, &flow_count,
+                NULL, OXS_STATS_FLOW_COUNT_LEN);
+   }
+
+   if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_PACKET_COUNT)) {
+       ovs_be64 pkt_count = 0;
+
+       if (fs) {
+           pkt_count = htonll(fs->packet_count);
+       }
+       oxs_put__(b, OFPXST_OFB_PACKET_COUNT, oxs, &pkt_count,
+               NULL, OXS_STATS_PACKET_COUNT_LEN);
+   }
+
+   if (oxs_bitmap_is_set(oxs_field_set, OFPXST_OFB_BYTE_COUNT)) {
+       ovs_be64 byte_count = 0;
+
+       if (fs) {
+           byte_count = htonll(fs->byte_count);
+       }
+       oxs_put__(b, OFPXST_OFB_BYTE_COUNT, oxs, &byte_count,
+                NULL, OXS_STATS_BYTE_COUNT_LEN);
+   }
+
+   stat_len = b->size - start_len;
+   return stat_len;
+}
+
+/* Appends to 'b' an struct ofp_oxs_stat followed by the aggregate flow entry
+ * statistics in OXS format , plus enough zero bytes to pad the data appended
+ * out to a multiple of 8.
+ *
+ * Specify the OpenFlow version in use as 'version'.
+ *
+ * This function can cause 'b''s data to be reallocated.
+ *
+ * Returns the number of bytes appended to 'b', excluding the padding.  Never
+ * returns zero. */
+int
+oxs_put_agg_stat(struct ofpbuf *b, const struct ofputil_aggregate_stats *fs,
+                 enum ofp_version version, uint8_t oxs_set_field)
+{
+   int stat_len;
+   struct ofp_oxs_stat *oxs;
+   size_t start_len = b->size;
+
+   ofpbuf_put_uninit(b, sizeof *oxs);
+   stat_len = (ox_put_agg_raw(b, version, fs, oxs_set_field)
+                + 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 void
+oxs_put_duration(struct ofpbuf *b,
+                 const struct ofputil_flow_removed *fr,
+                 enum ofp_version version)
+{
+    ovs_be64 duration = 0;
+
+    if (fr) {
+        uint64_t 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)
+{
+    ovs_be64 pkt_count = 0;
+
+    if (fr) {
+        pkt_count = htonll(fr->packet_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)
+{
+    ovs_be64 byte_count = 0;
+
+    if (fr) {
+        byte_count = htonll(fr->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: {
+            ovs_be64 duration;
+
+            memcpy(&duration, payload, sizeof (duration));
+            uint64_t duration_ = ntohll(duration);
+            fr->duration_sec = ((uint32_t) ((duration_ &
+                                            0xFFFFFFFF00000000LL) >> 32));
+            fr->duration_nsec = ((uint32_t) (duration_ & 0xFFFFFFFFLL));
+        }
+        break;
+        case OFPXST_OFB_PACKET_COUNT: {
+            ovs_be64 packet_count;
+
+            memcpy(&packet_count, payload, sizeof (packet_count));
+            fr->packet_count = ntohll(packet_count);
+
+        }
+        break;
+        case OFPXST_OFB_BYTE_COUNT: {
+            ovs_be64 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);
+
+}
diff --git a/lib/ox-stat.h b/lib/ox-stat.h
new file mode 100644
index 0000000..7b14b29
--- /dev/null
+++ b/lib/ox-stat.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OX_STAT_H
+#define OX_STAT_H 1
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include "compiler.h"
+#include "flow.h"
+#include "openvswitch/meta-flow.h"
+#include "openvswitch/ofp-errors.h"
+#include "openvswitch/types.h"
+#include "openvswitch/ofp-flow.h"
+#include "openvswitch/ofp-monitor.h"
+
+struct ox_field {
+    const char *name;
+    uint16_t fl_type;
+};
+
+int oxs_put_stat(struct ofpbuf *, const struct ofputil_flow_stats *,
+                 enum ofp_version, uint8_t );
+int oxs_pull_stat(struct ofpbuf *,struct ofputil_flow_stats *,
+                  uint16_t *,uint8_t *);
+int oxs_put_agg_stat(struct ofpbuf *, const struct ofputil_aggregate_stats *,
+                     enum ofp_version, uint8_t );
+int oxs_pull_agg_stat(struct ofpbuf , struct ofputil_aggregate_stats *);
+int oxs_flow_removed_stat_put(struct ofpbuf *b,
+                              const struct ofputil_flow_removed *fr,
+                              enum ofp_version version);
+int oxs_flow_removed_stat_pull(struct ofpbuf *b,
+                               struct ofputil_flow_removed *ofr);
+void
+oxs_bitmap_set(uint8_t *oxs_field_set, enum  oxs_ofb_stat_fields i);
+void
+oxs_bitmap_set_all(uint8_t *oxs_field_set);
+bool
+oxs_bitmap_is_set(uint8_t oxs_field_set, enum  oxs_ofb_stat_fields i);
+void oxs_put__(struct ofpbuf *, enum oxs_ofb_stat_fields,
+               enum ofp_version, const void *, const void *, size_t);
+bool parse_oxs_key(char **stringp, char **keyp);
+bool parse_oxs_field(const char *name, const struct ox_field **f_out);
+
+
+#endif /* ox_stat.h */
diff --git a/lib/rconn.c b/lib/rconn.c
index 2eebbff..ee139a8 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -1401,6 +1401,8 @@ is_admitted_msg(const struct ofpbuf *b)
     case OFPTYPE_DESC_STATS_REPLY:
     case OFPTYPE_FLOW_STATS_REQUEST:
     case OFPTYPE_FLOW_STATS_REPLY:
+    case OFPTYPE_FLOW_DESC_REQUEST:
+    case OFPTYPE_FLOW_DESC_REPLY:
     case OFPTYPE_AGGREGATE_STATS_REQUEST:
     case OFPTYPE_AGGREGATE_STATS_REPLY:
     case OFPTYPE_TABLE_STATS_REQUEST:
diff --git a/lib/vconn.c b/lib/vconn.c
index aeb2cd7..5ec6396 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -940,7 +940,6 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
     struct ofpbuf *reply = *replyp;
-
     for (;;) {
         int retval;
         bool more;
@@ -958,14 +957,14 @@ recv_flow_stats_reply(struct vconn *vconn, ovs_be32 send_xid,
             } while (((struct ofp_header *) reply->data)->xid != send_xid);
 
             error = ofptype_decode(&type, reply->data);
-            if (error || type != OFPTYPE_FLOW_STATS_REPLY) {
+            if (error || (type != OFPTYPE_FLOW_DESC_REPLY &&
+                          type != OFPTYPE_FLOW_STATS_REPLY)) {
                 VLOG_WARN_RL(&rl, "received bad reply: %s",
                              ofp_to_string(reply->data, reply->size,
                                            NULL, NULL, 1));
                 return EPROTO;
             }
         }
-
         /* Pull an individual flow stats reply out of the message. */
         retval = ofputil_decode_flow_stats_reply(fs, reply, false, ofpacts);
         switch (retval) {
@@ -1004,7 +1003,6 @@ vconn_dump_flows(struct vconn *vconn,
     struct ofputil_flow_stats *fses = NULL;
     size_t n_fses = 0;
     size_t allocated_fses = 0;
-
     struct ofpbuf *request = ofputil_encode_flow_stats_request(fsr, protocol);
     const struct ofp_header *oh = request->data;
     ovs_be32 send_xid = oh->xid;
@@ -1023,6 +1021,7 @@ vconn_dump_flows(struct vconn *vconn,
 
         struct ofputil_flow_stats *fs = &fses[n_fses];
         error = recv_flow_stats_reply(vconn, send_xid, &reply, fs, &ofpacts);
+
         if (error) {
             if (error == EOF) {
                 error = 0;
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index a982de9..9a25d3f 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -4485,7 +4485,6 @@ handle_aggregate_stats_request(struct ofconn *ofconn,
     if (error) {
         return error;
     }
-
     memset(&stats, 0, sizeof stats);
     unknown_packets = unknown_bytes = false;
 
@@ -8116,6 +8115,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
         return handle_desc_stats_request(ofconn, oh);
 
     case OFPTYPE_FLOW_STATS_REQUEST:
+    case OFPTYPE_FLOW_DESC_REQUEST:
         return handle_flow_stats_request(ofconn, oh);
 
     case OFPTYPE_AGGREGATE_STATS_REQUEST:
@@ -8193,6 +8193,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
     case OFPTYPE_DESC_STATS_REPLY:
     case OFPTYPE_FLOW_STATS_REPLY:
+    case OFPTYPE_FLOW_DESC_REPLY:
     case OFPTYPE_QUEUE_STATS_REPLY:
     case OFPTYPE_PORT_STATS_REPLY:
     case OFPTYPE_TABLE_STATS_REPLY:
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index ab7ba26..7e6693d 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -638,6 +638,22 @@ OFPT_FLOW_REMOVED (OF1.3) (xid=0x0): dl_vlan=9 reason=hard table_id=5 cookie:0xf
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_FLOW_REMOVED - OF1.5])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 0b 00 80 00 00 00 02 01 00 00 00 11 00 22 00 \
+00 00 00 00 00 00 00 01 00 01 00 2d 80 00 00 04 \
+00 00 00 02 80 00 06 06 52 54 00 c3 00 89 80 00 \
+0a 02 08 00 80 00 10 01 00 80 00 04 08 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 34 80 02 00 08 \
+00 00 00 98 29 e6 ed c0 80 02 02 08 00 00 00 98 \
+00 00 00 00 80 02 08 08 00 00 00 00 00 00 00 02 \
+80 02 0a 08 00 00 00 00 00 00 00 80 00 00 00 00 \
+"], [0], [dnl
+OFPT_FLOW_REMOVED (OF1.5) (xid=0x2): priority=0,ip,metadata=0,in_port=2,dl_dst=52:54:00:c3:00:89,nw_tos=0 reason=idle table_id=1 cookie:0x1 duration152.703s idle4352 hard8704 pkts2 bytes128
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_PORT_STATUS - OF1.0])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1392,6 +1408,18 @@ OFPST_FLOW request (OF1.3) (xid=0x2):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_FLOW request - OF1.5])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 12 00 38 00 00 00 04 00 11 00 00 00 00 00 00 \
+ff 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 01 00 04 00 00 00 00 \
+"], [0], [dnl
+OFPST_FLOW_DESC request (OF1.5) (xid=0x4):
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_FLOW reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1471,6 +1499,32 @@ OFPST_FLOW reply (OF1.2) (xid=0x2):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_FLOW reply - OF1.5])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 13 01 00 00 00 00 04 00 11 00 00 00 00 00 00 \
+00 78 00 00 00 00 80 00 00 00 00 00 00 05 00 00 \
+00 00 00 00 00 00 00 00 00 01 00 0c 80 00 00 04 \
+00 00 00 02 00 00 00 00 00 00 00 34 80 02 00 08 \
+00 00 00 c4 0b 06 e0 40 80 02 02 08 00 00 00 c4 \
+00 00 00 00 80 02 08 08 00 00 00 00 00 00 00 02 \
+80 02 0a 08 00 00 00 00 00 00 00 80 00 00 00 00 \
+00 04 00 18 00 00 00 00 00 00 00 10 ff ff ff fa \
+00 00 00 00 00 00 00 00 00 78 00 00 00 00 0f a0 \
+00 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 \
+00 01 00 0c 80 00 00 04 00 00 00 03 00 00 00 00 \
+00 00 00 34 80 02 00 08 00 00 00 b3 25 40 be 40 \
+80 02 02 08 00 00 00 b3 00 00 00 00 80 02 08 08 \
+00 00 00 00 00 00 00 02 80 02 0a 08 00 00 00 00 \
+00 00 00 80 00 00 00 00 00 04 00 18 00 00 00 00 \
+00 00 00 10 ff ff ff fa 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_FLOW_DESC reply (OF1.5) (xid=0x4):
+ cookie=0x0, duration=196.185s, table=0, n_packets=2, n_bytes=128, send_flow_rem reset_counts idle_age=196, in_port=2 actions=NORMAL
+ cookie=0x0, duration=179.625s, table=0, n_packets=2, n_bytes=128, send_flow_rem reset_counts idle_age=179, priority=4000,in_port=3 actions=NORMAL
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_AGGREGATE request - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1507,6 +1561,20 @@ OFPST_AGGREGATE request (OF1.3) (xid=0x2):
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_AGGREGATE request - OF1.5])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 12 00 60 00 00 00 04 00 02 00 00 00 00 00 00 \
+ff 00 00 00 ff ff ff ff ff ff ff ff 00 00 00 00 \
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 01 00 04 00 00 00 00 00 00 00 24 80 02 06 04 \
+00 00 00 00 80 02 08 08 00 00 00 00 00 00 00 00 \
+80 02 0a 08 00 00 00 00 00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+OFPST_AGGREGATE request (OF1.5) (xid=0x4):
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_AGGREGATE reply - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
 AT_CHECK([ovs-ofctl ofp-print "\
@@ -1540,6 +1608,18 @@ OFPST_AGGREGATE reply (OF1.3) (xid=0x2): packet_count=121 byte_count=19279 flow_
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPST_AGGREGATE reply - OF1.5])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 13 00 38 00 00 00 04 00 02 00 00 00 00 00 00 \
+00 00 00 24 80 02 06 04 00 00 00 03 80 02 08 08 \
+00 00 00 00 00 00 00 79 80 02 0a 08 00 00 00 00 \
+00 00 4b 4f 00 00 00 00 \
+"], [0], [dnl
+OFPST_AGGREGATE reply (OF1.5) (xid=0x4): packet_count=121 byte_count=19279 flow_count=3
+])
+AT_CLEANUP
+
 AT_SETUP([OFPST_TABLE request - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "0110000c0000000100030000"], [0], [dnl
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 600afdd..3c99e87 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -7265,11 +7265,96 @@ flow_mods_reset_counts () {
 # OpenFlow versions >= 1.3 should behave the same way
 flow_mods_reset_counts 13
 flow_mods_reset_counts 14
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - flow stats reset_counts OpenFlow1.5])
+OVS_VSWITCHD_START
+flow="ip,actions=NORMAL"
+
+ovs-appctl time/stop
+
+AT_CHECK([ovs-ofctl add-flow br0 $flow])
+
+warp_and_dump_OF () {
+    AT_CHECK([ovs-appctl time/warp 1000], [0], [ignore])
+    AT_CHECK([ovs-appctl revalidator/purge], [0])
+
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 dump-flows br0 ], [0], [stdout])
+    if [[ "$6X" = "X" ]]; then
+        expected=" cookie=0x0, duration=$2s, table=0, n_packets=$3, n_bytes=$4, idle_age=$5, ip actions=NORMAL"
+    else
+        expected=" cookie=0x0, duration=$2s, table=0, n_packets=$3, n_bytes=$4, $6 idle_age=$5, ip actions=NORMAL"
+    fi
+     AT_CHECK_UNQUOTED([strip_xids < stdout | sed -n 's/duration=\([[0-9]]*\)\.*[[0-9]]*s/duration=\1s/p' | sort], [0], [dnl
+$expected
+])
+}
+
+send_packet () {
+    ovs-appctl netdev-dummy/receive br0 'in_port(0),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no)'
+}
+
+# OpenFlow 1.5, explicit reset_counts
+flow_mods_reset_counts () {
+    # Reset to a known state
+    AT_CHECK([ovs-ofctl add-flow br0 $flow])
+
+    send_packet
+    warp_and_dump_OF $1 1 1 118 1 reset_counts
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 add-flow br0 $flow])
+    # add-flow without flags resets duration, but not counts,
+    # idle age is inherited from the old flow
+    warp_and_dump_OF $1 1 1 118 2
+
+    send_packet
+    warp_and_dump_OF $1 2 2 236 1
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 mod-flows br0 $flow])
+    # mod-flows without flags does not reset duration nor counts,
+    # idle age is inherited from the old flow
+    warp_and_dump_OF $1 3 2 236 2
+
+    send_packet
+    warp_and_dump_OF $1 4 3 354 1
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 add-flow br0 reset_counts,$flow])
+    # add-flow with reset_counts resets both duration and counts,
+    # idle age is inherited from the old flow
+    warp_and_dump_OF $1 1 0 0 2 reset_counts
+
+    send_packet
+    warp_and_dump_OF $1 2 1 118 1 reset_counts
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 mod-flows br0 reset_counts,$flow])
+    # mod-flows with reset_counts resets counts, but not duration,
+    # idle age is inherited from the old flow
+    warp_and_dump_OF $1 3 0 0 2 reset_counts
+
+    # Modify flow having reset_counts flag without reset_counts
+    send_packet
+    warp_and_dump_OF $1 4 1 118 1 reset_counts
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 mod-flows br0 $flow])
+    warp_and_dump_OF $1 5 1 118 2 reset_counts
+
+    # Add flow having reset_counts flag without reset_counts
+    send_packet
+    warp_and_dump_OF $1 6 2 236 1 reset_counts
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 add-flow br0 $flow])
+    warp_and_dump_OF $1 1 2 236 2
+
+    # Modify flow w/o reset_counts flag with a flow_mod having reset_counts
+    send_packet
+    warp_and_dump_OF $1 2 3 354 1
+    AT_CHECK_UNQUOTED([ovs-ofctl -O OpenFlow$1 mod-flows br0 reset_counts,$flow])
+    warp_and_dump_OF $1 3 0 0 2
+}
+
+# OpenFlow versions >= 1.3 should behave the same way
 flow_mods_reset_counts 15
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+
 AT_SETUP([ofproto-dpif - flow stats, set-n-threads])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl add-flow br0 "ip,actions=NORMAL"])
diff --git a/tests/ofproto.at b/tests/ofproto.at
index c1beea7..6dc57f2 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -1402,8 +1402,9 @@ AT_CHECK([ovs-ofctl -O OpenFlow14 dump-flows br0 | ofctl_strip], [0], [dnl
 OFPST_FLOW reply (OF1.4):
  check_overlap reset_counts in_port=1 actions=drop
 ])
+# OF1.5 makes the flags invisible.
 AT_CHECK([ovs-ofctl -O OpenFlow15 dump-flows br0 | ofctl_strip], [0], [dnl
-OFPST_FLOW reply (OF1.5):
+OFPST_FLOW_DESC reply (OF1.5):
  check_overlap reset_counts in_port=1 actions=drop
 ])
 OVS_VSWITCHD_STOP
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 7649bc5..8b99d21 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -227,8 +227,8 @@ By default, \fBovs\-ofctl\fR prints flow entries in the same order
 that the switch sends them, which is unlikely to be intuitive or
 consistent.  Use \fB\-\-sort\fR and \fB\-\-rsort\fR to control display
 order.  The \fB\-\-names\fR/\fB\-\-no\-names\fR and
-\fB\-\-stats\fR/\fB\-\-no\-stats\fR options also affect output
-formatting.  See the descriptions of these options, under
+\fB\-\-stats\fR/\fB\-\-no\-stats\fR \fB\-\-oxs\-stats\fR options also affect
+output formatting.  See the descriptions of these options, under
 \fBOPTIONS\fR below, for more information
 .
 .TP
@@ -2358,6 +2358,33 @@ Bundles require OpenFlow 1.4 or higher.  An explicit \fB-O
 OpenFlow14\fR option is not needed, but you may need to enable
 OpenFlow 1.4 support for OVS by setting the OVSDB \fIprotocols\fR
 column in the \fIbridge\fR table.
+.
+.RE
+.RE
+.IP "\fB\-\-oxs-stats\fR"
+From OpenFlow1.5, the flow stat fields are described using the OpenFlow
+Extensible Stat (OXS) format, which is a compact type-length-value (TLV)
+format. Some \fBovs\-ofctl\fR commands accept an argument that describes  oxs-
+field or oxs-fields. Such oxs-fields comprise a series of fields,
+separated by commas or white space.  (Embedding  spaces  into  a flow
+description normally  requires quoting to prevent the shell from breaking
+the description into multiple arguments.)
+.PP
+The oxs-fields comprises of 5 fields and oxs-field value is only
+displayed in the flow table output only when the corresponding oxs-field
+is passed as an argument.
+.RS
+.IP \fBduration\fR
+Displays the entire duration of the flow in the output.
+.IP \fBidle_time\fR
+Displays the time that flow entry has been idle in the output.
+.IP \fBpacket_count\fR
+Displays the total packet-count of the flow in the output.
+.IP \fBbyte_count\fR
+Displays the total packet-count of the flow in the output.
+.IP \fBflow_count\fR
+Displays the total flow count in the output.
+.RE
 .RE
 .
 .so lib/ofp-version.man
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 386e4f0..ec1099c 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -75,6 +75,7 @@
 #include "timeval.h"
 #include "unixctl.h"
 #include "util.h"
+#include "ox-stat.h"
 
 VLOG_DEFINE_THIS_MODULE(ofctl);
 
@@ -150,6 +151,10 @@ static bool should_show_names(void);
 /* --stats, --no-stats: Show statistics in flow dumps? */
 static int show_stats = 1;
 
+/* --oxs-stats: Show only requested OXS-fields in the flow dump */
+static bool oxs = 1;
+static uint8_t oxs_field_set = 0;
+
 /* --pcap: Makes "compose-packet" print a pcap on stdout. */
 static int print_pcap = 0;
 
@@ -182,6 +187,25 @@ main(int argc, char *argv[])
 }
 
 static void
+set_oxs_bitmap(char *field)
+{
+
+    char *keyp;
+    char *fieldp;
+    fieldp = field;
+
+    while (parse_oxs_key(&fieldp, &keyp)) {
+        const struct ox_field *oxfs;
+
+        if (parse_oxs_field(keyp, &oxfs)) {
+             oxs_bitmap_set(&oxs_field_set,oxfs->fl_type);
+        } else {
+           ovs_fatal(0, "%s:unknown oxs field", keyp);
+        }
+    }
+}
+
+static void
 add_sort_criterion(enum sort_order order, const char *field)
 {
     struct sort_criterion *sc;
@@ -215,6 +239,7 @@ parse_options(int argc, char *argv[])
         OPT_BUNDLE,
         OPT_COLOR,
         OPT_MAY_CREATE,
+        OPT_OXS_STATS,
         OPT_READ_ONLY,
         DAEMON_OPTION_ENUMS,
         OFP_VERSION_OPTION_ENUMS,
@@ -235,6 +260,7 @@ parse_options(int argc, char *argv[])
         {"no-names", no_argument, &use_names, 0},
         {"stats", no_argument, &show_stats, 1},
         {"no-stats", no_argument, &show_stats, 0},
+        {"oxs-stats", required_argument, NULL, OPT_OXS_STATS},
         {"unixctl",     required_argument, NULL, OPT_UNIXCTL},
         {"help", no_argument, NULL, 'h'},
         {"option", no_argument, NULL, 'o'},
@@ -377,6 +403,11 @@ parse_options(int argc, char *argv[])
             may_create = true;
             break;
 
+        case OPT_OXS_STATS:
+            oxs = 0;
+            set_oxs_bitmap(optarg);
+            break;
+
         DAEMON_OPTION_HANDLERS
         OFP_VERSION_OPTION_HANDLERS
         VLOG_OPTION_HANDLERS
@@ -425,7 +456,20 @@ parse_options(int argc, char *argv[])
     allowed_protocols &= version_protocols;
     mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
                                   allowed_protocols));
-
+   /* Openflow 1.5 should also be given explicitly with --oxs-stats option */
+    if (!oxs) {
+        enum ofputil_protocol oxs_allowed_protocols = OFPUTIL_P_OF15_UP;
+        if (!(oxs_allowed_protocols & version_protocols)) {
+            char *protocols =
+            ofputil_protocols_to_string(oxs_allowed_protocols);
+            struct ds version_s = DS_EMPTY_INITIALIZER;
+
+            ofputil_format_version_bitmap_names(&version_s, versions);
+            ovs_fatal(0, "None of the enabled OpenFlow versions (%s) supports "
+                  "oxs (%s).(Use -O to enable additional OpenFlow versions)",
+                   ds_cstr(&version_s), protocols);
+        }
+    }
     colors_init(enable_color);
 }
 
@@ -693,6 +737,50 @@ dump_transaction(struct vconn *vconn, struct ofpbuf *request)
 }
 
 static void
+dump_agg_transaction(struct vconn *vconn, struct ofpbuf *request,
+                     struct ofputil_aggregate_stats *stats)
+{
+    const struct ofp_header *oh = request->data;
+    if (ofpmsg_is_stat_request(oh)) {
+        ovs_be32 send_xid = oh->xid;
+        enum ofpraw request_raw;
+        bool done = false;
+
+        ofpraw_decode_partial(&request_raw, request->data, request->size);
+        ofpraw_stats_request_to_reply(request_raw, oh->version);
+        send_openflow_buffer(vconn, request);
+
+        while (!done) {
+            ovs_be32 recv_xid;
+            struct ofpbuf *reply;
+
+            run(vconn_recv_block(vconn, &reply),
+                "OpenFlow packet receive failed");
+            recv_xid = ((struct ofp_header *) reply->data)->xid;
+            if (send_xid == recv_xid) {
+
+                ofputil_decode_aggregate_stats_reply(stats, reply->data);
+                done = true;
+            } else {
+                VLOG_DBG("received reply with xid %08"PRIx32" "
+                         "!= expected %08"PRIx32, recv_xid, send_xid);
+            }
+            ofpbuf_delete(reply);
+        }
+    } else {
+        struct ofpbuf *reply;
+
+        run(vconn_transact(vconn, request, &reply), "talking to %s",
+            vconn_get_name(vconn));
+        ofp_print(stdout, reply->data, reply->size,
+                  ports_to_show(vconn_get_name(vconn)),
+                  tables_to_show(vconn_get_name(vconn)),
+                  verbosity + 1);
+        ofpbuf_delete(reply);
+    }
+}
+
+static void
 dump_trivial_transaction(const char *vconn_name, enum ofpraw raw)
 {
     struct ofpbuf *request;
@@ -1475,7 +1563,6 @@ ofctl_dump_flows__(int argc, char *argv[], bool aggregate)
     struct ofputil_flow_stats_request fsr;
     enum ofputil_protocol protocol;
     struct vconn *vconn;
-
     vconn = prepare_dump_flows(argc, argv, aggregate, &fsr, &protocol);
     dump_transaction(vconn, ofputil_encode_flow_stats_request(&fsr, protocol));
     vconn_close(vconn);
@@ -1550,7 +1637,7 @@ compare_flows(const void *afs_, const void *bfs_)
 static void
 ofctl_dump_flows(struct ovs_cmdl_context *ctx)
 {
-    if (!n_criteria && !should_show_names() && show_stats) {
+    if (!n_criteria && !should_show_names() && show_stats && oxs) {
         ofctl_dump_flows__(ctx->argc, ctx->argv, false);
         return;
     } else {
@@ -1571,8 +1658,12 @@ ofctl_dump_flows(struct ovs_cmdl_context *ctx)
         struct ds s = DS_EMPTY_INITIALIZER;
         for (size_t i = 0; i < n_fses; i++) {
             ds_clear(&s);
-            ofp_print_flow_stats(&s, &fses[i], ports_to_show(ctx->argv[1]),
-                                 tables_to_show(ctx->argv[1]), show_stats);
+            if (!oxs) {
+                ofp_print_flow_oxs_stats(&s, &fses[i], oxs, oxs_field_set);
+            } else {
+                ofp_print_flow_stats(&s, &fses[i], ports_to_show(ctx->argv[1]),
+                                     tables_to_show(ctx->argv[1]), show_stats);
+            }
             printf(" %s\n", ds_cstr(&s));
         }
         ds_destroy(&s);
@@ -1589,7 +1680,27 @@ ofctl_dump_flows(struct ovs_cmdl_context *ctx)
 static void
 ofctl_dump_aggregate(struct ovs_cmdl_context *ctx)
 {
-    ofctl_dump_flows__(ctx->argc, ctx->argv, true);
+    if (oxs) {
+        ofctl_dump_flows__(ctx->argc, ctx->argv, true);
+    } else {
+        struct ofputil_aggregate_stats stats;
+        struct ofputil_flow_stats_request fsr;
+        enum ofputil_protocol protocol;
+        struct vconn *vconn;
+
+        vconn = prepare_dump_flows(ctx->argc, ctx->argv, true,
+                                   &fsr, &protocol);
+        dump_agg_transaction(vconn,
+                             ofputil_encode_flow_stats_request(&fsr,
+                             protocol), &stats);
+        struct ds s = DS_EMPTY_INITIALIZER;
+        ds_clear(&s);
+        ofp_print_flow_oxs_agg_stats(&s, stats, oxs, oxs_field_set);
+        printf(" %s\n", ds_cstr(&s));
+        ds_destroy(&s);
+
+        vconn_close(vconn);
+    }
 }
 
 static void
