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

你可能感兴趣的:(linux内核)