diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index 60c8986..adcf42b 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -209,6 +209,30 @@ int ct_dpif_ipf_get_status(struct dpif *dpif, bool *ipf_v4_enabled,
             : EOPNOTSUPP);
 }
 
+int
+ct_dpif_ipf_dump_start(struct dpif *dpif, struct ipf_dump_ctx **dump_ctx)
+{
+    return (dpif->dpif_class->ipf_dump_start
+           ? dpif->dpif_class->ipf_dump_start(dpif, dump_ctx)
+           : EOPNOTSUPP);
+}
+
+int
+ct_dpif_ipf_dump_next(struct dpif *dpif, void *dump_ctx,  char **dump)
+{
+    return (dpif->dpif_class->ipf_dump_next
+            ? dpif->dpif_class->ipf_dump_next(dpif, dump_ctx, dump)
+            : EOPNOTSUPP);
+}
+
+int
+ct_dpif_ipf_dump_done(struct dpif *dpif, void *dump_ctx)
+{
+    return (dpif->dpif_class->ipf_dump_done
+            ? dpif->dpif_class->ipf_dump_done(dpif, dump_ctx)
+            : EOPNOTSUPP);
+}
+
 void
 ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
 {
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index 8a24128..0db17d9 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -17,6 +17,7 @@
 #ifndef CT_DPIF_H
 #define CT_DPIF_H
 
+#include "ipf.h"
 #include "openvswitch/types.h"
 #include "packets.h"
 
@@ -209,6 +210,9 @@ int ct_dpif_ipf_get_status(struct dpif *dpif, bool *, unsigned int *,
                            unsigned int *, bool *, unsigned int *,
                            unsigned int *, unsigned int *, unsigned int *,
                            unsigned int *, unsigned int *);
+int ct_dpif_ipf_dump_start(struct dpif *dpif, struct ipf_dump_ctx **);
+int ct_dpif_ipf_dump_next(struct dpif *dpif, void *, char **);
+int ct_dpif_ipf_dump_done(struct dpif *dpif, void *);
 void ct_dpif_entry_uninit(struct ct_dpif_entry *);
 void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *,
                           bool verbose, bool print_stats);
diff --git a/lib/dpctl.c b/lib/dpctl.c
index 84064cd..7c1aa65 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -35,6 +35,7 @@
 #include "dpif.h"
 #include "openvswitch/dynamic-string.h"
 #include "flow.h"
+#include "ipf.h"
 #include "openvswitch/match.h"
 #include "netdev.h"
 #include "netdev-dpdk.h"
@@ -1852,12 +1853,37 @@ dpctl_ct_ipf_set_nfrag_max(int argc, const char *argv[],
     return error;
 }
 
