summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2015-10-10 19:41:32 -0600
committerSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>2015-10-12 10:56:09 -0600
commit7efed4e30259da5348c4a7c2c77a0d0d4b13834d (patch)
tree333d4e6a4a5f0d87f0a2110e24664cffcb9d5a03
parent35b34f09ab343ae8a75fcb9ff3cea180cf58992a (diff)
downloadandroid_external_android-clat-7efed4e30259da5348c4a7c2c77a0d0d4b13834d.tar.gz
android_external_android-clat-7efed4e30259da5348c4a7c2c77a0d0d4b13834d.tar.bz2
android_external_android-clat-7efed4e30259da5348c4a7c2c77a0d0d4b13834d.zip
clatd: Use the TUN_NOCHECKSUM flag for the tun device
This is needed to handle cases when the packet socket receives a GRO coalesced packet which will not have a valid TCP checksum. TUN_NOCHECKSUM is used only when the checksum has already been verified prior to this and GRO is being used. Change-Id: I1409967523152bb7620b4881526e78e8c222cc72
-rw-r--r--clatd.c3
-rw-r--r--config.h2
-rw-r--r--tun.c71
-rw-r--r--tun.h1
4 files changed, 77 insertions, 0 deletions
diff --git a/clatd.c b/clatd.c
index faeb679..ca21984 100644
--- a/clatd.c
+++ b/clatd.c
@@ -496,6 +496,9 @@ 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/config.h b/config.h
index e31a81d..82a91be 100644
--- a/config.h
+++ b/config.h
@@ -39,6 +39,8 @@ 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);
diff --git a/tun.c b/tun.c
index 49f0ea7..8068b2f 100644
--- a/tun.c
+++ b/tun.c
@@ -22,10 +22,14 @@
#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
*/
@@ -61,6 +65,11 @@ int tun_alloc(char *dev, int fd) {
return err;
}
strcpy(dev, ifr.ifr_name);
+
+ if (rx_checksum_offloaded) {
+ ioctl(fd, TUNSETNOCSUM, 1);
+ }
+
return 0;
}
@@ -87,3 +96,65 @@ 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) {
+ int fd;
+ struct ifreq ifr;
+ struct ethtool_value eval;
+
+ if (!dev){
+ return 0;
+ }
+
+ if(get_ethtool_feature_val(dev, ETHTOOL_GGRO) &&
+ get_ethtool_feature_val(dev, ETHTOOL_GRXCSUM)) {
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/tun.h b/tun.h
index bcdd10e..f1c41bf 100644
--- a/tun.h
+++ b/tun.h
@@ -33,5 +33,6 @@ 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