diff options
-rw-r--r-- | clatd.c | 5 | ||||
-rw-r--r-- | clatd_test.cpp | 3 | ||||
-rw-r--r-- | config.h | 2 | ||||
-rw-r--r-- | ring.c | 12 | ||||
-rw-r--r-- | ring.h | 3 | ||||
-rw-r--r-- | translate.c | 9 | ||||
-rw-r--r-- | translate.h | 4 | ||||
-rw-r--r-- | tun.c | 67 | ||||
-rw-r--r-- | tun.h | 1 |
9 files changed, 24 insertions, 82 deletions
@@ -364,7 +364,7 @@ void read_packet(int read_fd, int write_fd, int to_ipv6) { packet = (uint8_t *) (tun_header + 1); readlen -= sizeof(*tun_header); - translate_packet(write_fd, to_ipv6, packet, readlen); + translate_packet(write_fd, to_ipv6, packet, readlen, TP_CSUM_NONE); } /* function: event_loop @@ -496,9 +496,6 @@ int main(int argc, char **argv) { // run under a regular user drop_root(); - //check HW features and disable checksum validation if already handled by hardware - rx_checksum_offloaded = check_csum_offload(uplink_interface); - // we can create tun devices as non-root because we're in the VPN group. tunnel.fd4 = tun_open(); if(tunnel.fd4 < 0) { diff --git a/clatd_test.cpp b/clatd_test.cpp index 7e218f0..6e374d2 100644 --- a/clatd_test.cpp +++ b/clatd_test.cpp @@ -30,6 +30,7 @@ extern "C" { #include "translate.h" #include "config.h" #include "clatd.h" +#include "ring.h" } // For convenience. @@ -456,7 +457,7 @@ void do_translate_packet(const uint8_t *original, size_t original_len, uint8_t * break; } - translate_packet(write_fd, (version == 4), original, original_len); + translate_packet(write_fd, (version == 4), original, original_len, TP_CSUM_NONE); snprintf(foo, sizeof(foo), "%s: Invalid translated packet", msg); if (version == 6) { @@ -39,8 +39,6 @@ struct clat_config { extern struct clat_config Global_Clatd_Config; -extern int rx_checksum_offloaded; - int read_config(const char *file, const char *uplink_interface, const char *plat_prefix, unsigned net_id); void config_generate_local_ipv6_subnet(struct in6_addr *interface_ip); @@ -117,9 +117,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); } @@ -42,6 +42,9 @@ struct tun_data; // results in 656 frames (1048576 bytes). #define TP_NUM_BLOCKS 16 +#define TP_CSUM_NONE (0) +#define TP_CSUM_UNNECESSARY (1) + struct packet_ring { uint8_t *base; struct tpacket2_hdr *next; diff --git a/translate.c b/translate.c index ddc9bac..bce9270 100644 --- a/translate.c +++ b/translate.c @@ -108,8 +108,8 @@ struct in6_addr ipv4_addr_to_ipv6_addr(uint32_t addr4) { * tun_header - tunnel header, already allocated * proto - ethernet protocol id: ETH_P_IP(ipv4) or ETH_P_IPV6(ipv6) */ -void fill_tun_header(struct tun_pi *tun_header, uint16_t proto) { - tun_header->flags = 0; +void fill_tun_header(struct tun_pi *tun_header, uint16_t proto, uint16_t skip_csum) { + tun_header->flags = htons(skip_csum); tun_header->proto = htons(proto); } @@ -491,8 +491,9 @@ void send_rawv6(int fd, clat_packet out, int iov_len) { * to_ipv6 - true if translating to ipv6, false if translating to ipv4 * packet - packet * packetsize - size of packet + * skip_csum - true if kernel has to skip checksum validation, false if it has to validate checksum. */ -void translate_packet(int fd, int to_ipv6, const uint8_t *packet, size_t packetsize) { +void translate_packet(int fd, int to_ipv6, const uint8_t *packet, size_t packetsize, uint16_t skip_csum) { int iov_len = 0; // Allocate buffers for all packet headers. @@ -524,7 +525,7 @@ void translate_packet(int fd, int to_ipv6, const uint8_t *packet, size_t packets } else { iov_len = ipv6_packet(out, CLAT_POS_IPHDR, packet, packetsize); if (iov_len > 0) { - fill_tun_header(&tun_targ, ETH_P_IP); + fill_tun_header(&tun_targ, ETH_P_IP, skip_csum); out[CLAT_POS_TUNHDR].iov_len = sizeof(tun_targ); send_tun(fd, out, iov_len); } diff --git a/translate.h b/translate.h index aa8b736..3c249eb 100644 --- a/translate.h +++ b/translate.h @@ -42,14 +42,14 @@ uint16_t packet_length(clat_packet packet, clat_packet_index pos); int is_in_plat_subnet(const struct in6_addr *addr6); // Functions to create tun, IPv4, and IPv6 headers. -void fill_tun_header(struct tun_pi *tun_header, uint16_t proto); +void fill_tun_header(struct tun_pi *tun_header, uint16_t proto, uint16_t skip_csum); void fill_ip_header(struct iphdr *ip_targ, uint16_t payload_len, uint8_t protocol, const struct ip6_hdr *old_header); void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol, const struct iphdr *old_header); // Translate and send packets. -void translate_packet(int fd, int to_ipv6, const uint8_t *packet, size_t packetsize); +void translate_packet(int fd, int to_ipv6, const uint8_t *packet, size_t packetsize, uint16_t skip_csum); // Translate IPv4 and IPv6 packets. int ipv4_packet(clat_packet out, clat_packet_index pos, const uint8_t *packet, size_t len); @@ -22,14 +22,10 @@ #include <linux/if.h> #include <linux/if_tun.h> #include <sys/ioctl.h> -#include <linux/ethtool.h> #include <sys/uio.h> -#include "config.h" #include "clatd.h" -int rx_checksum_offloaded = 0; - /* function: tun_open * tries to open the tunnel device */ @@ -65,11 +61,6 @@ int tun_alloc(char *dev, int fd) { return err; } strcpy(dev, ifr.ifr_name); - - if (rx_checksum_offloaded) { - ioctl(fd, TUNSETNOCSUM, 1); - } - return 0; } @@ -96,61 +87,3 @@ int set_nonblocking(int fd) { int send_tun(int fd, clat_packet out, int iov_len) { return writev(fd, out, iov_len); } - -/* function: get_ethtool_feature_val - * gets if a particular ethtool feature is enabled - * dev - the device name to query the feature on - * cmd - the feature to query - * returns: 1 if feature is enabled, 0 if disabled - */ -int get_ethtool_feature_val(char *dev, int cmd) { - int fd; - struct ifreq ifr; - struct ethtool_value eval; - - if (!dev){ - return 0; - } - - if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { - return 0; - } - - memset(&ifr, 0, sizeof(ifr)); - memset(&eval, 0, sizeof(eval)); - strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); - eval.cmd = cmd; - eval.data = 0; - ifr.ifr_data = (caddr_t)&eval; - if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) { - close(fd); - return 0; - } - - close(fd); - - if (!eval.data) { - return 0; - } - - return 1; -} - -/* function: check_csum_offload - * checks if GRO and RXCSUM are enabled on the device - * dev - the device name to query on - * returns: 1 if checksum is offloaded, 0 if checksum needs - * to be validated in network stack. - */ -int check_csum_offload(char *dev) { - if (!dev){ - return 0; - } - - if(get_ethtool_feature_val(dev, ETHTOOL_GGRO) && - get_ethtool_feature_val(dev, ETHTOOL_GRXCSUM)) { - return 1; - } - - return 0; -} @@ -33,6 +33,5 @@ int tun_open(); int tun_alloc(char *dev, int fd); int send_tun(int fd, clat_packet out, int iov_len); int set_nonblocking(int fd); -int check_csum_offload(char *dev); #endif |