diff --git a/NEWS b/NEWS
index ba201cf..08094c5 100644
--- a/NEWS
+++ b/NEWS
@@ -19,6 +19,8 @@ Post-v2.5.0
      * queue-get-config command now allows a queue ID to be specified.
      * '--bundle' option can now be used with OpenFlow 1.3.
      * New option "--color" to produce colorized output for some commands.
+     * New commands "dump-ipfix-bridge" and "dump-ipfix-flow" to dump bridge
+       IPFIX statistics and flow based IPFIX statistics.
    - DPDK:
      * New option "n_rxq" for PMD interfaces.
        Old 'other_config:n-dpdk-rxqs' is no longer supported.
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 8950335..4a792e8 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -774,6 +774,23 @@ struct nx_aggregate_stats_request {
      */
 };
 OFP_ASSERT(sizeof(struct nx_aggregate_stats_request) == 8);
+
+struct nx_ipfix_stats_reply {
+    ovs_be64 total_flows;
+    ovs_be64 current_flows;
+    ovs_be64 pkts;
+    ovs_be64 ipv4_pkts;
+    ovs_be64 ipv6_pkts;
+    ovs_be64 error_pkts;
+    ovs_be64 ipv4_error_pkts;
+    ovs_be64 ipv6_error_pkts;
+    ovs_be64 tx_pkts;
+    ovs_be64 tx_errors;
+    ovs_be32 collector_set_id; /* Range 0 to 4,294,967,295. */
+    uint8_t pad[4];            /* Pad to a multiple of 8. */
+};
+OFP_ASSERT(sizeof(struct nx_ipfix_stats_reply) == 88);
+
 
 /* NXT_SET_CONTROLLER_ID.
  *
diff --git a/include/openvswitch/ofp-errors.h b/include/openvswitch/ofp-errors.h
index f963d2b..a378909 100644
--- a/include/openvswitch/ofp-errors.h
+++ b/include/openvswitch/ofp-errors.h
@@ -781,6 +781,14 @@ enum ofperr {
      * continuation was generated, or continuation was not generated by this
      * Open vSwitch instance. */
     OFPERR_NXR_STALE,
+
+/* ## ---------- ## */
+/* ## NXT_STATS  ## */
+/* ## ---------- ## */
+
+    /* NX1.0-1.1(1,535), NX1.2+(36).  Protocol is not configured on this
+     * Open vSwitch instance. */
+    OFPERR_NXST_NOT_CONFIGURED,
 };
 
 const char *ofperr_domain_get_name(enum ofp_version);
diff --git a/include/openvswitch/ofp-msgs.h b/include/openvswitch/ofp-msgs.h
index 560cbe0..8dab858 100644
--- a/include/openvswitch/ofp-msgs.h
+++ b/include/openvswitch/ofp-msgs.h
@@ -467,6 +467,18 @@ enum ofpraw {
 
     /* NXT 1.0+ (28): uint8_t[8][]. */
     OFPRAW_NXT_RESUME,
+
+    /* NXST 1.0+ (3): void. */
+    OFPRAW_NXST_IPFIX_BRIDGE_REQUEST,
+
+    /* NXST 1.0+ (3): struct nx_ipfix_stats_reply. */
+    OFPRAW_NXST_IPFIX_BRIDGE_REPLY,
+
+    /* NXST 1.0+ (4): void. */
+    OFPRAW_NXST_IPFIX_FLOW_REQUEST,
+
+    /* NXST 1.0+ (4): struct nx_ipfix_stats_reply[]. */
+    OFPRAW_NXST_IPFIX_FLOW_REPLY,
 };
 
 /* Decoding messages into OFPRAW_* values. */
