#include <string.h>
#include <unistd.h>
-#include "connectivity.h"
#include "coverage.h"
#include "dpif-linux.h"
#include "dpif-netdev.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "ovs-atomic.h"
+#include "packet-dpif.h"
#include "packets.h"
#include "poll-loop.h"
#include "rtnetlink-link.h"
-#include "seq.h"
#include "shash.h"
#include "socket-util.h"
#include "sset.h"
int tap_fd;
};
-struct netdev_rx_linux {
- struct netdev_rx up;
+struct netdev_rxq_linux {
+ struct netdev_rxq up;
bool is_tap;
int fd;
};
return CONTAINER_OF(netdev, struct netdev_linux, up);
}
-static struct netdev_rx_linux *
-netdev_rx_linux_cast(const struct netdev_rx *rx)
+static struct netdev_rxq_linux *
+netdev_rxq_linux_cast(const struct netdev_rxq *rx)
{
ovs_assert(is_netdev_linux_class(netdev_get_class(rx->netdev)));
- return CONTAINER_OF(rx, struct netdev_rx_linux, up);
+ return CONTAINER_OF(rx, struct netdev_rxq_linux, up);
}
\f
static void netdev_linux_update(struct netdev_linux *netdev,
unsigned int ifi_flags, unsigned int mask)
OVS_REQUIRES(dev->mutex)
{
- seq_change(connectivity_seq_get());
+ netdev_change_seq_changed(&dev->up);
if ((dev->ifi_flags ^ ifi_flags) & IFF_RUNNING) {
dev->carrier_resets++;
free(netdev);
}
-static struct netdev_rx *
-netdev_linux_rx_alloc(void)
+static struct netdev_rxq *
+netdev_linux_rxq_alloc(void)
{
- struct netdev_rx_linux *rx = xzalloc(sizeof *rx);
+ struct netdev_rxq_linux *rx = xzalloc(sizeof *rx);
return &rx->up;
}
static int
-netdev_linux_rx_construct(struct netdev_rx *rx_)
+netdev_linux_rxq_construct(struct netdev_rxq *rxq_)
{
- struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+ struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
struct netdev *netdev_ = rx->up.netdev;
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
int error;
}
static void
-netdev_linux_rx_destruct(struct netdev_rx *rx_)
+netdev_linux_rxq_destruct(struct netdev_rxq *rxq_)
{
- struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+ struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
if (!rx->is_tap) {
close(rx->fd);
}
static void
-netdev_linux_rx_dealloc(struct netdev_rx *rx_)
+netdev_linux_rxq_dealloc(struct netdev_rxq *rxq_)
{
- struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+ struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
free(rx);
}
}
static int
-netdev_linux_rx_recv_sock(int fd, struct ofpbuf *buffer)
+netdev_linux_rxq_recv_sock(int fd, struct ofpbuf *buffer)
{
size_t size;
ssize_t retval;
ofpbuf_reserve(buffer, VLAN_HEADER_LEN);
size = ofpbuf_tailroom(buffer);
- iov.iov_base = buffer->data;
+ iov.iov_base = ofpbuf_data(buffer);
iov.iov_len = size;
msgh.msg_name = NULL;
msgh.msg_namelen = 0;
return EMSGSIZE;
}
- buffer->size += retval;
+ ofpbuf_set_size(buffer, ofpbuf_size(buffer) + retval);
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
const struct tpacket_auxdata *aux;
}
static int
-netdev_linux_rx_recv_tap(int fd, struct ofpbuf *buffer)
+netdev_linux_rxq_recv_tap(int fd, struct ofpbuf *buffer)
{
ssize_t retval;
size_t size = ofpbuf_tailroom(buffer);
do {
- retval = read(fd, buffer->data, size);
+ retval = read(fd, ofpbuf_data(buffer), size);
} while (retval < 0 && errno == EINTR);
if (retval < 0) {
return EMSGSIZE;
}
- buffer->size += retval;
+ ofpbuf_set_size(buffer, ofpbuf_size(buffer) + retval);
return 0;
}
static int
-netdev_linux_rx_recv(struct netdev_rx *rx_, struct ofpbuf **packet, int *c)
+netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct dpif_packet **packets,
+ int *c)
{
- struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+ struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
struct netdev *netdev = rx->up.netdev;
+ struct dpif_packet *packet;
struct ofpbuf *buffer;
ssize_t retval;
int mtu;
mtu = ETH_PAYLOAD_MAX;
}
- buffer = ofpbuf_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu, DP_NETDEV_HEADROOM);
+ packet = dpif_packet_new_with_headroom(VLAN_ETH_HEADER_LEN + mtu,
+ DP_NETDEV_HEADROOM);
+ buffer = &packet->ofpbuf;
retval = (rx->is_tap
- ? netdev_linux_rx_recv_tap(rx->fd, buffer)
- : netdev_linux_rx_recv_sock(rx->fd, buffer));
+ ? netdev_linux_rxq_recv_tap(rx->fd, buffer)
+ : netdev_linux_rxq_recv_sock(rx->fd, buffer));
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_));
+ ovs_strerror(errno), netdev_rxq_get_name(rxq_));
}
- ofpbuf_delete(buffer);
+ dpif_packet_delete(packet);
} else {
dp_packet_pad(buffer);
- packet[0] = buffer;
+ packets[0] = packet;
*c = 1;
}
}
static void
-netdev_linux_rx_wait(struct netdev_rx *rx_)
+netdev_linux_rxq_wait(struct netdev_rxq *rxq_)
{
- struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+ struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
poll_fd_wait(rx->fd, POLLIN);
}
static int
-netdev_linux_rx_drain(struct netdev_rx *rx_)
+netdev_linux_rxq_drain(struct netdev_rxq *rxq_)
{
- struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_);
+ struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_);
if (rx->is_tap) {
struct ifreq ifr;
- int error = af_inet_ifreq_ioctl(netdev_rx_get_name(rx_), &ifr,
+ int error = af_inet_ifreq_ioctl(netdev_rxq_get_name(rxq_), &ifr,
SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
if (error) {
return error;
* The kernel maintains a packet transmission queue, so the caller is not
* expected to do additional queuing of packets. */
static int
-netdev_linux_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal)
+netdev_linux_send(struct netdev *netdev_, struct dpif_packet **pkts, int cnt,
+ bool may_steal)
{
- const void *data = pkt->data;
- size_t size = pkt->size;
+ int i;
+ int error = 0;
- for (;;) {
+ /* 'i' is incremented only if there's no error */
+ for (i = 0; i < cnt;) {
+ const void *data = ofpbuf_data(&pkts[i]->ofpbuf);
+ size_t size = ofpbuf_size(&pkts[i]->ofpbuf);
ssize_t retval;
if (!is_tap_netdev(netdev_)) {
retval = write(netdev->tap_fd, data, size);
}
- if (may_steal) {
- ofpbuf_delete(pkt);
- }
-
if (retval < 0) {
/* The Linux AF_PACKET implementation never blocks waiting for room
* for packets, instead returning ENOBUFS. Translate this into
* EAGAIN for the caller. */
- if (errno == ENOBUFS) {
- return EAGAIN;
- } else if (errno == EINTR) {
+ error = errno == ENOBUFS ? EAGAIN : errno;
+ if (error == EINTR) {
+ /* continue without incrementing 'i', i.e. retry this packet */
continue;
- } else if (errno != EAGAIN) {
- VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
- netdev_get_name(netdev_), ovs_strerror(errno));
}
- return errno;
+ break;
} else if (retval != size) {
- VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%"PRIuSIZE"d bytes of "
- "%"PRIuSIZE") on %s", retval, size, netdev_get_name(netdev_));
- return EMSGSIZE;
- } else {
- return 0;
+ VLOG_WARN_RL(&rl, "sent partial Ethernet packet (%"PRIuSIZE" bytes"
+ " of %"PRIuSIZE") on %s", retval, size,
+ netdev_get_name(netdev_));
+ error = EMSGSIZE;
+ break;
}
+
+ /* Process the next packet in the batch */
+ i++;
}
+
+ if (may_steal) {
+ for (i = 0; i < cnt; i++) {
+ dpif_packet_delete(pkts[i]);
+ }
+ }
+
+ if (error && error != EAGAIN) {
+ VLOG_WARN_RL(&rl, "error sending Ethernet packet on %s: %s",
+ netdev_get_name(netdev_), ovs_strerror(error));
+ }
+
+ return error;
+
}
/* Registers with the poll loop to wake up from the next call to poll_block()
netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst,
const struct ovs_vport_stats *src)
{
- dst->rx_packets = get_unaligned_u64(&src->rx_packets);
- dst->tx_packets = get_unaligned_u64(&src->tx_packets);
- dst->rx_bytes = get_unaligned_u64(&src->rx_bytes);
- dst->tx_bytes = get_unaligned_u64(&src->tx_bytes);
- dst->rx_errors = get_unaligned_u64(&src->rx_errors);
- dst->tx_errors = get_unaligned_u64(&src->tx_errors);
- dst->rx_dropped = get_unaligned_u64(&src->rx_dropped);
- dst->tx_dropped = get_unaligned_u64(&src->tx_dropped);
+ dst->rx_packets = get_32aligned_u64(&src->rx_packets);
+ dst->tx_packets = get_32aligned_u64(&src->tx_packets);
+ dst->rx_bytes = get_32aligned_u64(&src->rx_bytes);
+ dst->tx_bytes = get_32aligned_u64(&src->tx_bytes);
+ dst->rx_errors = get_32aligned_u64(&src->rx_errors);
+ dst->tx_errors = get_32aligned_u64(&src->tx_errors);
+ dst->rx_dropped = get_32aligned_u64(&src->rx_dropped);
+ dst->tx_dropped = get_32aligned_u64(&src->tx_dropped);
dst->multicast = 0;
dst->collisions = 0;
dst->rx_length_errors = 0;
error = 0;
}
} else if (netdev->vport_stats_error) {
- /* stats not available from OVS then use ioctl stats. */
+ /* stats not available from OVS then use netdev stats. */
*stats = dev_stats;
} else {
+ /* Use kernel netdev's packet and byte counts since vport's counters
+ * do not reflect packet counts on the wire when GSO, TSO or GRO are
+ * enabled. */
+ stats->rx_packets = dev_stats.rx_packets;
+ stats->rx_bytes = dev_stats.rx_bytes;
+ stats->tx_packets = dev_stats.tx_packets;
+ stats->tx_bytes = dev_stats.tx_bytes;
+
stats->rx_errors += dev_stats.rx_errors;
stats->tx_errors += dev_stats.tx_errors;
stats->rx_dropped += dev_stats.rx_dropped;
stats->tx_heartbeat_errors = 0;
stats->tx_window_errors = 0;
} else {
+ /* Use kernel netdev's packet and byte counts since vport counters
+ * do not reflect packet counts on the wire when GSO, TSO or GRO
+ * are enabled. */
+ stats->rx_packets = dev_stats.tx_packets;
+ stats->rx_bytes = dev_stats.tx_bytes;
+ stats->tx_packets = dev_stats.rx_packets;
+ stats->tx_bytes = dev_stats.rx_bytes;
+
stats->rx_dropped += dev_stats.tx_dropped;
stats->tx_dropped += dev_stats.rx_dropped;
struct dpif_linux_vport vport;
int err;
- vport_stats.rx_packets = stats->rx_packets;
- vport_stats.tx_packets = stats->tx_packets;
- vport_stats.rx_bytes = stats->rx_bytes;
- vport_stats.tx_bytes = stats->tx_bytes;
- vport_stats.rx_errors = stats->rx_errors;
- vport_stats.tx_errors = stats->tx_errors;
- vport_stats.rx_dropped = stats->rx_dropped;
- vport_stats.tx_dropped = stats->tx_dropped;
+ put_32aligned_u64(&vport_stats.rx_packets, stats->rx_packets);
+ put_32aligned_u64(&vport_stats.tx_packets, stats->tx_packets);
+ put_32aligned_u64(&vport_stats.rx_bytes, stats->rx_bytes);
+ put_32aligned_u64(&vport_stats.tx_bytes, stats->tx_bytes);
+ put_32aligned_u64(&vport_stats.rx_errors, stats->rx_errors);
+ put_32aligned_u64(&vport_stats.tx_errors, stats->tx_errors);
+ put_32aligned_u64(&vport_stats.rx_dropped, stats->rx_dropped);
+ put_32aligned_u64(&vport_stats.tx_dropped, stats->tx_dropped);
dpif_linux_vport_init(&vport);
vport.cmd = OVS_VPORT_CMD_SET;
\
netdev_linux_update_flags, \
\
- netdev_linux_rx_alloc, \
- netdev_linux_rx_construct, \
- netdev_linux_rx_destruct, \
- netdev_linux_rx_dealloc, \
- netdev_linux_rx_recv, \
- netdev_linux_rx_wait, \
- netdev_linux_rx_drain, \
+ netdev_linux_rxq_alloc, \
+ netdev_linux_rxq_construct, \
+ netdev_linux_rxq_destruct, \
+ netdev_linux_rxq_dealloc, \
+ netdev_linux_rxq_recv, \
+ netdev_linux_rxq_wait, \
+ netdev_linux_rxq_drain, \
}
const struct netdev_class netdev_linux_class =