简体   繁体   中英

How to enable offloading on raw socket

I know this question must have been asked before, but I can't find a good solution to it.

I am writing a C program on Ubuntu 12.04 that uses a raw sockets to send TCP packets. Calculating checksum is time-consuming so I tried to offload it to my NIC.

struct sockaddr intfAddr
rawSock = socket(AF_INET,SOCK_PACKET,htons(3)); //ETH_P_ALL = 3
if (rawSock == -1) { perror("failed to create raw socket");  exit(-1); }
memset(&intfAddr, 0, sizeof (struct sockaddr));
intfAddr.sa_family = AF_INET;
strcpy(intfAddrs.sa_data,  "eth0"); 
system("ifconfig eth0 promisc);
//sprintf(cmd, "ethtool -K %s rx off", intfName);   system(cmd);
if (bind(rawSock, (struct sockaddr *)&intfAddr, sizeof(intfAddrs[intf])) == -1) {
    perror("failed to bind"); exit(-1);
}   

I sent the TCP packets from one PC and used wireshark to capture the packets on another PC that's connected to the sending PC. Wireshark can capture all the packets but unfortunately TCP checksum is not correct -- the sending PC's NIC didn't do the checksum calculation. If I set packets with TCP checksum being 0, the wireshark will see the packets with checksum being 0.

This is confusing since the linux command "ethtool -k eth0" on the sending PC shows that tx offload is on.

$ ethtool -k eth0
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: off
tcp-segmentation-offload: off
udp-fragmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off

Any ideas? Thanks!

Why are you using the ETH_P_ALL?, try to use htons(8) for ETH_P_IP, and another problem in your code is that you are using the packet family, PF is used to send/receive data at the device driver (OSI layer 2), if you are going to use Packet family along with RAW_SOCK you need to generate each single header yourself, so try to create the socket instance as follows :

; IP header would be provided by the kernel
int s = socket (AF_INET, SOCK_RAW, IPPROTO_TCP);
; if you wanna use the Packet Family, do the following
sd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);

In this case you have to provide headers yourself and for the checksum, do a reseach about tcp pseudo header and use this function to calculate it

    unsigned short csum(unsigned short *buf, int nwords)
{       //
        unsigned long sum;
        for(sum=0; nwords>0; nwords--)
                sum += *buf++;
        sum = (sum >> 16) + (sum &0xffff);
        sum += (sum >> 16);
        return (unsigned short)(~sum);
}

good luck :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM