如何在原始套接字上启用卸载

时间:2014-06-21 15:49:58

标签: c linux networking ethernet raw-sockets

我知道此问题之前一定有问题,但我找不到合适的解决方案。

我正在Ubuntu 12.04上编写一个C程序,它使用原始套接字发送TCP数据包。计算校验和非常耗时,因此我尝试将其卸载到我的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);
}   

我从一台PC发送了TCP数据包,并使用wireshark捕获连接到发送PC的另一台PC上的数据包。 Wireshark可以捕获所有数据包但不幸的是TCP校验和不正确 - 发送PC的NIC没有进行校验和计算。如果我将TCP校验和设置为0,则wireshark将看到校验和为0的数据包。

这很令人困惑,因为发送PC上的linux命令“ethtool -k eth0”显示tx offload已打开。

$ 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

有什么想法吗?谢谢!

1 个答案:

答案 0 :(得分:0)

为什么使用ETH_P_ALL ?,尝试将htons(8)用于ETH_P_IP,而代码中的另一个问题是您正在使用数据包系列,PF用于在设备驱动程序处发送/接收数据(OSI)第2层),如果你要使用Packet系列和RAW_SOCK,你需要自己生成每个单独的头,所以尝试按如下方式创建套接字实例:

; 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);

在这种情况下,您必须自己提供标头并为校验和提供有关tcp伪标头的研究并使用此函数进行计算

    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);
}
祝你好运:)