内核IP隧道接收处理框架

内核使用inet_add_protocol注册了三种类型的隧道接收处理函数,三种类型分别为IPv4-in-IPv4隧道类型IPPROTO_IPIP(4)、IPv6-in-IPv4隧道IPPROTO_IPV6(41)和MIPS-in-IP隧道IPPROTO_MPLS(137)。接收处理函数分别为:tunnel4_rcv、tunnel64_rcv和tunnelmpls4_rcv。具体参见tunnel4_protocol、tunnel64_protocol和tunnelmpls4_protocol网络协议结构体的实例。

static int __init tunnel4_init(void)
{
    if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP))
        goto err;
    if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6))
        goto err;
    if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS))
        goto err;
}

IPPROTO_IPIP类型的网络协议结构tunnel4_protocol如下,其handler回调函数指定为tunnel4_rcv:

static const struct net_protocol tunnel4_protocol = {
    .handler    =   tunnel4_rcv,
    .err_handler    =   tunnel4_err,
    .no_policy  =   1,  /* no XFRM_POLICY_IN */
};

隧道数据包接收

IPPROTO_IPIP类型数据包由注册的函数tunnel4_rcv处理。其为一个分发函数,遍历所有注册在tunnel4_handlers链表上的xfrm_tunnel类型结构,调用其成员中的handler函数指针处理接收到的数据包。优先级高的xfrm_tunnel结构先处理数据包,成功处理后(结果为0),终止遍历。

static int tunnel4_rcv(struct sk_buff *skb)
{
    struct xfrm_tunnel *handler;

    for_each_tunnel_rcu(tunnel4_handlers, handler)
        if (!handler->handler(skb))
            return 0;
}

类似的,IPPROTO_IPV6类型数据包由注册的函数tunnel64_rcv处理,其遍历注册在tunnel64_handlers链表的xfrm_tunnel元素,调用成员handler回调函数。

static int tunnel64_rcv(struct sk_buff *skb)
{
    struct xfrm_tunnel *handler;

    for_each_tunnel_rcu(tunnel64_handlers, handler)
        if (!handler->handler(skb))
            return 0;
}

IPPROTO_MPLS类型数据包由注册的函数tunnelmpls4_rcv处理,其遍历tunnelmpls4_handlers链表的xfrm_tunnel元素。

static int tunnelmpls4_rcv(struct sk_buff *skb)
{
    struct xfrm_tunnel *handler;

    for_each_tunnel_rcu(tunnelmpls4_handlers, handler)
        if (!handler->handler(skb))
            return 0;
}

隧道结构的注册

函数xfrm4_tunnel_register负责向系统中注册xfrm_tunnel结构。目前内核支持的xfrm_tunnel结构分为三个大类:

1)对应于AF_INET协议族(即IPPROTO_IPIP)的ipip_handler(net/ipv6/sit.c),优先级为1;ipip_handler(net/ipv4/ipip.c),优先级2;以及xfrm_tunnel_handler(net/ipv4/xfrm4_tunnel.c),优先级为3。
2)对应于AF_INET6协议族(即IPPROTO_IPV6)的sit_handler(net/ipv6/sit.c),优先级为1;和xfrm64_tunnel_handler(net/ipv4/xfrm4_tunnel.c),优先级为2。
3)最后是,AF_MPLS协议族(即IPPROTO_MPLS协议)的mplsip_handler(net/ipv4/ipip.c),优先级为1;和mplsip_handler(net/ipv6/sit.c),优先级为2。
 

int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family)
{
    struct xfrm_tunnel __rcu **pprev;
    struct xfrm_tunnel *t;

    int priority = handler->priority;

    for (pprev = fam_handlers(family);
         (t = rcu_dereference_protected(*pprev, lockdep_is_held(&tunnel4_mutex))) != NULL;
         pprev = &t->next) {
        if (t->priority > priority)
            break;
    }
    handler->next = *pprev;
    rcu_assign_pointer(*pprev, handler);
}

函数fam_handlers根据协议族的值返回其xfrm_tunnel链表的首指针,对于三个协议族AF_INET、AF_INET6和AF_MPLS,首指针分别为tunnel4_handlers、tunnel64_handlers和tunnelmpls4_handlers。三个链表中的元素都是按照优先级由高到低排序,priority数值越小,优先级越高。

static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family)
{
    return (family == AF_INET) ? &tunnel4_handlers :
        (family == AF_INET6) ? &tunnel64_handlers :
        &tunnelmpls4_handlers;
}

隧道接收流程

如下图:

 ip_local_deliver_finish
    |     		
 inet_protos[proto]
    |        
 IPPROTO_IPIP (4)
    |         |
    |    tunnel4_rcv
    |         |
    |         +---- ipip_rcv (net/ipv4/ipip.c)
    |         |         |----- ipip_tunnel_rcv(skb, IPPROTO_IPIP)
    |         |
    |         +---- ipip_rcv (net/ipv6/sit.c)
    |         |         |----- sit_tunnel_rcv(skb, IPPROTO_IPIP)
    |         |		   
    |         +---- xfrm_tunnel_rcv (net/ipv4/xfrm4_tunnel.c)       
    |                   |----- xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr)
    |        
 IPPROTO_IPV6 (41)
    |         |
    |    tunnel64_rcv
    |         |
    |         +---- ipip6_rcv (net/ipv6/sit.c)
    |         |
    |         +---- xfrm_tunnel_rcv (net/ipv4/xfrm4_tunnel.c)
    |                    |----- xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr)
    |
 IPPROTO_MPLS (137)
    |         |
    |    tunnelmpls4_rcv
    |         |
    |         +---- mplsip_rcv (net/ipv4/ipip.c)
    |         |          |----- ipip_tunnel_rcv(skb, IPPROTO_MPLS)
    |         |
    |         +---- mplsip_rcv (net/ipv6/sit.c)
   +++                   |----- sit_tunnel_rcv(skb, IPPROTO_MPLS)

内核版本

Linux-4.15

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页