Linux协议栈实现分析
linux 协议栈 udp checksum校验

linux 协议栈 udp checksum校验UDP(用户数据报协议)是一种无连接的传输层协议,它提供了面向事务的简单数据传输服务。
UDP在IP(Internet协议)之上工作,负责将数据通过网络传输到目标地址。
在传输数据时,UDP协议栈会使用校验和(checksum)来保证数据的完整性。
校验和是一种简单的错误检测机制,用于检测在数据传输过程中是否有任何错误发生。
UDP协议栈使用校验和来验证接收到的数据是否与发送时的数据相同,以确保数据的完整性。
校验和的计算方法是通过对数据报的每个16位字进行二进制求和,并取其反码作为校验和的值。
当数据传输到接收端时,接收端会重新计算接收到的数据的校验和,并将计算结果与接收到的校验和进行比较,以确认数据的完整性。
UDP协议栈的校验和机制有助于提高数据传输的可靠性。
通过校验和,可以在传输过程中检测到数据是否被篡改、丢失或者损坏。
如果接收端计算出的校验和与接收到的校验和不匹配,那么接收端就会知道数据在传输过程中发生了错误,并且可以通知发送端重新发送数据。
UDP的校验和机制虽然可以检测出大部分的传输错误,但并不能保证100%的数据完整性。
由于校验和的计算相对简单,可能会有一些错误情况导致校验和校验通过,但实际数据却已经发生了错误。
这是因为校验和仅仅是一种简单的错误检测机制,无法恢复数据或者纠正错误。
除了校验和之外,UDP并没有提供其他的错误检测和纠正机制。
相比于TCP(传输控制协议),UDP的设计更加简单和灵活,但也更加容易发生数据损坏或丢失的问题。
因此,在使用UDP进行数据传输时,通常需要对数据进行额外的校验和验证,以确保数据的可靠性。
总结起来,UDP协议栈在数据传输过程中使用校验和机制来保证数据的完整性。
它通过计算发送数据的校验和,并将其附加在数据报中。
接收端在接收到数据时,会重新计算接收到的数据的校验和,并与接收到的校验和进行比较,以确认数据的完整性。
尽管校验和机制能够检测大部分的传输错误,但并不能保证100%的数据完整性,因此在使用UDP传输数据时,需要额外的错误检测和纠正机制来提高数据传输的可靠性。
linux内核堆栈解析方法

在 Linux 系统中,内核堆栈(kernel stack)用于执行内核代码。
当发生操作系统内核崩溃、内核出现异常或需要调试时,理解和分析内核堆栈十分重要。
以下是分析 Linux 内核堆栈的常用方法:使用dmesg:当内核发生故障时,错误信息和堆栈追踪通常会输出到内核日志。
你可以使用 dmesg 命令查看内核日志中的堆栈追踪。
dmesg | grep -i stack操作系统崩溃时的系统日志:有时通过分析内核崩溃时的系统日志(如/var/log/syslog 或/var/log/messages、/var/log/kern.log)也可以找到有关堆栈信息。
使用 dump_stack() 函数:在内核代码中,你可以使用 dump_stack() 函数打印当前线程的堆栈信息。
这在调试内核代码时非常有用。
系统核心转储(Core Dump):内核崩溃时,操作系统有时会生成系统核心转储文件。
你可以使用 GNU Debugger(GDB)来分析内核转储文件。
首先,安装 Linux 的调试符号表(debugging symbols),然后使用 gdb 命令加载符号表和内核转储文件,最后使用 bt(backtrace)命令查看堆栈追踪。
gdb path/to/vmlinux path/to/core_dump(gdb) bt请注意,要使内核生成核心转储文件,需要正确配置内核。
具体配置方法取决于你所使用的 Linux 发行版。
内核调试器(如 KGDB 和 KDB):如果你正在研究内核问题,可以使用内核调试器 KGDB 或 KDB。
KGDB 是基于 GDB 的内核调试器,可以在源代码级别进行调试。
KDB 则是一个基于文本的内核调试器。
使用这些工具,你可以从内核级别设置断点、单步执行代码、检查内存内容和调用堆栈等。
通过以上方法可以帮助你分析 Linux 内核堆栈。
如何选择最佳方法取决于你的具体需求和问题。
在进行内核调试之前,请确保熟悉 Linux 操作系统和内核开发的基本知识。
linux 协议栈

