summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Luke <chrisy@flirble.org>2016-05-23 21:30:26 -0400
committerDamjan Marion <damarion@cisco.com>2016-05-28 16:34:39 +0000
commit4b46c84901b6ea393a5118d7835d77aa6b3cef58 (patch)
treebf3904f56a3c4098ddc32b2a25df8d84bb621a10
parent1220afe52a03936c3d81c0e7e2e771f06dd04c25 (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.c2
-rw-r--r--vnet/vnet/devices/af_packet/device.c39
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;