+static void
+dpctl_dump_ipf(struct dpif *dpif, struct dpctl_params *dpctl_p)
+{
+    struct ipf_dump_ctx *dump_ctx;
+    char *dump;
+
+    int error = ct_dpif_ipf_dump_start(dpif, &dump_ctx);
+    if (error) {
+        dpctl_error(dpctl_p, error, "starting ipf dump");
+        return;
+    }
+
+    dpctl_print(dpctl_p, "\n\tFragment Lists:\n\n");
+    while (!(error = ct_dpif_ipf_dump_next(dpif, dump_ctx, &dump))) {
+        dpctl_print(dpctl_p, "%s\n", dump);
+        free(dump);
+    }
+
+    if (error && error != EOF) {
+        dpctl_error(dpctl_p, error, "dumping ipf entry");
+    }
+
+    ct_dpif_ipf_dump_done(dpif, dump_ctx);
+}
+
 static int
 dpctl_ct_ipf_get_status(int argc, const char *argv[],
                         struct dpctl_params *dpctl_p)
 {
     struct dpif *dpif;
-    int error = dpctl_ct_open_dp(argc, argv, dpctl_p, &dpif, 2);
+    int error = dpctl_ct_open_dp(argc, argv, dpctl_p, &dpif, 3);
     if (!error) {
         bool ipf_v4_enabled;
         unsigned int min_v4_frag_size;
@@ -1916,6 +1942,11 @@ dpctl_ct_ipf_get_status(int argc, const char *argv[],
         } else {
             dpctl_error(dpctl_p, error,
                         "ipf status could not be retrieved");
+            return error;
+        }
+
+        if (argc > 1 && !strncmp(argv[argc - 1], "verbose", 7)) {
+            dpctl_dump_ipf(dpif, dpctl_p);
         }
 
         dpif_close(dpif);
@@ -2229,7 +2260,7 @@ static const struct dpctl_command all_commands[] = {
        dpctl_ct_ipf_set_min_frag, DP_RW },
     { "ipf-set-maxfrags", "[dp] maxfrags", 1, 2,
        dpctl_ct_ipf_set_nfrag_max, DP_RW },
-    { "ipf-get-status", "[dp]", 0, 1, dpctl_ct_ipf_get_status,
+    { "ipf-get-status", "[dp] [verbose]", 0, 2, dpctl_ct_ipf_get_status,
       DP_RO },
     { "help", "", 0, INT_MAX, dpctl_help, DP_RO },
     { "list-commands", "", 0, INT_MAX, dpctl_list_commands, DP_RO },
diff --git a/lib/dpctl.man b/lib/dpctl.man
index 2e8c287..afb270e 100644
--- a/lib/dpctl.man
+++ b/lib/dpctl.man
@@ -296,6 +296,7 @@ module while fragments are incomplete, but will timeout after 15 seconds.
 Memory pool sizing should be set accordingly when fragmentation is enabled.
 .
 .TP
-\*(DX\fBipf\-get\-status\fR [\fIdp\fR]
+\*(DX\fBipf\-get\-status\fR [\fIdp\fR] [\fIverbose\fR]
 Gets the configuration settings and fragment counters associated with the
-fragmentation handling of the userspace datapath connection tracker.
+fragmentation handling of the userspace datapath connection tracker.  If
+verbose is specified, also dumps the ipf list entries.
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 35094f0..37f786b 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -5924,6 +5924,28 @@ dpif_netdev_ipf_get_status(struct dpif *dpif OVS_UNUSED,
     return 0;
 }
 
+static int
+dpif_netdev_ipf_dump_start(struct dpif *dpif OVS_UNUSED,
+                           struct ipf_dump_ctx **ipf_dump_ctx)
+{
+    return ipf_dump_start(ipf_dump_ctx);
+}
+
+static int
+dpif_netdev_ipf_dump_next(struct dpif *dpif OVS_UNUSED,
+                          void *ipf_dump_ctx, char **dump)
+{
+    return ipf_dump_next(ipf_dump_ctx, dump);
+}
+
+static int
+dpif_netdev_ipf_dump_done(struct dpif *dpif OVS_UNUSED,
+                          void *ipf_dump_ctx)
+{
+    return ipf_dump_done(ipf_dump_ctx);
+
+}
+
 const struct dpif_class dpif_netdev_class = {
     "netdev",
     dpif_netdev_init,
@@ -5976,6 +5998,9 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_ipf_set_min_frag,
     dpif_netdev_ipf_set_nfrag_max,
     dpif_netdev_ipf_get_status,
+    dpif_netdev_ipf_dump_start,
+    dpif_netdev_ipf_dump_next,
+    dpif_netdev_ipf_dump_done,
     dpif_netdev_meter_get_features,
     dpif_netdev_meter_set,
     dpif_netdev_meter_get,
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index 73bf31a..e0833fb 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -2998,6 +2998,9 @@ const struct dpif_class dpif_netlink_class = {
     NULL,                       /* ipf_set_min_frag */
     NULL,                       /* ipf_set_nfrag_max */
     NULL,                       /* ipf_get_status */
+    NULL,                       /* ipf_dump_start */
+    NULL,                       /* ipf_dump_next */
+    NULL,                       /* ipf_dump_done */
     dpif_netlink_meter_get_features,
     dpif_netlink_meter_set,
     dpif_netlink_meter_get,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 82fbbfc..385394f 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -24,6 +24,7 @@
 
 #include "openflow/openflow.h"
 #include "dpif.h"
+#include "ipf.h"
 #include "util.h"
 
 #ifdef  __cplusplus
@@ -457,6 +458,10 @@ struct dpif_class {
         unsigned int *, bool *, unsigned int *, unsigned int *,
         unsigned int *, unsigned int *, unsigned int *,
         unsigned int *);
+    int (*ipf_dump_start)(struct dpif *, struct ipf_dump_ctx **);
+    /* Gets an ipf list entry to display. */
+    int (*ipf_dump_next)(struct dpif *, void *, char **);
+    int (*ipf_dump_done)(struct dpif *, void *);
     /* Meters */
 
     /* Queries 'dpif' for supported meter features.
diff --git a/lib/ipf.c b/lib/ipf.c
index a62f4ea..2963dd5 100644
--- a/lib/ipf.c
+++ b/lib/ipf.c
@@ -52,6 +52,10 @@ enum ipf_list_state {
     IPF_LIST_STATE_NUM,
 };
 
+static char *ipf_state_name[IPF_LIST_STATE_NUM] =
+    {"unused", "reassemble fail", "other frag", "first frag", "last frag",
+     "first/last frag", "complete"};
+
 enum ipf_list_type {
     IPF_FRAG_COMPLETED_LIST,
     IPF_FRAG_EXPIRY_LIST,
@@ -1310,3 +1314,73 @@ ipf_get_status(struct ipf_status *ipf_status)
     ipf_status->n6frag_overlap = atomic_count_get(&n6frag_overlap);
     return 0;
 }
+
+struct ipf_dump_ctx {
+    struct hmap_position bucket_pos;
+};
+
+int
+ipf_dump_start(struct ipf_dump_ctx **ipf_dump_ctx)
+{
+    *ipf_dump_ctx = xzalloc(sizeof **ipf_dump_ctx);
+    return 0;
+}
+
+static void
+ipf_dump_create(const struct ipf_list *ipf_list, struct ds *ds)
+{
+
+    ds_put_cstr(ds, "frag list elem=(");
+    if (ipf_list->key.dl_type == htons(ETH_TYPE_IP)) {
+        ds_put_format(ds, "src="IP_FMT",dst="IP_FMT",",
+                      IP_ARGS(ipf_list->key.src_addr.ipv4_aligned),
+                      IP_ARGS(ipf_list->key.dst_addr.ipv4_aligned));
+    } else {
+        ds_put_cstr(ds, "src=");
+        ipv6_format_addr(&ipf_list->key.src_addr.ipv6_aligned, ds);
+        ds_put_cstr(ds, ",dst=");
+        ipv6_format_addr(&ipf_list->key.dst_addr.ipv6_aligned, ds);
+        ds_put_cstr(ds, ",");
+    }
+
+    ds_put_format(ds, "recirc_id=%u,ip_id=%u,dl_type=0x%x,zone=%u,nw_proto=%u",
+                  ipf_list->key.recirc_id, ntohl(ipf_list->key.ip_id),
+                  ntohs(ipf_list->key.dl_type), ipf_list->key.zone,
+                  ipf_list->key.nw_proto);
+
+    ds_put_format(ds, ",num_fragments=%u,state=%s",
+                  ipf_list->last_inuse_idx + 1,
+                  ipf_state_name[ipf_list->state]);
+
+    ds_put_cstr(ds, ")");
+}
+
+int
+ipf_dump_next(struct ipf_dump_ctx *ipf_dump_ctx, char **dump)
+{
+    ipf_lock_lock(&ipf_lock);
+
+    struct hmap_node *node = hmap_at_position(&frag_lists,
+                                              &ipf_dump_ctx->bucket_pos);
+    if (!node) {
+        ipf_lock_unlock(&ipf_lock);
+        return EOF;
+    } else {
+        struct ipf_list *ipf_list_;
+        INIT_CONTAINER(ipf_list_, node, node);
+        struct ipf_list ipf_list = *ipf_list_;
+        ipf_lock_unlock(&ipf_lock);
+        struct ds ds = DS_EMPTY_INITIALIZER;
+        ipf_dump_create(&ipf_list, &ds);
+        *dump = xstrdup(ds.string);
+        ds_destroy(&ds);
+        return 0;
+    }
+}
+
+int
+ipf_dump_done(struct ipf_dump_ctx *ipf_dump_ctx)
+{
+    free(ipf_dump_ctx);
+    return 0;
+}
diff --git a/lib/ipf.h b/lib/ipf.h
index a9fee06..866c711 100644
--- a/lib/ipf.h
+++ b/lib/ipf.h
@@ -72,4 +72,15 @@ ipf_set_nfrag_max(uint32_t value);
 int
 ipf_get_status(struct ipf_status *ipf_status);
 
+struct ipf_dump_ctx;
+
+int
+ipf_dump_start(struct ipf_dump_ctx **ipf_dump_ctx);
+
+int
+ipf_dump_next(struct ipf_dump_ctx *ipf_dump_ctx, char **dump);
+
+int
+ipf_dump_done(struct ipf_dump_ctx *ipf_dump_ctx);
+
 #endif /* ipf.h */