@@ -691,6 +703,10 @@ enum ofptype {
     OFPTYPE_NXT_TLV_TABLE_REQUEST, /* OFPRAW_NXT_TLV_TABLE_REQUEST. */
     OFPTYPE_NXT_TLV_TABLE_REPLY, /* OFPRAW_NXT_TLV_TABLE_REPLY. */
     OFPTYPE_NXT_RESUME,          /* OFPRAW_NXT_RESUME. */
+    OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST, /* OFPRAW_NXST_IPFIX_BRIDGE_REQUEST */
+    OFPTYPE_IPFIX_BRIDGE_STATS_REPLY, /* OFPRAW_NXST_IPFIX_BRIDGE_REPLY */
+    OFPTYPE_IPFIX_FLOW_STATS_REQUEST, /* OFPRAW_NXST_IPFIX_FLOW_REQUEST */
+    OFPTYPE_IPFIX_FLOW_STATS_REPLY,   /* OFPRAW_NXST_IPFIX_FLOW_REPLY */
 
     /* Flow monitor extension. */
     OFPTYPE_FLOW_MONITOR_CANCEL,        /* OFPRAW_NXT_FLOW_MONITOR_CANCEL. */
diff --git a/include/openvswitch/ofp-util.h b/include/openvswitch/ofp-util.h
index 854482b..7a5c905 100644
--- a/include/openvswitch/ofp-util.h
+++ b/include/openvswitch/ofp-util.h
@@ -1139,6 +1139,25 @@ int ofputil_decode_port_stats(struct ofputil_port_stats *, struct ofpbuf *msg);
 enum ofperr ofputil_decode_port_stats_request(const struct ofp_header *request,
                                               ofp_port_t *ofp10_port);
 
+struct ofputil_ipfix_stats {
+    uint32_t collector_set_id;  /* Used only for flow-based IPFIX statistics. */
+    uint64_t total_flows;  /* Totabl flows of this IPFIX exporter. */
+    uint64_t current_flows;  /* Current flows of this IPFIX exporter. */
+    uint64_t pkts;  /* Successfully sampled packets. */
+    uint64_t ipv4_pkts;  /* Successfully sampled IPV4 packets. */
+    uint64_t ipv6_pkts;  /* Successfully sampled IPV6 packets. */
+    uint64_t error_pkts;  /* Error packets when sampling. */
+    uint64_t ipv4_error_pkts;  /* Error IPV4 packets when sampling. */
+    uint64_t ipv6_error_pkts;  /* Error IPV6 packets when sampling. */
+    uint64_t tx_pkts;  /* TX IPFIX packets. */
+    uint64_t tx_errors;  /* IPFIX packets TX errors. */
+};
+
+void ofputil_append_ipfix_stat(struct ovs_list *replies,
+                              const struct ofputil_ipfix_stats *ois);
+size_t ofputil_count_ipfix_stats(const struct ofp_header *);
+int ofputil_pull_ipfix_stats(struct ofputil_ipfix_stats *, struct ofpbuf *msg);
+
 struct ofputil_queue_stats_request {
     ofp_port_t port_no;           /* OFPP_ANY means "all ports". */
     uint32_t queue_id;
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 5e49c60..5747ec6 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -3240,6 +3240,88 @@ ofp_print_requestforward(struct ds *string, const struct ofp_header *oh)
 }
 
 static void
+print_ipfix_stat(struct ds *string, const char *leader, uint64_t stat, int more)
+{
+    ds_put_cstr(string, leader);
+    if (stat != UINT64_MAX) {
+        ds_put_format(string, "%"PRIu64, stat);
+    } else {
+        ds_put_char(string, '?');
+    }
+    if (more) {
+        ds_put_cstr(string, ", ");
+    } else {
+        ds_put_cstr(string, "\n");
+    }
+}
+
+static void
+ofp_print_nxst_ipfix_bridge_reply(struct ds *string, const struct ofp_header *oh)
+{
+    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
+    for (;;) {
+        struct ofputil_ipfix_stats is;
+        int retval;
+
+        retval = ofputil_pull_ipfix_stats(&is, &b);
+        if (retval) {
+            if (retval != EOF) {
+                ds_put_cstr(string, " ***parse error***");
+            }
+            return;
+        }
+
+        ds_put_cstr(string, "\n  bridge ipfix: ");
+        print_ipfix_stat(string, "flows=", is.total_flows, 1);
+        print_ipfix_stat(string, "current flows=", is.current_flows, 1);
+        print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
+        print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
+        print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
+        print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
+        ds_put_cstr(string, "                ");
+        print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
+        print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
+        print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
+        print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
+    }
+}
+
+static void
+ofp_print_nxst_ipfix_flow_reply(struct ds *string, const struct ofp_header *oh)
+{
+    ds_put_format(string, " %"PRIuSIZE" ids\n", ofputil_count_ipfix_stats(oh));
+
+    struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
+    for (;;) {
+        struct ofputil_ipfix_stats is;
+        int retval;
+
+        retval = ofputil_pull_ipfix_stats(&is, &b);
+        if (retval) {
+            if (retval != EOF) {
+                ds_put_cstr(string, " ***parse error***");
+            }
+            return;
+        }
+
+        ds_put_cstr(string, "  id");
+        ds_put_format(string, " %3"PRIuSIZE": ", (size_t) is.collector_set_id);
+        print_ipfix_stat(string, "flows=", is.total_flows, 1);
+        print_ipfix_stat(string, "current flows=", is.current_flows, 1);
+        print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
+        print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
+        print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
+        print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
+        ds_put_cstr(string, "          ");
+        print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
+        print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
+        print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
+        print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
+    }
+}
+
+
+static void
 ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
                 struct ds *string, int verbosity)
 {
@@ -3529,6 +3611,16 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
     case OFPTYPE_NXT_RESUME:
         ofp_print_packet_in(string, msg, verbosity);
         break;
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
+        break;
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
+        ofp_print_nxst_ipfix_bridge_reply(string, oh);
+        break;
+    case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
+        break;
+    case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
+        ofp_print_nxst_ipfix_flow_reply(string, oh);
+        break;
     }
 }
 
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 2c6fb1f..0fbf22f 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -7944,6 +7944,92 @@ ofputil_decode_port_stats_request(const struct ofp_header *request,
     }
 }
 
+static void
+ofputil_ipfix_stats_to_reply(const struct ofputil_ipfix_stats *ois,
+                            struct nx_ipfix_stats_reply *reply)
+{
+    reply->collector_set_id = htonl(ois->collector_set_id);
+    reply->total_flows = htonll(ois->total_flows);
+    reply->current_flows = htonll(ois->current_flows);
+    reply->pkts = htonll(ois->pkts);
+    reply->ipv4_pkts = htonll(ois->ipv4_pkts);
+    reply->ipv6_pkts = htonll(ois->ipv6_pkts);
+    reply->error_pkts = htonll(ois->error_pkts);
+    reply->ipv4_error_pkts = htonll(ois->ipv4_error_pkts);
+    reply->ipv6_error_pkts = htonll(ois->ipv6_error_pkts);
+    reply->tx_pkts = htonll(ois->tx_pkts);
+    reply->tx_errors = htonll(ois->tx_errors);
+}
+
+/* Encode a ipfix stat for 'ois' and append it to 'replies'. */
+void
+ofputil_append_ipfix_stat(struct ovs_list *replies,
+                         const struct ofputil_ipfix_stats *ois)
+{
+    struct nx_ipfix_stats_reply *reply = ofpmp_append(replies, sizeof *reply);
+    ofputil_ipfix_stats_to_reply(ois, reply);
+}
+
+static enum ofperr
+ofputil_ipfix_stats_from_nx(struct ofputil_ipfix_stats *is,
+                            const struct nx_ipfix_stats_reply *reply)
+{
+    is->collector_set_id = ntohl(reply->collector_set_id);
+    is->total_flows = ntohll(reply->total_flows);
+    is->current_flows = ntohll(reply->current_flows);
+    is->pkts = ntohll(reply->pkts);
+    is->ipv4_pkts = ntohll(reply->ipv4_pkts);
+    is->ipv6_pkts = ntohll(reply->ipv6_pkts);
+    is->error_pkts = ntohll(reply->error_pkts);
+    is->ipv4_error_pkts = ntohll(reply->ipv4_error_pkts);
+    is->ipv6_error_pkts = ntohll(reply->ipv6_error_pkts);
+    is->tx_pkts = ntohll(reply->tx_pkts);
+    is->tx_errors = ntohll(reply->tx_errors);
+
+    return 0;
+}
+
+int
+ofputil_pull_ipfix_stats(struct ofputil_ipfix_stats *is, struct ofpbuf *msg)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    memset(is, 0xFF, sizeof (*is));
+
+    error = (msg->header ? ofpraw_decode(&raw, msg->header)
+             : ofpraw_pull(&raw, msg));
+    if (error) {
+        return error;
+    }
+
+    if (!msg->size) {
+        return EOF;
+    } else if (raw == OFPRAW_NXST_IPFIX_BRIDGE_REPLY ||
+               raw == OFPRAW_NXST_IPFIX_FLOW_REPLY) {
+        struct nx_ipfix_stats_reply *reply;
+
+        reply = ofpbuf_try_pull(msg, sizeof *reply);
+        return ofputil_ipfix_stats_from_nx(is, reply);
+    } else {
+        OVS_NOT_REACHED();
+    }
+}
+
+
+/* Returns the number of ipfix stats elements in
+ * OFPTYPE_IPFIX_BRIDGE_STATS_REPLY or OFPTYPE_IPFIX_FLOW_STATS_REPLY
+ * message 'oh'. */
+size_t
+ofputil_count_ipfix_stats(const struct ofp_header *oh)
+{
+    uint16_t len = ntohs(oh->length);
+    struct ofpbuf b = ofpbuf_const_initializer(oh, len);
+    ofpraw_pull_assert(&b);
+
+    return  (len - sizeof(*oh)) / sizeof(struct ofputil_ipfix_stats);
+}
+
 /* Frees all of the "struct ofputil_bucket"s in the 'buckets' list. */
 void
 ofputil_bucket_list_destroy(struct ovs_list *buckets)
