Linux-2.6.25 TCPIP函数调用大致流程
Linux TCP-IP

Linux对TCP/IP的支持浅析( 北京工业大学魏勇100022 )本文着重分析了Linux中网络协议栈TCP/IP的实现,重点放在协议栈的整体结构和Linux网络设备驱动程序的分析上面。
下面的介绍中将以Linux中的ne2000网络设备驱动程序为例来分析Linux对网络的支持。
1. Linux网络支持的基本原理Linux的网络实现是以BSD为模型的,它支持BSD sockets(及一些扩展)。
Linux选用这个编程接口是因为它很流行,并且有助于应用程序从Linux平台移植到其它Unix 平台。
Linux下的TCP/IP 网络协议栈的各层之间是通过一系列互相连接的层次结构来实现Internet地址族的,具体结构层次如图1所示。
图1 Linux下结构层次示意图其中:BSD socket层由专门用来处理BSD Socket的通用套接字管理软件来处理,它由INET socket 层来支持。
INET Socket为基于IP的协议TCP和UDP管理传输端点。
在IP层,实现了Internet协议的代码。
这些代码要给传输的数据加上一个IP头,并且知道如何把传入的IP包送给TCP或者UDP协议。
在IP层以下,就是具体得型号各异的各种网络设备,如PLIP、SLIP和以太网。
不过要注意,这些网络设备不一定都是物理设备,可以使用像Loopback这样的虚拟网络设备,纯粹是用软件来实现的。
在Linux中,为了简化对设备的管理,将所有的外围设备都归结为三类:字符设备(如键盘,鼠标等)、块设备(如硬盘、软驱等)和网络设备(如网卡、串口等等)。
为了将网络环境中的物理网络设备的多样性屏蔽,Linux对所有的网络物理设备抽象并且定义了一个统一的概念:接口(Interface)。
对于所有的网络硬件的访问都是通过接口进行访问的,接口实际上提供了一个对于所有类型的网络硬件的一致化的操作集合,用来处理对数据的发送和接收。
对于每一个已经驱动了的网络设备,都用一个struct device的数据结构表示。
linux 路由选取过程

linux 路由选取过程Linux 路由选取过程导语:在计算机网络中,路由是实现不同网络之间数据传输的关键技术之一。
Linux 操作系统作为一种常用的服务器操作系统,其路由选取过程对于网络的稳定和性能具有重要影响。
本文将介绍Linux 路由选取过程的基本原理和具体操作步骤,帮助读者更好地理解和使用 Linux 路由功能。
一、概述在计算机网络中,路由器是将数据从源地址传输到目的地址的核心设备,而路由选取就是指在众多可选路由路径中,选择最佳的路径进行数据传输。
Linux 操作系统提供了强大的路由功能,通过路由表和路由算法实现路由选取过程。
二、路由表路由表是一种存储路由器信息的数据结构,它记录了目的网络的地址和下一跳路由器的地址。
Linux 操作系统中的路由表可以通过命令"route"或"ip route"来查看和管理。
路由表中的每一条记录包含目的网络地址、子网掩码、下一跳地址和出接口等信息。
其中,目的网络地址指的是数据包要到达的目的地网络的网络号;子网掩码用于将目的网络地址和源地址进行逻辑与运算,以判断数据包是否在同一网络中;下一跳地址是指数据包从当前路由器出发,需要通过的下一个路由器的地址;出接口是指数据包离开当前路由器的网络接口。
三、路由算法Linux 操作系统使用的路由算法主要有静态路由和动态路由两种。
静态路由是由网络管理员手动配置的路由信息,不会根据网络状况进行调整。
动态路由则是根据网络拓扑和链路状态自动计算生成的路由信息,能够根据网络变化实时更新。
1. 静态路由静态路由是通过手动配置路由表实现的,它的优点是简单、稳定,适用于小型网络或需要固定路由路径的场景。
在 Linux 操作系统中,可以通过编辑"/etc/network/interfaces"文件来配置静态路由信息。
静态路由的配置步骤如下:(1)打开终端,使用 root 权限登录;(2)编辑"/etc/network/interfaces"文件,添加静态路由信息,格式如下:```up route add -net 目的网络地址/子网掩码 gw 下一跳地址dev 出接口```其中,目的网络地址和子网掩码为目标网络的地址和掩码;下一跳地址为数据包到达目标网络时需要通过的下一个路由器的地址;出接口为数据包离开当前路由器的网络接口。
linux tcp connect实例

