&dpif_linux_class,
#endif
&dpif_netdev_class,
+ &dpif_planetlab_class,
};
struct registered_dpif_class {
int error;
};
+/* This is called for actions that need the context of the datapath to be
+ * meaningful. */
static void
-dpif_execute_helper_execute__(void *aux_, struct ofpbuf *packet,
- const struct flow *flow,
- const struct nlattr *actions, size_t actions_len)
+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;
- 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;
+ 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();
}
}
-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,
- bool may_steal OVS_UNUSED)
-{
- 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)
+dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute)
{
- struct dpif_execute_helper_aux aux;
- enum odp_key_fitness fit;
- struct flow flow;
+ struct dpif_execute_helper_aux aux = {dpif, 0};
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;
-
- odp_execute_actions(&aux, execute->packet, &flow,
+ odp_execute_actions(&aux, execute->packet, &execute->md,
execute->actions, execute->actions_len,
- dpif_execute_helper_output_cb,
- dpif_execute_helper_userspace_cb);
+ dpif_execute_helper_cb);
return aux.error;
}
-static int
-dpif_execute__(struct dpif *dpif, const struct dpif_execute *execute)
+/* 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.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. */
+int
+dpif_execute(struct dpif *dpif, struct dpif_execute *execute)
{
int error;
COVERAGE_INC(dpif_execute);
if (execute->actions_len > 0) {
- error = (execute->needs_help
+ error = (execute->needs_help || nl_attr_oversized(execute->actions_len)
? dpif_execute_with_help(dpif, execute)
: dpif->dpif_class->execute(dpif, execute));
} else {
return error;
}
-/* Causes 'dpif' to perform the 'actions_len' bytes of actions in 'actions' on
- * the Ethernet frame specified in 'packet' taken from the flow specified in
- * the 'key_len' bytes of 'key'. ('key' is mostly redundant with 'packet', but
- * it contains some metadata that cannot be recovered from 'packet', such as
- * tunnel and in_port.)
- *
- * 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 'actions_len' is too long for a Netlink attribute.
- *
- * Returns 0 if successful, otherwise a positive errno value. */
-int
-dpif_execute(struct dpif *dpif,
- const struct nlattr *key, size_t key_len,
- const struct nlattr *actions, size_t actions_len,
- struct ofpbuf *buf, bool needs_help)
-{
- 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.
/* Help the dpif provider to execute one op. */
struct dpif_op *op = ops[0];
- op->error = dpif_execute__(dpif, &op->u.execute);
+ op->error = dpif_execute(dpif, &op->u.execute);
ops++;
n_ops--;
}
break;
case DPIF_OP_EXECUTE:
- op->error = dpif_execute__(dpif, &op->u.execute);
+ op->error = dpif_execute(dpif, &op->u.execute);
break;
default:
* '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