diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index db1f831..84e6488 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -20,6 +20,8 @@
 
 #include "ct-dpif.h"
 
+#include "dpif-provider.h"
+
 /* Declarations for conntrack entry formatting. */
 struct flags {
     uint32_t flag;
@@ -46,6 +48,65 @@ static const struct flags ct_dpif_status_flags[] = {
     { 0, NULL } /* End marker. */
 };
 
+/* Dumping */
+
+/* Start dumping the entries from the connection tracker used by 'dpif'.
+ *
+ * 'dump' must be the address of a pointer to a struct ct_dpif_dump_state,
+ * which should be passed (unaltered) to ct_dpif_dump_{next,done}().
+ *
+ * If 'zone' is not NULL, it should point to an integer identifing a
+ * conntrack zone to which the dump will be limited.
+ *
+ * If there has been a problem the function returns a non-zero value
+ * that represents the error.  Otherwise it returns zero. */
+int
+ct_dpif_dump_start(struct dpif *dpif, struct ct_dpif_dump_state **dump,
+                   const uint16_t *zone)
+{
+    int err;
+
+    err = (dpif->dpif_class->ct_dump_start
+           ? dpif->dpif_class->ct_dump_start(dpif, dump, zone)
+           : EOPNOTSUPP);
+
+    if (!err) {
+        (*dump)->dpif = dpif;
+    }
+
+    return err;
+}
+
+/* Dump one connection from a tracker, and put it in 'entry'.
+ *
+ * 'dump' should have been initialized by ct_dpif_dump_start().
+ *
+ * The function returns 0, if an entry has been dumped succesfully.
+ * Otherwise it returns a non-zero value which can be:
+ * - EOF: meaning that there are no more entries to dump.
+ * - an error value.
+ * In both cases, the user should call ct_dpif_dump_done(). */
+int
+ct_dpif_dump_next(struct ct_dpif_dump_state *dump, struct ct_dpif_entry *entry)
+{
+    struct dpif *dpif = dump->dpif;
+
+    return (dpif->dpif_class->ct_dump_next
+            ? dpif->dpif_class->ct_dump_next(dpif, dump, entry)
+            : EOPNOTSUPP);
+}
+
+/* Free resources used by 'dump' */
+int
+ct_dpif_dump_done(struct ct_dpif_dump_state *dump)
+{
+    struct dpif *dpif = dump->dpif;
+
+    return (dpif->dpif_class->ct_dump_done
+            ? dpif->dpif_class->ct_dump_done(dpif, dump)
+            : EOPNOTSUPP);
+}
+
 /* Free memory held by 'entry'. */
 void
 ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index 5127ec2..03f1c20 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -165,6 +165,16 @@ struct ct_dpif_entry {
     uint32_t mark;
 };
 
+struct dpif;
+
+struct ct_dpif_dump_state {
+    struct dpif *dpif;
+};
+
+int ct_dpif_dump_start(struct dpif *, struct ct_dpif_dump_state **,
+                       const uint16_t *zone);
+int ct_dpif_dump_next(struct ct_dpif_dump_state *, struct ct_dpif_entry *);
+int ct_dpif_dump_done(struct ct_dpif_dump_state *);
 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/dpif-netdev.c b/lib/dpif-netdev.c
index 47fa9e2..0f76249 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -3687,6 +3687,9 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_enable_upcall,
     dpif_netdev_disable_upcall,
     dpif_netdev_get_datapath_version,
+    NULL,                       /* ct_dump_start */
+    NULL,                       /* ct_dump_next */
+    NULL,                       /* ct_dump_done */
 };
 
 static void
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index c195042..bf81e61 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -2319,6 +2319,9 @@ const struct dpif_class dpif_netlink_class = {
     NULL,                       /* enable_upcall */
     NULL,                       /* disable_upcall */
     dpif_netlink_get_datapath_version, /* get_datapath_version */
+    NULL,                       /* ct_dump_start */
+    NULL,                       /* ct_dump_next */
+    NULL,                       /* ct_dump_done */
 };
 
 static int
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 5415897..f00e635 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -73,6 +73,9 @@ dpif_flow_dump_thread_init(struct dpif_flow_dump_thread *thread,
     thread->dpif = dump->dpif;
 }
 
+struct ct_dpif_dump_state;
+struct ct_dpif_entry;
+
 /* Datapath interface class structure, to be defined by each implementation of
  * a datapath interface.
  *
@@ -390,6 +393,28 @@ struct dpif_class {
     /* Get datapath version. Caller is responsible for freeing the string
      * returned.  */
     char *(*get_datapath_version)(void);
+
+    /* Conntrack entry dumping interface.
+     *
+     * These functions are used by ct-dpif.c to provide a datapath-agnostic
+     * dumping interface to the connection trackes provided by the
+     * datapaths.
+     *
+     * ct_dump_start() should put in '*state' a pointer to a newly allocated
+     * stucture that will be passed by the caller to ct_dump_next() and
+     * ct_dump_done(). If 'zone' is not NULL, only the entries in '*zone'
+     * should be dumped.
+     *
+     * ct_dump_next() should fill 'entry' with information from a connection
+     * and prepare to dump the next one on a subsequest invocation.
+     *
+     * ct_dump_done should perform any cleanup necessary (including
+     * deallocating the 'state' structure, if applicable). */
+    int (*ct_dump_start)(struct dpif *, struct ct_dpif_dump_state **state,
+                         const uint16_t *zone);
+    int (*ct_dump_next)(struct dpif *, struct ct_dpif_dump_state *,
+                        struct ct_dpif_entry *entry);
+    int (*ct_dump_done)(struct dpif *, struct ct_dpif_dump_state *state);
 };
 
 extern const struct dpif_class dpif_netlink_class;