linux tcp connect实例Linux TCP Connect实例一、简介Linux TCP Connect是一个用于建立TCP连接的系统调用函数。
它允许应用程序发起对远程主机的连接请求,并在连接成功建立后进行数据传输。
本文将介绍Linux TCP Connect的使用方法,并给出一个实例来说明其具体应用。
二、Linux TCP Connect函数说明Linux TCP Connect函数的原型如下:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);其中,sockfd是一个已经通过socket函数创建的套接字描述符,addr是一个指向目标服务器地址的结构体指针,addrlen是addr结构体的长度。
三、实例假设我们需要编写一个客户端程序,与服务器建立TCP连接,发送一段字符串,并接收服务器返回的响应。
我们需要创建一个套接字,使用socket函数:```cint sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {perror("socket");return -1;}```其中,AF_INET表示使用IPv4协议,SOCK_STREAM表示使用TCP协议。
接下来,我们需要指定服务器的地址和端口号,并将其存储在一个sockaddr_in结构体中:```cstruct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080);if (inet_pton(AF_INET, "服务器IP地址", &server_addr.sin_addr) <= 0) {perror("inet_pton");return -1;}```其中,8080是服务器的端口号,"服务器IP地址"是服务器的IP地然后,我们可以使用connect函数建立TCP连接:```cif (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {perror("connect");return -1;}```如果连接成功,connect函数将返回0;否则,返回-1。
tcp报文解析流程

tcp报文解析流程TCP报文解析流程TCP(Transmission Control Protocol)是一种可靠的传输协议,它将数据划分为一系列的报文段进行传输。
在网络通信中,接收端需要对接收到的TCP报文进行解析,以获取有效的数据,并进行相应的处理。
本文将介绍TCP报文解析的流程。
1. 报文段的接收TCP报文是基于IP报文进行封装的,因此首先需要接收到IP报文。
IP报文中包含了源IP地址、目的IP地址等信息,以及封装的TCP 报文段。
接收端通过网络接口收到IP报文后,将其传递给TCP层进行处理。
2. 报文头部解析TCP报文段包括报文头部和数据两部分。
接收端首先需要对报文头部进行解析,以获取报文的各项控制信息。
TCP报文头部包含了源端口号、目的端口号、序列号、确认号等字段,这些字段用于实现可靠的数据传输。
3. 校验和验证在报文头部解析完毕后,接收端需要对报文进行校验和验证。
校验和是TCP协议用于检测数据是否在传输过程中发生错误的一种机制。
接收端通过对报文头部和数据部分进行计算,得到一个校验和值,并与报文中的校验和字段进行比对,以判断报文是否出现错误。
4. 数据分段重组TCP报文段在传输过程中可能会被分成多个IP报文进行传输,因此接收端需要对接收到的多个报文进行重组,以获取完整的TCP报文段。
接收端通过报文头部中的序列号和数据长度等信息,对接收到的报文进行排序和合并,得到原始的TCP报文段。
5. 数据处理与传递当TCP报文段重组完毕后,接收端可以对其中的数据部分进行处理,并将解析出的有效数据交给上层应用进行处理。
接收端根据报文头部中的控制信息,对数据进行重组、去重、排序等操作,以保证数据的可靠传输。
6. 确认应答在接收端完成对TCP报文的处理后,需要向发送端发送确认应答,以告知发送端接收到报文的情况。
确认应答中包含了确认号等信息,用于告知发送端下一个期望接收的报文段的序列号。
7. 重传机制如果接收端在一定时间内没有收到发送端发送的报文段或确认应答,将会触发重传机制。
Linux系统调用详细全过程