linux 协议栈Linux协议栈,又称网络协议栈,是指在Linux操作系统中负责处理网络通信传输的一系列协议和软件集合。
它是实现网络通信的核心组件,负责在应用层和网络硬件之间进行数据传输和信息处理。
Linux协议栈由多个协议层组成,包括物理层、数据链路层、网络层、传输层和应用层。
物理层负责将数据从高层转化为物理信号进行传送,而数据链路层负责将数据在网络间的传递过程中进行帧的封装和解封装,以及网卡的驱动程序。
网络层则负责寻址和路由功能,传输层实现了可靠的端到端通信,应用层提供了各种网络服务。
在物理层的硬件设备中,网络接口卡(NIC)是协议栈与外部网络通信的接口。
协议栈通过驱动程序与NIC进行交互,将数据封装成数据包,并通过数据链路层将数据发往目的地。
在数据链路层,协议栈通过各种链路层协议(如以太网协议)进行数据帧的封装和解封装。
网络层则根据不同的网络协议(如IP协议)进行寻址和路由,将数据从源主机传送到目的主机。
传输层通过传输协议(如TCP或UDP)实现端到端的可靠数据传输。
而应用层则提供了各种网络服务,如HTTP、FTP、DNS等。
Linux协议栈的优点在于其开放源代码的特性和丰富的功能。
由于其开源的特性,用户可以自由地进行定制和修改。
并且,Linux协议栈支持多种网络协议和服务,如IP、TCP、UDP、FTP等。
这使得Linux操作系统具有很高的灵活性和可扩展性,能够满足不同的用户需求。
另外,由于众多开发者的贡献和不断的更新迭代,Linux协议栈也具有较高的稳定性和安全性。
然而,Linux协议栈也存在一些挑战和问题。
对于一些特殊的应用场景和网络需求,Linux协议栈可能无法提供最佳的性能和效果。
此外,在网络安全方面,由于Linux协议栈的复杂性和开放性,也面临着一些潜在的安全风险和漏洞。
总的来说,Linux协议栈是Linux操作系统中的重要组件,负责处理网络通信传输。
它由多个协议层组成,实现了从物理层到应用层的数据传输和处理。
嵌入式Linux学习笔记(五)通讯协议制定和下位机代码实现

