diff options
Diffstat (limited to 'ring.c')
| -rw-r--r-- | ring.c | 14 |
1 files changed, 13 insertions, 1 deletions
@@ -29,6 +29,8 @@ #include "translate.h" #include "tun.h" +#define TP_STATUS_CSUM_UNNECESSARY (1 << 7) + int ring_create(struct tun_data *tunnel) { int packetsock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); if (packetsock < 0) { @@ -117,9 +119,19 @@ static struct tpacket2_hdr* ring_advance(struct packet_ring *ring) { */ void ring_read(struct packet_ring *ring, int write_fd, int to_ipv6) { struct tpacket2_hdr *tp = ring->next; + uint16_t val = TP_CSUM_NONE; if (tp->tp_status & TP_STATUS_USER) { + //We expect only GRO coalesced packets to have TP_STATUS_CSUMNOTREADY + //(ip_summed = CHECKSUM_PARTIAL) in this path. Note that these packets have already gone + //through checksum validation in GRO engine. CHECKSUM_PARTIAL is defined to be 3 while + //CHECKSUM_UNNECESSARY is defined to be 1. + //Kernel only checks for CHECKSUM_UNNECESSARY (TP_CSUM_UNNECESSARY) bit while processing a + //packet, so its ok to pass only this bit rather than the full ip_summed field. + if ((tp->tp_status & TP_STATUS_CSUMNOTREADY) || (tp->tp_status & TP_STATUS_CSUM_UNNECESSARY)) { + val = TP_CSUM_UNNECESSARY; + } uint8_t *packet = ((uint8_t *) tp) + tp->tp_net; - translate_packet(write_fd, to_ipv6, packet, tp->tp_len); + translate_packet(write_fd, to_ipv6, packet, tp->tp_len, val); tp->tp_status = TP_STATUS_KERNEL; tp = ring_advance(ring); } |
