日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux内核udp校验和计算函数,Linux 内核IP和UDP检验和计算

發布時間:2025/3/15 linux 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux内核udp校验和计算函数,Linux 内核IP和UDP检验和计算 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

{

iph->check = 0;

iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);

}

·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 {

__wsum?????????????????????? csum;

struct {

__u16? csum_start;

__u16? csum_offset;

};

};

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)

{

const struct iphdr *iph = ip_hdr(skb);

if (uh->check == 0) {

skb->ip_summed = CHECKSUM_UNNECESSARY;

} else if (skb->ip_summed == CHECKSUM_COMPLETE) {

if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len,

proto, skb->csum))

skb->ip_summed = CHECKSUM_UNNECESSARY;

}

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 !skb_csum_unnecessary(skb) &&

{

sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));

if (likely(!sum)) {

if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))

netdev_rx_csum_fault(skb->dev);

skb->ip_summed = CHECKSUM_UNNECESSARY;

}

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層頭的校驗值。

(對于支持scatter and gather的報文必須要傳輸層頭在線性空間才能使用硬件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;

d

最后在dev_queue_xmit發送的時候發現設備不支持硬件checksum就會進行軟件計算

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

struct netdev_queue *txq)

{

/* If packet is not checksummed and device does not

* support checksumming for this protocol, complete

* checksumming here.

*/

if (skb->ip_summed == CHECKSUM_PARTIAL) {

skb_set_transport_header(skb,

skb_checksum_start_offset(skb));

if (!(features & NETIF_F_ALL_CSUM) &&

skb_checksum_help(skb))

goto out_kfree_skb;

}

}

總結

以上是生活随笔為你收集整理的linux内核udp校验和计算函数,Linux 内核IP和UDP检验和计算的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。