嵌⼊式Linux学习笔记(五)通讯协议制定和下位机代码实现⽬录 通讯协议可以理解为约束多设备通讯的⼀套规则,像Modbus,TCP/IP, BLE都是在⽣产⽣活常⽤的协议。
不过协议落实到实际应⽤后,就可以理解为对数据的结构化处理,我之前写的串⼝点亮LED的实现就涉及了简单的协议制定,对于嵌⼊式Linux来说,那⼀套协议当然也可以实践,但是那套协议有个重要的缺陷,协议内部从起始端的数据接收,⼀直到发送端的数据接收,都是和硬件强耦合的,这就造成如果我们由多种途径修改内部数据,协议很难被复⽤,另外每⼀次最后的执⾏都是直接操作硬件,当然只有串⼝控制时没有问题,但当有多个渠道(如⽹络,CAN,BLE等模块)同时操作硬件时,涉及硬件的同步问题繁琐且很难约束,因此本节就改进之前的协议,进⾏代码的实现。
参考资料 1. 2.《C++ Primer Plus》协议制定 协议的制定在⼤致的数据发送和返回数据结构上可以与原有的协议⼤致⼀致。
上位机发送指令包含起始位,地址位(⽤于多机通讯),数据长度(指⽰内部后⾯的数据长度),实际数据,CRC校验位这些基础结构,不过增加了数据编号位,它是2字节的随机数,在处理完成后可以⽤于上位机验证返回的数据是否正常,不过对⽐可以发现,原先协议⾥⾯的指令不在上位机数据结构,这个后⾯会提到。
下位机返回指令也是起始位,地址位,ACK应答状态,数据长度,数据区和CRC校验位,同时包含编号⽤于上位机的校验, 上位机发送数据结构: 下位机返回数据结构: 确认了通讯的结构后,下位机代码就可以实现了,其中接收数据代码如下:1int protocol_info::check_receive_data(int fd)2 {3int nread;4int CrcRecv, CrcCacl;5struct req_frame *frame_ptr;67/*从设备中读取数据*/8 nread = this->device_read(fd, &this->rx_ptr[this->rx_size],9 (this->max_buf_size-this->rx_size));10if(nread > 0)11 {12this->rx_size += nread;13 frame_ptr = (struct req_frame *)this->rx_ptr;1415/*接收到头不符合预期*/16if(frame_ptr->head != PROTOCOL_REQ_HEAD) {17 USR_DEBUG("No Valid Head\n");18this->rx_size = 0;19return RT_FAIL;20 }2122/*已经接收到长度数据*/23else if(this->rx_size > 5){24int nLen;2526/*设备ID检测*/27if(frame_ptr->id != PROTOCOL_DEVICE_ID)28 {29this->rx_size = 0;30 USR_DEBUG("Valid ID\n");31return RT_FAIL;32 }3334/*获取接收数据的总长度*/35this->rx_data_size = LENGTH_CONVERT(frame_ptr->length);3637/*crc冗余校验*/38 nLen = this->rx_data_size+FRAME_HEAD_SIZE+CRC_SIZE;39if(this->rx_size >= nLen)40 {41/*计算head后到CRC尾之前的所有数据的CRC值*/42 CrcRecv = (this->rx_ptr[nLen-2]<<8) + this->rx_ptr[nLen-1];43 CrcCacl = this->crc_calculate(&this->rx_ptr[1], nLen-CRC_SIZE-1);44if(CrcRecv == CrcCacl){45this->packet_id = LENGTH_CONVERT(frame_ptr->packet_id);46return RT_OK;47 }48else{49this->rx_size = 0;50 USR_DEBUG("CRC Check ERROR!. rx_data:%d, r:%d, c:%d\n", this->rx_data_size, CrcRecv, CrcCacl);51return RT_FAIL;52 }53 }54 }55 }56return RT_EMPTY;57 }View Code 因为是嵌⼊式Linux开发,因此推荐使⽤C++, 封装可以让代码结构更加清晰,从代码的实现可以看到实现包含:硬件的数据接收,起始位检测,数据编号的获取,以及后续数据的接收和数据的CRC校验,⾄于发送数据,则主要是创建发送数据的接⼝,代码如下:1/**2 * ⽣成发送的数据包格式3 *4 * @param ack 应答数据的状态5 * @param size 应答有效数据的长度6 * @param pdata 应答有效数据的⾸指针7 *8 * @return 执⾏执⾏的结果9*/10int protocol_info::create_send_buf(uint8_t ack, uint16_t size, uint8_t *pdata)11 {12 uint8_t out_size, index;13 uint16_t crc_calc;1415 out_size = 0;16this->tx_ptr[out_size++] = PROTOCOL_ACK_HEAD;17this->tx_ptr[out_size++] = PROTOCOL_DEVICE_ID;18this->tx_ptr[out_size++] = (uint8_t)(this->packet_id>>8);19this->tx_ptr[out_size++] = (uint8_t)(this->packet_id&0xff);20this->tx_ptr[out_size++] = ack;21this->tx_ptr[out_size++] = (uint8_t)(size>>8);22this->tx_ptr[out_size++] = (uint8_t)(size&0xff);2324if(size != 0 && pdata != NULL)25 {26for(index=0; index<size; index++)27 {28this->tx_ptr[out_size++] = *(pdata+index);29 }30 }3132 crc_calc = this->crc_calculate(&this->tx_ptr[1], out_size-1);33this->tx_ptr[out_size++] = (uint8_t)(crc_calc>>8);34this->tx_ptr[out_size++] = (uint8_t)(crc_calc&0xff);3536return out_size;37 }View Code 这部分即为通讯相关的结构数据实现,通关协议的发送和接收结构的剥离,此时我们已经能够处理实际的数据,下⾯也是主要改进内容。
linux QOS(TC) 功能实现分析