@@ -9828,6 +9914,10 @@ ofputil_is_bundlable(enum ofptype type)
     case OFPTYPE_NXT_TLV_TABLE_REQUEST:
     case OFPTYPE_NXT_TLV_TABLE_REPLY:
     case OFPTYPE_NXT_RESUME:
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
+    case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
+    case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
         break;
     }
 
diff --git a/lib/rconn.c b/lib/rconn.c
index 8482d47..51e1b1b 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -1426,6 +1426,10 @@ is_admitted_msg(const struct ofpbuf *b)
     case OFPTYPE_NXT_TLV_TABLE_REQUEST:
     case OFPTYPE_NXT_TLV_TABLE_REPLY:
     case OFPTYPE_NXT_RESUME:
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
+    case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
+    case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
     default:
         return true;
     }
diff --git a/ofproto/collectors.c b/ofproto/collectors.c
index 5b29212..74d511d 100644
--- a/ofproto/collectors.c
+++ b/ofproto/collectors.c
@@ -102,10 +102,13 @@ collectors_destroy(struct collectors *c)
     }
 }
 
-/* Sends the 'n'-byte 'payload' to each of the collectors in 'c'. */
-void
+/* Sends the 'n'-byte 'payload' to each of the collectors in 'c'.
+ * Return the number of IPFIX packets which were sent unsuccessfully*/
+size_t
 collectors_send(const struct collectors *c, const void *payload, size_t n)
 {
+    uint16_t errors = 0;
+
     if (c) {
         size_t i;
 
@@ -116,9 +119,12 @@ collectors_send(const struct collectors *c, const void *payload, size_t n)
                 VLOG_WARN_RL(&rl, "%s: sending to collector failed (%s)",
                              s, ovs_strerror(errno));
                 free(s);
+                errors++;
             }
         }
     }
+
+    return errors;
 }
 
 int
diff --git a/ofproto/collectors.h b/ofproto/collectors.h
index 6529b8d..1e4e961 100644
--- a/ofproto/collectors.h
+++ b/ofproto/collectors.h
@@ -27,7 +27,7 @@ int collectors_create(const struct sset *targets, uint16_t default_port,
                       struct collectors **);
 void collectors_destroy(struct collectors *);
 
-void collectors_send(const struct collectors *, const void *, size_t);
+size_t collectors_send(const struct collectors *, const void *, size_t);
 
 int collectors_count(const struct collectors *);
 
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 79ba234..eec71d7 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -33,7 +33,6 @@
 #include "sset.h"
 #include "util.h"
 #include "timeval.h"
-#include "util.h"
 #include "openvswitch/vlog.h"
 
 VLOG_DEFINE_THIS_MODULE(ipfix);
@@ -48,6 +47,15 @@ static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
 #define BFD_CONTROL_DEST_PORT        3784
 #define BFD_ECHO_DEST_PORT           3785
 
+enum ipfix_sampled_packet_type {
+    IPFIX_SAMPLED_PKT_UNKNOWN = 0x00,
+    IPFIX_SAMPLED_PKT_IPV4_OK = 0x01,
+    IPFIX_SAMPLED_PKT_IPV6_OK = 0x02,
+    IPFIX_SAMPLED_PKT_IPV4_ERROR = 0x03,
+    IPFIX_SAMPLED_PKT_IPV6_ERROR = 0x04,
+    IPFIX_SAMPLED_PKT_OTHERS = 0x05
+};
+
 /* The standard layer2SegmentId (ID 351) element is included in vDS to send
  * the VxLAN tunnel's VNI. It is 64-bit long, the most significant byte is
  * used to indicate the type of tunnel (0x01 = VxLAN, 0x02 = GRE) and the three
@@ -75,6 +83,8 @@ enum dpif_ipfix_tunnel_type {
     NUM_DPIF_IPFIX_TUNNEL
 };
 
+typedef struct ofputil_ipfix_stats ofproto_ipfix_stats;
+
 struct dpif_ipfix_port {
     struct hmap_node hmap_node; /* In struct dpif_ipfix's "tunnel_ports" hmap. */
     struct ofport *ofport;      /* To retrieve port stats. */
