+ struct dpif_execute execute;
+
+ execute.key = key;
+ execute.key_len = key_len;
+ execute.actions = actions;
+ execute.actions_len = actions_len;
+ execute.packet = buf;
+ execute.needs_help = needs_help || nl_attr_oversized(actions_len);
+ return dpif_execute__(dpif, &execute);
+}
+
+/* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the order in
+ * which they are specified, placing each operation's results in the "output"
+ * members documented in comments.
+ *
+ * This function exists because some datapaths can perform batched operations
+ * faster than individual operations. */
+void
+dpif_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops)
+{
+ if (dpif->dpif_class->operate) {
+ while (n_ops > 0) {
+ size_t chunk;
+
+ /* Count 'chunk', the number of ops that can be executed without
+ * needing any help. Ops that need help should be rare, so we
+ * expect this to ordinarily be 'n_ops', that is, all the ops. */
+ for (chunk = 0; chunk < n_ops; chunk++) {
+ struct dpif_op *op = ops[chunk];
+
+ if (op->type == DPIF_OP_EXECUTE && op->u.execute.needs_help) {
+ break;
+ }
+ }
+
+ if (chunk) {
+ /* Execute a chunk full of ops that the dpif provider can
+ * handle itself, without help. */
+ size_t i;
+
+ dpif->dpif_class->operate(dpif, ops, chunk);
+
+ for (i = 0; i < chunk; i++) {
+ struct dpif_op *op = ops[i];
+
+ switch (op->type) {
+ case DPIF_OP_FLOW_PUT:
+ log_flow_put_message(dpif, &op->u.flow_put, op->error);
+ break;
+
+ case DPIF_OP_FLOW_DEL:
+ log_flow_del_message(dpif, &op->u.flow_del, op->error);
+ break;
+
+ case DPIF_OP_EXECUTE:
+ log_execute_message(dpif, &op->u.execute, op->error);
+ break;
+ }
+ }
+
+ ops += chunk;
+ n_ops -= chunk;
+ } else {
+ /* Help the dpif provider to execute one op. */
+ struct dpif_op *op = ops[0];
+
+ op->error = dpif_execute__(dpif, &op->u.execute);
+ ops++;
+ n_ops--;
+ }
+ }
+ } else {
+ size_t i;
+
+ for (i = 0; i < n_ops; i++) {
+ struct dpif_op *op = ops[i];
+
+ switch (op->type) {
+ case DPIF_OP_FLOW_PUT:
+ op->error = dpif_flow_put__(dpif, &op->u.flow_put);
+ break;
+
+ case DPIF_OP_FLOW_DEL:
+ op->error = dpif_flow_del__(dpif, &op->u.flow_del);
+ break;
+
+ case DPIF_OP_EXECUTE:
+ op->error = dpif_execute__(dpif, &op->u.execute);
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+ }
+ }
+}
+
+/* Returns a string that represents 'type', for use in log messages. */
+const char *
+dpif_upcall_type_to_string(enum dpif_upcall_type type)
+{
+ switch (type) {
+ case DPIF_UC_MISS: return "miss";
+ case DPIF_UC_ACTION: return "action";
+ case DPIF_N_UC_TYPES: default: return "<unknown>";