Linux 核心IP和UDP檢驗和計算

2021-06-19 22:20:44 字數 4239 閱讀 9830

·ip checksum a.

接收報文

struct iphdr *iph = ip_hdr(skb);

if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))

goto checksum_error;

b.傳送報文

ip_send_check(iph);

·udp checksum a.

網絡卡裝置屬性

#define netif_f_ip_csum     2   /* 基於ipv4的l4層

checksum. */  

#define netif_f_no_csum     4   /* 裝置可靠不需要l4層

checksum. loopack. */  

#define netif_f_hw_csum     8   /* 基於所有協議的l4層

checksum*/  

#define netif_f_ipv6_csum   16  /* 基於ipv6的l4層

checksum*/  

通過ethtool可以檢視網絡卡是否支援硬體checksum

ethtool -k eth0

offload parameters for eth0:

cannot get device rx csum settings: operation not supported

cannot get device udp large send offload settings: operation not supported

rx-checksumming: off

tx-checksumming: on

scatter-gather: on

tcp segmentation offload: off

udp fragmentation offload: off

generic segmentation offload: off

tx-checksumming: on  表明支援傳送hardware checksum。 b.

linux udp checksum

資料結構

union ;

};1)

skb->csum和skb->ip_summed這兩個域也是與4層校驗相關的,這兩個域的含義依賴於skb表示的是乙個輸入包還是乙個輸出包。 2)

當網絡卡裝置能提供硬體checksum並且作為輸出包的時候,表示為skb-> csum_start和skb-> csum_offset

csum_start: offset from skb->head where checksumming should start

csum_offset: offset from csum_start where checksum should be stored

當資料報是乙個輸入包時

skb->ip_summed表示的是四層校驗的狀態,下面的幾個巨集定義表示了裝置驅動傳遞給4層的一些資訊。

#define checksum_none 0  

#define checksum_unnecessary 1  

#define checksum_complete 2  

skb->csum:存放硬體或者軟體計算的payload的checksum不包括偽頭,但是是否有意義由skb->ip_summed的值決定。

checksum_none表示csum域中的校驗值是無意義的,需要l4層自己校驗payload和偽頭。有可能是硬體檢驗出錯或者硬體沒有校驗功能,協議棧軟體更改如pskb_trim_rcsum函式。

checksum_unnecessary表示網絡卡或者協議棧已經計算和驗證了l4層的頭和校驗值。也就是計算了tcp udp的偽頭。還有一種情況就是回環,因為在回環中錯誤發生的概率太低了,因此就不需要計算校驗來節省cpu事件。

checksum_complete表示網絡卡已經計算了l4層payload的校驗,並且csum已經被賦值,此時l4層的接收者只需要加偽頭並驗證校驗結果。 1)

在l4層發現如果udp->check位段被設為0,那麼skb->ip_summed直接設為checksum_unnecessary,放行該報文。

2)   如果skb->ip_summed為checksum_complete,則把skb->csum加上偽頭進行校驗,成功則將skb->ip_summed設為checksum_unnecessary,

放行該資料報。

3)   通過上述後skb->ip_summed還不是checksum_unnecessary,那麼重新計算偽頭賦給skb->csum。

4)    將還不是checksum_unnecessary的資料報文的payload加上skb->csum進行checksum計算,成功將設為checksum_unnecessary並放行,失敗則丟棄。

udp4_csum_init(skb, uh, proto)

else if (skb->ip_summed == checksum_complete)

if (!skb_csum_unnecessary(skb))

skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,

skb->len, proto, 0); }

if (udp_lib_checksum_complete(skb))

goto csum_error;

static inline int udp_lib_checksum_complete(struct sk_buff *skb)

return sum; }

} 當資料報是輸出包時

skb->csum表示為csum_start和csum_offset,它表示硬體網絡卡存放將要計算的校驗值的位址,和最後填充的便宜。這個域在輸出包時使用,只在校驗值在硬體計算的情況下才對於網絡卡真正有意義。硬體checksum功能只能用於非分片報文。

而此時ip_summed可以被設定的值有下面兩種:

#define checksum_none       0  

#define checksum_partial 3

checksum_none 表示協議棧計算好了校驗值,裝置不需要做任何事。checksum_partial表示協議棧算好了偽頭需要硬體計算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指向傳輸層頭

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 ,l4層的偽頭的校驗已經完畢,並且已經加入uh->check欄位中,此時只需要裝置計算整個頭4層頭的校驗值。

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;

d最後在dev_queue_xmit傳送的時候發現裝置不支援硬體checksum就會進行軟體計算

int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,

struct netdev_queue *txq)

}

Ip 首部檢驗和字段

ip icmp igmp tcp udp等協議的校驗和演算法都是相同的,演算法如下 在傳送資料時,為了計算數ip據報的校驗和。應該按如下步驟 1 把ip資料報的首部都置為0,包括校驗和字段。2 把首部看成以16位為單位的數字組成,依次進行二進位制反碼求和。3 把得到的結果存入校驗和字段中。在接收資料...

IP首部檢驗和計算

計算ip首部檢驗和 如上圖,計算?是多少?計算 從08 00之後開始計算到後面的08 00即 兩個位元組的相加 45 00 00 20 d5 56 00 00 80 01 de b7 45 5d c0 a8 00 dc 等於 3800f 然後溢位的再次加到後面即 800f 3 等於 8012 最後用...

UDP報文段和其檢驗和小結

如圖所示 tcp首部行開銷為20位元組而udp則為8位元組,所以udp分組首部開銷更小。文件為 rfc 1071 從上圖的報文段結構我們知道每個首部欄位為16位元。現在假設源埠號 目的埠號和長度字段三個16位元字分別為 源埠號 0110 0110 0110 0000 十進位制 26208 目的埠號 ...