+/* Returns new thread-local state for use with dpif_flow_dump_next(). */
+struct dpif_flow_dump_thread *
+dpif_flow_dump_thread_create(struct dpif_flow_dump *dump)
+{
+ return dump->dpif->dpif_class->flow_dump_thread_create(dump);
+}
+
+/* Releases 'thread'. */
+void
+dpif_flow_dump_thread_destroy(struct dpif_flow_dump_thread *thread)
+{
+ thread->dpif->dpif_class->flow_dump_thread_destroy(thread);
+}
+
+/* Attempts to retrieve up to 'max_flows' more flows from 'thread'. Returns 0
+ * if and only if no flows remained to be retrieved, otherwise a positive
+ * number reflecting the number of elements in 'flows[]' that were updated.
+ * The number of flows returned might be less than 'max_flows' because
+ * fewer than 'max_flows' remained, because this particular datapath does not
+ * benefit from batching, or because an error occurred partway through
+ * retrieval. Thus, the caller should continue calling until a 0 return value,
+ * even if intermediate return values are less than 'max_flows'.
+ *
+ * No error status is immediately provided. An error status for the entire
+ * dump operation is provided when it is completed by calling
+ * dpif_flow_dump_destroy().
+ *
+ * All of the data stored into 'flows' is owned by the datapath, not by the
+ * caller, and the caller must not modify or free it. The datapath guarantees
+ * that it remains accessible and unchanged until the first of:
+ * - The next call to dpif_flow_dump_next() for 'thread', or
+ * - The next rcu quiescent period. */
+int
+dpif_flow_dump_next(struct dpif_flow_dump_thread *thread,
+ struct dpif_flow *flows, int max_flows)
+{
+ struct dpif *dpif = thread->dpif;
+ int n;
+
+ ovs_assert(max_flows > 0);
+ n = dpif->dpif_class->flow_dump_next(thread, flows, max_flows);
+ if (n > 0) {
+ struct dpif_flow *f;
+
+ for (f = flows; f < &flows[n] && should_log_flow_message(0); f++) {
+ log_flow_message(dpif, 0, "flow_dump",
+ f->key, f->key_len, f->mask, f->mask_len,
+ &f->ufid, &f->stats, f->actions, f->actions_len);