6
系统命令、内核函数
系统调用与系统命令
系统命令相对API来说,更高一层。每个系统命令
都是一个执行程序,如ls命令等。这些命令的实现
调用了系统调用。
系统调用与内核函数
系统调用是用户进入内核的接口层,它本身并非内
核函数,但是它由内核函数实现。
进入内核后,不同的系统调用会找到各自对应的内
常,CPU便被切换到内核态执行内核函
数,转到了系统调用处理程序的入口:
system_call()。
int $0x80指令将用户态的执行模式转变为内
核态,并将控制权交给系统调用过程的起点
system_call()处理函数。
4
system_call()函数
system_cal()检查系统调用号,该号码告诉内核
SYMBOL_NAME(sys_exit)
.long
.longSYMBOL_NAME(sys_read)
SYMBOL_NAME(sys_fork)
.long
.longSYMBOL_NAME(sys_write)
SYMBOL_NAME(sys_read)
.long
.longSYMBOL_NAME(sys_open)
SYMBOL_NAME(sys_write)
.long
.long
…… SYMBOL_NAME(sys_open)
……
……
……
.long
SYMBOL_NAME(sys_getuid)
.long SYMBOL_NAME(sys_getuid)
* 4
+
21
系统调用的返回
当服务例程结束时,system_call( ) 从eax
linux下tcp-ip栈和Netfilter的分析编程

NetFilter架构流程一个数据包按照如下图所示的过程通过Netfilter系统:--->[1]--->[ROUTE]--->[3]--->[4]--->| ^| |local || [ROUTE]v |[2] [5]| ^| |v |从图中可以看到IPv4一共有5个钩子函数,分别为:1 NF_IP_PRE_ROUTING2 NF_IP_LOCAL_IN3 NF_IP_FORWARD4 NF_IP_POST_ROUTING5 NF_IP_LOCAL_OUT数据报从左边进入系统,进行IP校验以后,数据报经过第一个钩子函数NF_IP_PRE_ROUTING[1]进行处理;然后就进入路由代码,其决定该数据包是需要转发还是发给本机的;若该数据包是发被本机的,则该数据经过钩子函数NF_IP_LOCAL_IN[2]处理以后然后传递给上层协议;若该数据包应该被转发则它被NF_IP_FORWARD[3]处理;经过转发的数据报经过最后一个钩子函数NF_IP_POST_ ROUTING[4]处理以后,再传输到网络上。
本地产生的数据经过钩子函数NF_IP_LOCAL_OUT [5]处理可以后,进行路由选择处理,然后经过NF_IP_POST_ROUTING[4]处理以后发送到网络上。
内核模块可以对一个或多个这样的钩子函数进行注册挂接,并且在数据报经过这些钩子函数时被调用,从而模块可以修改这些数据报,并向netfilter返回如下值:NF_ACCEPT 继续正常传输数据报NF_DROP 丢弃该数据报,不再传输NF_STOLEN 模块接管该数据报,不要继续传输该数据报NF_QUEUE 对该数据报进行排队(通常用于将数据报给用户空间的进程进行处理)NF_REPEAT 再次调用该钩子函数内核模块可以注册一个新的规则表(table),并要求数据报流经指定的规则表。
这种数据报选择用于实现数据报过滤(filter表),网络地址转换(Nat表)及数据报处理(mangle表)。
linux tcp参数

linux tcp参数Linux是一种开源的操作系统,它具有灵活的定制性和高度的可配置性,包括TCP参数。
TCP(传输控制协议)是Internet协议套件的一部分,它提供可靠的、面向连接的数据传输服务。
TCP参数可以帮助调整系统的网络性能,以适应不同的网络环境和应用场景。
创建TCP连接时涉及以下参数:1. TCP SYN重试次数SYN是TCP连接建立的第一个消息,如果没有得到回应,则需要进行重试。
在Linux中,可以通过tcp_syn_retries参数来设置SYN 重试次数,默认值为6次。
如果需要更快的连接建立速度,可以将该值降低,但是可能会增加连接失败的风险。
2. TCP SYNACK重试次数SYNACK是对SYN的回应,在Linux中,可以通过tcp_synack_retries参数来设置SYNACK重试次数,默认值为5次。
如果网络环境较差,可以适当增加该值,以提高连接建立的成功率。
3. TCP连接超时时间如果连接建立过程中超过了设置的超时时间,连接将被认为是失败的。
在Linux中,可以通过tcp_synack_retries参数来设置连接超时时间,默认值为30秒。
如果网络环境不稳定,可以适当增加该值,以减少连接超时的情况。
TCP数据传输时涉及以下参数:1. TCP窗口大小TCP窗口大小指发送方在等待接收方确认之前可以发送的数据量。
在Linux中,可以通过tcp_window_scaling参数来设置TCP窗口大小,默认值为开启窗口大小自适应。
适当增加窗口大小可以提高数据传输的效率,但是也可能会增加网络拥塞的风险。
2. TCP拥塞控制算法TCP拥塞控制算法用于防止网络拥塞。
在Linux中,可以通过tcp_congestion_control参数来设置拥塞控制算法,默认值为cubic。
如果网络环境较差,可以选择更加严格的拥塞控制算法,以避免网络拥塞。
3. TCP延迟确认TCP延迟确认指接收方在接收到数据后不会立即发送确认消息,而是等待一段时间后再发送。
Linux系统中TCPIP网络配置文件

