1. 程式人生 > >IPv6實現--傳入包的處理流程(1)

IPv6實現--傳入包的處理流程(1)

IPv6中資料包的接收處理流程

在一個IPSEC包進入到網路層呼叫~/net/ipv6/ip6_input.c中的ipv6_rcv()函式,然後進入第一個鉤子NF_HOOK(PF_INET6, NF_INET_PRE_ROUTING, skb, dev, NULL,ip6_rcv_finish);對於NF_HOOK的作用解釋是, 如果沒有配置netfilter,可以簡單認為NF_HOOK就等於直接呼叫ip6_rcv_finish (skb)。

Ipv6_rcv()會處理hopbyhop報頭,在ipv6_parse_hopopts()函式中處理。注意ip6_parse_tlv()的處理過程,它本身只處理PAD0和PAD1的type,就是rfc2460裡面最早定義的兩個選項,其它選項都是通過tlvprochopopt_lst中定義的回撥函式來處理的。這樣就能夠根據將來協議的發展,靈活的新增新的hopbyhop型別,而不需要修改這個函式本身。

ip6_rcv_finish()是一個行內函數:
inline int ip6_rcv_finish( struct sk_buff *skb)
{
    if (skb->dst == NULL)
        ip6_route_input(skb);

    return dst_input(skb);
}

對於除hopbyhop以外的擴充套件報頭的處理,是通過路由表來進行的。在ip6_rcv_finish()裡面,會呼叫ip6_route_input(skb),這個函式返回的是路由表中對應的fib6_node,這個節點的input函式,就會根據不同的目的地呼叫不同的函式來處理。

在核心程式碼中查到的為input函式指標賦值的地方在~net/ipv6/route.c中:
struct rt6_info *addrconf_dst_alloc()函式       rt->u.dst.input = ip6_input;
int ip6_route_add()函式                       if (addr_type & IPV6_ADDR_MULTICAST)
                                        rt->u.dst.input = ip6_mc_input;
                                            else
                                        rt->u.dst.input = ip6_forward;
而ip6_mc_input()函式最終又會呼叫 ip6_input()函式。

如果資料報文是到本機,這個函式就是ip6_input()函式。擴充套件報頭的處理就在ip6_input()函式中。然後ip6_input()通過鉤子NF_HOOK(PF_INET6, NF_INET_LOCAL_IN, skb, skb->dev, NULL, ip6_input_finish);呼叫ip6_input_finish()。 然後通過struct inet6_protocol *ipprot變數呼叫在inet6_protos[]裡面註冊了的ipv6各個擴充套件報頭的處理函式,語句為ret = ipprot->handler(skb);
ip6_input_finish()中開始進入IP上層函式的處理,包括TCP、UDP、ICMP、ESP、AH等,這些協議都需要定義struct inet6_protocol這個結構掛接到ipv6的協議連結串列中,當接收到IP資料包時,會根據包中定義的IP協議號找到該結構,然後呼叫其成員handler函式進行處理。IPsec處理模組也是從這個函式進入處理的,當資料解密以後呼叫了netif_rx函式,文件描述說這個操作是把解密以後的包從新放回IP層 也就是從新執行ip6_rcv函式的開始過程.

具體的流程圖可以參照《linux網路體系結構》一書p374的圖


參考:
http://blog.csdn.net/uestc_huan/archive/2009/01/08/3735884.aspx
http://linux.chinaunix.net/bbs/thread-1017655-1-1.html