+struct dpif_execute_helper_aux {
+ struct dpif *dpif;
+ int error;
+};
+
+static void
+dpif_execute_helper_execute__(void *aux_, struct ofpbuf *packet,
+ const struct flow *flow,
+ const struct nlattr *actions, size_t actions_len)
+{
+ struct dpif_execute_helper_aux *aux = aux_;
+ struct dpif_execute execute;
+ struct odputil_keybuf key_stub;
+ struct ofpbuf key;
+ int error;
+
+ ofpbuf_use_stub(&key, &key_stub, sizeof key_stub);
+ odp_flow_key_from_flow(&key, flow, flow->in_port.odp_port);
+
+ execute.key = key.data;
+ execute.key_len = key.size;
+ execute.actions = actions;
+ execute.actions_len = actions_len;
+ execute.packet = packet;
+ execute.needs_help = false;
+
+ error = aux->dpif->dpif_class->execute(aux->dpif, &execute);
+ if (error) {
+ aux->error = error;
+ }
+}
+
+static void
+dpif_execute_helper_output_cb(void *aux, struct ofpbuf *packet,
+ const struct flow *flow, odp_port_t out_port)
+{
+ uint64_t actions_stub[DIV_ROUND_UP(NL_A_U32_SIZE, 8)];
+ struct ofpbuf actions;
+
+ ofpbuf_use_stack(&actions, actions_stub, sizeof actions_stub);
+ nl_msg_put_u32(&actions, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(out_port));
+
+ dpif_execute_helper_execute__(aux, packet, flow,
+ actions.data, actions.size);
+}
+
+static void
+dpif_execute_helper_userspace_cb(void *aux, struct ofpbuf *packet,
+ const struct flow *flow,
+ const struct nlattr *action)
+{
+ dpif_execute_helper_execute__(aux, packet, flow,
+ action, NLA_ALIGN(action->nla_len));
+}
+
+/* Executes 'execute' by performing most of the actions in userspace and
+ * passing the fully constructed packets to 'dpif' for output and userspace
+ * actions.
+ *
+ * This helps with actions that a given 'dpif' doesn't implement directly. */
+static int
+dpif_execute_with_help(struct dpif *dpif, const struct dpif_execute *execute)
+{
+ struct dpif_execute_helper_aux aux;
+ enum odp_key_fitness fit;
+ struct ofpbuf *packet;
+ struct flow flow;
+
+ COVERAGE_INC(dpif_execute_with_help);
+
+ fit = odp_flow_key_to_flow(execute->key, execute->key_len, &flow);
+ if (fit == ODP_FIT_ERROR) {
+ return EINVAL;
+ }
+
+ aux.dpif = dpif;
+ aux.error = 0;
+
+ packet = ofpbuf_clone_with_headroom(execute->packet, VLAN_HEADER_LEN);
+ odp_execute_actions(&aux, packet, &flow,
+ execute->actions, execute->actions_len,
+ dpif_execute_helper_output_cb,
+ dpif_execute_helper_userspace_cb);
+ ofpbuf_delete(packet);
+
+ return aux.error;
+}
+