@@ -91,6 +101,8 @@ struct dpif_ipfix_exporter {
     struct ovs_list cache_flow_start_timestamp_list;  /* ipfix_flow_cache_entry. */
     uint32_t cache_active_timeout;  /* In seconds. */
     uint32_t cache_max_flows;
+
+    ofproto_ipfix_stats stats;
 };
 
 struct dpif_ipfix_bridge_exporter {
@@ -984,17 +996,21 @@ ipfix_init_header(uint32_t export_time_sec, uint32_t seq_number,
     hdr->obs_domain_id = htonl(obs_domain_id);
 }
 
-static void
+static size_t
 ipfix_send_msg(const struct collectors *collectors, struct dp_packet *msg)
 {
     struct ipfix_header *hdr;
+    size_t tx_errors;
 
     /* Adjust the length in the header. */
     hdr = dp_packet_data(msg);
     hdr->length = htons(dp_packet_size(msg));
 
-    collectors_send(collectors, dp_packet_data(msg), dp_packet_size(msg));
+    tx_errors = collectors_send(collectors,
+                                dp_packet_data(msg), dp_packet_size(msg));
     dp_packet_set_size(msg, 0);
+
+    return tx_errors;
 }
 
 static uint16_t
@@ -1150,20 +1166,23 @@ ipfix_init_template_msg(void *msg_stub, uint32_t export_time_sec,
     set_hdr->set_id = htons(IPFIX_SET_ID_TEMPLATE);
 }
 
-static void
+static size_t
 ipfix_send_template_msg(const struct collectors *collectors,
                         struct dp_packet *msg, size_t set_hdr_offset)
 {
     struct ipfix_set_header *set_hdr;
+    size_t tx_errors;
 
     /* Send template message. */
     set_hdr = (struct ipfix_set_header*)
               ((uint8_t*)dp_packet_data(msg) + set_hdr_offset);
     set_hdr->length = htons(dp_packet_size(msg) - set_hdr_offset);
 
-    ipfix_send_msg(collectors, msg);
+    tx_errors = ipfix_send_msg(collectors, msg);
 
     dp_packet_uninit(msg);
+
+    return tx_errors;
 }
 
 static void
@@ -1172,9 +1191,11 @@ ipfix_send_template_msgs(struct dpif_ipfix_exporter *exporter,
 {
     uint64_t msg_stub[DIV_ROUND_UP(MAX_MESSAGE_LEN, 8)];
     struct dp_packet msg;
-    size_t set_hdr_offset, tmpl_hdr_offset;
+    size_t set_hdr_offset, tmpl_hdr_offset, error_pkts;
     struct ipfix_template_record_header *tmpl_hdr;
     uint16_t field_count;
+    size_t tx_packets = 0;
+    size_t tx_errors = 0;
     enum ipfix_proto_l2 l2;
     enum ipfix_proto_l3 l3;
     enum ipfix_proto_l4 l4;
@@ -1199,8 +1220,10 @@ ipfix_send_template_msgs(struct dpif_ipfix_exporter *exporter,
                      */
                     if (dp_packet_size(&msg) >= MAX_MESSAGE_LEN) {
                         /* Send template message. */
-                        ipfix_send_template_msg(exporter->collectors,
-                                                &msg, set_hdr_offset);
+                        error_pkts = ipfix_send_template_msg(exporter->collectors,
+                                                             &msg, set_hdr_offset);
+                        tx_errors += error_pkts;
+                        tx_packets += collectors_count(exporter->collectors) - error_pkts;
 
                         /* Reinitialize the template msg. */
                         ipfix_init_template_msg(msg_stub, export_time_sec,
@@ -1224,7 +1247,12 @@ ipfix_send_template_msgs(struct dpif_ipfix_exporter *exporter,
     }
 
     /* Send template message. */
-    ipfix_send_template_msg(exporter->collectors, &msg, set_hdr_offset);
+    error_pkts = ipfix_send_template_msg(exporter->collectors, &msg, set_hdr_offset);
+    tx_errors += error_pkts;
+    tx_packets += collectors_count(exporter->collectors) - error_pkts;
+
+    exporter->stats.tx_pkts += tx_packets;
+    exporter->stats.tx_errors += tx_errors;
 
     /* XXX: Add Options Template Sets, at least to define a Flow Keys
      * Option Template. */
@@ -1326,14 +1354,117 @@ ipfix_cache_aggregate_entries(struct ipfix_flow_cache_entry *from_entry,
     }
 }
 
+/* Get statistics */
+static void
+ipfix_get_stats__(const struct dpif_ipfix_exporter *exporter,
+                  ofproto_ipfix_stats *stats)
+{
+    memset(stats, 0xFF, sizeof *stats);
+
+    if (!exporter) {
+        return;
+    }
+
+    *stats=exporter->stats;
+}
+
+static void
+ipfix_get_bridge_stats(const struct dpif_ipfix_bridge_exporter *exporter,
+                       ofproto_ipfix_stats *stats)
+{
+    ipfix_get_stats__(&exporter->exporter, stats);
+}
+
+static void
+ipfix_get_flow_stats(const struct dpif_ipfix_flow_exporter *exporter,
+                     ofproto_ipfix_stats *stats)
+{
+    ipfix_get_stats__(&exporter->exporter, stats);
+    stats->collector_set_id = exporter->options->collector_set_id;
+}
+
+int
+dpif_ipfix_get_stats(const struct dpif_ipfix *di,
+                     bool bridge_ipfix,
+                     struct ovs_list *replies)
+    OVS_EXCLUDED(mutex)
+{
+    struct dpif_ipfix_flow_exporter_map_node *flow_exporter_node;
+    struct ofputil_ipfix_stats ois;
+
+    ovs_mutex_lock(&mutex);
+    if (bridge_ipfix) {
+        if (!di->bridge_exporter.options) {
+            ovs_mutex_unlock(&mutex);
+            return OFPERR_NXST_NOT_CONFIGURED;
+        }
+
+        ipfix_get_bridge_stats(&di->bridge_exporter, &ois);
+        ofputil_append_ipfix_stat(replies, &ois);
+    } else {
+        if (hmap_count(&di->flow_exporter_map) == 0) {
+            ovs_mutex_unlock(&mutex);
+            return OFPERR_NXST_NOT_CONFIGURED;
+        }
+
+        HMAP_FOR_EACH (flow_exporter_node, node,
+                       &di->flow_exporter_map) {
+            ipfix_get_flow_stats(&flow_exporter_node->exporter, &ois);
+            ofputil_append_ipfix_stat(replies, &ois);
+        }
+    }
+    ovs_mutex_unlock(&mutex);
+
+    return 0;
+}
+
+/* Update partial ipfix stats */
+static void
+ipfix_update_stats(struct dpif_ipfix_exporter *exporter,
+                   bool new_flow,
+                   size_t current_flows,
+                   enum ipfix_sampled_packet_type sampled_pkt_type)
+{
+    if (new_flow) {
+        exporter->stats.total_flows++;
+        exporter->stats.current_flows = current_flows;
+    }
+    exporter->stats.pkts++;
+
+    switch (sampled_pkt_type) {
+    case IPFIX_SAMPLED_PKT_IPV4_OK:
+        exporter->stats.ipv4_pkts++;
+        break;
+    case IPFIX_SAMPLED_PKT_IPV6_OK:
+        exporter->stats.ipv6_pkts++;
+        break;
+    case IPFIX_SAMPLED_PKT_IPV4_ERROR:
+        exporter->stats.ipv4_error_pkts++;
+        exporter->stats.error_pkts++;
+        break;
+    case IPFIX_SAMPLED_PKT_IPV6_ERROR:
+        exporter->stats.ipv6_error_pkts++;
+        exporter->stats.error_pkts++;
+        break;
+    case IPFIX_SAMPLED_PKT_UNKNOWN:
+        exporter->stats.error_pkts++;
+        break;
+    case IPFIX_SAMPLED_PKT_OTHERS:
+    default:
+        break;
+    }
+}
+
 /* Add an entry into a flow cache.  The entry is either aggregated into
  * an existing entry with the same flow key and free()d, or it is
- * inserted into the cache. */
+ * inserted into the cache. And IPFIX stats will be updated */
 static void
 ipfix_cache_update(struct dpif_ipfix_exporter *exporter,
-                   struct ipfix_flow_cache_entry *entry)
+                   struct ipfix_flow_cache_entry *entry,
+                   enum ipfix_sampled_packet_type sampled_pkt_type)
 {
     struct ipfix_flow_cache_entry *old_entry;
+    size_t current_flows = 0;
 
     old_entry = ipfix_cache_find_entry(exporter, &entry->flow_key);
 
@@ -1348,17 +1479,19 @@ ipfix_cache_update(struct dpif_ipfix_exporter *exporter,
                        &entry->cache_flow_start_timestamp_list_node);
 
         /* Enforce exporter->cache_max_flows limit. */
-        if (hmap_count(&exporter->cache_flow_key_map)
-            > exporter->cache_max_flows) {
+        current_flows = hmap_count(&exporter->cache_flow_key_map);
+        ipfix_update_stats(exporter, true, current_flows, sampled_pkt_type);
+        if (current_flows > exporter->cache_max_flows) {
             dpif_ipfix_cache_expire_now(exporter, false);
         }
     } else {
         ipfix_cache_aggregate_entries(entry, old_entry);
         free(entry);
+        ipfix_update_stats(exporter, false, current_flows, sampled_pkt_type);
     }
 }
 
-static void
+static enum ipfix_sampled_packet_type
 ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
                        const struct dp_packet *packet, const struct flow *flow,
                        uint64_t packet_delta_count, uint32_t obs_domain_id,
@@ -1372,6 +1505,7 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
     enum ipfix_proto_l3 l3;
     enum ipfix_proto_l4 l4;
     enum ipfix_proto_tunnel tunnel = IPFIX_PROTO_NOT_TUNNELED;
+    enum ipfix_sampled_packet_type sampled_pkt_type = IPFIX_SAMPLED_PKT_UNKNOWN;
     uint8_t ethernet_header_length;
     uint16_t ethernet_total_length;
 
@@ -1391,12 +1525,15 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
         case IPPROTO_UDP:
         case IPPROTO_SCTP:
             l4 = IPFIX_PROTO_L4_TCP_UDP_SCTP;
+            sampled_pkt_type = IPFIX_SAMPLED_PKT_IPV4_OK;
             break;
         case IPPROTO_ICMP:
             l4 = IPFIX_PROTO_L4_ICMP;
+            sampled_pkt_type = IPFIX_SAMPLED_PKT_IPV4_OK;
             break;
         default:
             l4 = IPFIX_PROTO_L4_UNKNOWN;
+            sampled_pkt_type = IPFIX_SAMPLED_PKT_IPV4_ERROR;
         }
         break;
     case ETH_TYPE_IPV6:
@@ -1406,17 +1543,21 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
         case IPPROTO_UDP:
         case IPPROTO_SCTP:
             l4 = IPFIX_PROTO_L4_TCP_UDP_SCTP;
+            sampled_pkt_type = IPFIX_SAMPLED_PKT_IPV6_OK;
             break;
         case IPPROTO_ICMPV6:
             l4 = IPFIX_PROTO_L4_ICMP;
+            sampled_pkt_type = IPFIX_SAMPLED_PKT_IPV6_OK;
             break;
         default:
             l4 = IPFIX_PROTO_L4_UNKNOWN;
+            sampled_pkt_type = IPFIX_SAMPLED_PKT_IPV6_ERROR;
         }
         break;
     default:
         l3 = IPFIX_PROTO_L3_UNKNOWN;
         l4 = IPFIX_PROTO_L4_UNKNOWN;
+        sampled_pkt_type = IPFIX_SAMPLED_PKT_OTHERS;
     }
 
     if (tunnel_port && tunnel_key) {
@@ -1569,6 +1710,8 @@ ipfix_cache_entry_init(struct ipfix_flow_cache_entry *entry,
         entry->minimum_ip_total_length = 0;
         entry->maximum_ip_total_length = 0;
     }
+
+    return sampled_pkt_type;
 }
 
 /* Send each single data record in its own data set, to simplify the
@@ -1650,14 +1793,20 @@ ipfix_send_data_msg(struct dpif_ipfix_exporter *exporter,
 {
     uint64_t msg_stub[DIV_ROUND_UP(MAX_MESSAGE_LEN, 8)];
     struct dp_packet msg;
+    size_t tx_errors;
+
     dp_packet_use_stub(&msg, msg_stub, sizeof msg_stub);
 
     ipfix_init_header(export_time_sec, exporter->seq_number++,
                       entry->flow_key.obs_domain_id, &msg);
     ipfix_put_data_set(export_time_sec, entry, flow_end_reason, &msg);
-    ipfix_send_msg(exporter->collectors, &msg);
+    tx_errors = ipfix_send_msg(exporter->collectors, &msg);
 
     dp_packet_uninit(&msg);
+
+    exporter->stats.current_flows--;
+    exporter->stats.tx_pkts += collectors_count(exporter->collectors) - tx_errors;
+    exporter->stats.tx_errors += tx_errors;
 }
 
 static void
@@ -1669,13 +1818,16 @@ dpif_ipfix_sample(struct dpif_ipfix_exporter *exporter,
                   const struct flow_tnl *tunnel_key)
 {
     struct ipfix_flow_cache_entry *entry;
+    enum ipfix_sampled_packet_type sampled_packet_type;
 
     /* Create a flow cache entry from the sample. */
     entry = xmalloc(sizeof *entry);
-    ipfix_cache_entry_init(entry, packet, flow, packet_delta_count,
-                           obs_domain_id, obs_point_id,
-                           output_odp_port, tunnel_port, tunnel_key);
-    ipfix_cache_update(exporter, entry);
+    sampled_packet_type = ipfix_cache_entry_init(entry, packet,
+                                                 flow, packet_delta_count,
+                                                 obs_domain_id, obs_point_id,
+                                                 output_odp_port, tunnel_port,
+                                                 tunnel_key);
+    ipfix_cache_update(exporter, entry, sampled_packet_type);
 }
 
 static bool
