+struct dpif_execute_helper_aux {
+ struct dpif *dpif;
+ int error;
+};
+
+/* This is called for actions that need the context of the datapath to be
+ * meaningful. */
+static void
+dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet,
+ const struct pkt_metadata *md,
+ const struct nlattr *action, bool may_steal OVS_UNUSED)
+{
+ struct dpif_execute_helper_aux *aux = aux_;
+ struct dpif_execute execute;
+ int type = nl_attr_type(action);
+
+ switch ((enum ovs_action_attr)type) {
+ case OVS_ACTION_ATTR_OUTPUT:
+ case OVS_ACTION_ATTR_USERSPACE:
+ execute.actions = action;
+ execute.actions_len = NLA_ALIGN(action->nla_len);
+ execute.packet = packet;
+ execute.md = *md;
+ execute.needs_help = false;
+ aux->error = aux->dpif->dpif_class->execute(aux->dpif, &execute);
+ break;
+
+ case OVS_ACTION_ATTR_PUSH_VLAN:
+ case OVS_ACTION_ATTR_POP_VLAN:
+ case OVS_ACTION_ATTR_PUSH_MPLS:
+ case OVS_ACTION_ATTR_POP_MPLS:
+ case OVS_ACTION_ATTR_SET:
+ case OVS_ACTION_ATTR_SAMPLE:
+ case OVS_ACTION_ATTR_UNSPEC:
+ case __OVS_ACTION_ATTR_MAX:
+ OVS_NOT_REACHED();
+ }
+}
+
+/* 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, struct dpif_execute *execute)
+{
+ struct dpif_execute_helper_aux aux = {dpif, 0};
+
+ COVERAGE_INC(dpif_execute_with_help);
+
+ odp_execute_actions(&aux, execute->packet, &execute->md,
+ execute->actions, execute->actions_len,
+ dpif_execute_helper_cb);
+ return aux.error;
+}
+
+/* Causes 'dpif' to perform the 'execute->actions_len' bytes of actions in
+ * 'execute->actions' on the Ethernet frame in 'execute->packet' and on packet
+ * metadata in 'execute->md'. The implementation is allowed to modify both the
+ * '*execute->packet' and 'execute->md'.
+ *
+ * Some dpif providers do not implement every action. The Linux kernel
+ * datapath, in particular, does not implement ARP field modification. If
+ * 'needs_help' is true, the dpif layer executes in userspace all of the
+ * actions that it can, and for OVS_ACTION_ATTR_OUTPUT and
+ * OVS_ACTION_ATTR_USERSPACE actions it passes the packet through to the dpif
+ * implementation.
+ *
+ * This works even if 'execute->actions_len' is too long for a Netlink
+ * attribute.