内核网络协议栈传输层协议框架

 

Linux内核支持的传输层协议包括传统的TCP,UDP,以及IPIP、GRE等隧道协议。内核协议栈使用net_protocol结构体表示其所支持的传输层协议,系统初始化或者相应协议模块加载时,具体的协议将根据协议号将其实现的net_protocol结构体注册到协议栈中,即以协议号为索引添加到全局结构体指针数组inet_protos[]中。inet_protos数据大小为MAX_INET_PROTOS(256),由于IP头部中protocol字段为8bit位,256以足够保存所有协议。

	struct net_protocol {
		int         (*early_demux)(struct sk_buff *skb);
		int         (*early_demux_handler)(struct sk_buff *skb);
		int         (*handler)(struct sk_buff *skb);
		void        (*err_handler)(struct sk_buff *skb, u32 info);
		unsigned int  no_policy:1,
					  netns_ok:1,
					  icmp_strict_tag_validation:1;
	};
	struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly;

传输层的预分流功能(early_demux/early_demux_handler)目前只有TCP和UDP协议有实现,其它类型不支持。handler回调函数为协议的核心处理函数。内核提供inet_add_protocol函数向系统注册协议处理结构。

传输层协议

目前Linux内核协议栈支持的协议有以下,分成3个组列出:

标准传输协议:

    -------------------------------------------------------------------------------    
    |	 协议号                 |  协议栈注册结构        |     处理函数(handler)   |
    -------------------------------------------------------------------------------
    |    IPPROTO_UDP(17)      |  udp_protocol         |     udp_rcv             |
    |    IPPROTO_TCP(6)       |  tcp_protocol         |     tcp_v4_rcv          |
    |    IPPROTO_ICMP(1)      |  icmp_protocol        |     icmp_rcv            |
    |    IPPROTO_IGMP(2)      |  igmp_protocol        |     igmp_rcv            |
    |    IPPROTO_DCCP(33)     |  dccp_v4_protocol     |     dccp_v4_rcv         |
    |    IPPROTO_SCTP(132)    |  sctp_protocol        |     sctp_rcv            |
    |    IPPROTO_UDPLITE(136) |  udplite_protocol     |     udplite_rcv         |
    |    IPPROTO_PIM(103)     |  pim_protocol         |     pim_rcv             |
    -------------------------------------------------------------------------------

隧道相关协议:

    -------------------------------------------------------------------------------    
    |    IPPROTO_L2TP(115)    |  _ip_protocol     |     _ip_recv        |
    |    IPPROTO_IPIP(4)      |  tunnel4_protocol     |     tunnel4_rcv         |
    |    IPPROTO_IPV6(41)     |  tunnel64_protocol    |     tunnel64_rcv        |
    |    IPPROTO_MPLS(137)    |  tunnelmpls4_protocol |     tunnelmpls4_rcv     |
    |    IPPROTO_GRE(47)      |  net_gre_protocol     |     gre_rcv             |
    -------------------------------------------------------------------------------

IPSec相关协议:

    -------------------------------------------------------------------------------
	|	IPPROTO_AH(51)        | ah4_protocol          |     xfrm4_ah_rcv        |
	|	IPPROTO_ESP(50)       | esp4_protocol         |     xfrm4_esp_rcv       |
	|	IPPROTO_COMP(108)     | ipcomp4_protocol      |     xfrm4_ipcomp_rcv    |
    -------------------------------------------------------------------------------

对于IPv6与以上IPv4结构相同。内核协议栈使用inet6_protocol结构体表示其所支持的传输层协议,使用inet6_add_protocol向内核注册协议。

	struct inet6_protocol {
		void    (*early_demux)(struct sk_buff *skb);
		void    (*early_demux_handler)(struct sk_buff *skb);
		int     (*handler)(struct sk_buff *skb);
	
		void    (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info);
		unsigned int    flags;  /* INET6_PROTO_xxx */
	};

目前内核支持的IPv6传输层协议:

	-------------------------------------------------------------------------------
	|	协议号                |   协议栈注册结构         |   处理函数(handler) |
	-------------------------------------------------------------------------------		
	|	IPPROTO_SCTP          |   sctpv6_protocol        |   sctp6_rcv            |
	|	IPPROTO_UDPLITE       |   udplitev6_protocol     |   udplitev6_rcv        |
	|	IPPROTO_UDP           |   udpv6_protocol         |   udpv6_rcv            |
	|	IPPROTO_FRAGMENT      |   frag_protocol          |   ipv6_frag_rcv        |
	|	IPPROTO_ROUTING       |   rthdr_protocol         |   ipv6_rthdr_rcv       |
	|	IPPROTO_DSTOPTS       |   destopt_protocol       |   ipv6_destopt_rcv     |
	|	IPPROTO_NONE          |   nodata_protocol        |   dst_discard          |
	|	IPPROTO_TCP           |   tcpv6_protocol         |   tcp_v6_rcv           |
	|	IPPROTO_PIM           |   pim6_protocol          |   pim6_rcv             |
	|	IPPROTO_ICMPV6        |   icmpv6_protocol        |   icmpv6_rcv           |
	|	IPPROTO_DCCP          |   dccp_v6_protocol       |   dccp_v6_rcv          |
    -------------------------------------------------------------------------------

隧道相关协议:

    -------------------------------------------------------------------------------
    |    IPPROTO_L2TP         |    _ip6_protocol     |    _ip6_recv       |
    |    IPPROTO_IPV6         |    tunnel6_protocol      |    tunnel6_rcv         |
    |    IPPROTO_IPIP         |    tunnel46_protocol     |    tunnel46_rcv        |
    |    IPPROTO_GRE          |    ip6gre_protocol       |    gre_rcv             |
    -------------------------------------------------------------------------------