diff --git a/ofproto/ofproto-dpif-ipfix.h b/ofproto/ofproto-dpif-ipfix.h
index 2bb0e43..c8e4593 100644
--- a/ofproto/ofproto-dpif-ipfix.h
+++ b/ofproto/ofproto-dpif-ipfix.h
@@ -46,6 +46,8 @@ void dpif_ipfix_set_options(
     const struct ofproto_ipfix_bridge_exporter_options *,
     const struct ofproto_ipfix_flow_exporter_options *, size_t);
 
+int dpif_ipfix_get_stats(const struct dpif_ipfix *, bool, struct ovs_list *);
+
 void dpif_ipfix_bridge_sample(struct dpif_ipfix *, const struct dp_packet *,
                               const struct flow *,
                               odp_port_t, odp_port_t, const struct flow_tnl *);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 91529fe..8a3c525 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1960,6 +1960,21 @@ set_ipfix(
 }
 
 static int
+get_ipfix_stats(const struct ofproto *ofproto_,
+                bool bridge_ipfix,
+                struct ovs_list *replies)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+    struct dpif_ipfix *di = ofproto->ipfix;
+
+    if (!di) {
+        return OFPERR_NXST_NOT_CONFIGURED;
+    }
+
+    return dpif_ipfix_get_stats(di, bridge_ipfix, replies);
+}
+
+static int
 set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
