- 浏览: 266159 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
daknife:
谢谢你的这篇文章,让我大概了解了select的一部分底层原理。 ...
Linux-2.6.25 select系统调用源码分析 -
gjlzjb:
非常有用,谢谢哈。另外问下,您是否用过Pheonix Syst ...
Why Map/Reduce? -
zhangyafei_kimi:
canbo 写道请问,我怎么生成安装包,提供给其它用户安装呢? ...
下载最新的Google Chrome源码并编译 -
canbo:
请问,我怎么生成安装包,提供给其它用户安装呢?
下载最新的Google Chrome源码并编译
Linux-2.6.25 TCPIP函数调用大致流程
学习目的,随手笔记。函数和文字说明会不断补充更新。
Changelog
2008.10.08 最近找工作忙。暂时缓缓
插口层
系统调用
send
sys_send
sys_sendto
sendto
sys_sendto
sock_sendmsg
sendmsg
sys_sendmsg
sock_sendmsg
write
sys_write
vfs_write
file->f_op->write = do_sync_write
filp->f_op->aio_write = sock_aio_write
do_sock_write
__sock_sendmsg
writev
sys_writev
vfs_writev
do_readv_writev
do_sync_readv_writev
sock_aio_write
do_sock_write
__sock_sendmsg
recv
sys_recv
sys_recvfrom
recvfrom
sys_recvfrom
sock_recvmsg
recvmsg
sys_recvmsg
sock_recvmsg
read
sys_read
vfs_read
file->f_op->read= do_sync_read
filp->f_op->aio_read= sock_aio_read
do_sock_read
__sock_recvmsg
readv
sys_readv
vfs_readv
do_readv_readv
do_sync_readv_readv
sock_aio_read
do_sock_read
__sock_recvmsg
socket
listen
connect
bind
select
close
shutdown
ioctl
getsockname
getpeername
setsockopt
getsockopt
内部实现函数
sock_sendmsg
__sock_sendmsg
__sock_sendmsg
sock->ops->sendmsg
对于TCP就是tcp_sendmsg,否则就是inet_sendmsg。后者调用sk->sk_prot->sendmsg,会继续分用为udp_sendmsg或raw_sendmsg函数
sock_recvmsg
__sock_recvmsg
__sock_recvmsg
sock->ops->recvmsg = sock_common_recvmsg
sock_common_recvmsg对于不同协议,是tcp_recvmsg,udp_sendmsg或raw_sendmsg函数。
运输层
TCP
系统调用sys_connect间接调用了tcp_v4_connect
tcp_v4_connect
ip_route_connect(寻找路由)
__ip_route_output_key
ip_route_output_flow★
tcp_connect(构造一个SYN并发送)
tcp_transmit_skb
inet_csk_reset_xmit_timer(启动一个超时定时器,等待SYN+ACK)
TCP的写函数最终都调用了tcp_sendmsg
tcp_sendmsg★
__tcp_push_appending_frames
tcp_write_xmit
tcp_transmit_skb
tcp_push_one
tcp_transmit_skb
tcp_push
__tcp_push_pending_frames
TCP发送数据共有三种途径__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_skb
build包头
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_rcv
tcp_rcv_established(ESTABLISHED)★
tcp_child_process
tcp_rcv_state_process
tcp_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_WAIT)
tcp_v4_send_ack(发送ACK)
sock结构被初始化的时候,发送和接收数据的缓冲队列也被初始化完成,接收数据用到以下三个队列:
sk->receive_queue
sk->prequeue
sk->sk_backlog
sk->prequeue:如果sk没有被用户态程序锁定,则先进入prequeue
sk->receive_queue:接收到数据包的sk_buff链表队列,如果数据包过多,造成receive_queue满,或者sock被用户程序锁定,将转入sk_backlog
sk->sk_backlog:当sock_owned_by_user函数返回真时候,(sk)->sk_lock.owner被锁定,使用sk_add_backlog()函数(该函数实现非常简单,只是一个为链表添加节点的动作)将SKB加入这个后备队列。
tcp_rcv_established
TCP接受里面最主要的就是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_tail
tcp_event_data_recv(更新状态)
tcp_rcv_state_process
TCP协议的状态机,状态转移函数。ESTABLISHED和TIME_WAIT状态之外的其他状态都会调用此函数
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_pkt
ip_local_out
__ip_local_out
nf_hook(dst_output)
dst_output
tcp_rcv_synsent_state_process(SYN_SENT)
tcp_reset
tcp_ack(收到ACK)
tcp_set_state(SYN_RECV->ESTABLISHED或者FIN_WAIT1->FIN_WAIT2)
tcp_time_wait(CLOSING->TIME_WAIT)
tcp_update_metrics(LAST_ACK)
...(都是和TCP协议状态转移相关的东西,这里目的是打通上下,以后慢慢分析)
还有两个出镜率较高的函数tcp_v4_send_reset和tcp_v4_send_ack
tcp_v4_send_reset(发送RST)
ip_send_reply
ip_route_output_key
ip_push_pending_frames
tcp_v4_send_ack(发送ACK)
ip_send_reply
ip_route_output_key
ip_push_pending_frames
用户子上而下的读函数都间接的调用了tcp_recvmsg
tcp_recvmsg★
skb_copy_datagram_iovec
tcp_recv_urg(接受一个字节的URG数据)
UDP
UDP的写函数都调用了udp_sendmsg
udp_sendmsg★
ip_route_output_flow
ip_append_data
udp_flush_pending_frames
ip_flush_pending_frames
udp_push_pending_frames
ip_push_pending_frames
硬件->IP层->运输层收到数据,添加到对应的SOCKET缓冲区中
由ip_rcv间接调用
udp_rcv
__udp4_lib_rcv
if(是多播或广播)
__udp4_lib_mcast_deliver
udp_queue_rcv_skb(对每个需要接受的UDP SOCKET缓冲调用)
__udp4_lib_lookup
udp_queue_rcv_skb
把数据块sk_buff放到一个sock结构的接受缓存的末尾中
udp_queue_rcv_skb
sock_queue_rcv_skb
skb_queue_tail
用户子上而下的读函数都间接的调用了udp_recvmsg
udp_recvmsg★
__skb_recv_datagram
skb_copy_datagram_iovec
skb_copy_and_csum_datagram_iovec
原始套接字
RAW Socket的写函数都调用了raw_sendmsg
raw_sendmsg★
ip_route_output_flow
if(设置了IP_HDRINCL选项,即自己构造ip头部)
raw_send_hdrinc★
else
ip_append_data
ip_flush_pending_frames或
ip_push_pending_frames
自底向上的收包
raw_rcv
由ip_forward调用ip_call_ra_chain,然后再调用的raw_rcv
raw_rcv
sock_queue_rcv_skb
skb_queue_tail
sk->sk_data_ready = sock_def_readable
waitqueue_active
sk_wake_async
用户子上而下的读函数都间接的调用了raw_recvmsg
raw_recvmsg★
skb_recv_datagram
__skb_recv_datagram
wait_for_packet(如果没有数据,则调用此函数等待数据)
ICMP
在任何需要发送ICMP报文的时候都会调用此函数
icmp_send
__ip_route_output_key
ip_route_output_slow
ip_route_output_key
ip_route_output_flow
icmp_push_reply
ip_append_data
ip_flush_pending_frames或
ip_push_pending_frames
硬件->IP层->运输层收到ICMP数据,作出处理逻辑
由ip_rcv间接调用
icmp_rcv
完全就是icmp协议的处理逻辑,通过函数指针icmp_pointers[icmph->type].handler调用了一下函数中的某一个
icmp_discard
icmp_unreach
icmp_redirect
icmp_timestamp
icmp_address
icmp_address_reply
icmp_echo
网络层
IP发送
网络层中主要的发送函数有以下三个:ip_push_pending_frames,ip_queue_xmit,raw_send_hdrinc
ip_push_pending_frames★
将所有pending状态的IP分组组合成一个IP分组,并发送
ip_local_out
ip_queue_xmit★
ip_route_output_flow(找路由)
ip_local_out
raw_send_hdrinc★
NF_HOOK(dst_output)
ip_local_out★
__ip_local_out
nf_hook(dst_output)
dst_output
路由选择
ip_route_output_flow★
__ip_route_output_key
ip_route_output_slow
路由选择
ip_route_output_slow★
fib_lookup
ip_mkroute_output
__mkroute_output
rt_hash
rt_intern_hash
arp_bind_neighbour
__neigh_lookup_errno
neigh_lookup
neigh_create
dst_output★
dst->output = ip_output
NF_HOOK_COND(ip_finish_output)
dst_output
ip_fragment
ip_finish_output2
neigh_hh_output
hh->hh_output = dev_queue_xmit★
dst->neighbour->output = neigh_resolve_output
neigh->ops->queue_xmit = dev_queue_xmit★
IP接受
接收IPv4包,由netif_rx间接调用
ip_rcv★
NF_HOOK
ip_rcv_finish
ip_route_input
dst_input
dst->input(可能是ip_local_deliver或ip_forward)
if(是发给本地的包)
dst->input是ip_local_deliver
NF_HOOK
ip_local_deliver_finish
ipprot->handler(可能是tcp_v4_rcv,udp_rcv,icmp_rcv,igmp_rcv)
else
dst->input是ip_forward
更新路由
ip_route_input★
ip_route_input_mc(多播)
rt_hash
rt_intern_hash
ip_route_input_slow(其它)
ip_mkroute_input
__mkroute_input
rt_hash
rt_intern_hash
每收到一个IP报文都会调用此函数更新路由表。ip_route_input函数的上半部分是在hash table寻找路由项,如果找到就返回。找不到才会调用后面的ip_route_input_mc或ip_route_input_slow来更新路由表。
转发
ip_forward★
ip_call_ra_chain
raw_rcv★
xfrm4_route_forward(处理路由)
xfrm_route_forward
__xfrm_route_forward
xfrm_lookup
__xfrm_lookup
xfrm_find_bundle
afinfo->find_bundle = __xfrm4_find_bundle
xfrm_bundle_create
xfrm_dst_lookup
afinfo->dst_lookup = xfrm4_dst_lookup
__ip_route_output_key
ip_route_output_slow★
处理各个参数(在一定条件下发送ICMP)
ip_decrease_ttl(减少TTL)
NF_HOOK(ip_forward_finish)
dst_output
链路层
接收帧
由硬件驱动在中断处理程序中直接调用netif_rx
netif_rx★
if(netpoll_rx函数与把数据拿走)
return
__skb_queue_tail(把所有收到的数据保存起来)
napi_schedule
__napi_schedule
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
在net_dev_init函数中初始化了软中断:
open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
所以NET_RX_SOFTIRQ中断的处理函数是net_rx_action,NET_TX_SOFTIRQ中断的处理函数是net_tx_action。需要让上层接收数据时,只要触发相应的软中断,如__raise_softirq_irqoff(NET_RX_SOFTIRQ)。内核就会在适当时机执行do_softirq来处理pending的软中断。
net_rx_action★
n->poll = process_backlog
netif_receive_skb
pt_prev->func = ip_rcv★(在这里完成了交接)
__raise_softirq_irqoff(NET_RX_SOFTIRQ)
发送帧
dev_queue_xmit★
rcu_read_lock_bh
if(设备有发送队列)
q->enqueue(将数据追加到发送队列,软中断处理函数net_tx_action会执行真正的发送工作)
else
dev_hard_start_xmit
dev->hard_start_xmit = el_start_xmit★
调用outw汇编指令发送数据,够底层了
rcu_read_unlock_bh
net_tx_action★
__kfree_skb(释放已发送的,此时中断由dev_kfree_skb_irq函数发起)
qdisc_run
__qdisc_run
qdisc_restart
dev_hard_start_xmit★
netif_schedule
netif_schedule
netif_schedule★
__netif_schedule
raise_softirq_irqoff(NET_TX_SOFTIRQ)
学习目的,随手笔记。函数和文字说明会不断补充更新。
Changelog
2008.10.08 最近找工作忙。暂时缓缓
插口层
系统调用
send
sys_send
sys_sendto
sendto
sys_sendto
sock_sendmsg
sendmsg
sys_sendmsg
sock_sendmsg
write
sys_write
vfs_write
file->f_op->write = do_sync_write
filp->f_op->aio_write = sock_aio_write
do_sock_write
__sock_sendmsg
writev
sys_writev
vfs_writev
do_readv_writev
do_sync_readv_writev
sock_aio_write
do_sock_write
__sock_sendmsg
recv
sys_recv
sys_recvfrom
recvfrom
sys_recvfrom
sock_recvmsg
recvmsg
sys_recvmsg
sock_recvmsg
read
sys_read
vfs_read
file->f_op->read= do_sync_read
filp->f_op->aio_read= sock_aio_read
do_sock_read
__sock_recvmsg
readv
sys_readv
vfs_readv
do_readv_readv
do_sync_readv_readv
sock_aio_read
do_sock_read
__sock_recvmsg
socket
listen
connect
bind
select
close
shutdown
ioctl
getsockname
getpeername
setsockopt
getsockopt
内部实现函数
sock_sendmsg
__sock_sendmsg
__sock_sendmsg
sock->ops->sendmsg
对于TCP就是tcp_sendmsg,否则就是inet_sendmsg。后者调用sk->sk_prot->sendmsg,会继续分用为udp_sendmsg或raw_sendmsg函数
sock_recvmsg
__sock_recvmsg
__sock_recvmsg
sock->ops->recvmsg = sock_common_recvmsg
sock_common_recvmsg对于不同协议,是tcp_recvmsg,udp_sendmsg或raw_sendmsg函数。
运输层
TCP
系统调用sys_connect间接调用了tcp_v4_connect
tcp_v4_connect
ip_route_connect(寻找路由)
__ip_route_output_key
ip_route_output_flow★
tcp_connect(构造一个SYN并发送)
tcp_transmit_skb
inet_csk_reset_xmit_timer(启动一个超时定时器,等待SYN+ACK)
TCP的写函数最终都调用了tcp_sendmsg
tcp_sendmsg★
__tcp_push_appending_frames
tcp_write_xmit
tcp_transmit_skb
tcp_push_one
tcp_transmit_skb
tcp_push
__tcp_push_pending_frames
TCP发送数据共有三种途径__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_skb
build包头
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_rcv
tcp_rcv_established(ESTABLISHED)★
tcp_child_process
tcp_rcv_state_process
tcp_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_WAIT)
tcp_v4_send_ack(发送ACK)
sock结构被初始化的时候,发送和接收数据的缓冲队列也被初始化完成,接收数据用到以下三个队列:
sk->receive_queue
sk->prequeue
sk->sk_backlog
sk->prequeue:如果sk没有被用户态程序锁定,则先进入prequeue
sk->receive_queue:接收到数据包的sk_buff链表队列,如果数据包过多,造成receive_queue满,或者sock被用户程序锁定,将转入sk_backlog
sk->sk_backlog:当sock_owned_by_user函数返回真时候,(sk)->sk_lock.owner被锁定,使用sk_add_backlog()函数(该函数实现非常简单,只是一个为链表添加节点的动作)将SKB加入这个后备队列。
tcp_rcv_established
TCP接受里面最主要的就是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_tail
tcp_event_data_recv(更新状态)
tcp_rcv_state_process
TCP协议的状态机,状态转移函数。ESTABLISHED和TIME_WAIT状态之外的其他状态都会调用此函数
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_pkt
ip_local_out
__ip_local_out
nf_hook(dst_output)
dst_output
tcp_rcv_synsent_state_process(SYN_SENT)
tcp_reset
tcp_ack(收到ACK)
tcp_set_state(SYN_RECV->ESTABLISHED或者FIN_WAIT1->FIN_WAIT2)
tcp_time_wait(CLOSING->TIME_WAIT)
tcp_update_metrics(LAST_ACK)
...(都是和TCP协议状态转移相关的东西,这里目的是打通上下,以后慢慢分析)
还有两个出镜率较高的函数tcp_v4_send_reset和tcp_v4_send_ack
tcp_v4_send_reset(发送RST)
ip_send_reply
ip_route_output_key
ip_push_pending_frames
tcp_v4_send_ack(发送ACK)
ip_send_reply
ip_route_output_key
ip_push_pending_frames
用户子上而下的读函数都间接的调用了tcp_recvmsg
tcp_recvmsg★
skb_copy_datagram_iovec
tcp_recv_urg(接受一个字节的URG数据)
UDP
UDP的写函数都调用了udp_sendmsg
udp_sendmsg★
ip_route_output_flow
ip_append_data
udp_flush_pending_frames
ip_flush_pending_frames
udp_push_pending_frames
ip_push_pending_frames
硬件->IP层->运输层收到数据,添加到对应的SOCKET缓冲区中
由ip_rcv间接调用
udp_rcv
__udp4_lib_rcv
if(是多播或广播)
__udp4_lib_mcast_deliver
udp_queue_rcv_skb(对每个需要接受的UDP SOCKET缓冲调用)
__udp4_lib_lookup
udp_queue_rcv_skb
把数据块sk_buff放到一个sock结构的接受缓存的末尾中
udp_queue_rcv_skb
sock_queue_rcv_skb
skb_queue_tail
用户子上而下的读函数都间接的调用了udp_recvmsg
udp_recvmsg★
__skb_recv_datagram
skb_copy_datagram_iovec
skb_copy_and_csum_datagram_iovec
原始套接字
RAW Socket的写函数都调用了raw_sendmsg
raw_sendmsg★
ip_route_output_flow
if(设置了IP_HDRINCL选项,即自己构造ip头部)
raw_send_hdrinc★
else
ip_append_data
ip_flush_pending_frames或
ip_push_pending_frames
自底向上的收包
raw_rcv
由ip_forward调用ip_call_ra_chain,然后再调用的raw_rcv
raw_rcv
sock_queue_rcv_skb
skb_queue_tail
sk->sk_data_ready = sock_def_readable
waitqueue_active
sk_wake_async
用户子上而下的读函数都间接的调用了raw_recvmsg
raw_recvmsg★
skb_recv_datagram
__skb_recv_datagram
wait_for_packet(如果没有数据,则调用此函数等待数据)
ICMP
在任何需要发送ICMP报文的时候都会调用此函数
icmp_send
__ip_route_output_key
ip_route_output_slow
ip_route_output_key
ip_route_output_flow
icmp_push_reply
ip_append_data
ip_flush_pending_frames或
ip_push_pending_frames
硬件->IP层->运输层收到ICMP数据,作出处理逻辑
由ip_rcv间接调用
icmp_rcv
完全就是icmp协议的处理逻辑,通过函数指针icmp_pointers[icmph->type].handler调用了一下函数中的某一个
icmp_discard
icmp_unreach
icmp_redirect
icmp_timestamp
icmp_address
icmp_address_reply
icmp_echo
网络层
IP发送
网络层中主要的发送函数有以下三个:ip_push_pending_frames,ip_queue_xmit,raw_send_hdrinc
ip_push_pending_frames★
将所有pending状态的IP分组组合成一个IP分组,并发送
ip_local_out
ip_queue_xmit★
ip_route_output_flow(找路由)
ip_local_out
raw_send_hdrinc★
NF_HOOK(dst_output)
ip_local_out★
__ip_local_out
nf_hook(dst_output)
dst_output
路由选择
ip_route_output_flow★
__ip_route_output_key
ip_route_output_slow
路由选择
ip_route_output_slow★
fib_lookup
ip_mkroute_output
__mkroute_output
rt_hash
rt_intern_hash
arp_bind_neighbour
__neigh_lookup_errno
neigh_lookup
neigh_create
dst_output★
dst->output = ip_output
NF_HOOK_COND(ip_finish_output)
dst_output
ip_fragment
ip_finish_output2
neigh_hh_output
hh->hh_output = dev_queue_xmit★
dst->neighbour->output = neigh_resolve_output
neigh->ops->queue_xmit = dev_queue_xmit★
IP接受
接收IPv4包,由netif_rx间接调用
ip_rcv★
NF_HOOK
ip_rcv_finish
ip_route_input
dst_input
dst->input(可能是ip_local_deliver或ip_forward)
if(是发给本地的包)
dst->input是ip_local_deliver
NF_HOOK
ip_local_deliver_finish
ipprot->handler(可能是tcp_v4_rcv,udp_rcv,icmp_rcv,igmp_rcv)
else
dst->input是ip_forward
更新路由
ip_route_input★
ip_route_input_mc(多播)
rt_hash
rt_intern_hash
ip_route_input_slow(其它)
ip_mkroute_input
__mkroute_input
rt_hash
rt_intern_hash
每收到一个IP报文都会调用此函数更新路由表。ip_route_input函数的上半部分是在hash table寻找路由项,如果找到就返回。找不到才会调用后面的ip_route_input_mc或ip_route_input_slow来更新路由表。
转发
ip_forward★
ip_call_ra_chain
raw_rcv★
xfrm4_route_forward(处理路由)
xfrm_route_forward
__xfrm_route_forward
xfrm_lookup
__xfrm_lookup
xfrm_find_bundle
afinfo->find_bundle = __xfrm4_find_bundle
xfrm_bundle_create
xfrm_dst_lookup
afinfo->dst_lookup = xfrm4_dst_lookup
__ip_route_output_key
ip_route_output_slow★
处理各个参数(在一定条件下发送ICMP)
ip_decrease_ttl(减少TTL)
NF_HOOK(ip_forward_finish)
dst_output
链路层
接收帧
由硬件驱动在中断处理程序中直接调用netif_rx
netif_rx★
if(netpoll_rx函数与把数据拿走)
return
__skb_queue_tail(把所有收到的数据保存起来)
napi_schedule
__napi_schedule
__raise_softirq_irqoff(NET_RX_SOFTIRQ);
在net_dev_init函数中初始化了软中断:
open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
所以NET_RX_SOFTIRQ中断的处理函数是net_rx_action,NET_TX_SOFTIRQ中断的处理函数是net_tx_action。需要让上层接收数据时,只要触发相应的软中断,如__raise_softirq_irqoff(NET_RX_SOFTIRQ)。内核就会在适当时机执行do_softirq来处理pending的软中断。
net_rx_action★
n->poll = process_backlog
netif_receive_skb
pt_prev->func = ip_rcv★(在这里完成了交接)
__raise_softirq_irqoff(NET_RX_SOFTIRQ)
发送帧
dev_queue_xmit★
rcu_read_lock_bh
if(设备有发送队列)
q->enqueue(将数据追加到发送队列,软中断处理函数net_tx_action会执行真正的发送工作)
else
dev_hard_start_xmit
dev->hard_start_xmit = el_start_xmit★
调用outw汇编指令发送数据,够底层了
rcu_read_unlock_bh
net_tx_action★
__kfree_skb(释放已发送的,此时中断由dev_kfree_skb_irq函数发起)
qdisc_run
__qdisc_run
qdisc_restart
dev_hard_start_xmit★
netif_schedule
netif_schedule
netif_schedule★
__netif_schedule
raise_softirq_irqoff(NET_TX_SOFTIRQ)
- Linux-2.6.25_TCPIP函数调用流程.zip (11.1 KB)
- 下载次数: 44
发表评论
-
HTTP客户请求的数据格式说明
2008-12-27 18:51 1402HTTP客户请求的数据格式说明 HTTP请求包括三部分:请 ... -
Linux和WIndows都不支持自连接
2008-12-09 09:29 1758Cygwin下结果: connect() 127 Transp ... -
SO_RCVBUF选项的大小和接受窗口字节数关系
2008-12-08 20:08 7838运行下面程序的同时打开任何一个抓包工具分析。 实验表明Win ... -
TCPIP点点滴滴
2008-12-06 23:32 1305之前学到的TCPIP里面很多点点滴滴都没有做笔记,可以了。 ... -
UDP的ICMP差错的测试程序
2008-12-03 10:07 2240/* 作者:张亚霏 2008-12-03早 */ ... -
epoll的一个demo,备忘
2008-12-02 21:12 4429/** 张亚霏修改 文件名:epoll_demo. ... -
用asio的定时器实现带超时的connect,备忘
2008-11-30 19:39 7485// test.cpp : 定义控制台应用程序的入口点。 ... -
自己写的IOCP的程序,备忘(2009-02-05更新)
2008-11-30 19:10 3044#include <winsock2.h> ... -
TCP连接非正常断开的检测
2008-10-24 14:58 4589如果主机崩溃,write是 ... -
exit和_exit的区别
2008-10-23 19:38 1923exit()在结束调用它的进程之前,要进行如下步骤: 1.cl ... -
UDP数据包截断
2008-10-04 11:20 3374Posix系列的recv、recvfrom、read函数均无法 ... -
TCP协议里的时间
2008-10-04 11:18 3115一、建立连接 在发送SYN报文段后,如果在75秒没有收到相应 ... -
Linux-2.6.25 select系统调用源码分析
2008-10-04 11:12 11889Linux 2.6.25中的select系统调用 主要有4个函 ...
相关推荐
本压缩包"linux-2.6.25-android-1.0_r1.tar.gz"包含了Android开发初期所依赖的Linux内核源代码,版本号为2.6.25,这标志着一个里程碑,因为它是Android 1.0_r1版本的一部分。让我们一同深入探讨这个版本的内核以及它...
linux-2.6.25.tar.bz2 正版 编译很成功
《Linux2.6.25移植手册》的子文件《Linuxrebuild fortq24420embedsky.pdf》很可能提供了具体的操作步骤和实例,帮助读者实际操作每一个移植环节,从而加深对整个移植流程的理解。 总之,这份手册是TQ2440和Sky2440...
虚拟机vm下fedora系统下安装vmtools时用到的一个软件。为了方便虚拟机系统读取该文件。已经把他转成了.iso文件。只需加载到光驱就可以在虚拟机里读取了。 安装过程参考:...
在安装vmware tools时需要,这是.iso文件,直接在虚拟机中光盘中打开并拷贝到根目录下,在终端中运行rpm -ivh kernel-devel-2.6.25-14.fc9.i686.rpm即可
"kernel-devel-2.6.25-14.fc9.i686" 是一个针对FEDORA9操作系统的内核开发包,主要用于为开发者提供构建内核模块所需的头文件和符号链接。这个包是i686架构的,意味着它是为32位处理器设计的。在Linux系统中,内核是...
《libxml2-2.6.25:Linux系统中的XML解析库详解》 libxml2是开源软件项目,它提供了一个强大的XML解析库,广泛应用于各种操作系统,包括Linux。这个压缩包“libxml2-2.6.25.tar.gz”就是针对Linux系统的特定版本,...
kernel-2.6.25-14.fc9.src.rpm 这个更详细点 带各种配置文件
Smarty-2.6.25.tar.gz 是这个特定版本的Smarty模板引擎的压缩包,包含了该版本的所有源代码和相关文件。 Smarty的核心理念是将程序逻辑与展示逻辑分离。在传统的PHP开发中,开发者往往会在PHP代码中混杂HTML,使得...
".tar.gz"是一种常见的归档格式,由Unix/Linux系统中的tar命令创建,然后使用gzip工具进行压缩,以减少文件大小,便于传输和存储。解压这个文件通常需要两个步骤:首先使用tar命令解压.tar文件,然后使用gunzip或...
Smarty-2.6.25.zip 是一个包含 Smarty 模板引擎版本 2.6.25 的压缩包。Smarty 是一个广泛使用的 PHP 类库,它将应用逻辑与展示逻辑分离,使得 PHP 开发者可以更方便地创建和管理 Web 应用程序的前端模板。在 Web ...
5. **插件系统**:Smarty拥有丰富的内置函数和插件,如日期格式化、字符串操作等,同时也支持自定义插件,进一步扩展其功能。 6. **模板继承**:通过使用`{extends}`标签,可以创建基础模板并由其他模板继承,方便...
Smarty是一个使用PHP写出来的模板引擎,是目前业界最著名的PHP模板引擎之一。它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离。...
你是不是也在安装Fedora的VMware-Tools遇到麻烦呢?当你找到答案的时候,你就需要这个软件包了!
标题中的"peak-linux-driver-6.20.rar_pcan_peak_peak dongle_peak-linux-driver"揭示了这个压缩包的内容主要是关于PEAK-System公司的PCAN接口卡的Linux驱动程序,版本为6.20。"pcan"是PCAN的缩写,代表了控制器局域...
这里使用的工具链是`arm-linux-gcc3.4.4`,以及`u-boot`和`busybox1.10.1`。整个工作目录位于`/home/wbzh/`下,具体的步骤包括: 1. **解压内核源码**: - 使用`tar jxvf /home/wbzh/linux-2.6.25.tar.bz2`命令...
在Fedora的情况下,可以从`http://download.fedora.redhat.com/pub/`获取,例如,作者下载的是`kernel-2.6.25-14.fc9.src.rpm`。如果你选择下载`.tar.gz`格式的源码包,例如`linux-2.6.0-test11.tar.gz`,则需将其...
他选择了下载Android发布的内核版本(如linux-2.6.25-android-1.0_r1.tar.gz),并剥离了与G1手机硬件平台相关的内容,保留了与主线内核不同且硬件无关的改动,同时添加了与Mini2440硬件平台相关的驱动和配置。...
kernel-devel-2.6.25.14-108.fc9.i686.rpm 内核源码 解压过后 usr/src/kernels/2.6.25.14-108.fc9.i686/