·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检验和计算相关推荐

  1. linux读取文件修改时间函数,Linux服务器编程之utime()函数修改文件存取时间

    Linux服务器编程之utime()函数修改文件存取时间 C语言utime()函数:修改文件的存取时间和更改时间 头文件: #include #include 定义函数: int utime(cons ...

  2. linux实现自己的write函数,Linux 内核源码阅读 - write 系统调用的实现

    最近在看write系统调用的实现,虽然还有一下细节不是很清楚,但是大致的实现机理还是有一定的理解了.总结如下: 这里假设最普通的情况,不考虑Direct IO 的情况.从全家的高度看,要往一个文件中写 ...

  3. Linux内核剖析-----IO复用函数epoll内核源码剖析

    本文参考董浩博客 http://donghao.org/uii/   epoll内核实现 (1)内核为epoll做准备工作 这个模块在内核初始化时(操作系统启动)注册了一个新的文件系统,叫" ...

  4. linux下通过字符串调用函数,linux中字符串转换函数 simple_strtoul

    转自 http://blog.csdn.net/tommy_wxie/article/details/7480087 Linux内核中提供的一些字符串转换函数: lib/vsprintf.c 1. u ...

  5. linux c数字转字符串函数,Linux常用C函数—字符串转换篇

    Linux 常用C 函数-字符串转换篇 atof (将字符串转换成浮点型数) 相关函数 atoi ,atol ,strtod ,strtol ,strtoul 定义函数 double atof(con ...

  6. linux下spi有哪些函数,linux下怎么快速的使用 SPI 驱动。

    ek_spi_devices 数组就在本文件内. /* * SPI devices. */ static struct spi_board_info ek_spi_devices[] = { #if ...

  7. linux c中字符替换函数,Linux C 支持正则表达式的字符串替换函数

    [root@localhost src]# cat a.c /** * Linux C 支持正则表达式的字符串替换函数 * * Author: cnscn@163.com * Homepage: ww ...

  8. linux进制转换的函数,Linux shell 进制转换

    源地址链接:http://blog.csdn.net/axdc_qa_team/article/details/6090182 既然有需要,就把搜到感觉有用的进制转换函数或指令都贴在这里,便于以后应用 ...

  9. linux获取机器cpuid地址函数,Linux下获取CPUID、硬盘序列号与MAC地址

    在很多系统软件的开发中,需要使用一些系统的唯一性信息.所以,得到主机的CPUID.硬盘序列号及网卡的MAC地址,就成个一件很重要的应用. 本人经过一番google即自己的钻研,基本上实现了这几个功能. ...

最新文章

  1. [一道搜狗输入法的面试题]C++转换构造函数和类型转换函数
  2. android左右旋转动画效果图,Android新姿势:3D翻转效果原理
  3. 基于VHDL报警系统设计
  4. POJ-1556 The Doors 线段相交+最短路
  5. 网红第一股上市首日暴跌37% “为人低调”王思聪评价:公司本身有问题
  6. merge语句_SQL Server MERGE语句概述和示例
  7. 开关电源模块并联供电系统_你了解UWE/F_S-1/3WR3系列小功率模块电源吗?
  8. CISCO 路由器(1)
  9. PyQt5,资源文件 .qrc 的使用
  10. 计算机系统时间无法更改,Win7电脑无法修改系统时间如何解决?
  11. Unity5.3官方VR教程重磅登场-系列4 VR中的用户界面
  12. win10双显卡开机黑屏时间长
  13. 超文本标签语言html的主要特点,福建教师招考整理:超文本标记语言(HTML)
  14. DHTML、XHMLT、HTML的区别
  15. Qt + libVlc
  16. 计算机常见故障 英语词汇,计算机常用英语词汇大全剖析.doc
  17. 【中科院】分子生物学-朱玉贤第四版-笔记-第13讲 原核生物表达调控
  18. 看电影用这个小程序,爆米花钱肯定给你省出来!
  19. SpringBoot 图片上传,预览与下载
  20. 包装大小与商品价格问题

热门文章

  1. 管程由哪三部分组成_黄蜀葵烘干机是由哪几个部分组成的
  2. VC2010运行C程序时黑框一闪就没
  3. JAVA增删查改的实现
  4. excel工具箱_WPS搬来救兵智能工具箱,强大到Excel没有还手之力
  5. java算法概述,Java数据结构与算法基础(一)概述与线性结构
  6. CRITIC法之python
  7. python动态爬取知乎_python爬虫从小白到高手 Day2 动态页面的爬取
  8. 微信公众平台服务器 反馈,微信公众号开发之大坑
  9. AMR无限增发代币至任意以太坊地址的漏洞利用及修复过程
  10. 表示探索、探究的几个词