in drivers/vector_kern.c [958:1045]
static int vector_mmsg_rx(struct vector_private *vp)
{
int packet_count, i;
struct vector_queue *qi = vp->rx_queue;
struct sk_buff *skb;
struct mmsghdr *mmsg_vector = qi->mmsg_vector;
void **skbuff_vector = qi->skbuff_vector;
int header_check;
/* Refresh the vector and make sure it is with new skbs and the
* iovs are updated to point to them.
*/
prep_queue_for_rx(qi);
/* Fire the Lazy Gun - get as many packets as we can in one go. */
packet_count = uml_vector_recvmmsg(
vp->fds->rx_fd, qi->mmsg_vector, qi->max_depth, 0);
if (packet_count < 0)
vp->in_error = true;
if (packet_count <= 0)
return packet_count;
/* We treat packet processing as enqueue, buffer refresh as dequeue
* The queue_depth tells us how many buffers have been used and how
* many do we need to prep the next time prep_queue_for_rx() is called.
*/
qi->queue_depth = packet_count;
for (i = 0; i < packet_count; i++) {
skb = (*skbuff_vector);
if (mmsg_vector->msg_len > vp->header_size) {
if (vp->header_size > 0) {
header_check = vp->verify_header(
mmsg_vector->msg_hdr.msg_iov->iov_base,
skb,
vp
);
if (header_check < 0) {
/* Overlay header failed to verify - discard.
* We can actually keep this skb and reuse it,
* but that will make the prep logic too
* complex.
*/
dev_kfree_skb_irq(skb);
vp->estats.rx_encaps_errors++;
continue;
}
if (header_check > 0) {
vp->estats.rx_csum_offload_good++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
}
pskb_trim(skb,
mmsg_vector->msg_len - vp->rx_header_size);
skb->protocol = eth_type_trans(skb, skb->dev);
/*
* We do not need to lock on updating stats here
* The interrupt loop is non-reentrant.
*/
vp->dev->stats.rx_bytes += skb->len;
vp->dev->stats.rx_packets++;
netif_rx(skb);
} else {
/* Overlay header too short to do anything - discard.
* We can actually keep this skb and reuse it,
* but that will make the prep logic too complex.
*/
if (skb != NULL)
dev_kfree_skb_irq(skb);
}
(*skbuff_vector) = NULL;
/* Move to the next buffer element */
mmsg_vector++;
skbuff_vector++;
}
if (packet_count > 0) {
if (vp->estats.rx_queue_max < packet_count)
vp->estats.rx_queue_max = packet_count;
vp->estats.rx_queue_running_average =
(vp->estats.rx_queue_running_average + packet_count) >> 1;
}
return packet_count;
}