TCP/IP协议栈之三---------网络层

3.1IP发送 

网络层中主要的发送函数有以下三个:ip_push_pending_frames,ip_queue_xmit,raw_send_hdrinc     (ip_output.c/ipv4)

 

ip_push_pending_frames 

将所有pending状态的IP分组组合成一个IP分组,并发送 

    ip_local_out 

 

 

ip_queue_xmit (sk_buff *skb)★ 

    ip_route_output_flow(找路由) 

    ip_local_out 

 

 

raw_send_hdrinc★ 

    NF_HOOK(dst_output) 

 

 

ip_local_out★ (只找得到NF_IP_LOCAL_OUT)

    __ip_local_out 

       nf_hook(dst_output) 

    dst_output     (dst.h)

 

路由选择 

ip_route_output_flow (rtable* , flowi *, sock *,)    (route.c/ipv4) P138

    __ip_route_output_key 

       ip_route_output_slow 

 

         flowi结构的介绍在P137

路由选择 

ip_route_output_slow   (route.c/ipv4)

    fib_lookup 

    ip_mkroute_output    (创建对应路由cache表项,将fib查找的结果放入路由cache中,P147

       __mkroute_output 

       rt_hash 

       rt_intern_hash 

           arp_bind_neighbour dst   (绑定对应邻居表项 P151,赋值dst->neighbour,当然,如果已经存在,则不需要创建)

               __neigh_lookup_errno 

                   neigh_lookup 

                   neigh_create 

 

发送

dst_output   dst.h

    dst->output= ip_output (struct sk_buff *) (dstskb->dst,路由选择完后,就会填写该项) P158

   NF_HOOK_COND(ip_finish_output) 

        ip_finish_output2     P180

         1.(skb->dst->hh等于NULL)neigh_hh_output 

               hh->hh_output = dev_queue_xmit 

         2.(hh等于NULL)dst->neighbour->output= neigh_resolve_output 

               neigh->ops->queue_xmit = dev_queue_xmit 

                                                       (dev.c/core—链路层)

               发送报文的主函数。dev_queue_xmit能够通过两个路径,导致驱动发送函数hard_start_xmit的执行:

 *      与流量控制的接口(QoS层):这是通过qdisc_run函数完成的。

 *      直接调用hard_start_xmit:当设备不使用流量控制机制时。     

 

neigh_resolve_output 是很重要的函数,见linux内核协议源码分析P161.该函数主要干了以下几件事:

1.      子函数neigh_event_send把报文挂在arp报文队列中,必须要注意的是,要发送的 arp 报文并不是这个,而是 arp 模块从此报文中抽取相关信息,然后据此再创建一个 arp 报文。

2.      neigh_hh_init 函数初始化hh,并把其赋值给dst->hh

3.      给报文填上2层报文头,并调用neigh->ops->queue_xmit(skb)把报文发送到链路层

该函数还干的一个重要的事情在P172页,将状态置为 NUD_INCOMPLETE,表示正在解析中,

并把待解析的 socket 缓冲 skb 放入 arp_queue 队列中(其实这个就是上面的neigh_event_send)。然后启动邻居的定时器开始 ARP 解析(定时器的启动在P163页: 当 neighnud_state 被设置为 NUD_INCOMPLETE 后,该 neigh 的定时器函数将要采取一些操作了,这个 timer 是在 neigh_alloc 制定的)。继而在定时器中调用函数neigh->ops->solicit(P172页),然后发送arp_send,接收到对端的回应后,调用neigh_update更新邻居系统

 

注:针对IPV4协议,这里的skb->dst->output指针指向的函数可能是ip_output(单播报文)或者是ip_mc_output(组播报文)。

2:如果是IPV6协议,那指针指向的就是ip6_output

3IPV6协议skb->dst->output只会指向ip6_outputip6_mc_output被包裹在ip6_output中。

 

TCP/IP协议栈之三---------网络层_第1张图片


3.2IP接受 

接收IPv4包,由netif_rx间接调用 

ip_rcv(skb,dev)    ip_input.c/ipv4

    NF_HOOK 

    ip_rcv_finish (skb

        ip_route_input(skb,addr,addr,dev)该函数决定如何处理普通报文(是送往本地、还是转发、丢弃等

                                   (在该函数里面会进行路由选路,即给skb->dst赋值

 

)

       dst_input (skb)

           dst->input(skb)(可能是ip_local_deliver或ip_forward) 

           if(是发给本地的包) 

         dst->input是ip_local_deliver (skb)

                   NF_HOOK 

                   ip_local_deliver_finish (skb)

                   ipprot->handler(可能是tcp_v4_rcv,udp_rcv,icmp_rcv,igmp_rcv) socket解复用-书籍P54

           else 

               dst->input是ip_forward 

 

 

重要:skb->dst的初始化不是在ip_rcv_finish的开端(ip_route_input的开头),就是在ip_options_rcv_srr的尾端。skb->dst->input会设成ip_local_deliver或ip_forward,这取决于包的目的地址。

 

 

更新路由 

ip_route_input (skb,addr,addr,dev) 

       1.在缓存中查找,找到了则skb->dst =(struct dst_entry*)rth;

    2.ip_route_input_mc(多播) 

       rt_hash 

       rt_intern_hash 

    3.ip_route_input_slow(其它,查找路由表—详情见IP发送) 

       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(skb) 

1.从skb->dst拿到下一跳地址

2.ip_call_ra_chain 

raw_rcv 

3.ip_forward_finish

  dst_output 

 


你可能感兴趣的:(TCP/IP协议栈之三---------网络层)