IPSec相关协议:

    -------------------------------------------------------------------------------
    |    IPPROTO_AH(51)      |   ah4_protocol           |    xfrm6_ah_rcv        |
    |    IPPROTO_ESP(50)     |   esp4_protocol          |    xfrm6_esp_rcv       |
    |    IPPROTO_COMP(108)   |   ipcomp4_protocol       |    xfrm6_ipcomp_rcv    |
    -------------------------------------------------------------------------------

协议处理

网络层函数ip_local_deliver_finish(IPv6:ip6_input_finish)负责调用上层传输协议回调函数。如下代码所示,从IP头部取出protocol协议号字段,以此为所以到inet_protos(IPv6:inet6_protos)数组中取出相应的注册协议结构体,调用其中的回调函数(handler)。

static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    int protocol = ip_hdr(skb)->protocol;
    const struct net_protocol *ipprot;

    ipprot = rcu_dereference(inet_protos[protocol]);
    if (ipprot)
        ret = ipprot->handler(skb);
}

如果接收到ICMP错误信息,根据协议类型ICMP模块调用相应的协议错误处理函数(err_handler):

static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
{
    const struct net_protocol *ipprot;
    int protocol = iph->protocol;
(...)
    ipprot = rcu_dereference(inet_protos[protocol]);
    if (ipprot && ipprot->err_handler)
        ipprot->err_handler(skb, info);
}

预分流功能

预分流时网络层在处理接收到数据包时,在路由查找和netfilter的hook点NF_INET_LOCAL_IN之前,提前查找套接口,取得套接口中缓存路由项的功能。这样省去了之后的路由查找,此功能仅适用处于established状态的套接口。但是对于要转发的报文,增加了不必要的套接口查找操作。

在ip_rcv_finish函数中,根据协议号找到相应的协议处理结构,调用其中的early_demux回调函数。early_demux成员变量指向同结构中的early_demux_handler,用户可单独关闭TCP或者UDP的预分流,关闭时其early_demux指向空指针。用户可通过proc文件(/proc/sys/net/ipv4/ip_early_demux)整个关闭预分流功能。

static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
    const struct iphdr *iph = ip_hdr(skb);
    int (*edemux)(struct sk_buff *skb);
    struct net_device *dev = skb->dev;

    if (net->ipv4.sysctl_ip_early_demux &&
        !skb_dst(skb) &&
        !skb->sk &&
        !ip_is_fragment(iph)) {
        const struct net_protocol *ipprot;
        int protocol = iph->protocol;

        ipprot = rcu_dereference(inet_protos[protocol]);
        if (ipprot && (edemux = READ_ONCE(ipprot->early_demux)))
            err = edemux(skb);
    }
}

IPSec传输协议

关于IPSec的协议注册需要注意,内核子模块XFRM首先注册了通用的net_protocol结构和三个协议的回调函数(xfrm4_ah_rcv/xfrm4_esp_rcv/xfrm4_ipcomp_rcv)。但是这三个回调实际上不进行实际的报文处理,而是作为入口,根据注册的子协议结构,调用XFRM系统自身的子协议处理函数。例如对于ESP协议,XFRM模块注册了两个子协议结构esp4_protocol和vti_esp4_protocol,分别对应两个处理函数xfrm4_rcv和vti_rcv。

    --------------------------------------------------
    |    XFRM子协议结构         | XFRM子处理函数       |
    --------------------------------------------------
    |    ah4_protocol          |                     | 
    |    esp4_protocol         |    xfrm4_rcv        |
    |    ipcomp4_protocol      |                     |
    --------------------------------------------------
    |    vti_ah4_protocol      |                     |
    |    vti_esp4_protocol     |    vti_rcv          |
    |    vti_ipcomp4_protocol  |                     |
    --------------------------------------------------

XFRM模块提供xfrm4_protocol_register注册子协议结构,ah4_protocol为xfrm4_protocol类型的结构体变量,与以上的主协议变量ah4_protocol(net_protocol结构体)同名但是不同的数据结构。相同协议号的xfrm4_protocol结构体通过其成员next链接起来,内核中为三种协议(AH、ESP和IPCOMP)定义了链表头,分别为ah4_handlers、esp4_handlers。 协议入口函数(如xfrm4_ah_rcv)从头开始遍历链表(如ah4_handlers链表),依次调用其中的子处理函数。

struct xfrm4_protocol {
    int (*handler)(struct sk_buff *skb);
    int (*input_handler)(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type);
    int (*cb_handler)(struct sk_buff *skb, int err);
    int (*err_handler)(struct sk_buff *skb, u32 info);
    struct xfrm4_protocol __rcu *next;
    int priority;
}; 

对于IPv6 IPSec协议,代码框架与IPv4相同,使用xfrm6_protocol_register函数注册协议结构,子协议链条头指针分别为ah6_handlers、esp6_handlers和ipcomp6_handlers分别对应AH、ESP和IPCOMP三种协议。

    --------------------------------------------------
    |    XFRM子协议结构         | XFRM子处理函数       |
    --------------------------------------------------
    |    ah6_protocol          |                     | 
    |    esp6_protocol         |     xfrm6_rcv       |
    |    ipcomp6_protocol      |                     |
    --------------------------------------------------
    |    vti_ah6_protocol      |                     |
    |    vti_esp6_protocol     |     vti6_rcv        |
    |    vti_ipcomp6_protocol  |                     |
    --------------------------------------------------

内核版本

Linux-4.15

 

你可能感兴趣的:(TCPIP协议)