深入理解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协议及其源代码的主要内容,如果未能解决你的问题,请参考以下文章