mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 22:35:15 +00:00
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 <pshelar@nicira.com>
This commit is contained in:
@@ -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 \
|
||||
|
@@ -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 = {
|
||||
|
46
lib/dpif-netdev.h
Normal file
46
lib/dpif-netdev.h
Normal file
@@ -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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#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 */
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
||||
return (rx->pcap_handle
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#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
|
||||
|
@@ -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;
|
||||
|
@@ -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()
|
||||
|
25
lib/netdev.c
25
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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user