📄 linux-tcp ip源码阅读笔记.htm
字号:
target=_self>msn空间</A>
<LI class=listitem><A href="http://www.bosslink.com/" target=_self>世界经营者</A>
<LI class=listitem><A
href="http://www.confuchina.com/09%20xungu/lunyuminzujingshen.htm"
target=_self>中国儒学网</A>
<LI class=listitem><A
href="http://bbs.shiandci.net/cgi-bin/lb5000/leoboard.cgi"
target=_self>唐宋诗词论坛</A>
<LI class=listitem><A href="http://blog.csdn.net/danny_xcz/"
target=_self>纯月部落</A>
<LI class=listitem><A href="http://blog.csdn.net/bobobobo_8888/"
target=_self>飞天</A></LI></UL>
<H3 class=listtitle>存档</H3>
<UL class=list>
<LI><A href="http://blog.csdn.net/cz_hyf/archive/2006/06.aspx">2006年06月(2)</A>
<LI><A href="http://blog.csdn.net/cz_hyf/archive/2006/04.aspx">2006年04月(3)</A>
<LI><A href="http://blog.csdn.net/cz_hyf/archive/2006/03.aspx">2006年03月(1)</A>
<LI><A
href="http://blog.csdn.net/cz_hyf/archive/2006/02.aspx">2006年02月(22)</A></LI></UL>
<H3 class=listtitle>最近评论</H3>
<UL class=list>
<LI class=listitem>candy:<A title="点击查看《世界上最好博客的47个博客技巧 》"
href="http://blog.csdn.net/cz_hyf/archive/2006/06/07/777713.aspx">凡走过必留下痕迹~
<BR></A>
<LI class=listitem>鱼香茄子:<A title=点击查看《菜鸟伊始--本科四年(3)》
href="http://blog.csdn.net/cz_hyf/archive/2006/02/16/600778.aspx">扬州破吗?我就是扬州的.扬州是全国卫生城市,历史文化名城.她没有高楼大厦,但是是个适合居住的城市.</A>
<LI class=listitem>测试trackback:<A title=点击查看《windows下tomcat-mysql的配置》
href="http://blog.csdn.net/cz_hyf/archive/2006/02/20/603488.aspx">测试</A>
<LI class=listitem>急求qmail高手:<A title=点击查看《qmail总结笔记(1)》
href="http://blog.csdn.net/cz_hyf/archive/2006/02/19/602970.aspx">要求精通linux,不是会,而是要精通,我们将进行测试,不精通不要来尝试。
<BR>精通C及cgi等的编程 <BR>了解LDAP
<BR>开发过基于linux或其他基于UNIX的邮件系统,可以是使用开源的sendmail或qmail,也可以是自行编写邮件服务器的。
<BR><BR>以上全部是必要条件,不满足者请不要来尝试,具体需求待取得联络之后再提供,价格在1-2万元之间,要求一个月之内完……</A>
<LI class=listitem>马甲:<A title=点击查看《菜鸟伊始--本科四年(3)》
href="http://blog.csdn.net/cz_hyf/archive/2006/02/16/600778.aspx">你文中所述某君,我是极崇拜与佩服的。</A></LI></UL><BR><BR></DIV>
<DIV id=main>
<SCRIPT>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</SCRIPT>
<DIV class=post>
<DIV class=postTitle><A
href="http://blog.csdn.net/cz_hyf/archive/2006/02/19/602802.aspx"><IMG height=13
src="linux-Tcp IP源码阅读笔记.files/authorship.gif" width=15 border=0> linux-Tcp
IP协议栈源码阅读笔记</A>
<SCRIPT language=javascript>document.title="linux-Tcp IP协议栈源码阅读笔记 - "+document.title</SCRIPT>
</DIV>
<DIV class=postText>
<DIV>
<DIV><STRONG><FONT size=5></FONT></STRONG> </DIV>
<DIV><STRONG><FONT size=5>一.linux内核网络栈代码的准备知识</FONT></STRONG></DIV>
<DIV> </DIV>
<DIV><STRONG>1.</STRONG> <STRONG>linux内核ipv4网络部分分层结构</STRONG>:</DIV>
<DIV> </DIV>
<DIV><BR><STRONG>BSD socket层: </STRONG>这一部分处理BSD socket相关操作,每个socket在内核中以struct
socket结构体现。这一部分的文件</DIV>
<DIV> </DIV>
<DIV>主要有:/net/socket.c /net/protocols.c etc<BR><BR><STRONG>INET
socket层:</STRONG>BSD
socket是个可以用于各种网络协议的接口,而当用于tcp/ip,即建立了AF_INET形式的socket时,</DIV>
<DIV> </DIV>
<DIV>还需要保留些额外的参数,于是就有了struct sock结构。文件主要</DIV>
<DIV> </DIV>
<DIV>有:/net/ipv4/protocol.c /net/ipv4/af_inet.c /net/core/sock.c
etc<BR><BR><STRONG>TCP/UDP层:</STRONG>处理传输层的操作,传输层用struct inet_protocol和struct
proto两个结构表示。文件主要</DIV>
<DIV> </DIV>
<DIV>有:/net/ipv4/udp.c /net/ipv4/datagram.c /net/ipv4/tcp.c
/net/ipv4/tcp_input.c /net/ipv4//tcp_output.c /net/ipv4/tcp_minisocks.c
/net/ipv4/tcp_output.c /net/ipv4/tcp_timer.c </DIV>
<DIV> </DIV>
<DIV>etc <BR> <BR><STRONG>IP层:</STRONG>处理网络层的操作,网络层用struct
packet_type结构表示。文件主要有:/net/ipv4/ip_forward.c </DIV>
<DIV>ip_fragment.c ip_input.c ip_output.c
etc.<BR><BR><STRONG>数据链路层和驱动程序:</STRONG>每个网络设备以struct
net_device表示,通用的处理在dev.c中,驱动程序都在/driver/net目</DIV>
<DIV> </DIV>
<DIV>录下。<BR></DIV>
<DIV> </DIV>
<DIV><STRONG>2.</STRONG> <STRONG>两台主机建立udp通信所走过的函数列表</STRONG></DIV>
<DIV><STRONG></STRONG> </DIV>
<DIV>^<BR>| sys_read fs/read_write.c<BR>| sock_read net/socket.c<BR>| sock_recvmsg net/socket.c<BR>| inet_recvmsg net/ipv4/af_inet.c<BR>| udp_recvmsg net/ipv4/udp.c<BR>| skb_recv_datagram net/core/datagram.c<BR>| -------------------------------------------<BR>| sock_queue_rcv_skb include/net/sock.h<BR>| udp_queue_rcv_skb net/ipv4/udp.c<BR>| udp_rcv net/ipv4/udp.c<BR>| ip_local_deliver_finish
net/ipv4/ip_input.c<BR>| ip_local_deliver net/ipv4/ip_input.c<BR>| ip_recv net/ipv4/ip_input.c<BR>| net_rx_action net/dev.c<BR>| -------------------------------------------<BR>| netif_rx net/dev.c<BR>| el3_rx driver/net/3c309.c<BR>| el3_interrupt driver/net/3c309.c<BR><BR>==========================<BR><BR>| sys_write fs/read_write.c<BR>| sock_writev net/socket.c <BR>| sock_sendmsg net/socket.c<BR>| inet_sendmsg net/ipv4/af_inet.c<BR>| udp_sendmsg net/ipv4/udp.c<BR>| ip_build_xmit net/ipv4/ip_output.c<BR>| output_maybe_reroute net/ipv4/ip_output.c<BR>| ip_output net/ipv4/ip_output.c<BR>| ip_finish_output net/ipv4/ip_output.c<BR>| dev_queue_xmit net/dev.c<BR>| --------------------------------------------<BR>| el3_start_xmit driver/net/3c309.c<BR>V</DIV>
<DIV> </DIV>
<DIV> </DIV>
<DIV><STRONG>3.</STRONG> <STRONG>网络路径图、重要数据结构sk_buffer及路由介绍</STRONG></DIV>
<DIV><STRONG></STRONG> </DIV>
<DIV><STRONG> </STRONG>linux-net.pdf 第2.1章 第2.3章
第2.4章</DIV>
<DIV> </DIV>
<DIV><STRONG>4.</STRONG> <STRONG>从连接、发送、到接收数据包的过程</STRONG></DIV>
<DIV><STRONG></STRONG> </DIV>
<DIV> linux-net.pdf 第4、5、6章详细阐述</DIV>
<DIV> </DIV>
<DIV> </DIV>
<DIV><STRONG><FONT size=5>二.linux的tcp-ip栈代码的详细分析</FONT></STRONG></DIV>
<DIV><STRONG><FONT size=6></FONT></STRONG> </DIV>
<DIV><STRONG>1.数据结构(msghdr,sk_buff,socket,sock,proto_ops,proto)</STRONG></DIV>
<DIV><STRONG></STRONG> </DIV>
<DIV>bsd套接字层,操作的对象是socket,数据存放在msghdr这样的数据结构:</DIV>
<DIV> </DIV>
<DIV>创建socket需要传递family,type,protocol三个参数,创建socket其实就是创建一个socket实例,然后创建一个文件描述符结构,并且互相建立一些关联,即建立互相连接的指针,并且初始化这些对文件的写读操作映射到socket的read,write函数上来。</DIV>
<DIV> </DIV>
<DIV>同时初始化socket的操作函数(proto_ops结构),如果传入的type参数是STREAM类型,那么就初始化为SOCKET->ops为inet_stream_ops,如果是DGRAM类型,则SOCKET-ops为inet_dgram_ops。对于inet_stream_ops其实是一个结构体,包含了stream类型的socket操作的一些入口函数,在这些函数里主要做的是对socket进行相关的操作,同时通过调用下面提到的sock中的相关操作完成socket到sock层的传递。比如在inet_stream_ops里有个inet_release的操作,这个操作除了释放socket的类型空间操作外,还通过调用socket连接的sock的close操作,对于stream类型来说,即tcp_close来关闭sock</DIV>
<DIV>释放sock。</DIV>
<DIV> </DIV>
<DIV>创建socket同时还创建sock数据空间,初始化sock,初始化过程主要做的事情是初始化三个队列,receive_queue(接收到的数据包sk_buff链表队列),send_queue(需要发送数据包的sk_buff链表队列),backlog_queue(主要用于tcp中三次握手成功的那些数据包,自己猜的),根据family、type参数,初始化sock的操作,比如对于family为inet类型的,type为stream类型的,sock->proto初始化为tcp_prot.其中包括stream类型的协议sock操作对应的入口函数。</DIV>
<DIV> </DIV>
<DIV>在一端对socket进行write的过程中,首先会把要write的字符串缓冲区整理成msghdr的数据结构形式(参见linux内核2.4版源代码分析大全),然后调用sock_sendmsg把msghdr的数据传送至inet层,对于msghdr结构中数据区中的每个数据包,创建sk_buff结构,填充数据,挂至发送队列。一层层往下层协议传递。一下每层协议不再对数据进行拷贝。而是对sk_buff结构进行操作。</DIV>
<DIV> </DIV>
<DIV>inet套接字及以下层 数据存放在sk_buff这样的数据结构里:</DIV>
<DIV> </DIV>
<DIV>路由:</DIV>
<DIV> </DIV>
<DIV> 在linux的路由系统主要保存了三种与路由相关的数据,第一种是在物理上和本机相连接的主机地址信息表,第二种是保存了在网络访问中判断一个网络地址应该走什么路由的数据表;第三种是最新使用过的查询路由地址的缓存地址数据表。</DIV>
<DIV> 1.neighbour结构 neighbour_table{
}是一个包含和本机所连接的所有邻元素的信息的数据结构。该结构中有个元素是neighbour结构的数组,数组的每一个元素都是一个对应于邻机的neighbour结构,系统中由于协议的不同,会有不同的判断邻居的方式,每种都有neighbour_table{}类型的实例,这些实例是通过neighbour_table{}中的指针next串联起来的。在neighbour结构中,包含有与该邻居相连的网络接口设备net_device的指针,网络接口的硬件地址,邻居的硬件地址,包含有neigh_ops{}指针,这些函数指针是直接用来连接传输数据的,包含有queue_xmit(struct
* sk_buff)函数入口地址,这个函数可能会调用硬件驱动程序的发送函数。</DIV>
<DIV> </DIV>
<DIV> 2.FIB结构
在FIB中保存的是最重要的路由规则,通过对FIB数据的查找和换算,一定能够获得路由一个地址的方法。系统中路由一般采取的手段是:先到路由缓存中查找表项,如果能够找到,直接对应的一项作为路由的规则;如果不能找到,那么就到FIB中根据规则换算传算出来,并且增加一项新的,在路由缓存中将项目添加进去。</DIV>
<DIV></DIV>
<DIV> 3.route结构(即路由缓存中的结构)</DIV>
<DIV> </DIV>
<DIV> </DIV>
<DIV> </DIV>
<DIV>数据链路层:</DIV>
<DIV> </DIV>
<DIV>
net_device{}结构,对应于每一个网络接口设备。这个结构中包含很多可以直接获取网卡信息的函数和变量,同时包含很多对于网卡操作的函数,这些直接指向该网卡驱动程序的许多函数入口,包括发送接收数据帧到缓冲区等。当这些完成后,比如数据接收到缓冲区后便由netif_rx(在net/core/dev.c各种设备驱动程序的上层框架程序)把它们组成sk_buff形式挂到系统接收的backlog队列然后交由上层网络协议处理。同样,对于上层协议处理下来的那些sk_buff。便由dev_queue_xmit函数放入网络缓冲区,交给网卡驱动程序的发送程序处理。</DIV>
<DIV> </DIV>
<DIV>
在系统中存在一张链表dev_base将系统中所有的net_device{}结构连在一起。对应于内核初始化而言,系统启动时便为每个所有可能支持的网络接口设备申请了一个net_device{}空间并串连起来,然后对每个接点运行检测过程,如果检测成功,则在dev_base链表中保留这个接点,否则删除。对应于模块加载来说,则是调用register_netdev()注册net_device,在这个函数中运行检测过程,如果成功,则加到dev_base链表。否则就返回检测不到信息。删除同理,调用</DIV>
<DIV>unregister_netdev。</DIV>
<DIV> </DIV>
<DIV> </DIV>
<DIV><STRONG>2.启动分析</STRONG></DIV>
<DIV><STRONG></STRONG> </DIV>
<DIV><STRONG> 2.1 初始化进程</STRONG>
:start-kernel(main.c)---->do_basic_setup(main.c)---->sock_init(/net/socket.c)---->do_initcalls(main.c)</DIV>
<DIV> </DIV>
<DIV><STRONG>void __init sock_init(void)<BR></STRONG>{<BR> int i;</DIV>
<DIV> </DIV>
<DIV> printk(KERN_INFO "Linux NET4.0 for Linux
2.4\n");<BR> printk(KERN_INFO "Based upon Swansea University Computer
Society NET3.039\n");</DIV>
<DIV> </DIV>
<DIV> /*<BR> * Initialize all address (protocol) families.
每一项表示的是针对一个地址族的操作集合,例如对于ipv4来说,在net/ipv4/af_inet.c文件中的函数inet_proto_init()就调用sock_register()函数将inet_families_ops初始化到属于IPV4的net_families数组中的一项。<BR>
*/<BR> <BR> for (i = 0; i < NPROTO; i++)
<BR> net_families[i] = NULL; </DIV>
<DIV> </DIV>
<DIV> /*<BR> * Initialize sock SLAB
cache.初始化对于sock结构预留的内存的slab缓存。<BR> */<BR> <BR> sk_init();</DIV>
<DIV> </DIV>
<DIV>#ifdef SLAB_SKB<BR> /*<BR> * Initialize skbuff SLAB cache
初始化对于skbuff结构的slab缓存。以后对于skbuff的申请可以通过函数kmem_cache_alloc()在这个缓存中申请空间。<BR>
*/<BR> skb_init();<BR>#endif</DIV>
<DIV> </DIV>
<DIV> /*<BR> * Wan router layer. <BR> */</DIV>
<DIV> </DIV>
<DIV>#ifdef CONFIG_WAN_ROUTER <BR> wanrouter_init();<BR>#endif</DIV>
<DIV> </DIV>
<DIV> /*<BR> * Initialize the protocols
module. 向系统登记sock文件系统,并且将其安装到系统上来。<BR> */</DIV>
<DIV> </DIV>
<DIV> register_filesystem(&sock_fs_type);<BR> sock_mnt =
kern_mount(&sock_fs_type);<BR> /* The real protocol initialization is
performed when<BR> * do_initcalls is run. <BR> */</DIV>
<DIV><BR> /*<BR> * The netlink device handler may be needed
early.<BR> */</DIV>
<DIV> </DIV>
<DIV>#ifdef CONFIG_NET<BR> rtnetlink_init();<BR>#endif<BR>#ifdef
CONFIG_NETLINK_DEV<BR> init_netlink();<BR>#endif<BR>#ifdef
CONFIG_NETFILTER<BR> netfilter_init();<BR>#endif</DIV>
<DIV> </DIV>
<DIV>#ifdef CONFIG_BLUEZ<BR> bluez_init();<BR>#endif</DIV>
<DIV> </DIV>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -