diff options
author | Chris Luke <chrisy@flirble.org> | 2016-05-23 21:30:26 -0400 |
---|---|---|
committer | Damjan Marion <damarion@cisco.com> | 2016-05-28 16:34:39 +0000 |
commit | 4b46c84901b6ea393a5118d7835d77aa6b3cef58 (patch) | |
tree | bf3904f56a3c4098ddc32b2a25df8d84bb621a10 | |
parent | 1220afe52a03936c3d81c0e7e2e771f06dd04c25 (diff) |
VPP-84 af_packet retry on EAGAIN, count on errors
When af_packet signals the kernel that there are packets in the tx
ring with sendto() the kernel sometimes responds with EAGAIN.
Previously the af_packet driver would treat any error from sendto()
as fatal.
Whilst there's not much we can do about this, count the errors
and let's try to not die on the spot or sit in a loop forever.
Change-Id: Id76ba5e07b744f1ed6f348ec838a1ac506a381c9
Signed-off-by: Chris Luke <chrisy@flirble.org>
-rw-r--r-- | vnet/vnet/devices/af_packet/af_packet.c | 2 | ||||
-rw-r--r-- | vnet/vnet/devices/af_packet/device.c | 39 |
2 files changed, 32 insertions, 9 deletions
diff --git a/vnet/vnet/devices/af_packet/af_packet.c b/vnet/vnet/devices/af_packet/af_packet.c index b41eaf3ba82..e3ed3857982 100644 --- a/vnet/vnet/devices/af_packet/af_packet.c +++ b/vnet/vnet/devices/af_packet/af_packet.c @@ -115,7 +115,7 @@ create_packet_v2_sock(u8 * name, tpacket_req_t * rx_req, tpacket_req_t * tx_req, int opt = 1; if ((err = setsockopt(*fd, SOL_PACKET, PACKET_LOSS, &opt, sizeof(opt))) < 0) { - DBG_SOCK("Failed to set rx packet interface version"); + DBG_SOCK("Failed to set packet tx ring error handling option"); ret = VNET_API_ERROR_SYSCALL_ERROR_1; goto error; } diff --git a/vnet/vnet/devices/af_packet/device.c b/vnet/vnet/devices/af_packet/device.c index 0671d9e247d..f572632ce37 100644 --- a/vnet/vnet/devices/af_packet/device.c +++ b/vnet/vnet/devices/af_packet/device.c @@ -26,8 +26,11 @@ #include <vnet/devices/af_packet/af_packet.h> -#define foreach_af_packet_tx_func_error \ -_(FRAME_NOT_READY, "tx frame not ready") +#define foreach_af_packet_tx_func_error \ +_(FRAME_NOT_READY, "tx frame not ready") \ +_(TXRING_EAGAIN, "tx sendto temporary failure") \ +_(TXRING_FATAL, "tx sendto fatal failure") \ +_(TXRING_OVERRUN, "tx ring overrun") typedef enum { #define _(f,s) AF_PACKET_TX_ERROR_##f, @@ -96,7 +99,7 @@ af_packet_interface_tx (vlib_main_t * vm, tph = (struct tpacket2_hdr *) (block_start + tx_frame * frame_size); - if(tph->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING)) + if (PREDICT_FALSE(tph->tp_status & (TP_STATUS_SEND_REQUEST | TP_STATUS_SENDING))) { frame_not_ready++; goto next; @@ -116,21 +119,41 @@ af_packet_interface_tx (vlib_main_t * vm, tph->tp_status = TP_STATUS_SEND_REQUEST; n_sent++; next: + /* check if we've exhausted the ring */ + if (PREDICT_FALSE(frame_not_ready + n_sent == frame_num)) + break; + tx_frame = (tx_frame + 1) % frame_num; } CLIB_MEMORY_BARRIER(); - if (n_sent) + if (PREDICT_TRUE(n_sent)) { apif->next_tx_frame = tx_frame; - if (sendto(apif->fd, NULL, 0, MSG_DONTWAIT, NULL, 0) == -1) - clib_unix_error("tx sendto failure"); + + if (PREDICT_FALSE(sendto(apif->fd, NULL, 0, + MSG_DONTWAIT, NULL, 0) == -1)) + { + /* Uh-oh, drop & move on, but count whether it was fatal or not. + * Note that we have no reliable way to properly determine the + * disposition of the packets we just enqueued for delivery. + */ + vlib_error_count (vm, node->node_index, + unix_error_is_fatal(errno) ? + AF_PACKET_TX_ERROR_TXRING_FATAL : + AF_PACKET_TX_ERROR_TXRING_EAGAIN, + n_sent); + } } - if (frame_not_ready) + if (PREDICT_FALSE(frame_not_ready)) vlib_error_count (vm, node->node_index, AF_PACKET_TX_ERROR_FRAME_NOT_READY, - frame_not_ready); + frame_not_ready); + + if (PREDICT_FALSE(frame_not_ready + n_sent == frame_num)) + vlib_error_count (vm, node->node_index, AF_PACKET_TX_ERROR_TXRING_OVERRUN, + n_left); vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors); return frame->n_vectors; |