linux QOS 功能实现分析文档编号:00-6201-100当前版本:1.0.0.0创建日期:2008-7-24编写作者:wanghuaijialinux QOS 功能实现分析前言 (3)关于此文档 (3)参考资料 (3)Linux内核对QoS的支持 (5)对于入口数据包控制 (6)发送数据包的控制 (8)TC的具体设计与实现 (11)struct Qdisc_ops 说明 (15)LINUX 内核中安装策略对象过程 (17)前言关于此文档此文档是本人这段时间内学习QOS相关知识,总结并且整理出来的文档。
供大家参考。
本文档描述QOS相关知识,各章节说明如下:1前言,即此章节;2 QOS简介,介绍QOS基本知识、QOS提出的意义,以及QOS 的三种不同的服务模型;3:介绍QOS相关的技术,介绍了报文分类以及标记,拥塞管理技术,拥塞避免技术,以及流量整形和流量监管。
并且介绍了链路层相关的速度限制。
参考资料网络资源。
linux QOS 功能实现分析Linux内核对QoS的支持 (5)对于入口数据包控制 (6)发送数据包的控制 (8)TC的具体设计与实现 (11)struct Qdisc_ops 说明 (15)LINUX 内核中安装策略对象过程 (17)在传统的TCP/IP网络的路由器中,所有的IP数据包的传输都是采用FIFO(先进先出),尽最大努力传输的处理机制。
在早期网络数据量和关键业务数据不多的时候,并没有体现出非常大的缺点,路由器简单的把数据报丢弃来处理拥塞。
但是随着计算机网络的发展,数据量的急剧增长,以及多媒体,VOIP数据等对延时要求高的应用的增加。
路由器简单丢弃数据包的处理方法已经不再适合当前的网络。
单纯的增加网络带宽也不能从根本上解决问题。
所以网络的开发者们提出了服务质量的概念。
概括的说:就是针对各种不同需求,提供不同服务质量的网络服务功能。
提供QoS能力将是对未来IP网络的基本要求。
linux 协议栈 udp checksum校验

