calculate IP/TCP/UDP checsum
简单来说,就是对要计算的数据,以16bit为单元进行累加,然后取反。
TCP收包时,检查校验和:
static __sum16 tcp_v4_checksum_init(struct sk_buff *skb)
{
const struct iphdr *iph = ip_hdr(skb);
if (skb->ip_summed == CHECKSUM_COMPLETE) {
if (!tcp_v4_check(skb->len, iph->saddr, ///check TCP/UDP pseudo-header checksum
iph->daddr, skb->csum)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
return 0;
}
}
skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
skb->len, IPPROTO_TCP, 0); ///calc pseudo header checksum
if (skb->len <= 76) {
return __skb_checksum_complete(skb); /// 基于伪头累加和,计算整个数据包的checksum
}
return 0;
}
csum_tcpudp_nofold用于计算伪头的checksum,__skb_checksum_complete基于伪头累加和(skb->csum)计算整个skb的校验和。
net_device->features
net_device->features字段表示设备的各种特性。其中一些位用于表示硬件校验和的计算能力:
#define NETIF_F_IP_CSUM__NETIF_F(HW_CSUM)
#define NETIF_F_IP_CSUM__NETIF_F(IP_CSUM) ///ipv4 + TCP/UDP
#define NETIF_F_IPV6_CSUM__NETIF_F(IPV6_CSUM)
NETIF_F_IP_CSUM表示硬件可以计算L4 checksum,但是只针对IPV4的TCP和UDP。但是一些设备扩展支持VXLAN和NVGRE。
NETIF_F_IP_CSUM是一种协议感知的计算checksum的方法。具体来说,上层提供两个CSUM的参数(csum_start和csum_offset)。
NETIF_F_HW_CSUM is a protocol agnostic method to offload the transmit checksum. In this method the host
provides checksum related parameters in a transmit descriptor for a packet. These parameters include the
starting offset of data to checksum and the offset in the packet where the computed checksum is to be written. The
length of data to checksum is implicitly the length of the packet minus the starting offset.
值得一提的是,igb/ixgbe使用的NETIF_F_IP_CSUM.
sk_buff
取决于skb是接收封包,还是发送封包,skb->csum和skb->ip_summed的意义会不同。
/*
*@csum: Checksum (must incl