+ }
+}
+
+/* If 'dpif' creates its own I/O polling threads, refreshes poll threads
+ * configuration. */
+int
+dpif_poll_threads_set(struct dpif *dpif, const char *cmask)
+{
+ int error = 0;
+
+ if (dpif->dpif_class->poll_threads_set) {
+ error = dpif->dpif_class->poll_threads_set(dpif, cmask);
+ if (error) {
+ log_operation(dpif, "poll_threads_set", error);
+ }
+ }
+
+ return error;
+}
+
+/* Polls for an upcall from 'dpif' for an upcall handler. Since there
+ * there can be multiple poll loops, 'handler_id' is needed as index to
+ * identify the corresponding poll loop. If successful, stores the upcall
+ * into '*upcall', using 'buf' for storage. Should only be called if
+ * 'recv_set' has been used to enable receiving packets from 'dpif'.
+ *
+ * 'upcall->key' and 'upcall->userdata' point into data in the caller-provided
+ * 'buf', so their memory cannot be freed separately from 'buf'.
+ *
+ * The caller owns the data of 'upcall->packet' and may modify it. If
+ * packet's headroom is exhausted as it is manipulated, 'upcall->packet'
+ * will be reallocated. This requires the data of 'upcall->packet' to be
+ * released with ofpbuf_uninit() before 'upcall' is destroyed. However,
+ * when an error is returned, the 'upcall->packet' may be uninitialized
+ * and should not be released.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. Returns EAGAIN
+ * if no upcall is immediately available. */
+int
+dpif_recv(struct dpif *dpif, uint32_t handler_id, struct dpif_upcall *upcall,
+ struct ofpbuf *buf)
+{
+ int error = EAGAIN;
+
+ if (dpif->dpif_class->recv) {
+ error = dpif->dpif_class->recv(dpif, handler_id, upcall, buf);
+ if (!error) {
+ dpif_print_packet(dpif, upcall);
+ } else if (error != EAGAIN) {
+ log_operation(dpif, "recv", error);
+ }