linux 协议栈 udp checksum校验UDP(用户数据报协议)是一种无连接的传输层协议,它在Linux协议栈中起着重要的作用。
在UDP协议中,数据被划分为多个数据报发送。
每个数据报都包含一个UDP头部和数据部分。
UDP数据报的头部有两个重要字段:源端口和目标端口。
这两个字段指定了数据报发送和接收的应用程序。
除了这些字段,UDP头部还有一个长度为16位的校验和字段,用于检测数据在传输过程中是否被改动。
校验和是通过一个算法生成的,接收方可以使用相同的算法来验证数据的完整性。
UDP协议中的校验和是十分关键的,它提供了对数据完整性的保护。
在发送端,当数据报准备好发送时,操作系统会计算数据报的校验和并将其填充到UDP头部的校验和字段中。
接收方在收到数据报后,会重新计算校验和,并将其与接收到的校验和进行比较。
如果两个校验和不一致,那么接收方将会认为数据报被修改过,并丢弃该数据报。
UDP校验和算法是一种简单而有效的算法,它使用二进制反码求和来计算校验和。
具体步骤如下:1.将数据报的每个16位字节划分成两个8位的字节,即低字节和高字节。
2.将所有16位字节对进行二进制反码求和,得到一个32位的中间结果。
3.如果中间结果高16位的任何位上有进位,则将进位加到低16位上去。
4.将中间结果的低16位取反,得到最终的校验和。
UDP校验和的计算是在传输层的协议进行的,而不是在网络硬件上。
这就意味着校验和的计算和验证由操作系统负责,而不是由网络设备完成。
这种设计灵活性很高,可以适用于不同种类的网络接口。
UDP校验和的作用是保证数据在传输过程中的完整性。
如果数据在传输过程中被修改,那么校验和的值就会发生变化,接收方可以通过比较校验和的值来判断数据是否被篡改。
然而,UDP校验和并不能提供数据的机密性和真实性,因为它是一种简单的校验和算法,容易被攻击者伪造。
总而言之,UDP校验和在Linux协议栈中起着重要的作用,用于检测数据在传输过程中的完整性。
linux系统i2c协议详解
linux系统i2c协议详解I2C总线概述I2C(两线接口)是一种串行通信协议,用于连接嵌入式系统中的集成电路(IC)。
它以其低成本、低功耗和高可靠性著称。
I2C总线需要两条双向信号线:串行数据线(SDA)和串行时钟线(SCL)。
这些信号线由一个主设备控制,可以与多个从设备通信。
I2C通信I2C通信由以下步骤组成:起始条件:主设备将SDA线下拉至低电平,同时保持SCL线为高电平。
设备地址:主设备发送7位或10位从设备地址,后跟一个读/写位。
数据传输:主设备和从设备交换数据。
停止条件:主设备将SDA线拉至高电平,同时保持SCL线为高电平。
主设备和从设备I2C总线上的设备分为两种:主设备和从设备。
主设备:发起通信并控制总线。
通常是主微控制器或处理器。
从设备:响应主设备请求并提供或接收数据。
可以是传感器、执行器或其他外围设备。
I2C寻址从设备通过唯一的7位或10位地址进行寻址。
地址的最高位表示是否可读/写,0表示写,1表示读。
I2C模式I2C协议支持以下模式:主写从读:主设备向从设备写入数据,然后从从设备读取数据。
主读从写:主设备从从设备读取数据,然后向从设备写入数据。
从读从写:两个从设备在主设备的监督下进行通信。
I2C传输速率I2C传输速率通常在10kbps到400kbps之间。
速率由主设备设置。
I2C错误检测I2C协议包含几个错误检测机制,例如校验和和超时。
这些机制有助于确保数据的可靠传输。
I2C应用I2C总线用于各种应用,包括:传感器和执行器接口EEPROM和闪存编程LED和LCD控制模拟-数字转换器(ADC)和数字-模拟转换器(DAC)接口电源管理时钟同步I2C优点I2C协议的优点包括:低成本:无需额外的硬件接口低功耗:仅使用两根信号线高可靠性:错误检测机制确保数据完整性容易使用:简单的协议易于实施广泛采用:支持广泛的设备和库I2C缺点I2C协议的缺点包括:数据速率低:与其他串行接口相比,数据速率较低主机限制:总线上只能有一个主设备总线无仲裁:在总线冲突的情况下,没有内置的仲裁机制有限的寻址范围:仅支持有限数量的设备地址I2C技术演进I2C协议正在不断发展,以满足新应用的需求。
linux的bridge分析
linux的bridge分析Linux网桥模型:Linux内核通过一个虚拟的网桥设备来实现桥接的,这个设备可以绑定若干个以太网接口设备,从而将它们桥接起来。
如下图所示:网桥设备br0绑定了eth0和eth1。
对于网络协议栈的上层来说,只看得到br0,因为桥接是在数据链路层实现的,上层不需要关心桥接的细节。
于是协议栈上层需要发送的报文被送到br0,网桥设备的处理代码再来判断报文该被转发到eth0或是eth1,或者两者皆是;反过来,从eth0或从eth1接收到的报文被提交给网桥的处理代码,在这里会判断报文该转发、丢弃、或提交到协议栈上层。
而有时候eth0、eth1也可能会作为报文的源地址或目的地址,直接参与报文的发送与接收(从而绕过网桥)。
相关数据结构:其中最左边的net_device是一个代表网桥的虚拟设备结构,它关联了一个net_bridge结构,这是网桥设备所特有的数据结构。
在net_bridge结构中,port_list成员下挂一个链表,链表中的每一个节点(net_bridge_port结构)关联到一个真实的网口设备的net_device。
网口设备也通过其br_port指针做反向的关联(那么显然,一个网口最多只能同时被绑定到一个网桥)。
net_bridge结构中还维护了一个hash表,是用来处理地址学习的。
当网桥准备转发一个报文时,以报文的目的Mac地址为key,如果可以在hash表中索引到一个net_bridge_fdb_entry结构,通过这个结构能找到一个网口设备的net_device,于是报文就应该从这个网口转发出去;否则,报文将从所有网口转发。
网桥数据包的处理流程:接收过程:对于数据包的处理流程并没有明显的主线,主要就是根据内核代码中网桥部分的源码进行分析。
网口设备接收到的报文最终通过net_receive_skb函数被网络协议栈所接收。
这个函数主要做三件事情:1、如果有抓包程序需要skb,将skb复制给它们;2、处理桥接;3、将skb提交给网络层。
Linux下的多线程机制的分析与实现
Lnx下 的多 线程 机 制 的分 析 与实现 iu
赵 东 ,周 卫 云2 ,赵 作人 3
103 ;. 3022 长春广顺 电子科技有 限公 司 , 长春 吉林 163) 104 102 ; 301 (. 1长春 师范学 院计算机科 学与技 术学 院 , 吉林长春
vi *a :调 用此 函数 可以创建一 个新 的线程 ,新 线程创建 后执行 sl一r te o d ) , ̄ o i 指定 的程序 。其 中参数 ar t a un t t 是 用户希望 创建线 程的属性 ,当为 N L U L时表示 以默认 的属性 创建 线程 。ag 向 sr r te传递 的参数 。 r是 tt o i a un
I tph e d n tra ph e d tr a
—
—
ji phed—th a ,vi * *s t ) o n(tr a rd o te d tu :这 个 函数 的作 用 是 等待 一 个 线 程 的结 束 。调用 as dt h(ted~t ted :参数 p r d 表的线 程一 旦终 止 ,立 即释放 调该线 程 占有 的所 ec p r a h a h a) pr te 代 ha
的指 针 。
2 2 线程控 制 函数 .
ph e d tra
—
sl vi) - e f(o :为了区 分线 程 ,在 线程 创 建 时 系统 为 其分 配 一个 唯一 的 I 号 ,由 p r d d I ) te ha
—
ce e r at
( )返 回给 调用者 ,也可 以通 过 p r d sl )获取 自己的线 程 I。 te — e ha f( D
究。
・
36 ・
linux socket 内核原理
Linux中的Socket是一种用于网络通信的编程接口,它允许进程通过网络进行数据传输。
Socket在Linux内核中的实现涉及到多个组件和原理。
1. 网络协议栈:Linux内核中的网络协议栈负责处理网络通信的各个层次,包括物理层、数据链路层、网络层和传输层。
Socket通过网络协议栈与网络进行交互。
2. 套接字数据结构:在Linux内核中,套接字(Socket)被实现为一种数据结构,用于表示网络连接。
套接字数据结构包含了连接的相关信息,如IP地址、端口号等。
3. 文件描述符:在Linux中,套接字被视为一种文件,因此每个套接字都有一个对应的文件描述符。
通过文件描述符,进程可以对套接字进行读写操作。
4. 网络设备驱动程序:Linux内核中的网络设备驱动程序负责处理网络设备的底层操作,如发送和接收数据包。
套接字通过网络设备驱动程序与网络设备进行通信。
5. 网络协议处理:当进程通过套接字发送或接收数据时,Linux内核会根据套接字的协议类型(如TCP或UDP)进行相应的协议处理。
这包括建立连接、数据分片、错误检测等操作。
6. 系统调用:在用户空间中,进程通过系统调用(如socket、bind、connect等)来创建和操作套接字。
系统调用会触发内核中相应的函数,完成套接字的创建和操作。
总的来说,Linux内核中的Socket实现涉及到网络协议栈、套接字数据结构、文件描述符、网络设备驱动程序、网络协议处理和系统调用等多个组件和原理。
这些组件和原理共同工作,使得进程能够通过套接字进行网络通信。
{"code":0,"msg":"请求出现异常","data":{}}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
sockfd_lookup()
__sock_create()
security_socket_bind()
security_socket_listen()
sock_alloc()
sock_alloc()
security_ops->socket_bind()
sock->ops->listen()
security_socket_accept()
t
tcp raw_v4_input ip_local_deliver
数据包发往本地 检查ip数据包的内容
Ip_forward
Tcp_output.c:278
如果定义了NETFILTER,则先进入 IP_FORWARD
Iq
ip_options_compile ip_forward_finish ip_route_input_slow 在缓存中找到
NF_HOOK(PF_INET, NF_IP_PRE_ROUTING)
packet_type->func()(ip_rcv、arp_rcv) dev->hard_start_xmit() 驱动层 如驱动中的e1000_xmit_frame() handle_bridge() 桥模式 netif_receive_skb()
填充 sock_queue_rcv_skb() IP 层
tcp_v4_rcv()
udp_rcv()
raw_rcv()
write调用
write()
send调用
recv()
sendto调用
recvfrom() Sock层
sys_write()
sys_send() sys_sendfrom()
sock_writev()
__skb_queue_tail() skb_queue_tail(&sk->sk_receive_queue, skb)
tcp_rcv_established()
sock_queue_rcv_skb()
tcp_v4_do_rcv() ip_queue_xmit() raw_send_hdrinc() ip_route_output_flow() ip_push_pending_frames() tcp_v4_rcv()
inet_sockraw_ops->recvmsg()
sock_common_recvmsg()
sk->sk_prot->recvmsg()
tcp_prot->recvmsg()
udp_prot->recvmsg()
raw_prot->recvmsg()
tcp_recvmsg()
udp_recvmsg()
sys_read()
sys_recv() sys_recvfrom()
sock_readv()
sock_readv_writev()
sock_recvmsg()
INET Sock层
sock->ops->recvmsg()
inet_stream_ops->recvmsg()
inet_dgram_ops->recvmsg()
udp_queue_rcv_skb()
icmp_pointers->handler()
raw_rcv_skb()
udp_rcv()
icmp_rcv()
raw_rcv()
ipprot->handler() NF_HOOK(PF_INET, NF_IP_LOCAL_OUT) tcp、udp
raw_v4_input() raw ip_local_deliver_finish()
ip_output.c:367
lter
进行路由,并把skb->dst->input函数 指针指向ip_local_deliver或ip_error 或ip_forward或ip Route.c:1658-1675行,在路由时 会先在路由缓存中查找,没找到则 由ip_route_input_slow函数从路 由表中查,并加入到缓存中
__skb_queue_tail
tcp_rcv_established
tcp_v4_do_rcv
将数据包放入队列的尾部 sk->receive_queue 并调用sk->data_ready通知上层数据 到达
在这之间做了tcp checksum校验等
tcp_v4_rcv
ipprot->protocol = TCP
ip_route_connect()
sock_close()
tcp_connect()
sock->ops->release()
tcp_transmit_skb()
tcp_close()、udp_close()
read调用
read()
recv调用
recv()
recvfrom调用
recvfrom() Sock层
dst_output()
ip_forward_finish()
raw_rcv()
NF_HOOK(PF_INET, NF_IP_LOCAL_IN)
skb->dst->output()
NF_HOOK(PF_INET, NF_IP_FORWARD)
ip_call_ra_chain()
ip_defrag()
ip_mc_output() 分p_output()
ip_forward() forward
ip_local_deliver() local_in skb->dst->input()
ip_finish_output()
dst_input()
NF_HOOK(PF_INET, NF_IP_POST_ROUTING) ip_finish_output2()
raw_recvmsg()
sk->receive_quene NULL sk->sk_backlog_rcv() NOT NULL 读取
skb_recv_datagram()
skb_dequeue() 读取
sk->sk_receive_queue
填充 tcp_v4_do_rcv() tcp_rcv_established()
c:1622行,调用dev->poll(dev, &budget)
Net_rx_action
如果定义 POST_
q.c:90行,产生软中断,通过全局变量 q_vec的函数指针调用net_rx_action
2847行,函数net_dev_init中,将 _action函数指针传给softirq_vec.action, oftirq中通过h->action调用net_rx_action
ip
ip_forward_options
ip_output.c:397
ip_
ip_route_input ip_send ip_rcv_finish
如果定义了NETF LOCAL_OUT
ip
如果定义了NETFILTER,则先进入 PRE_ROUTING
ip_fragment ip_rcv
如果产生了分片 即skb->len > rt->u.dst.pmtu 并将ip_output函数指针做为参数 给ip_fragment
sock_readv_writev()
sock_sendmsg()
INET Sock层
sock->ops->sendmsg()
inet_stream_ops->sendmsg()
Protocol.c:56行开始,初始化全局数组 inet_protos, 在ip_input.c:262行查找到相应的接收函数 (tcp、udp、icmp、igmp)
udp_rcv
ipprot->protocol = UDP
ip_local_deliver_finish
如果定义了NETFILTER,则先进入LOCAL_IN 转发 数据 包
sys_socketcall()
sys_socketcall()
sys_socketcall()
sys_socketcall()
sys_socket()
sys_bind()
sys_listen()
sys_accept()
sock_create()
sockfd_lookup()
sockfd_lookup()
ESTABLISHE D
^-tcp_output.c:1332行,tcp_transmit_skb tcp_output.c:278行,ip_queue_xmit | |如果定义了NETFILTER,先进入LOCAL_OUT | ip_output.c:401行:ip_queue_xmit2 ip_output.c:317行;skb->dst->output(skb); (在route.c的ip_route_*put*函数中进 dst->output函数指针付值=ip_output或 ip_mc_output或ip_rt_bug) case TCP_SYN_RECV(收到ACK)(Server端) 如果ouput tcp_set_state 能会到 tcp_data_snd_check (tcp_input.c:4030) tcp_ack_snd_check (tcp_input.c:4031) LISTEN
Dev.c:1489行,调用ip_rcv函数 在ip_output.c:1001行初始化了 ip_packet_type,使它的成员func指向 ip_rcv函数 Dev.c:1553行,通过__skb_dequeue 函数取得sk_buff,