X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=c1d93237eb59165d9fbd13b008d1812dcde0bce3;hb=HEAD;hp=75ce7c65fd371c820eff219345e6bffe53f37916;hpb=f35c2d60cd793f424ed0958505d8ec40a5878520;p=sliver-openvswitch.git diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 75ce7c65f..c1d93237e 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -47,9 +47,9 @@ #include #include -#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" @@ -65,7 +65,6 @@ #include "packets.h" #include "poll-loop.h" #include "rtnetlink-link.h" -#include "seq.h" #include "shash.h" #include "socket-util.h" #include "sset.h" @@ -423,8 +422,8 @@ struct netdev_linux { int tap_fd; }; -struct netdev_rx_linux { - struct netdev_rx up; +struct netdev_rxq_linux { + struct netdev_rxq up; bool is_tap; int fd; }; @@ -461,6 +460,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) @@ -482,11 +482,11 @@ netdev_linux_cast(const struct netdev *netdev) 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); } static void netdev_linux_update(struct netdev_linux *netdev, @@ -614,7 +614,7 @@ netdev_linux_changed(struct netdev_linux *dev, 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++; @@ -771,17 +771,17 @@ netdev_linux_dealloc(struct netdev *netdev_) 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; @@ -867,9 +867,9 @@ 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); @@ -877,9 +877,9 @@ netdev_linux_rx_destruct(struct netdev_rx *rx_) } 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); } @@ -901,7 +901,7 @@ auxdata_has_vlan_tci(const struct tpacket_auxdata *aux) } 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; @@ -917,7 +917,7 @@ netdev_linux_rx_recv_sock(int fd, struct ofpbuf *buffer) 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; @@ -937,7 +937,7 @@ netdev_linux_rx_recv_sock(int fd, struct ofpbuf *buffer) 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; @@ -964,13 +964,13 @@ netdev_linux_rx_recv_sock(int fd, struct ofpbuf *buffer) } 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) { @@ -979,41 +979,58 @@ netdev_linux_rx_recv_tap(int fd, struct ofpbuf *buffer) 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 *buffer) +netdev_linux_rxq_recv(struct netdev_rxq *rxq_, struct ofpbuf **packet, int *c) { - struct netdev_rx_linux *rx = netdev_rx_linux_cast(rx_); - int retval; + struct netdev_rxq_linux *rx = netdev_rxq_linux_cast(rxq_); + 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_)); + ? 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_rxq_get_name(rxq_)); + } + ofpbuf_delete(buffer); + } else { + dp_packet_pad(buffer); + packet[0] = buffer; + *c = 1; } return retval; } 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; @@ -1035,8 +1052,11 @@ netdev_linux_rx_drain(struct netdev_rx *rx_) * 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_, const void *data, size_t size) +netdev_linux_send(struct netdev *netdev_, struct ofpbuf *pkt, bool may_steal) { + const void *data = ofpbuf_data(pkt); + size_t size = ofpbuf_size(pkt); + for (;;) { ssize_t retval; @@ -1087,6 +1107,10 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) 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 @@ -1539,9 +1563,17 @@ netdev_linux_get_stats(const struct netdev *netdev_, 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; @@ -1605,6 +1637,14 @@ netdev_tap_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) 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; @@ -2735,13 +2775,13 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off, \ 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 =