From: Pravin Date: Thu, 20 Mar 2014 17:54:37 +0000 (-0700) Subject: netdev: Extend rx_recv to pass multiple packets. X-Git-Tag: sliver-openvswitch-2.2.90-1~6^2~46 X-Git-Url: http://git.onelab.eu/?p=sliver-openvswitch.git;a=commitdiff_plain;h=df1e5a3bc7d772237de0ca19663e4a5a9b8f403b netdev: Extend rx_recv to pass multiple packets. DPDK can receive multiple packets but current netdev API does not allow that. Following patch allows dpif-netdev receive batch of packet in a rx_recv() call for any netdev port. This will be used by dpdk-netdev. Signed-off-by: Pravin B Shelar --- diff --git a/lib/automake.mk b/lib/automake.mk index 1460ee29d..6b0442c08 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -52,6 +52,7 @@ lib_libopenvswitch_la_SOURCES = \ lib/dhparams.h \ lib/dirs.h \ lib/dpif-netdev.c \ + lib/dpif-netdev.h \ lib/dpif-provider.h \ lib/dpif.c \ lib/dpif.h \ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 3d0c09fde..254f8b840 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -69,10 +69,6 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev); /* Configuration parameters. */ enum { MAX_FLOWS = 65536 }; /* Maximum number of flows in flow table. */ -/* Enough headroom to add a vlan tag, plus an extra 2 bytes to allow IP - * headers to be aligned on a 4-byte boundary. */ -enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN }; - /* Queues. */ enum { MAX_QUEUE_LEN = 128 }; /* Maximum number of packets per queue. */ enum { QUEUE_MASK = MAX_QUEUE_LEN - 1 }; @@ -343,7 +339,7 @@ static int dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *, const struct nlattr *userdata) OVS_EXCLUDED(dp->queue_rwlock); static void dp_netdev_execute_actions(struct dp_netdev *dp, - const struct flow *, struct ofpbuf *, + const struct flow *, struct ofpbuf *, bool may_steal, struct pkt_metadata *, const struct nlattr *actions, size_t actions_len) @@ -1468,8 +1464,8 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute) flow_extract(execute->packet, md, &key); ovs_rwlock_rdlock(&dp->port_rwlock); - dp_netdev_execute_actions(dp, &key, execute->packet, md, execute->actions, - execute->actions_len); + dp_netdev_execute_actions(dp, &key, execute->packet, false, md, + execute->actions, execute->actions_len); ovs_rwlock_unlock(&dp->port_rwlock); return 0; @@ -1682,12 +1678,10 @@ dp_forwarder_main(void *f_) { struct dp_forwarder *f = f_; struct dp_netdev *dp = f->dp; - struct ofpbuf packet; f->name = xasprintf("forwarder_%u", ovsthread_id_self()); set_subprogram_name("%s", f->name); - ofpbuf_init(&packet, 0); while (!latch_is_set(&dp->exit_latch)) { bool received_anything; int i; @@ -1701,25 +1695,19 @@ dp_forwarder_main(void *f_) if (port->rx && port->node.hash >= f->min_hash && port->node.hash <= f->max_hash) { - int buf_size; + struct ofpbuf *packets[NETDEV_MAX_RX_BATCH]; + int count; int error; - int mtu; - - if (netdev_get_mtu(port->netdev, &mtu)) { - mtu = ETH_PAYLOAD_MAX; - } - buf_size = DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + mtu; - - ofpbuf_clear(&packet); - ofpbuf_reserve_with_tailroom(&packet, DP_NETDEV_HEADROOM, - buf_size); - error = netdev_rx_recv(port->rx, &packet); + error = netdev_rx_recv(port->rx, packets, &count); if (!error) { + int i; struct pkt_metadata md = PKT_METADATA_INITIALIZER(port->port_no); - dp_netdev_port_input(dp, &packet, &md); + for (i = 0; i < count; i++) { + dp_netdev_port_input(dp, packets[i], &md); + } received_anything = true; } else if (error != EAGAIN && error != EOPNOTSUPP) { static struct vlog_rate_limit rl @@ -1755,7 +1743,6 @@ dp_forwarder_main(void *f_) poll_block(); } - ofpbuf_uninit(&packet); free(f->name); @@ -1853,6 +1840,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet, struct flow key; if (packet->size < ETH_HEADER_LEN) { + ofpbuf_delete(packet); return; } flow_extract(packet, md, &key); @@ -1863,7 +1851,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet, dp_netdev_flow_used(netdev_flow, packet, &key); actions = dp_netdev_flow_get_actions(netdev_flow); - dp_netdev_execute_actions(dp, &key, packet, md, + dp_netdev_execute_actions(dp, &key, packet, true, md, actions->actions, actions->size); dp_netdev_count_packet(dp, DP_STAT_HIT); } else if (dp->handler_queues) { @@ -1871,6 +1859,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet, dp_netdev_output_userspace(dp, packet, flow_hash_5tuple(&key, 0) % dp->n_handlers, DPIF_UC_MISS, &key, NULL); + ofpbuf_delete(packet); } } @@ -1899,6 +1888,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet, if (userdata) { buf_size += NLA_ALIGN(userdata->nla_len); } + buf_size += packet->size; ofpbuf_init(buf, buf_size); /* Put ODP flow. */ @@ -1912,10 +1902,8 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet, NLA_ALIGN(userdata->nla_len)); } - /* Steal packet data. */ - ovs_assert(packet->source == OFPBUF_MALLOC); - upcall->packet = *packet; - ofpbuf_use(packet, NULL, 0); + upcall->packet.data = ofpbuf_put(buf, packet->data, packet->size); + upcall->packet.size = packet->size; seq_change(q->seq); @@ -1958,18 +1946,11 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, 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, flow_hash_5tuple(aux->key, 0) % aux->dp->n_handlers, DPIF_UC_ACTION, aux->key, userdata); - if (!may_steal) { - ofpbuf_uninit(packet); - } break; } case OVS_ACTION_ATTR_PUSH_VLAN: @@ -1982,17 +1963,23 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet, case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } + + if (may_steal) { + ofpbuf_delete(packet); + } } static void dp_netdev_execute_actions(struct dp_netdev *dp, const struct flow *key, - struct ofpbuf *packet, struct pkt_metadata *md, + struct ofpbuf *packet, bool may_steal, + struct pkt_metadata *md, const struct nlattr *actions, size_t actions_len) OVS_REQ_RDLOCK(dp->port_rwlock) { struct dp_netdev_execute_aux aux = {dp, key}; - odp_execute_actions(&aux, packet, md, actions, actions_len, dp_execute_cb); + odp_execute_actions(&aux, packet, may_steal, md, + actions, actions_len, dp_execute_cb); } const struct dpif_class dpif_netdev_class = { diff --git a/lib/dpif-netdev.h b/lib/dpif-netdev.h new file mode 100644 index 000000000..f844d8413 --- /dev/null +++ b/lib/dpif-netdev.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DPIF_NETDEV_H +#define DPIF_NETDEV_H 1 + +#include +#include +#include +#include "openvswitch/types.h" +#include "ofpbuf.h" +#include "packets.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enough headroom to add a vlan tag, plus an extra 2 bytes to allow IP + * headers to be aligned on a 4-byte boundary. */ +enum { DP_NETDEV_HEADROOM = 2 + VLAN_HEADER_LEN }; + +static inline void dp_packet_pad(struct ofpbuf *b) +{ + if (b->size < ETH_TOTAL_MIN) { + ofpbuf_put_zeros(b, ETH_TOTAL_MIN - b->size); + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* netdev.h */ diff --git a/lib/dpif.c b/lib/dpif.c index b33d13e7f..dbf1c101d 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1150,7 +1150,7 @@ dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute) COVERAGE_INC(dpif_execute_with_help); - odp_execute_actions(&aux, execute->packet, &execute->md, + odp_execute_actions(&aux, execute->packet, false, &execute->md, execute->actions, execute->actions_len, dpif_execute_helper_cb); return aux.error; diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c index 585ca7f76..cb996194f 100644 --- a/lib/netdev-bsd.c +++ b/lib/netdev-bsd.c @@ -49,6 +49,7 @@ #include "rtbsd.h" #include "connectivity.h" #include "coverage.h" +#include "dpif-netdev.h" #include "dynamic-string.h" #include "fatal-signal.h" #include "ofpbuf.h" @@ -151,6 +152,7 @@ static int af_link_ioctl(unsigned long command, const void *arg); #endif static void netdev_bsd_run(void); +static int netdev_bsd_get_mtu(const struct netdev *netdev_, int *mtup); static bool is_netdev_bsd_class(const struct netdev_class *netdev_class) @@ -620,13 +622,32 @@ netdev_rx_bsd_recv_tap(struct netdev_rx_bsd *rx, struct ofpbuf *buffer) } static int -netdev_bsd_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer) +netdev_bsd_rx_recv(struct netdev_rx *rx_, struct ofpbuf **packet, int *c) { struct netdev_rx_bsd *rx = netdev_rx_bsd_cast(rx_); + struct netdev *netdev = rx->up.netdev; + struct ofpbuf *buffer; + ssize_t retval; + int mtu; + + if (netdev_bsd_get_mtu(netdev_bsd_cast(netdev), &mtu)) { + mtu = ETH_PAYLOAD_MAX; + } + + buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, DP_NETDEV_HEADROOM); - return (rx->pcap_handle + retval = (rx->pcap_handle ? netdev_rx_bsd_recv_pcap(rx, buffer) : netdev_rx_bsd_recv_tap(rx, buffer)); + + if (retval) { + ofpbuf_delete(buffer); + } else { + dp_packet_pad(buffer); + packet[0] = buffer; + *c = 1; + } + return retval; } /* diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c index f23fc9fd3..ecd7317df 100644 --- a/lib/netdev-dummy.c +++ b/lib/netdev-dummy.c @@ -21,6 +21,7 @@ #include #include "connectivity.h" +#include "dpif-netdev.h" #include "flow.h" #include "list.h" #include "netdev-provider.h" @@ -755,12 +756,11 @@ netdev_dummy_rx_dealloc(struct netdev_rx *rx_) } static int -netdev_dummy_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer) +netdev_dummy_rx_recv(struct netdev_rx *rx_, struct ofpbuf **arr, int *c) { struct netdev_rx_dummy *rx = netdev_rx_dummy_cast(rx_); struct netdev_dummy *netdev = netdev_dummy_cast(rx->up.netdev); struct ofpbuf *packet; - int retval; ovs_mutex_lock(&netdev->mutex); if (!list_is_empty(&rx->recv_queue)) { @@ -774,22 +774,15 @@ netdev_dummy_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer) if (!packet) { return EAGAIN; } + ovs_mutex_lock(&netdev->mutex); + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += packet->size; + ovs_mutex_unlock(&netdev->mutex); - if (packet->size <= ofpbuf_tailroom(buffer)) { - memcpy(buffer->data, packet->data, packet->size); - buffer->size += packet->size; - retval = 0; - - ovs_mutex_lock(&netdev->mutex); - netdev->stats.rx_packets++; - netdev->stats.rx_bytes += packet->size; - ovs_mutex_unlock(&netdev->mutex); - } else { - retval = EMSGSIZE; - } - ofpbuf_delete(packet); - - return retval; + dp_packet_pad(packet); + arr[0] = packet; + *c = 1; + return 0; } static void diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 75ce7c65f..2aa674a9a 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -50,6 +50,7 @@ #include "connectivity.h" #include "coverage.h" #include "dpif-linux.h" +#include "dpif-netdev.h" #include "dynamic-string.h" #include "fatal-signal.h" #include "hash.h" @@ -461,6 +462,7 @@ static int af_packet_sock(void); static bool netdev_linux_miimon_enabled(void); static void netdev_linux_miimon_run(void); static void netdev_linux_miimon_wait(void); +static int netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup); static bool is_netdev_linux_class(const struct netdev_class *netdev_class) @@ -984,17 +986,34 @@ netdev_linux_rx_recv_tap(int fd, struct ofpbuf *buffer) } static int -netdev_linux_rx_recv(struct netdev_rx *rx_, struct ofpbuf *buffer) +netdev_linux_rx_recv(struct netdev_rx *rx_, struct ofpbuf **packet, int *c) { struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); - int retval; + struct netdev *netdev = rx->up.netdev; + struct ofpbuf *buffer; + ssize_t retval; + int mtu; + + if (netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu)) { + mtu = ETH_PAYLOAD_MAX; + } + + buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, DP_NETDEV_HEADROOM); retval = (rx->is_tap ? netdev_linux_rx_recv_tap(rx->fd, buffer) : netdev_linux_rx_recv_sock(rx->fd, buffer)); - if (retval && retval != EAGAIN && retval != EMSGSIZE) { - VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s", - ovs_strerror(errno), netdev_rx_get_name(rx_)); + + if (retval) { + if (retval != EAGAIN && retval != EMSGSIZE) { + VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s", + ovs_strerror(errno), netdev_rx_get_name(rx_)); + } + ofpbuf_delete(buffer); + } else { + dp_packet_pad(buffer); + packet[0] = buffer; + *c = 1; } return retval; diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 673d3aba7..0711bb997 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -634,28 +634,18 @@ struct netdev_class { void (*rx_destruct)(struct netdev_rx *); void (*rx_dealloc)(struct netdev_rx *); - /* Attempts to receive a packet from 'rx' into the tailroom of 'buffer', - * which should initially be empty. If successful, returns 0 and - * increments 'buffer->size' by the number of bytes in the received packet, - * otherwise a positive errno value. Returns EAGAIN immediately if no - * packet is ready to be received. + /* Attempts to receive batch of packets from 'rx' and place array of pointers + * into '*pkt'. netdev is responsible for allocating buffers. + * '*cnt' points to packet count for given batch. Once packets are returned + * to caller, netdev should give up ownership of ofpbuf data. * - * Must return EMSGSIZE, and discard the packet, if the received packet - * is longer than 'ofpbuf_tailroom(buffer)'. - * - * Implementations may make use of VLAN_HEADER_LEN bytes of tailroom to - * add a VLAN header which is obtained out-of-band to the packet. If - * this occurs then VLAN_HEADER_LEN bytes of tailroom will no longer be - * available for the packet, otherwise it may be used for the packet - * itself. - * - * It is advised that the tailroom of 'buffer' should be - * VLAN_HEADER_LEN bytes longer than the MTU to allow space for an - * out-of-band VLAN header to be added to the packet. + * Implementations should allocate buffer with DP_NETDEV_HEADROOM headroom + * and add a VLAN header which is obtained out-of-band to the packet. * + * Caller is expected to pass array of size MAX_RX_BATCH. * This function may be set to null if it would always return EOPNOTSUPP * anyhow. */ - int (*rx_recv)(struct netdev_rx *rx, struct ofpbuf *buffer); + int (*rx_recv)(struct netdev_rx *rx, struct ofpbuf **pkt, int *cnt); /* Registers with the poll loop to wake up from the next call to * poll_block() when a packet is ready to be received with netdev_rx_recv() diff --git a/lib/netdev.c b/lib/netdev.c index e9c8d8f03..0d7b69d24 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -551,22 +551,13 @@ netdev_rx_close(struct netdev_rx *rx) } } -/* Attempts to receive a packet from 'rx' into the tailroom of 'buffer', which - * must initially be empty. If successful, returns 0 and increments - * 'buffer->size' by the number of bytes in the received packet, otherwise a - * positive errno value. +/* Attempts to receive batch of packets from 'rx'. * * Returns EAGAIN immediately if no packet is ready to be received. * * Returns EMSGSIZE, and discards the packet, if the received packet is longer * than 'ofpbuf_tailroom(buffer)'. * - * Implementations may make use of VLAN_HEADER_LEN bytes of tailroom to - * add a VLAN header which is obtained out-of-band to the packet. If - * this occurs then VLAN_HEADER_LEN bytes of tailroom will no longer be - * available for the packet, otherwise it may be used for the packet - * itself. - * * It is advised that the tailroom of 'buffer' should be * VLAN_HEADER_LEN bytes longer than the MTU to allow space for an * out-of-band VLAN header to be added to the packet. At the very least, @@ -575,23 +566,15 @@ netdev_rx_close(struct netdev_rx *rx) * This function may be set to null if it would always return EOPNOTSUPP * anyhow. */ int -netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf *buffer) +netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf **buffers, int *cnt) { int retval; - ovs_assert(buffer->size == 0); - ovs_assert(ofpbuf_tailroom(buffer) >= ETH_TOTAL_MIN); - - retval = rx->netdev->netdev_class->rx_recv(rx, buffer); + retval = rx->netdev->netdev_class->rx_recv(rx, buffers, cnt); if (!retval) { COVERAGE_INC(netdev_received); - if (buffer->size < ETH_TOTAL_MIN) { - ofpbuf_put_zeros(buffer, ETH_TOTAL_MIN - buffer->size); - } - return 0; - } else { - return retval; } + return retval; } /* Arranges for poll_block() to wake up when a packet is ready to be received diff --git a/lib/netdev.h b/lib/netdev.h index 410c35bb7..a4dd99b26 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -161,7 +161,7 @@ void netdev_rx_close(struct netdev_rx *); const char *netdev_rx_get_name(const struct netdev_rx *); -int netdev_rx_recv(struct netdev_rx *, struct ofpbuf *); +int netdev_rx_recv(struct netdev_rx *rx, struct ofpbuf **buffers, int *cnt); void netdev_rx_wait(struct netdev_rx *); int netdev_rx_drain(struct netdev_rx *); @@ -313,6 +313,8 @@ typedef void netdev_dump_queue_stats_cb(unsigned int queue_id, int netdev_dump_queue_stats(const struct netdev *, netdev_dump_queue_stats_cb *, void *aux); +enum { NETDEV_MAX_RX_BATCH = 256 }; /* Maximum number packets in rx_recv() batch. */ + #ifdef __cplusplus } #endif diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 096c113fa..cf33eb779 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -141,13 +141,14 @@ odp_execute_set_action(struct ofpbuf *packet, const struct nlattr *a, } static void -odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *, +odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, + 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 pkt_metadata *md, - const struct nlattr *action, +odp_execute_sample(void *dp, struct ofpbuf *packet, bool steal, + struct pkt_metadata *md, const struct nlattr *action, odp_execute_cb dp_execute_action, bool more_actions) { const struct nlattr *subactions = NULL; @@ -175,13 +176,14 @@ odp_execute_sample(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, } } - odp_execute_actions__(dp, packet, md, nl_attr_get(subactions), + odp_execute_actions__(dp, packet, steal, md, nl_attr_get(subactions), nl_attr_get_size(subactions), dp_execute_action, more_actions); } static void -odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, +odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, + struct pkt_metadata *md, const struct nlattr *actions, size_t actions_len, odp_execute_cb dp_execute_action, bool more_actions) { @@ -196,10 +198,11 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, case OVS_ACTION_ATTR_OUTPUT: case OVS_ACTION_ATTR_USERSPACE: if (dp_execute_action) { + bool may_steal; /* Allow 'dp_execute_action' to steal the packet data if we do * not need it any more. */ - bool steal = !more_actions && left <= NLA_ALIGN(a->nla_len); - dp_execute_action(dp, packet, md, a, steal); + may_steal = steal && (!more_actions && left <= NLA_ALIGN(a->nla_len)); + dp_execute_action(dp, packet, md, a, may_steal); } break; @@ -228,7 +231,7 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, break; case OVS_ACTION_ATTR_SAMPLE: - odp_execute_sample(dp, packet, md, a, dp_execute_action, + odp_execute_sample(dp, packet, steal, md, a, dp_execute_action, more_actions || left > NLA_ALIGN(a->nla_len)); break; @@ -240,10 +243,16 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, } void -odp_execute_actions(void *dp, struct ofpbuf *packet, struct pkt_metadata *md, +odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, + struct pkt_metadata *md, const struct nlattr *actions, size_t actions_len, odp_execute_cb dp_execute_action) { - odp_execute_actions__(dp, packet, md, actions, actions_len, + odp_execute_actions__(dp, packet, steal, md, actions, actions_len, dp_execute_action, false); + + if (!actions_len && steal) { + /* Drop action. */ + ofpbuf_delete(packet); + } } diff --git a/lib/odp-execute.h b/lib/odp-execute.h index 670e8ea51..6f1b9bd77 100644 --- a/lib/odp-execute.h +++ b/lib/odp-execute.h @@ -35,8 +35,8 @@ typedef void (*odp_execute_cb)(void *dp, struct ofpbuf *packet, * to 'dp_execute_action', if non-NULL. Currently this is called only for * 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 pkt_metadata *, +void odp_execute_actions(void *dp, struct ofpbuf *packet, bool steal, + struct pkt_metadata *, const struct nlattr *actions, size_t actions_len, odp_execute_cb dp_execute_action); #endif diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 9b6ce104e..df7cf7d5f 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2135,7 +2135,7 @@ execute_controller_action(struct xlate_ctx *ctx, int len, &ctx->xout->odp_actions, &ctx->xout->wc); - odp_execute_actions(NULL, packet, &md, ctx->xout->odp_actions.data, + odp_execute_actions(NULL, packet, false, &md, ctx->xout->odp_actions.data, ctx->xout->odp_actions.size, NULL); pin = xmalloc(sizeof *pin);