UDP checksum可以分為四個部分

1. Pseudo Header

2. UDP Header

3. UDP Data

4. Padding

通常新式的網卡都會支援計算udp checksum

可以透過ethtool -k 網卡名稱檢查

而在Linux kernel Layer4中有定義在接收或送出packet時用到的幾個macro

  • 接收packet

skb->ip_summed是判斷是否計算checksum的重點,可決定skb->csum帶的pseudo header的checksum值是否有意義,又可分為下列幾種macro的情況

#define CHECKSUM_NONE 0  

#define CHECKSUM_UNNECESSARY 1  

#define CHECKSUM_COMPLETE 2  

CHECKSUM_NONE表示csum代表的值無意義,需要kernel中Layer4自行計算。有可能是硬體計算出錯或是硬體不支援計算功能

CHECKSUM_UNNECESSARY表示網卡或protocol stack已經計算了checksum值。

CHECKSUM_COMPLETE表示網卡已經計算了Layer4 payload的驗算,並且已經塞到csum中,此时Layer4的接收者只需要加pseudo header並驗算结果。

下面是步驟

1 Layer4發現如果udp->check被設為0,那麼skb->ip_summed直接設為CHECKSUM_UNNECESSARY,放行packet。

2)   如果skb->ip_summed為CHECKSUM_COMPLETE,則把skb->csum加上pseudo header進行驗算,成功則將skb->ip_summed設為CHECKSUM_UNNECESSARY 放行該packet。

3)   通過上述後skb->ip_summed還不是CHECKSUM_UNNECESSARY,那麼重新計算pseudo header给skb->csum

4)   將還不是CHECKSUM_UNNECESSARY的packet的payload加上skb->csum進checksum計算,成功將設為CHECKSUM_UNNECESSARY並放行,失敗則丟棄

  • 送出packet

ip->summed有下列兩種可能

#define CHECKSUM_NONE      0  

#define CHECKSUM_PARTIAL  3

CHECKSUM_NONE 表示protocol stack計算好了checksum,網卡不需要做任何事。CHECKSUM_PARTIAL表示protocol stack算好了pseudo header需要網卡計算payload checksum

下面是步驟

 

1)對於UDP socket開啟UDP_CSUM_NOXMIT /* UDP csum disabled */

 uh->check = 0

skb->ip_summed = CHECKSUM_NONE;

 

2)軟體udp checksum

struct iphdr *iph = ip_hdr(skb);

struct udphdr *uh = udp_hdr(skb);

uh->check = 0;                                     

skb->csum = csum_partial(skb_transport_header (skb), skb->len, 0); //skb->data指向transport layer header

uh->check = csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, iph->protocol, skb->csum);

skb->ip_summed = CHECKSUM_NONE;

//Todo: scatter and gather

 

3)  硬體checksum: 只能是ip报文長度小於mtu的数据报(没有分片的报文)

CHECKSUM_PARTIAL表示使用網卡checksum Layer4的pseudo header的驗算已經完成,並且已經加入uh->check中,此时只需要硬體計算剩下的部分

(對於支援scatter and gather的报文必須要transport header在線性空間才能使用硬體checksum功能)

uh->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, IPPROTO_UDP, 0);

skb->csum_start = skb_transport_header (skb) - skb->head;

skb->csum_offset = offsetof(struct udphdr, check);

skb->ip_summed = CHECKSUM_PARTIAL;

 

4) 最後在dev_queue_xmit發送的时候發現網卡不支援硬體checksum就會進行軟體運算

ref : http://wenx05124561.blog.163.com/blog/static/124000805201242032041268/

arrow
arrow
    文章標籤
    UDP Linux
    全站熱搜

    w180112 發表在 痞客邦 留言(0) 人氣()