summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dpif-linux.c14
-rw-r--r--lib/dpif-netdev.c50
-rw-r--r--lib/dpif-provider.h14
-rw-r--r--lib/dpif.c22
-rw-r--r--lib/dpif.h27
-rw-r--r--lib/odp-execute.c51
-rw-r--r--lib/odp-execute.h14
-rw-r--r--lib/ofpbuf.c11
-rw-r--r--lib/ofpbuf.h2
-rw-r--r--ofproto/ofproto-dpif-upcall.c29
-rw-r--r--ofproto/ofproto-dpif-xlate.c13
11 files changed, 135 insertions, 112 deletions
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index c403daa68..54d7f2a1a 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1461,14 +1461,20 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
memset(upcall, 0, sizeof *upcall);
upcall->type = type;
- upcall->packet = buf;
- upcall->packet->data = CONST_CAST(struct nlattr *,
- nl_attr_get(a[OVS_PACKET_ATTR_PACKET]));
- upcall->packet->size = nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]);
upcall->key = CONST_CAST(struct nlattr *,
nl_attr_get(a[OVS_PACKET_ATTR_KEY]));
upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]);
upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
+
+ /* Allow overwriting the netlink attribute header without reallocating. */
+ ofpbuf_use_stub(&upcall->packet,
+ CONST_CAST(struct nlattr *,
+ nl_attr_get(a[OVS_PACKET_ATTR_PACKET])) - 1,
+ nl_attr_get_size(a[OVS_PACKET_ATTR_PACKET]) +
+ sizeof(struct nlattr));
+ upcall->packet.data = (char *)upcall->packet.data + sizeof(struct nlattr);
+ upcall->packet.size -= sizeof(struct nlattr);
+
*dp_ifindex = ovs_header->dp_ifindex;
return 0;
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 20f4a9e22..b4d76fc1f 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -166,7 +166,7 @@ static int do_add_port(struct dp_netdev *, const char *devname,
static int do_del_port(struct dp_netdev *, odp_port_t port_no);
static int dpif_netdev_open(const struct dpif_class *, const char *name,
bool create, struct dpif **);
-static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
+static int dp_netdev_output_userspace(struct dp_netdev *, struct ofpbuf *,
int queue_no, const struct flow *,
const struct nlattr *userdata);
static void dp_netdev_execute_actions(struct dp_netdev *, const struct flow *,
@@ -344,6 +344,7 @@ dp_netdev_purge_queues(struct dp_netdev *dp)
while (q->tail != q->head) {
struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+ ofpbuf_uninit(&u->upcall.packet);
ofpbuf_uninit(&u->buf);
}
}
@@ -1154,20 +1155,15 @@ dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
/* Get packet metadata. */
error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len, &md);
if (!error) {
- struct ofpbuf *copy;
struct flow key;
- /* Make a deep copy of 'packet', because we might modify its data. */
- copy = ofpbuf_clone_with_headroom(execute->packet, DP_NETDEV_HEADROOM);
-
/* Extract flow key. */
- flow_extract(copy, md.skb_priority, md.pkt_mark, &md.tunnel,
+ 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, copy,
+ dp_netdev_execute_actions(dp, &key, execute->packet,
execute->actions, execute->actions_len);
ovs_mutex_unlock(&dp_netdev_mutex);
- ofpbuf_delete(copy);
}
return error;
}
@@ -1214,7 +1210,6 @@ dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall,
struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
*upcall = u->upcall;
- upcall->packet = buf;
ofpbuf_uninit(buf);
*buf = u->buf;
@@ -1296,18 +1291,20 @@ dpif_netdev_run(struct dpif *dpif)
struct dp_netdev_port *port;
struct dp_netdev *dp;
struct ofpbuf packet;
+ size_t buf_size;
ovs_mutex_lock(&dp_netdev_mutex);
dp = get_dp_netdev(dpif);
- ofpbuf_init(&packet,
- DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + dp->max_mtu);
+ ofpbuf_init(&packet, 0);
+
+ buf_size = DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + dp->max_mtu;
LIST_FOR_EACH (port, node, &dp->port_list) {
int error;
- /* Reset packet contents. */
+ /* Reset packet contents. Packet data may have been stolen. */
ofpbuf_clear(&packet);
- ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM);
+ ofpbuf_reserve_with_tailroom(&packet, DP_NETDEV_HEADROOM, buf_size);
error = port->rx ? netdev_rx_recv(port->rx, &packet) : EOPNOTSUPP;
if (!error) {
@@ -1351,7 +1348,7 @@ dpif_netdev_wait(struct dpif *dpif)
}
static int
-dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
+dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
int queue_no, const struct flow *flow,
const struct nlattr *userdata)
{
@@ -1365,7 +1362,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
upcall->type = queue_no;
/* Allocate buffer big enough for everything. */
- buf_size = ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size;
+ buf_size = ODPUTIL_FLOW_KEY_BYTES;
if (userdata) {
buf_size += NLA_ALIGN(userdata->nla_len);
}
@@ -1382,15 +1379,10 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
NLA_ALIGN(userdata->nla_len));
}
- /* Put packet.
- *
- * We adjust 'data' and 'size' in 'buf' so that only the packet itself
- * is visible in 'upcall->packet'. The ODP flow and (if present)
- * userdata become part of the headroom. */
- ofpbuf_put_zeros(buf, 2);
- buf->data = ofpbuf_put(buf, packet->data, packet->size);
- buf->size = packet->size;
- upcall->packet = buf;
+ /* Steal packet data. */
+ ovs_assert(packet->source == OFPBUF_MALLOC);
+ upcall->packet = *packet;
+ ofpbuf_use(packet, NULL, 0);
seq_change(dp->queue_seq);
@@ -1421,14 +1413,22 @@ dp_netdev_action_output(void *aux_, struct ofpbuf *packet,
static void
dp_netdev_action_userspace(void *aux_, struct ofpbuf *packet,
const struct flow *flow OVS_UNUSED,
- const struct nlattr *a)
+ const struct nlattr *a, bool may_steal)
{
struct dp_netdev_execute_aux *aux = aux_;
const struct nlattr *userdata;
userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
+
+ /* Make a copy if we are not allowed to steal the packet's data. */
+ if (!may_steal) {
+ packet = ofpbuf_clone_with_headroom(packet, DP_NETDEV_HEADROOM);
+ }
dp_netdev_output_userspace(aux->dp, packet, DPIF_UC_ACTION, aux->key,
userdata);
+ if (!may_steal) {
+ ofpbuf_uninit(packet);
+ }
}
static void
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 1afac99e4..f279934b6 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -341,11 +341,15 @@ struct dpif_class {
* '*upcall', using 'buf' for storage. Should only be called if 'recv_set'
* has been used to enable receiving packets from 'dpif'.
*
- * The implementation should point 'upcall->packet' and 'upcall->key' into
- * data in the caller-provided 'buf'. If necessary to make room, the
- * implementation may expand the data in 'buf'. (This is hardly a great
- * way to do things but it works out OK for the dpif providers that exist
- * so far.)
+ * The implementation should point 'upcall->key' and 'upcall->userdata'
+ * (if any) into data in the caller-provided 'buf'. The implementation may
+ * also use 'buf' for storing the data of 'upcall->packet'. If necessary
+ * to make room, the implementation may reallocate the data in '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.
*
* This function must not block. If no upcall is pending when it is
* called, it should return EAGAIN without blocking. */
diff --git a/lib/dpif.c b/lib/dpif.c
index f3845db81..270e6419a 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1108,7 +1108,8 @@ dpif_execute_helper_output_cb(void *aux, struct ofpbuf *packet,
static void
dpif_execute_helper_userspace_cb(void *aux, struct ofpbuf *packet,
const struct flow *flow,
- const struct nlattr *action)
+ const struct nlattr *action,
+ bool may_steal OVS_UNUSED)
{
dpif_execute_helper_execute__(aux, packet, flow,
action, NLA_ALIGN(action->nla_len));
@@ -1124,7 +1125,6 @@ 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);
@@ -1137,13 +1137,10 @@ dpif_execute_with_help(struct dpif *dpif, const struct dpif_execute *execute)
aux.dpif = dpif;
aux.error = 0;
- packet = ofpbuf_clone_with_headroom(execute->packet, VLAN_HEADER_LEN);
- odp_execute_actions(&aux, packet, &flow,
+ odp_execute_actions(&aux, execute->packet, &flow,
execute->actions, execute->actions_len,
dpif_execute_helper_output_cb,
dpif_execute_helper_userspace_cb);
- ofpbuf_delete(packet);
-
return aux.error;
}
@@ -1186,8 +1183,7 @@ int
dpif_execute(struct dpif *dpif,
const struct nlattr *key, size_t key_len,
const struct nlattr *actions, size_t actions_len,
- const struct ofpbuf *buf,
- bool needs_help)
+ struct ofpbuf *buf, bool needs_help)
{
struct dpif_execute execute;
@@ -1316,10 +1312,8 @@ dpif_recv_set(struct dpif *dpif, bool enable)
* '*upcall', using 'buf' for storage. Should only be called if
* dpif_recv_set() has been used to enable receiving packets on 'dpif'.
*
- * 'upcall->packet' and 'upcall->key' point into data in the caller-provided
- * 'buf', so their memory cannot be freed separately from 'buf'. (This is
- * hardly a great way to do things but it works out OK for the dpif providers
- * and clients that exist so far.)
+ * 'upcall->key' and 'upcall->userdata' point into data in the caller-provided
+ * 'buf', so their memory cannot be freed separately from 'buf'.
*
* Returns 0 if successful, otherwise a positive errno value. Returns EAGAIN
* if no upcall is immediately available. */
@@ -1331,8 +1325,8 @@ dpif_recv(struct dpif *dpif, struct dpif_upcall *upcall, struct ofpbuf *buf)
struct ds flow;
char *packet;
- packet = ofp_packet_to_string(upcall->packet->data,
- upcall->packet->size);
+ packet = ofp_packet_to_string(upcall->packet.data,
+ upcall->packet.size);
ds_init(&flow);
odp_flow_key_format(upcall->key, upcall->key_len, &flow);
diff --git a/lib/dpif.h b/lib/dpif.h
index 499ee7917..d447a8656 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -35,10 +35,10 @@
* The terms written in quotes below are defined in later sections.
*
* When a datapath "port" receives a packet, it extracts the headers (the
- * "flow"). If the datapath's "flow table" contains a "flow entry" whose flow
- * is the same as the packet's, then it executes the "actions" in the flow
- * entry and increments the flow's statistics. If there is no matching flow
- * entry, the datapath instead appends the packet to an "upcall" queue.
+ * "flow"). If the datapath's "flow table" contains a "flow entry" matching
+ * the packet, then it executes the "actions" in the flow entry and increments
+ * the flow's statistics. If there is no matching flow entry, the datapath
+ * instead appends the packet to an "upcall" queue.
*
*
* Ports
@@ -368,6 +368,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "netdev.h"
#include "util.h"
@@ -380,7 +381,6 @@ struct dpif;
struct ds;
struct flow;
struct nlattr;
-struct ofpbuf;
struct sset;
struct dpif_class;
@@ -521,8 +521,7 @@ int dpif_flow_dump_done(struct dpif_flow_dump *);
int dpif_execute(struct dpif *,
const struct nlattr *key, size_t key_len,
const struct nlattr *actions, size_t actions_len,
- const struct ofpbuf *,
- bool needs_help);
+ struct ofpbuf *, bool needs_help);
/* Operation batching interface.
*
@@ -565,7 +564,7 @@ struct dpif_execute {
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. */
- const struct ofpbuf *packet; /* Packet to execute. */
+ struct ofpbuf *packet; /* Packet to execute. */
/* Some dpif providers do not implement every action. The Linux kernel
* datapath, in particular, does not implement ARP field modification.
@@ -601,15 +600,17 @@ const char *dpif_upcall_type_to_string(enum dpif_upcall_type);
/* A packet passed up from the datapath to userspace.
*
- * If 'key', 'actions', or 'userdata' is nonnull, then it points into data
- * owned by 'packet', so their memory cannot be freed separately. (This is
- * hardly a great way to do things but it works out OK for the dpif providers
- * and clients that exist so far.)
+ * The 'packet', 'key' and 'userdata' may point into data in a buffer
+ * provided by the caller, so the buffer should be released only after the
+ * upcall processing has been finished.
+ *
+ * While being processed, the 'packet' may be reallocated, so the packet must
+ * be separately released with ofpbuf_uninit().
*/
struct dpif_upcall {
/* All types. */
enum dpif_upcall_type type;
- struct ofpbuf *packet; /* Packet data. */
+ struct ofpbuf packet; /* Packet data. */
struct nlattr *key; /* Flow key. */
size_t key_len; /* Length of 'key' in bytes. */
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index af3370d88..5f5b13b12 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -139,14 +139,15 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a,
}
static void
+odp_execute_actions__(void *dp, struct ofpbuf *packet, struct flow *key,
+ const struct nlattr *actions, size_t actions_len,
+ odp_output_cb output, odp_userspace_cb userspace,
+ bool more_actions);
+
+static void
odp_execute_sample(void *dp, struct ofpbuf *packet, struct flow *key,
- const struct nlattr *action,
- void (*output)(void *dp, struct ofpbuf *packet,
- const struct flow *key,
- odp_port_t out_port),
- void (*userspace)(void *dp, struct ofpbuf *packet,
- const struct flow *key,
- const struct nlattr *action))
+ const struct nlattr *action, odp_output_cb output,
+ odp_userspace_cb userspace, bool more_actions)
{
const struct nlattr *subactions = NULL;
const struct nlattr *a;
@@ -173,19 +174,16 @@ odp_execute_sample(void *dp, struct ofpbuf *packet, struct flow *key,
}
}
- odp_execute_actions(dp, packet, key, nl_attr_get(subactions),
- nl_attr_get_size(subactions), output, userspace);
+ odp_execute_actions__(dp, packet, key, nl_attr_get(subactions),
+ nl_attr_get_size(subactions), output, userspace,
+ more_actions);
}
-void
-odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
- const struct nlattr *actions, size_t actions_len,
- void (*output)(void *dp, struct ofpbuf *packet,
- const struct flow *key,
- odp_port_t out_port),
- void (*userspace)(void *dp, struct ofpbuf *packet,
- const struct flow *key,
- const struct nlattr *action))
+static void
+odp_execute_actions__(void *dp, struct ofpbuf *packet, struct flow *key,
+ const struct nlattr *actions, size_t actions_len,
+ odp_output_cb output, odp_userspace_cb userspace,
+ bool more_actions)
{
const struct nlattr *a;
unsigned int left;
@@ -202,7 +200,10 @@ odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
case OVS_ACTION_ATTR_USERSPACE: {
if (userspace) {
- userspace(dp, packet, key, a);
+ /* Allow 'userspace' to steal the packet data if we do not
+ * need it any more. */
+ bool steal = !more_actions && left <= NLA_ALIGN(a->nla_len);
+ userspace(dp, packet, key, a, steal);
}
break;
}
@@ -232,7 +233,8 @@ odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
break;
case OVS_ACTION_ATTR_SAMPLE:
- odp_execute_sample(dp, packet, key, a, output, userspace);
+ odp_execute_sample(dp, packet, key, a, output, userspace,
+ more_actions || left > NLA_ALIGN(a->nla_len));
break;
case OVS_ACTION_ATTR_UNSPEC:
@@ -241,3 +243,12 @@ odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
}
}
}
+
+void
+odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
+ const struct nlattr *actions, size_t actions_len,
+ odp_output_cb output, odp_userspace_cb userspace)
+{
+ odp_execute_actions__(dp, packet, key, actions, actions_len, output,
+ userspace, false);
+}
diff --git a/lib/odp-execute.h b/lib/odp-execute.h
index 5d9fa90bd..90a6788ce 100644
--- a/lib/odp-execute.h
+++ b/lib/odp-execute.h
@@ -18,6 +18,7 @@
#ifndef EXECUTE_ACTIONS_H
#define EXECUTE_ACTIONS_H 1
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "openvswitch/types.h"
@@ -26,13 +27,14 @@ struct flow;
struct nlattr;
struct ofpbuf;
+typedef void (*odp_output_cb)(void *dp, struct ofpbuf *packet,
+ const struct flow *key, odp_port_t out_port);
+typedef void (*odp_userspace_cb)(void *dp, struct ofpbuf *packet,
+ const struct flow *key,
+ const struct nlattr *action, bool may_steal);
+
void
odp_execute_actions(void *dp, struct ofpbuf *packet, struct flow *key,
const struct nlattr *actions, size_t actions_len,
- void (*output)(void *dp, struct ofpbuf *packet,
- const struct flow *key,
- odp_port_t out_port),
- void (*userspace)(void *dp, struct ofpbuf *packet,
- const struct flow *key,
- const struct nlattr *action));
+ odp_output_cb output, odp_userspace_cb userspace);
#endif
diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c
index 30ae12e6d..1b18b14ad 100644
--- a/lib/ofpbuf.c
+++ b/lib/ofpbuf.c
@@ -431,6 +431,17 @@ ofpbuf_reserve(struct ofpbuf *b, size_t size)
b->data = (char*)b->data + size;
}
+/* Reserves 'size' bytes of headroom so that they can be later allocated with
+ * ofpbuf_push_uninit() without reallocating the ofpbuf. */
+void
+ofpbuf_reserve_with_tailroom(struct ofpbuf *b, size_t headroom,
+ size_t tailroom)
+{
+ ovs_assert(!b->size);
+ ofpbuf_prealloc_tailroom(b, headroom + tailroom);
+ b->data = (char*)b->data + headroom;
+}
+
/* Prefixes 'size' bytes to the head end of 'b', reallocating and copying its
* data if necessary. Returns a pointer to the first byte of the data's
* location in the ofpbuf. The new data is left uninitialized. */
diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h
index 0c12162c7..f945cb54c 100644
--- a/lib/ofpbuf.h
+++ b/lib/ofpbuf.h
@@ -82,6 +82,8 @@ void *ofpbuf_put_zeros(struct ofpbuf *, size_t);
void *ofpbuf_put(struct ofpbuf *, const void *, size_t);
char *ofpbuf_put_hex(struct ofpbuf *, const char *s, size_t *n);
void ofpbuf_reserve(struct ofpbuf *, size_t);
+void ofpbuf_reserve_with_tailroom(struct ofpbuf *b, size_t headroom,
+ size_t tailroom);
void *ofpbuf_push_uninit(struct ofpbuf *b, size_t);
void *ofpbuf_push_zeros(struct ofpbuf *, size_t);
void *ofpbuf_push(struct ofpbuf *b, const void *, size_t);
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index be5656363..53a9e82c0 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -301,6 +301,7 @@ static void
upcall_destroy(struct upcall *upcall)
{
if (upcall) {
+ ofpbuf_uninit(&upcall->dpif_upcall.packet);
ofpbuf_uninit(&upcall->upcall_buf);
free(upcall);
}
@@ -650,7 +651,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
n_misses = 0;
LIST_FOR_EACH_SAFE (upcall, next, list_node, upcalls) {
struct dpif_upcall *dupcall = &upcall->dpif_upcall;
- struct ofpbuf *packet = dupcall->packet;
+ struct ofpbuf *packet = &dupcall->packet;
struct flow_miss *miss = &fmb->miss_buf[n_misses];
struct flow_miss *existing_miss;
struct ofproto_dpif *ofproto;
@@ -735,13 +736,13 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
memset(&cookie, 0, sizeof cookie);
memcpy(&cookie, nl_attr_get(dupcall->userdata),
sizeof cookie.sflow);
- dpif_sflow_received(sflow, dupcall->packet, &flow, odp_in_port,
+ dpif_sflow_received(sflow, packet, &flow, odp_in_port,
&cookie);
}
break;
case IPFIX_UPCALL:
if (ipfix) {
- dpif_ipfix_bridge_sample(ipfix, dupcall->packet, &flow);
+ dpif_ipfix_bridge_sample(ipfix, packet, &flow);
}
break;
case FLOW_SAMPLE_UPCALL:
@@ -754,7 +755,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
/* The flow reflects exactly the contents of the packet.
* Sample the packet using it. */
- dpif_ipfix_flow_sample(ipfix, dupcall->packet, &flow,
+ dpif_ipfix_flow_sample(ipfix, packet, &flow,
cookie.flow_sample.collector_set_id,
cookie.flow_sample.probability,
cookie.flow_sample.obs_domain_id,
@@ -808,7 +809,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
n_ops = 0;
LIST_FOR_EACH (upcall, list_node, upcalls) {
struct flow_miss *miss = upcall->flow_miss;
- struct ofpbuf *packet = upcall->dpif_upcall.packet;
+ struct ofpbuf *packet = &upcall->dpif_upcall.packet;
if (miss->xout.slow) {
struct xlate_in xin;
@@ -844,23 +845,19 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
}
}
- /* Execute batch. */
- for (i = 0; i < n_ops; i++) {
- opsp[i] = &ops[i];
- }
- dpif_operate(udpif->dpif, opsp, n_ops);
-
/* Special case for fail-open mode.
*
* If we are in fail-open mode, but we are connected to a controller too,
* then we should send the packet up to the controller in the hope that it
* will try to set up a flow and thereby allow us to exit fail-open.
*
- * See the top-level comment in fail-open.c for more information. */
+ * See the top-level comment in fail-open.c for more information.
+ *
+ * Copy packets before they are modified by execution. */
if (fail_open) {
LIST_FOR_EACH (upcall, list_node, upcalls) {
struct flow_miss *miss = upcall->flow_miss;
- struct ofpbuf *packet = upcall->dpif_upcall.packet;
+ struct ofpbuf *packet = &upcall->dpif_upcall.packet;
struct ofproto_packet_in *pin;
pin = xmalloc(sizeof *pin);
@@ -876,6 +873,12 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
}
}
+ /* Execute batch. */
+ for (i = 0; i < n_ops; i++) {
+ opsp[i] = &ops[i];
+ }
+ dpif_operate(udpif->dpif, opsp, n_ops);
+
list_move(&fmb->upcalls, upcalls);
if (fmb->reval_seq != seq_read(udpif->reval_seq)) {
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 065560f9b..56d007c25 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -572,18 +572,7 @@ xlate_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
/* Make the packet resemble the flow, so that it gets sent to
* an OpenFlow controller properly, so that it looks correct
* for sFlow, and so that flow_extract() will get the correct
- * vlan_tci if it is called on 'packet'.
- *
- * The allocated space inside 'packet' probably also contains
- * 'key', that is, both 'packet' and 'key' are probably part of
- * a struct dpif_upcall (see the large comment on that
- * structure definition), so pushing data on 'packet' is in
- * general not a good idea since it could overwrite 'key' or
- * free it as a side effect. However, it's OK in this special
- * case because we know that 'packet' is inside a Netlink
- * attribute: pushing 4 bytes will just overwrite the 4-byte
- * "struct nlattr", which is fine since we don't need that
- * header anymore. */
+ * vlan_tci if it is called on 'packet'. */
eth_push_vlan(packet, flow->vlan_tci);
}
/* We can't reproduce 'key' from 'flow'. */