struct ofpbuf *buf)
{
struct ovs_header *k_exec;
+ size_t key_ofs;
ofpbuf_prealloc_tailroom(buf, (64
+ d_exec->packet->size
- + d_exec->key_len
+ + ODP_KEY_METADATA_SIZE
+ d_exec->actions_len));
nl_msg_put_genlmsghdr(buf, 0, ovs_packet_family, NLM_F_REQUEST,
nl_msg_put_unspec(buf, OVS_PACKET_ATTR_PACKET,
d_exec->packet->data, d_exec->packet->size);
- nl_msg_put_unspec(buf, OVS_PACKET_ATTR_KEY, d_exec->key, d_exec->key_len);
+
+ key_ofs = nl_msg_start_nested(buf, OVS_PACKET_ATTR_KEY);
+ odp_key_from_pkt_metadata(buf, &d_exec->md);
+ nl_msg_end_nested(buf, key_ofs);
+
nl_msg_put_unspec(buf, OVS_PACKET_ATTR_ACTIONS,
d_exec->actions, d_exec->actions_len);
}
}
static int
-dpif_linux_execute(struct dpif *dpif_, const struct dpif_execute *execute)
+dpif_linux_execute(struct dpif *dpif_, struct dpif_execute *execute)
{
const struct dpif_linux *dpif = dpif_linux_cast(dpif_);
int queue_no, const struct flow *,
const struct nlattr *userdata);
static void dp_netdev_execute_actions(struct dp_netdev *, const struct flow *,
- struct ofpbuf *,
+ struct ofpbuf *, struct pkt_metadata *,
const struct nlattr *actions,
size_t actions_len);
-static void dp_netdev_port_input(struct dp_netdev *dp,
- struct dp_netdev_port *port,
- struct ofpbuf *packet);
+static void dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+ struct pkt_metadata *md);
static struct dpif_netdev *
dpif_netdev_cast(const struct dpif *dpif)
}
static int
-dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
+dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
- struct flow md;
- int error;
+ struct pkt_metadata *md = &execute->md;
+ struct flow key;
if (execute->packet->size < ETH_HEADER_LEN ||
execute->packet->size > UINT16_MAX) {
return EINVAL;
}
- /* Get packet metadata. */
- error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len, &md);
- if (!error) {
- struct flow key;
-
- /* Extract flow key. */
- flow_extract(execute->packet, md.skb_priority, md.pkt_mark, &md.tunnel,
- &md.in_port, &key);
- ovs_mutex_lock(&dp_netdev_mutex);
- dp_netdev_execute_actions(dp, &key, execute->packet,
- execute->actions, execute->actions_len);
- ovs_mutex_unlock(&dp_netdev_mutex);
- }
- return error;
+ /* Extract flow key. */
+ flow_extract(execute->packet, md->skb_priority, md->pkt_mark, &md->tunnel,
+ (union flow_in_port *)&md->in_port, &key);
+ ovs_mutex_lock(&dp_netdev_mutex);
+ dp_netdev_execute_actions(dp, &key, execute->packet, md, execute->actions,
+ execute->actions_len);
+ ovs_mutex_unlock(&dp_netdev_mutex);
+ return 0;
}
static int
}
static void
-dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
- struct ofpbuf *packet)
+dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+ struct pkt_metadata *md)
{
struct dp_netdev_flow *netdev_flow;
struct flow key;
- union flow_in_port in_port_;
if (packet->size < ETH_HEADER_LEN) {
return;
}
- in_port_.odp_port = port->port_no;
- flow_extract(packet, 0, 0, NULL, &in_port_, &key);
+ flow_extract(packet, md->skb_priority, md->pkt_mark, &md->tunnel,
+ (union flow_in_port *)&md->in_port, &key);
netdev_flow = dp_netdev_lookup_flow(dp, &key);
if (netdev_flow) {
dp_netdev_flow_used(netdev_flow, packet);
- dp_netdev_execute_actions(dp, &key, packet,
+ dp_netdev_execute_actions(dp, &key, packet, md,
netdev_flow->actions,
netdev_flow->actions_len);
dp->n_hit++;
error = port->rx ? netdev_rx_recv(port->rx, &packet) : EOPNOTSUPP;
if (!error) {
- dp_netdev_port_input(dp, port, &packet);
+ struct pkt_metadata md = PKT_METADATA_INITIALIZER(port->port_no);
+ dp_netdev_port_input(dp, &packet, &md);
} else if (error != EAGAIN && error != EOPNOTSUPP) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
};
static void
-dp_execute_cb(void *aux_, struct ofpbuf *packet, struct flow *flow OVS_UNUSED,
+dp_execute_cb(void *aux_, struct ofpbuf *packet,
+ const struct pkt_metadata *md OVS_UNUSED,
const struct nlattr *a, bool may_steal)
{
struct dp_netdev_execute_aux *aux = aux_;
static void
dp_netdev_execute_actions(struct dp_netdev *dp, const struct flow *key,
- struct ofpbuf *packet,
+ struct ofpbuf *packet, struct pkt_metadata *md,
const struct nlattr *actions, size_t actions_len)
{
struct dp_netdev_execute_aux aux = {dp, key};
- struct flow md = *key; /* Packet metadata, may be modified by actions. */
- odp_execute_actions(&aux, packet, &md, actions, actions_len,
- dp_execute_cb);
+ odp_execute_actions(&aux, packet, md, actions, actions_len, dp_execute_cb);
}
const struct dpif_class dpif_netdev_class = {
int (*flow_dump_done)(const struct dpif *dpif, void *state);
/* Performs the 'execute->actions_len' bytes of actions in
- * 'execute->actions' on the Ethernet frame specified in 'execute->packet'
- * taken from the flow specified in the 'execute->key_len' bytes of
- * 'execute->key'. ('execute->key' is mostly redundant with
- * 'execute->packet', but it contains some metadata that cannot be
- * recovered from 'execute->packet', such as tunnel and in_port.) */
- int (*execute)(struct dpif *dpif, const struct dpif_execute *execute);
+ * 'execute->actions' on the Ethernet frame in 'execute->packet'
+ * and on the packet metadata in 'execute->md'.
+ * May modify both packet and metadata. */
+ int (*execute)(struct dpif *dpif, struct dpif_execute *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
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;
- }
-}
-
/* 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, struct flow *flow,
+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:
- dpif_execute_helper_execute__(aux, packet, flow,
- action, NLA_ALIGN(action->nla_len));
+ 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:
*
* 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_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:
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include "netdev.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
-#include "netdev.h"
+#include "packets.h"
#include "util.h"
#ifdef __cplusplus
const struct dpif_flow_stats **);
int dpif_flow_dump_done(struct dpif_flow_dump *);
\f
-/* Packet operations. */
-
-int dpif_execute(struct dpif *,
- const struct nlattr *key, size_t key_len,
- const struct nlattr *actions, size_t actions_len,
- struct ofpbuf *, bool needs_help);
-\f
/* Operation batching interface.
*
* Some datapaths are faster at performing N operations together than the same
struct dpif_execute {
/* Raw support for execute passed along to the provider. */
- const struct nlattr *key; /* Partial flow key (only for metadata). */
- size_t key_len; /* Length of 'key' in bytes. */
const struct nlattr *actions; /* Actions to execute on packet. */
size_t actions_len; /* Length of 'actions' in bytes. */
struct ofpbuf *packet; /* Packet to execute. */
+ struct pkt_metadata md; /* Packet metadata. */
/* Some dpif providers do not implement every action. The Linux kernel
* datapath, in particular, does not implement ARP field modification.
bool needs_help;
};
+int dpif_execute(struct dpif *, struct dpif_execute *);
+
struct dpif_op {
enum dpif_op_type type;
int error;
#include <stdlib.h>
#include <string.h>
+#include "dpif.h"
#include "netlink.h"
#include "ofpbuf.h"
#include "odp-util.h"
static void
odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a,
- struct flow *md)
+ struct pkt_metadata *md)
{
enum ovs_key_attr type = nl_attr_type(a);
const struct ovs_key_ipv4 *ipv4_key;
}
static void
-odp_execute_actions__(void *dp, struct ofpbuf *packet, struct flow *key,
+odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *,
const struct nlattr *actions, size_t actions_len,
odp_execute_cb dp_execute_action, bool more_actions);
static void
-odp_execute_sample(void *dp, struct ofpbuf *packet, struct flow *md,
+odp_execute_sample(void *dp, struct ofpbuf *packet, struct pkt_metadata *md,
const struct nlattr *action,
odp_execute_cb dp_execute_action, bool more_actions)
{
}
static void
-odp_execute_actions__(void *dp, struct ofpbuf *packet, struct flow *md,
+odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md,
const struct nlattr *actions, size_t actions_len,
odp_execute_cb dp_execute_action, bool more_actions)
{
}
void
-odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *md,
+odp_execute_actions(void *dp, struct ofpbuf *packet, struct pkt_metadata *md,
const struct nlattr *actions, size_t actions_len,
odp_execute_cb dp_execute_action)
{
#include <stdint.h>
#include "openvswitch/types.h"
-struct flow;
struct nlattr;
struct ofpbuf;
+struct pkt_metadata;
typedef void (*odp_execute_cb)(void *dp, struct ofpbuf *packet,
- struct flow *metadata,
+ const struct pkt_metadata *,
const struct nlattr *action, bool may_steal);
/* Actions that need to be executed in the context of a datapath are handed
* actions OVS_ACTION_ATTR_OUTPUT and OVS_ACTION_ATTR_USERSPACE so
* 'dp_execute_action' needs to handle only these. */
void
-odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *metadata,
+odp_execute_actions(void *dp, struct ofpbuf *packet, struct pkt_metadata *,
const struct nlattr *actions, size_t actions_len,
odp_execute_cb dp_execute_action);
#endif
#include <string.h>
#include "byte-order.h"
#include "coverage.h"
+#include "dpif.h"
#include "dynamic-string.h"
#include "flow.h"
#include "netlink.h"
return ODP_FIT_ERROR;
}
if (unknown) {
- return ODP_FIT_TOO_MUCH;
+ return ODP_FIT_TOO_MUCH;
}
return ODP_FIT_PERFECT;
}
odp_flow_key_from_flow__(buf, mask, flow, u32_to_odp(odp_in_port_mask));
}
+/* Generate ODP flow key from the given packet metadata */
+void
+odp_key_from_pkt_metadata(struct ofpbuf *buf, const struct pkt_metadata *md)
+{
+ nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, md->skb_priority);
+
+ if (md->tunnel.ip_dst) {
+ tun_key_to_attr(buf, &md->tunnel);
+ }
+
+ nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, md->pkt_mark);
+
+ /* Add an ingress port attribute if 'odp_in_port' is not the magical
+ * value "ODPP_NONE". */
+ if (md->in_port != ODPP_NONE) {
+ nl_msg_put_odp_port(buf, OVS_KEY_ATTR_IN_PORT, md->in_port);
+ }
+}
+
+/* Generate packet metadata from the given ODP flow key. */
+void
+odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
+ struct pkt_metadata *md)
+{
+ const struct nlattr *nla;
+ size_t left;
+ uint32_t wanted_attrs = 1u << OVS_KEY_ATTR_PRIORITY |
+ 1u << OVS_KEY_ATTR_SKB_MARK | 1u << OVS_KEY_ATTR_TUNNEL |
+ 1u << OVS_KEY_ATTR_IN_PORT;
+
+ memset(md, 0, sizeof *md);
+ md->in_port = ODPP_NONE;
+
+ NL_ATTR_FOR_EACH (nla, left, key, key_len) {
+ uint16_t type = nl_attr_type(nla);
+ size_t len = nl_attr_get_size(nla);
+ int expected_len = odp_flow_key_attr_len(type);
+
+ if (len != expected_len && expected_len >= 0) {
+ continue;
+ }
+
+ if (type == OVS_KEY_ATTR_PRIORITY) {
+ md->skb_priority = nl_attr_get_u32(nla);
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_PRIORITY);
+ } else if (type == OVS_KEY_ATTR_SKB_MARK) {
+ md->pkt_mark = nl_attr_get_u32(nla);
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_SKB_MARK);
+ } else if (type == OVS_KEY_ATTR_TUNNEL) {
+ enum odp_key_fitness res;
+
+ res = odp_tun_key_from_attr(nla, &md->tunnel);
+ if (res == ODP_FIT_ERROR) {
+ memset(&md->tunnel, 0, sizeof md->tunnel);
+ } else if (res == ODP_FIT_PERFECT) {
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_TUNNEL);
+ }
+ } else if (type == OVS_KEY_ATTR_IN_PORT) {
+ md->in_port = nl_attr_get_odp_port(nla);
+ wanted_attrs &= ~(1u << OVS_KEY_ATTR_IN_PORT);
+ }
+
+ if (!wanted_attrs) {
+ return; /* Have everything. */
+ }
+ }
+}
+
uint32_t
odp_flow_key_hash(const struct nlattr *key, size_t key_len)
{
struct nlattr;
struct ofpbuf;
struct simap;
+struct pkt_metadata;
#define SLOW_PATH_REASONS \
/* These reasons are mutually exclusive. */ \
uint32_t odp_flow_key_hash(const struct nlattr *, size_t);
+/* Estimated space needed for metadata. */
+enum { ODP_KEY_METADATA_SIZE = 9 * 8 };
+void odp_key_from_pkt_metadata(struct ofpbuf *, const struct pkt_metadata *);
+void odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
+ struct pkt_metadata *md);
+
/* How well a kernel-provided flow key (a sequence of OVS_KEY_ATTR_*
* attributes) matches OVS userspace expectations.
*
struct ofpbuf;
struct ds;
+/* Datapath packet metadata */
+struct pkt_metadata {
+ struct flow_tnl tunnel; /* Encapsulating tunnel parameters. */
+ uint32_t skb_priority; /* Packet priority for QoS. */
+ uint32_t pkt_mark; /* Packet mark. */
+ odp_port_t in_port; /* Input port. */
+};
+
+#define PKT_METADATA_INITIALIZER(PORT) \
+ (struct pkt_metadata){ { 0, 0, 0, 0, 0, 0}, 0, 0, (PORT) }
+
bool dpid_from_string(const char *s, uint64_t *dpidp);
#define ETH_ADDR_LEN 6
op = &ops[n_ops++];
op->type = DPIF_OP_EXECUTE;
- op->u.execute.key = miss->key;
- op->u.execute.key_len = miss->key_len;
op->u.execute.packet = packet;
+ odp_key_to_pkt_metadata(miss->key, miss->key_len,
+ &op->u.execute.md);
op->u.execute.actions = miss->xout.odp_actions.data;
op->u.execute.actions_len = miss->xout.odp_actions.size;
op->u.execute.needs_help = (miss->xout.slow & SLOW_ACTION) != 0;
{
struct ofproto_packet_in *pin;
struct ofpbuf *packet;
- struct flow key;
+ struct pkt_metadata md = PKT_METADATA_INITIALIZER(0);
ctx->xout->slow |= SLOW_CONTROLLER;
if (!ctx->xin->packet) {
packet = ofpbuf_clone(ctx->xin->packet);
- key.skb_priority = 0;
- key.pkt_mark = 0;
- memset(&key.tunnel, 0, sizeof key.tunnel);
-
ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
&ctx->xout->odp_actions,
&ctx->xout->wc,
&ctx->mpls_depth_delta);
- odp_execute_actions(NULL, packet, &key, ctx->xout->odp_actions.data,
+ odp_execute_actions(NULL, packet, &md, ctx->xout->odp_actions.data,
ctx->xout->odp_actions.size, NULL);
pin = xmalloc(sizeof *pin);
{
struct eth_header *eth;
struct ofpbuf actions;
- struct ofpbuf key;
+ struct dpif_execute execute;
struct ofpbuf packet;
size_t start;
int error;
nl_msg_put_unspec_zero(&actions, OVS_USERSPACE_ATTR_USERDATA, 4);
nl_msg_end_nested(&actions, start);
- /* Compose an ODP flow key. The key is arbitrary but it must match the
- * packet that we compose later. */
- ofpbuf_init(&key, 64);
- nl_msg_put_u32(&key, OVS_KEY_ATTR_IN_PORT, 0);
- nl_msg_put_unspec_zero(&key, OVS_KEY_ATTR_ETHERNET,
- sizeof(struct ovs_key_ethernet));
- nl_msg_put_be16(&key, OVS_KEY_ATTR_ETHERTYPE, htons(0x1234));
-
- /* Compose a packet that matches the key. */
+ /* Compose a dummy ethernet packet. */
ofpbuf_init(&packet, ETH_HEADER_LEN);
eth = ofpbuf_put_zeros(&packet, ETH_HEADER_LEN);
eth->eth_type = htons(0x1234);
- /* Execute the actions. On older datapaths this fails with -ERANGE, on
+ /* Execute the actions. On older datapaths this fails with ERANGE, on
* newer datapaths it succeeds. */
- error = dpif_execute(backer->dpif, key.data, key.size,
- actions.data, actions.size, &packet, false);
+ execute.actions = actions.data;
+ execute.actions_len = actions.size;
+ execute.packet = &packet;
+ execute.md = PKT_METADATA_INITIALIZER(0);
+ execute.needs_help = false;
+
+ error = dpif_execute(backer->dpif, &execute);
ofpbuf_uninit(&packet);
- ofpbuf_uninit(&key);
ofpbuf_uninit(&actions);
switch (error) {
const struct ofpact *ofpacts, size_t ofpacts_len,
struct ofpbuf *packet)
{
- struct odputil_keybuf keybuf;
struct dpif_flow_stats stats;
struct xlate_out xout;
struct xlate_in xin;
ofp_port_t in_port;
- struct ofpbuf key;
+ struct dpif_execute execute;
int error;
ovs_assert((rule != NULL) != (ofpacts != NULL));
xin.resubmit_stats = &stats;
xlate_actions(&xin, &xout);
- ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
in_port = flow->in_port.ofp_port;
if (in_port == OFPP_NONE) {
in_port = OFPP_LOCAL;
}
- odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_port(ofproto, in_port));
+ execute.actions = xout.odp_actions.data;
+ execute.actions_len = xout.odp_actions.size;
+ execute.packet = packet;
+ execute.md.tunnel = flow->tunnel;
+ execute.md.skb_priority = flow->skb_priority;
+ execute.md.pkt_mark = flow->pkt_mark;
+ execute.md.in_port = ofp_port_to_odp_port(ofproto, in_port);
+ execute.needs_help = (xout.slow & SLOW_ACTION) != 0;
+
+ error = dpif_execute(ofproto->backer->dpif, &execute);
- error = dpif_execute(ofproto->backer->dpif, key.data, key.size,
- xout.odp_actions.data, xout.odp_actions.size, packet,
- (xout.slow & SLOW_ACTION) != 0);
xlate_out_uninit(&xout);
return error;