Fix the way transmit errors are handled to avoid getting out of sync between kernel and user space, which causes transmission to hang.
Fixes bug https://bugs.linaro.org/show_bug.cgi?id=1890 Signed-off-by: Stuart Haslam <stuart.has...@linaro.org> --- platform/linux-generic/pktio/socket_mmap.c | 59 +++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c index 79ff82d..2bdb72b 100644 --- a/platform/linux-generic/pktio/socket_mmap.c +++ b/platform/linux-generic/pktio/socket_mmap.c @@ -182,6 +182,7 @@ static inline unsigned pkt_mmap_v2_tx(int sock, struct ring *ring, unsigned n, i = 0; unsigned nb_tx = 0; int send_errno; + int total_len = 0; first_frame_num = ring->frame_num; frame_num = first_frame_num; @@ -195,6 +196,7 @@ static inline unsigned pkt_mmap_v2_tx(int sock, struct ring *ring, pkt_len = odp_packet_len(pkt_table[i]); ppd.v2->tp_h.tp_snaplen = pkt_len; ppd.v2->tp_h.tp_len = pkt_len; + total_len += pkt_len; buf = (uint8_t *)ppd.raw + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); @@ -215,28 +217,49 @@ static inline unsigned pkt_mmap_v2_tx(int sock, struct ring *ring, * failure a value of -1 is returned, even if the failure occurred * after some of the packets in the ring have already been sent, so we * need to inspect the packet status to determine which were sent. */ - for (frame_num = first_frame_num, n = 0; n < i; ++n) { - struct tpacket2_hdr *hdr = ring->rd[frame_num].iov_base; + if (odp_likely(ret == total_len)) { + nb_tx = i; + ring->frame_num = frame_num; + } else if (ret == -1) { + for (frame_num = first_frame_num, n = 0; n < i; ++n) { + struct tpacket2_hdr *hdr = ring->rd[frame_num].iov_base; + + if (odp_likely(hdr->tp_status == TP_STATUS_AVAILABLE || + hdr->tp_status == TP_STATUS_SENDING)) { + nb_tx++; + } else { + /* The remaining frames weren't sent, clear + * their status to indicate we're not waiting + * for the kernel to process them. */ + hdr->tp_status = TP_STATUS_AVAILABLE; + } - if (odp_likely(hdr->tp_status == TP_STATUS_AVAILABLE)) { - nb_tx++; - } else if (hdr->tp_status & TP_STATUS_WRONG_FORMAT) { - /* status will be cleared on the next send request */ - break; + if (++frame_num >= frame_count) + frame_num = 0; } - if (++frame_num >= frame_count) - frame_num = 0; - } - - ring->frame_num = (ring->frame_num + nb_tx) % frame_count; + ring->frame_num = (first_frame_num + nb_tx) % frame_count; + + if (nb_tx == 0 && SOCK_ERR_REPORT(send_errno)) { + __odp_errno = send_errno; + /* ENOBUFS indicates that the transmit queue is full, + * which will happen regularly when overloaded so don't + * print it */ + if (errno != ENOBUFS) + ODP_ERR("sendto(pkt mmap): %s\n", + strerror(send_errno)); + return -1; + } + } else { + /* Short send, return value is number of bytes sent so use this + * to determine number of complete frames sent. */ + for (n = 0; n < i && ret > 0; ++n) { + ret -= odp_packet_len(pkt_table[n]); + if (ret >= 0) + nb_tx++; + } - if (odp_unlikely(ret == -1 && - nb_tx == 0 && - SOCK_ERR_REPORT(send_errno))) { - __odp_errno = send_errno; - ODP_ERR("sendto(pkt mmap): %s\n", strerror(send_errno)); - return -1; + ring->frame_num = (first_frame_num + nb_tx) % frame_count; } for (i = 0; i < nb_tx; ++i) -- 2.1.1 _______________________________________________ lng-odp mailing list lng-odp@lists.linaro.org https://lists.linaro.org/mailman/listinfo/lng-odp