Linux系统中TCP/IP网络配置文件在Linux系统中,TCP/IP网络是通过若干个文本文件进行配置的,需要编辑这些文件来完成联网工作。
系统中重要的有关网络配置文件为:◆ /etc/sysconfig/network◆ /etc/HOSTNAME◆ /etc/hosts◆ /etc/services (服务名_端口号_协议名称)◆ /etc/protocols (系统支持的协议)◆ /etc/host.conf◆ /etc/nsswitch.conf◆ /etc/resolv.conf◆ /etc/rc.d/init.d/network接下来我们将对这些文件逐一讲述,这些文件都可以在系统运行时进行修改,不用启动或者停止任何守护程序,更改会立刻生效(除了/etc /sysconfig/network)。
另外,这些文件都支持由"#"开头的注释,每一个文件都有在UNIX手册页中的第5部分中有一项,可以用man 命令来获取它们。
◆ /etc/sysconfig/network 网络设置该文件用来指定服务器上的网络配置信息,包含了控制和网络有关的文件和守护程序的行为的参数。
下面是一个例子文件:NETWORKING=yesHOSTNAME=machine1GATEWAY=210.34.6.2FORWARD_IPV4=yesGATEWAYDEV=其中,NETWORK=yes/no 表示网络是否被配置;HOSTNAME=hostname hostname 表示服务器的主机名;GATEWAY=gw-ip gw-ip 表示网络网关的IP地址;FORWARD_IPV4=yes/no 是否开启IP转发功能;GAREWAYDEV=gw-dev gw-dw 表示网关的设备名,如:eth0等;为了和老的一些软件相兼容,"/etc/HOSTNAME"文件应该用和HOSTNAME=hostname相同的主机名。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Linux-2.6.25 TCPIP函数调用大致流程插口层系统调用sendsys_sendsys_sendtosendtosys_sendtosock_sendmsgsendmsgsys_sendmsgsock_sendmsgwritesys_writevfs_writefile->f_op->write = do_sync_writefilp->f_op->aio_write = sock_aio_writedo_sock_write__sock_sendmsgwritevsys_writevvfs_writevdo_readv_writevdo_sync_readv_writevsock_aio_writedo_sock_write__sock_sendmsgrecvsys_recvsys_recvfromrecvfromsys_recvfromsock_recvmsgrecvmsgsys_recvmsgsock_recvmsgreadsys_readvfs_readfile->f_op->read= do_sync_readfilp->f_op->aio_read= sock_aio_readdo_sock_read__sock_recvmsgreadvsys_readvvfs_readvdo_readv_readvdo_sync_readv_readvsock_aio_readdo_sock_read__sock_recvmsgsocketlistenconnectbindselectcloseshutdownioctlgetsocknamegetpeernamesetsockoptgetsockopt内部实现函数sock_sendmsg__sock_sendmsg__sock_sendmsgsock->ops->sendmsg对于TCP就是tcp_sendmsg,否则就是inet_sendmsg。
后者调用sk->sk_prot->sendmsg,会继续分用为udp_sendmsg或raw_sendmsg函数sock_recvmsg__sock_recvmsg__sock_recvmsgsock->ops->recvmsg = sock_common_recvmsgsock_common_recvmsg对于不同协议,是tcp_recvmsg,udp_sendmsg或raw_sendmsg函数。
运输层TCP系统调用sys_connect间接调用了tcp_v4_connecttcp_v4_connectip_route_connect(寻找路由)__ip_route_output_keyip_route_output_flow★tcp_connect(构造一个SYN并发送)tcp_transmit_skbinet_csk_reset_xmit_timer(启动一个超时定时器,等待SYN+ACK)TCP的写函数最终都调用了tcp_sendmsgtcp_sendmsg★__tcp_push_appending_framestcp_write_xmittcp_transmit_skbtcp_push_onetcp_transmit_skbtcp_push__tcp_push_pending_framesTCP发送数据共有三种途径__tcp_push_appending_frames,tcp_push_one,tcp_push,其中tcp_push调用了__tcp_push_pending_frames。
到底调用哪个或哪些函数取决于是否有PUSH 标志、NAGLE是否开启、和一些其他情况。
__tcp_push_appending_frames是试图一次发送完缓存队列中所有的skb。
tcp_push_one先计算拥塞窗口,然后只发送窗口大小的数据,如果窗口大小为0,则不发送任何数据。
TCP实际的发送函数,tcp_transmit_skb/* This routine actually transmits TCP packets queued in by* tcp_do_sendmsg(). This is used by both the initial* transmission and possible later retransmissions.* All SKB's seen here are completely headerless. It is our* job to build the TCP header, and pass the packet down to* IP so it can do the same plus pass the packet off to the* device.** We are working here with either a clone of the original* SKB, or a fresh unique copy made by the retransmit engine.*/tcp_transmit_skbbuild包头icsk->icsk_af_ops->queue_xmit = ip_queue_xmit★硬件->IP层->运输层收到数据,添加到对应的SOCKET缓冲区中,回复ACK由ip_rcv间接调用tcp_v4_rcv__inet_lookup(根据一些参数,查找sock结构)__inet_lookup_established(在已经建立的连接中找,通过inet_lhashfn在哈希表中查找) __inet_lookup_listener(在监听中的Socket中找,通过inet_lhashfn在哈希表中查找) tcp_v4_do_rcvtcp_rcv_established(ESTABLISHED)★tcp_child_processtcp_rcv_state_processtcp_rcv_state_process(除ESTABLISHED和TIME_WAIT之外)★tcp_prequeue(见后面详细解释)sk->sk_backlog_rcv = tcp_v4_do_rcv(又回到开头)sk_add_backlog(见后面详细解释)tcp_timewait_state_process(TIME_WAIT)tcp_v4_timewait_ack(TIME_W AIT)tcp_v4_send_ack(发送ACK)sock结构被初始化的时候,发送和接收数据的缓冲队列也被初始化完成,接收数据用到以下三个队列:sk->receive_queuesk->prequeuesk->sk_backlogsk->prequeue:如果sk没有被用户态程序锁定,则先进入prequeuesk->receive_queue:接收到数据包的sk_buff链表队列,如果数据包过多,造成receive_queue 满,或者sock被用户程序锁定,将转入sk_backlogsk->sk_backlog:当sock_owned_by_user函数返回真时候,(sk)->sk_lock.owner被锁定,使用sk_add_backlog()函数(该函数实现非常简单,只是一个为链表添加节点的动作)将SKB加入这个后备队列。
tcp_rcv_establishedTCP接受里面最主要的就是tcp_rcv_established和tcp_rcv_state_process了tcp_rcv_established★if(fast path)检查包头各字段tcp_ack(处理CK)tcp_data_snd_check(发送ACK)__skb_pull(腾出空间)__skb_queue_tail(把数据追加到接受缓冲区)else(slow path)tcp_data_queue对滑动窗口、序号做出处理__skb_pull__skb_queue_tailtcp_event_data_recv(更新状态)tcp_rcv_state_processTCP协议的状态机,状态转移函数。
ESTABLISHED和TIME_W AIT状态之外的其他状态都会调用此函数tcp_rcv_state_process★icsk->icsk_af_ops->conn_request(是tcp_v4_conn_request,LISTEN状态)tcp_v4_send_synack(发送SYN+ACK)ip_build_and_send_pktip_local_out__ip_local_outnf_hook(dst_output)dst_outputtcp_rcv_synsent_state_process(SYN_SENT)tcp_resettcp_ack(收到ACK)tcp_set_state(SYN_RECV->ESTABLISHED或者FIN_W AIT1->FIN_W AIT2)tcp_time_wait(CLOSING->TIME_WAIT)tcp_update_metrics(LAST_ACK)...(都是和TCP协议状态转移相关的东西,这里目的是打通上下,以后慢慢分析)还有两个出镜率较高的函数tcp_v4_send_reset和tcp_v4_send_acktcp_v4_send_reset(发送RST)ip_send_replyip_route_output_keyip_push_pending_framestcp_v4_send_ack(发送ACK)ip_send_replyip_route_output_keyip_push_pending_frames用户子上而下的读函数都间接的调用了tcp_recvmsgtcp_recvmsg★skb_copy_datagram_iovectcp_recv_urg(接受一个字节的URG数据)UDPUDP的写函数都调用了udp_sendmsgudp_sendmsg★ip_route_output_flowip_append_dataudp_flush_pending_framesip_flush_pending_framesudp_push_pending_framesip_push_pending_frames硬件->IP层->运输层收到数据,添加到对应的SOCKET缓冲区中由ip_rcv间接调用udp_rcv__udp4_lib_rcvif(是多播或广播)__udp4_lib_mcast_deliverudp_queue_rcv_skb(对每个需要接受的UDP SOCKET缓冲调用) __udp4_lib_lookupudp_queue_rcv_skb把数据块sk_buff放到一个sock结构的接受缓存的末尾中udp_queue_rcv_skbsock_queue_rcv_skbskb_queue_tail用户子上而下的读函数都间接的调用了udp_recvmsgudp_recvmsg★__skb_recv_datagramskb_copy_datagram_iovecskb_copy_and_csum_datagram_iovec原始套接字RAW Socket的写函数都调用了raw_sendmsgraw_sendmsg★ip_route_output_flowif(设置了IP_HDRINCL选项,即自己构造ip头部)raw_send_hdrinc★elseip_append_dataip_flush_pending_frames或ip_push_pending_frames自底向上的收包raw_rcv由ip_forward调用ip_call_ra_chain,然后再调用的raw_rcvraw_rcvsock_queue_rcv_skbskb_queue_tailsk->sk_data_ready = sock_def_readablewaitqueue_activesk_wake_async用户子上而下的读函数都间接的调用了raw_recvmsgraw_recvmsg★skb_recv_datagram__skb_recv_datagramwait_for_packet(如果没有数据,则调用此函数等待数据)ICMP在任何需要发送ICMP报文的时候都会调用此函数icmp_send__ip_route_output_keyip_route_output_slowip_route_output_keyip_route_output_flowicmp_push_replyip_append_dataip_flush_pending_frames或ip_push_pending_frames硬件->IP层->运输层收到ICMP数据,作出处理逻辑由ip_rcv间接调用icmp_rcv完全就是icmp协议的处理逻辑,通过函数指针icmp_pointers[icmph->type].handler调用了一下函数中的某一个icmp_discardicmp_unreachicmp_redirecticmp_timestampicmp_addressicmp_address_replyicmp_echo网络层IP发送网络层中主要的发送函数有以下三个:ip_push_pending_frames,ip_queue_xmit,raw_send_hdrincip_push_pending_frames★将所有pending状态的IP分组组合成一个IP分组,并发送ip_local_outip_queue_xmit★ip_route_output_flow(找路由)ip_local_outraw_send_hdrinc★NF_HOOK(dst_output)ip_local_out★__ip_local_outnf_hook(dst_output)dst_output路由选择ip_route_output_flow★__ip_route_output_keyip_route_output_slow路由选择ip_route_output_slow★fib_lookupip_mkroute_output__mkroute_outputrt_hashrt_intern_hasharp_bind_neighbour__neigh_lookup_errnoneigh_lookupneigh_createdst_output★dst->output = ip_outputNF_HOOK_COND(ip_finish_output)dst_outputip_fragmentip_finish_output2neigh_hh_outputhh->hh_output = dev_queue_xmit★dst->neighbour->output = neigh_resolve_outputneigh->ops->queue_xmit = dev_queue_xmit★IP接受接收IPv4包,由netif_rx间接调用ip_rcv★NF_HOOKip_rcv_finiship_route_inputdst_inputdst->input(可能是ip_local_deliver或ip_forward)if(是发给本地的包)dst->input是ip_local_deliverNF_HOOKip_local_deliver_finishipprot->handler(可能是tcp_v4_rcv,udp_rcv,icmp_rcv,igmp_rcv)elsedst->input是ip_forward更新路由ip_route_input★ip_route_input_mc(多播)rt_hashrt_intern_haship_route_input_slow(其它)ip_mkroute_input__mkroute_inputrt_hashrt_intern_hash每收到一个IP报文都会调用此函数更新路由表。