@@ -5555,6 +5570,7 @@ const struct ofproto_class ofproto_dpif_class = {
     get_netflow_ids,
     set_sflow,
     set_ipfix,
+    get_ipfix_stats,
     set_cfm,
     cfm_status_changed,
     get_cfm_status,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index d7fd50e..489933e 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1361,6 +1361,18 @@ struct ofproto_class {
         const struct ofproto_ipfix_flow_exporter_options
             *flow_exporters_options, size_t n_flow_exporters_options);
 
+    /*
+     * Get IPFIX stats on 'ofproto' according to the exporter of birdge
+     * IPFIX or flow based IPFIX.
+     *
+     * OFPERR_NXST_NOT_CONFIGURED as a return value indicates that bridge
+     * IPFIX or flow based IPFIX is not configured. */
+    int (*get_ipfix_stats)(
+        const struct ofproto *ofproto,
+        bool bridge_ipfix,
+        struct ovs_list *replies
+        );
+
     /* Configures connectivity fault management on 'ofport'.
      *
      * If 'cfm_settings' is nonnull, configures CFM according to its members.
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 835a397..2c558a6 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -863,6 +863,64 @@ ofproto_set_ipfix(struct ofproto *ofproto,
     }
 }
 
+static int
+ofproto_get_ipfix_stats(struct ofproto *ofproto,
+                        bool bridge_ipfix,
+                        struct ovs_list *replies)
+{
+    int error;
+
+    if (ofproto->ofproto_class->get_ipfix_stats) {
+        error = ofproto->ofproto_class->get_ipfix_stats(ofproto,
+                                                          bridge_ipfix,
+                                                          replies);
+    } else {
+        error = EOPNOTSUPP;
+    }
+
+    return error;
+}
+
+static enum ofperr
+handle_ipfix_bridge_stats_request(struct ofconn *ofconn,
+                                  const struct ofp_header *request)
+{
+    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+    struct ovs_list replies;
+    enum ofperr error;
+
+    ofpmp_init(&replies, request);
+    error = ofproto_get_ipfix_stats(ofproto, true, &replies);
+
+    if (!error) {
+        ofconn_send_replies(ofconn, &replies);
+    } else {
+        ofpbuf_list_delete(&replies);
+    }
+
+    return error;
+}
+
+static enum ofperr
+handle_ipfix_flow_stats_request(struct ofconn *ofconn,
+                                const struct ofp_header *request)
+{
+    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+    struct ovs_list replies;
+    enum ofperr error;
+
+    ofpmp_init(&replies, request);
+    error = ofproto_get_ipfix_stats(ofproto, false, &replies);
+
+    if (!error) {
+        ofconn_send_replies(ofconn, &replies);
+    } else {
+        ofpbuf_list_delete(&replies);
+    }
+
+    return error;
+}
+
 void
 ofproto_set_flow_restore_wait(bool flow_restore_wait_db)
 {
@@ -7356,6 +7414,12 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_NXT_TLV_TABLE_REQUEST:
         return handle_tlv_table_request(ofconn, oh);
 
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
+        return handle_ipfix_bridge_stats_request(ofconn, oh);
+
+    case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
+        return handle_ipfix_flow_stats_request(ofconn, oh);
+
     case OFPTYPE_HELLO:
     case OFPTYPE_ERROR:
     case OFPTYPE_FEATURES_REPLY:
@@ -7389,6 +7453,8 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     case OFPTYPE_REQUESTFORWARD:
     case OFPTYPE_TABLE_STATUS:
     case OFPTYPE_NXT_TLV_TABLE_REPLY:
+    case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
+    case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
     default:
         if (ofpmsg_is_stat_request(oh)) {
             return OFPERR_OFPBRC_BAD_STAT;
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 11337b5..ff1df39 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -3507,3 +3507,82 @@ OFPT_PORT_MOD (OF1.4) (xid=0x3): port: 3: addr:50:54:00:00:00:01
      advertise: 10MB-HD
 ])
 AT_CLEANUP
+
+AT_SETUP([NXST_IPFIX_BRIDGE - request])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+01 10 00 18 00 00 00 02 \
+ff ff 00 00 00 00 23 20 00 00 00 03 00 00 00 00 \
+"], [0], [dnl
+NXST_IPFIX_BRIDGE request (xid=0x2):
+])
+AT_CLEANUP
+
+AT_SETUP([NXST_IPFIX_BRIDGE - reply])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+01 11 00 70 00 00 00 02 \
+ff ff 00 00 00 00 23 20 00 00 00 03 00 00 00 00\
+00 00 00 00 00 00 00 01 \
+00 00 00 00 00 00 00 10 \
+00 00 00 00 00 00 00 78 \
+00 00 00 00 00 00 00 f0 \
+00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 a0 \
+00 00 00 00 00 00 00 02 \
+00 00 00 00 00 00 00 03 \
+00 00 00 00 00 00 00 04 \
+00 00 00 00 00 00 00 05 \
+00 00 00 00 00 00 00 00 \
+"], [0], [dnl
+NXST_IPFIX_BRIDGE reply (xid=0x2):
+  bridge ipfix: flows=1, current flows=16, sampled pkts=120, ipv4 ok=240, ipv6 ok=0, tx pkts=4
+                pkts errs=160, ipv4 errs=2, ipv6 errs=3, tx errs=5
+])
+AT_CLEANUP
+
+AT_SETUP([NXST_IPFIX_FLOW - request])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+01 10 00 18 00 00 00 02 \
+ff ff 00 00 00 00 23 20 00 00 00 04 00 00 00 00 \
+"], [0], [dnl
+NXST_IPFIX_FLOW request (xid=0x2):
+])
+AT_CLEANUP
+
+AT_SETUP([NXST_IPFIX_FLOW - reply])
+AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
+AT_CHECK([ovs-ofctl ofp-print "\
+01 11 00 C8 00 00 00 02 \
+ff ff 00 00 00 00 23 20 00 00 00 04 00 00 00 00\
+00 00 00 00 00 00 00 01 \
+00 00 00 00 00 00 00 10 \
+00 00 00 00 00 00 00 78 \
+00 00 00 00 00 00 00 f0 \
+00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 a0 \
+00 00 00 10 00 00 00 02 \
+00 00 00 00 00 00 00 03 \
+00 00 00 00 00 00 00 04 \
+00 00 00 00 00 00 00 05 \
+00 00 00 01 00 00 00 00 \
+00 00 00 00 00 00 00 01 \
+00 00 00 00 00 00 00 10 \
+00 00 00 00 00 00 00 78 \
+00 00 00 00 00 00 00 f0 \
+00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 a0 \
+00 00 00 10 00 00 00 02 \
+00 00 00 00 00 00 00 03 \
+00 00 00 00 00 00 00 04 \
+00 00 00 00 00 00 00 05 \
+00 00 00 02 00 00 00 00 \
+"], [0], [dnl
+NXST_IPFIX_FLOW reply (xid=0x2): 2 ids
+  id   1: flows=1, current flows=16, sampled pkts=120, ipv4 ok=240, ipv6 ok=0, tx pkts=4
+          pkts errs=160, ipv4 errs=68719476738, ipv6 errs=3, tx errs=5
+  id   2: flows=1, current flows=16, sampled pkts=120, ipv4 ok=240, ipv6 ok=0, tx pkts=4
+          pkts errs=160, ipv4 errs=68719476738, ipv6 errs=3, tx errs=5
+])
+AT_CLEANUP
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index d0aacfa..772c0d9 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -5790,9 +5790,9 @@ CHECK_NETFLOW_ACTIVE_EXPIRATION([[[::1]]])
 AT_CLEANUP
 
 dnl In the absence of an IPFIX collector to verify protocol correctness, simply
-dnl configure IPFIX and ensure that sample action generation works at the
+dnl configure bridge IPFIX and ensure that sample action generation works at the
 dnl datapath level.
-AT_SETUP([ofproto-dpif - Basic IPFIX sanity check])
+AT_SETUP([ofproto-dpif - Bridge IPFIX sanity check])
 OVS_VSWITCHD_START
 add_of_ports br0 1 2
 
@@ -5826,6 +5826,156 @@ packets:2, bytes:120, used:0.001s, actions:drop
 OVS_VSWITCHD_STOP(["/sending to collector failed/d"])
 AT_CLEANUP
 
+dnl Bridge IPFIX statistics check.
+AT_SETUP([ofproto-dpif - Bridge IPFIX statistics check])
+OVS_VSWITCHD_START
+add_of_ports br0 1 2
+
+dnl Negative test check
+AT_CHECK([ovs-ofctl dump-ipfix-bridge br0], [0], [dnl
+OFPT_ERROR (xid=0x2): NXST_NOT_CONFIGURED
+NXST_IPFIX_BRIDGE request (xid=0x2):
+])
+
+dnl Sample every packet using bridge-based sampling
+AT_CHECK([ovs-vsctl -- set bridge br0 ipfix=@fix -- \
+                    --id=@fix create ipfix targets=\"127.0.0.1:4739\" \
+                              sampling=1], [0], [ignore])
+
+dnl Send some packets that should be sampled
+for i in `seq 1 20`; do
+    AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800)'])
+done
+
+dnl There are 4 extra IPFIX template packets
+AT_CHECK([ovs-ofctl dump-ipfix-bridge br0], [0], [dnl
+NXST_IPFIX_BRIDGE reply (xid=0x2):
+  bridge ipfix: flows=20, current flows=0, sampled pkts=20, ipv4 ok=0, ipv6 ok=0, tx pkts=12
+                pkts errs=20, ipv4 errs=20, ipv6 errs=0, tx errs=12
+])
+
+dnl Remove the IPFIX configuration
+AT_CHECK([ovs-vsctl clear bridge br0 ipfix])
+AT_CHECK([ovs-appctl revalidator/purge])
+
+dnl Send some more packets, to ensure that these are not sampled.
+for i in `seq 1 2`; do
+    AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800)'])
+done
+AT_CHECK([ovs-ofctl dump-ipfix-bridge br0], [0], [dnl
+OFPT_ERROR (xid=0x2): NXST_NOT_CONFIGURED
+NXST_IPFIX_BRIDGE request (xid=0x2):
+])
+
+OVS_VSWITCHD_STOP(["/sending to collector failed/d"])
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - Flow IPFIX sanity check])
+OVS_VSWITCHD_START
+add_of_ports br0 1 2
+
+dnl Retrieve uuid of br0
+AT_CHECK([ovs-vsctl list bridge br0], [0], [stdout])
+bridge_uuid=`awk 'NR==1 {print $3}' stdout`
+
+AT_CHECK([ovs-vsctl -- create Flow_Sample_Collector_Set id=1 bridge=$bridge_uuid], [0], [stdout])
+dnl Retrieve uuid of the first record of Flow_Sample_Collector_Set
+collector_set_uuid=`awk 'NR==1 {print $1}' stdout`
+
+dnl Sample packet using flow-based sampling
+AT_CHECK([ovs-vsctl -- set Flow_Sample_Collector_Set $collector_set_uuid ipfix=@i -- \
+          --id=@i create IPFIX targets=\"127.0.0.1:4739\"], [0], [ignore])
+
+AT_DATA([flows.txt], [dnl
+in_port=1, actions=sample(probability=65535,collector_set_id=1),output:2
+])
+
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt], [0], [ignore])
+AT_CHECK([ovs-ofctl dump-flows br0], [0], [ignore])
+
+dnl Send some packets that should be sampled
+for i in `seq 1 3`; do
+    AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800)'])
+done
+AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
+flow-dump from non-dpdk interfaces:
+packets:2, bytes:120, used:0.001s, actions:sample(sample=100.0%,actions(userspace(pid=0,flow_sample(probability=65535,collector_set_id=1,obs_domain_id=0,obs_point_id=0)))),2
+])
+
+dnl Remove the flow which contains sample action
+AT_CHECK([ovs-ofctl del-flows br0 in_port=1], [0], [ignore])
+AT_CHECK([ovs-appctl revalidator/purge])
+
+dnl Send some more packets, to ensure that these are not sampled.
+for i in `seq 1 3`; do
+    AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800)'])
+done
+AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
+flow-dump from non-dpdk interfaces:
+packets:2, bytes:120, used:0.001s, actions:drop
+])
+
+OVS_VSWITCHD_STOP(["/sending to collector failed/d"])
+AT_CLEANUP
+
+dnl Flow based IPFIX statistics check.
+AT_SETUP([ofproto-dpif - Flow IPFIX statistics check])
+OVS_VSWITCHD_START
+add_of_ports br0 1 2
+
+dnl Negative test check
+AT_CHECK([ovs-ofctl dump-ipfix-flow br0], [0], [dnl
+OFPT_ERROR (xid=0x2): NXST_NOT_CONFIGURED
+NXST_IPFIX_FLOW request (xid=0x2):
+])
+
+dnl Retrieve uuid of br0
+AT_CHECK([ovs-vsctl list bridge br0], [0], [stdout])
+bridge_uuid=`awk 'NR==1 {print $3}' stdout`
+
+AT_CHECK([ovs-vsctl -- create Flow_Sample_Collector_Set id=1 bridge=$bridge_uuid], [0], [stdout])
+dnl Retrieve uuid of the first record of Flow_Sample_Collector_Set
+collector_set_uuid=`awk 'NR==1 {print $1}' stdout`
+
+dnl Sample packet using flow-based sampling
+AT_CHECK([ovs-vsctl -- set Flow_Sample_Collector_Set $collector_set_uuid ipfix=@i -- \
+          --id=@i create IPFIX targets=\"127.0.0.1:4739\"], [0], [ignore])
+
+AT_DATA([flows.txt], [dnl
+in_port=1, actions=sample(probability=65535,collector_set_id=1),output:2
+])
+
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt], [0], [ignore])
+
+dnl Send some packets that should be sampled
+for i in `seq 1 20`; do
+    AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800)'])
+done
+
+dnl There are 4 extra IPFIX template packets
+AT_CHECK([ovs-ofctl dump-ipfix-flow br0], [0], [dnl
+NXST_IPFIX_FLOW reply (xid=0x2): 1 ids
+  id   1: flows=20, current flows=0, sampled pkts=20, ipv4 ok=0, ipv6 ok=0, tx pkts=12
+          pkts errs=20, ipv4 errs=20, ipv6 errs=0, tx errs=12
+])
+
+dnl Remove the flow which contains sample action
+AT_CHECK([ovs-ofctl del-flows br0 in_port=1], [0], [ignore])
+AT_CHECK([ovs-vsctl destroy Flow_Sample_Collector_Set $collector_set_uuid], [0], [ignore])
+AT_CHECK([ovs-appctl revalidator/purge])
+
+dnl Send some more packets, to ensure that these are not sampled.
+for i in `seq 1 3`; do
+    AT_CHECK([ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800)'])
+done
+AT_CHECK([ovs-ofctl dump-ipfix-flow br0], [0], [dnl
+OFPT_ERROR (xid=0x2): NXST_NOT_CONFIGURED
+NXST_IPFIX_FLOW request (xid=0x2):
+])
+
+OVS_VSWITCHD_STOP(["/sending to collector failed/d"])
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - flow stats])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl add-flow br0 "ip,actions=NORMAL"])
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index e2e26f7..b53fe8e 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -255,6 +255,26 @@ This command has limited usefulness, because ports often have no
 configured queues and because the OpenFlow protocol provides only very
 limited information about the configuration of a queue.
 .
+.IP "\fBdump\-ipfix\-bridge \fIswitch
+Prints to the console the statistics of bridge IPFIX for \fIswitch\fR.
+If bridge IPFIX is configured on the \fIswitch\fR, IPFIX statistics
+can be retrieved.  Otherwise, error message will be printed.
+.IP
+This command uses an Open vSwitch extension that is only in Open
+vSwitch 2.6 and later.
+.
+.IP "\fBdump\-ipfix\-flow \fIswitch
+Prints to the console the statistics of flow based IPFIX for
+\fIswitch\fR.  If flow based IPFIX is configured on the \fIswitch\fR,
+statistics of all the collector set ids on the \fIswitch\fR will be
+printed.  Otherwise, print error message.
+.IP
+Refer to ovs-vswitchd.conf.db(8) for more details on configuring flow
+based IPFIX and collector set id.
+.IP
+This command uses an Open vSwitch extension that is only in Open
+vSwitch 2.6 and later.
+.
 .SS "OpenFlow 1.1+ Group Table Commands"
 .
 The following commands work only with switches that support OpenFlow
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 207588b..2ae0e81 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -425,6 +425,8 @@ usage(void)
            "  add-tlv-map SWITCH MAP      add TLV option MAPpings\n"
            "  del-tlv-map SWITCH [MAP] delete TLV option MAPpings\n"
            "  dump-tlv-map SWITCH      print TLV option mappings\n"
+           "  dump-ipfix-bridge SWITCH    print ipfix stats of bridge\n"
+           "  dump-ipfix-flow SWITCH      print flow ipfix of a bridge\n"
            "\nFor OpenFlow switches and controllers:\n"
            "  probe TARGET                probe whether TARGET is up\n"
            "  ping TARGET [N]             latency of N-byte echos\n"
@@ -2437,6 +2439,18 @@ ofctl_benchmark(struct ovs_cmdl_context *ctx)
 }
 
 static void
+ofctl_dump_ipfix_bridge(struct ovs_cmdl_context *ctx)
+{
+    dump_trivial_transaction(ctx->argv[1], OFPRAW_NXST_IPFIX_BRIDGE_REQUEST);
+}
+
+static void
+ofctl_dump_ipfix_flow(struct ovs_cmdl_context *ctx)
+{
+    dump_trivial_transaction(ctx->argv[1], OFPRAW_NXST_IPFIX_FLOW_REQUEST);
+}
+
+static void
 ofctl_group_mod__(const char *remote, struct ofputil_group_mod *gms,
                   size_t n_gms, enum ofputil_protocol usable_protocols)
 {
@@ -4027,6 +4041,11 @@ static const struct ovs_cmdl_command all_commands[] = {
     { "benchmark", "target n count",
       3, 3, ofctl_benchmark },
 
+    { "dump-ipfix-bridge", "switch",
+      1, 1, ofctl_dump_ipfix_bridge},
+    { "dump-ipfix-flow", "switch",
+      1, 1, ofctl_dump_ipfix_flow},
+
     { "ofp-parse", "file",
       1, 1, ofctl_ofp_parse },
     { "ofp-parse-pcap", "pcap",
