深入理解TCP协议及其源代码

Posted zhouz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解TCP协议及其源代码相关的知识,希望对你有一定的参考价值。

# TCP协议的初始化及socket创建TCP套接字描述符

1. TCP协议简介

  

1.  TCP协议的初始化

  从内核启动的起点 start_kernel 开始 -->  rest_init --> kernel_init --> do_basic_setup --> inet_init 

  Linux内核初始化过程中加载了TCP/IP协议栈,inet_init函数即为Linux内核初始化TCP/IP的入口位置

 1.1 inet_init 

    在inet_init中与初始化TCP相关的主要是proto_register和inet_add_protocol、tcp_init函数及tcp_prot和tcp_protocol两个结构体

    # proto_register第二个参数表示为tcp_prot分配cache高速缓存

   # 先tcp_prot注册,再在inet域中添加tcp协议,

   技术图片

    技术图片

      技术图片

      技术图片

     技术图片

 1.2 proto_register

   跟踪到proto_register, 其在net/core/sock.c文件中, 该函数初始化了tcp_prot

   技术图片

    到该文件中查看proto_register协议注册函数

    其中只介绍了部分,... 表示该处省略了一些内容

// 根据alloc_slab来决定是否为其分配告诉缓存
int
proto_register(struct proto *prot, int alloc_slab) { if (alloc_slab) { // 表明注册协议时要分配slab缓存 prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, // 由kmem_cache_create()完成TCP协议的slab缓存建立; SLAB_HWCACHE_ALIGN | prot->slab_flags, NULL); if (prot->slab == NULL) { pr_crit("%s: Can‘t create sock SLAB cache! ", prot->name); goto out; } if (prot->rsk_prot != NULL) { prot->rsk_prot->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", prot->name); // 申请内存空间 if (prot->rsk_prot->slab_name == NULL) goto out_free_sock_slab; prot->rsk_prot->slab = kmem_cache_create(prot->rsk_prot->slab_name, // 创建缓存 prot->rsk_prot->obj_size, 0, SLAB_HWCACHE_ALIGN, NULL); if (prot->rsk_prot->slab == NULL) { pr_crit("%s: Can‘t create request sock SLAB cache! ", prot->name); goto out_free_request_sock_slab_name; } } if (prot->twsk_prot != NULL) { prot->twsk_prot->twsk_slab_name = kasprintf(GFP_KERNEL, "tw_sock_%s", prot->name); if (prot->twsk_prot->twsk_slab_name == NULL) goto out_free_request_sock_slab; prot->twsk_prot->twsk_slab = kmem_cache_create(prot->twsk_prot->twsk_slab_name, prot->twsk_prot->twsk_obj_size, 0, SLAB_HWCACHE_ALIGN | prot->slab_flags, NULL); if (prot->twsk_prot->twsk_slab == NULL) goto out_free_timewait_sock_slab_name; } } mutex_lock(&proto_list_mutex);
// proto_list在/proc/net/protocols文件中输出当前系统支持的协议 list_add(
&prot->node, &proto_list); // 将tcp_prot添加到proto_list链表上,等下一次; proto_list是一個全局静态链表,inet域支持的所有协议都在这里链表中 assign_proto_idx(prot);         mutex_unlock(&proto_list_mutex); return 0; out_free_timewait_sock_slab_name: kfree(prot->twsk_prot->twsk_slab_name); out_free_request_sock_slab: if (prot->rsk_prot && prot->rsk_prot->slab) { kmem_cache_destroy(prot->rsk_prot->slab); prot->rsk_prot->slab = NULL; } out_free_request_sock_slab_name: if (prot->rsk_prot) kfree(prot->rsk_prot->slab_name); out_free_sock_slab: kmem_cache_destroy(prot->slab); prot->slab = NULL; out: return -ENOBUFS; } EXPORT_SYMBOL(proto_register);

  1.3 tcp_prot

    该结构体在/net/ipv4/tcp_ipv4.c文件中,查看源码, 包含了与tcp相关的所有信息, 指定了TCP协议栈的访问接口函数

    socket接口层里sock->opt->connect和sock->opt->accept对应的接口函数也是在这里初始化的

struct proto tcp_prot = {
    .name            = "TCP",           
    .owner            = THIS_MODULE,
    .close            = tcp_close,
    .connect        = tcp_v4_connect,
    .disconnect        = tcp_disconnect,
    .accept            = inet_csk_accept,
    .ioctl            = tcp_ioctl,
    .init            = tcp_v4_init_sock,    
    .destroy        = tcp_v4_destroy_sock,
    .shutdown        = tcp_shutdown,
    .setsockopt        = tcp_setsockopt,
    .getsockopt        = tcp_getsockopt,
    .recvmsg        = tcp_recvmsg,
    .sendmsg        = tcp_sendmsg,
    .sendpage        = tcp_sendpage,
    .backlog_rcv        = tcp_v4_do_rcv,
    .release_cb        = tcp_release_cb,
    .hash            = inet_hash,
    .unhash            = inet_unhash,
    .get_port        = inet_csk_get_port,
    .enter_memory_pressure    = tcp_enter_memory_pressure,
    .stream_memory_free    = tcp_stream_memory_free,
    .sockets_allocated    = &tcp_sockets_allocated,
    .orphan_count        = &tcp_orphan_count,
    .memory_allocated    = &tcp_memory_allocated,
    .memory_pressure    = &tcp_memory_pressure,
    .sysctl_mem        = sysctl_tcp_mem,
    .sysctl_wmem        = sysctl_tcp_wmem,
    .sysctl_rmem        = sysctl_tcp_rmem,
    .max_header        = MAX_TCP_HEADER,
    .obj_size        = sizeof(struct tcp_sock),
    .slab_flags        = SLAB_DESTROY_BY_RCU,
    .twsk_prot        = &tcp_timewait_sock_ops,
    .rsk_prot        = &tcp_request_sock_ops,
    .h.hashinfo        = &tcp_hashinfo,
    .no_autobind        = true,
#ifdef CONFIG_COMPAT
    .compat_setsockopt    = compat_tcp_setsockopt,
    .compat_getsockopt    = compat_tcp_getsockopt,
#endif
#ifdef CONFIG_MEMCG_KMEM
    .init_cgroup        = tcp_init_cgroup,
    .destroy_cgroup        = tcp_destroy_cgroup,
    .proto_cgroup        = tcp_proto_cgroup,
#endif
};
EXPORT_SYMBOL(tcp_prot);

   1.4 tcp_protocol

/* thinking of making this const? Don‘t.
 * early_demux can change based on sysctl.
 */
static struct net_protocol tcp_protocol = {
    .early_demux    =    tcp_v4_early_demux,
    .early_demux_handler =  tcp_v4_early_demux,
    .handler    =    tcp_v4_rcv,
    .err_handler    =    tcp_v4_err,
    .no_policy    =    1,
    .netns_ok    =    1,
    .icmp_strict_tag_validation = 1,
};

 

2. socket创建TCP套接字描述符

 

 

以上是关于深入理解TCP协议及其源代码的主要内容,如果未能解决你的问题,请参考以下文章

深入理解TCP协议及其源代码

深入理解TCP协议及其源代码

深入理解TCP协议及其源代码

深入理解TCP协议及其源代码

深入理解TCP协议及其源代码

深入理解TCP协议及其源代码