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

TCP协议初始化分析

 

在上一次实验中,已经对创建套接字的代码进行了简要分析,使用create_socket创建了套接字,这篇文章分析初始化的过程。

深入理解TCP协议及其源代码_第1张图片

 

 

 查看在函数中定义的tcp接口结构体,了解每个接口对应的处理函数。

 

struct proto tcp_prot = {
.name            = "TCP",
    .owner            = THIS_MODULE,
    .close            = tcp_close,
    .pre_connect        = tcp_v4_pre_connect,
    .connect        = tcp_v4_connect,
    .disconnect        = tcp_disconnect,
    .acc       
ept            = 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,
    .keepalive        = tcp_set_keepalive,
    .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,
    .leave_memory_pressure    = tcp_leave_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_offset    = offsetof(struct net, ipv4.sysctl_tcp_wmem),
    .sysctl_rmem_offset    = offsetof(struct net, ipv4.sysctl_tcp_rmem),
    .max_header        = MAX_TCP_HEADER,
    .obj_size        = sizeof(struct tcp_sock),
    .slab_flags        = SLAB_TYPESAFE_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
    .diag_destroy        = tcp_abort,
};

 

1、tcp协议的初始化找到init接口,发现其对应的处理方法是tcp_v4_init_sock,是一个静态类。

static int tcp_v4_init_sock(struct sock *sk)

{

struct inet_connection_sock *icsk = inet_csk(sk);

tcp_init_sock(sk);

icsk->icsk_af_ops = &ipv4_specific;

#ifdef CONFIG_TCP_MD5SIG

tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific;

#endif

return 0;

}

代码分成两段,在Init中使用的TCP MD5选项用于强化BGP协议的安全性,其基本原理是在TCP报文段的选项中携带MD5摘要。这个摘要的行为类似于这个报文的签名,其中包含这只有通信双方才能理解的信息。如果BGP协议使用TCP作为其传输层协议,使用MD5选项会有效减少安全隐患。

深入理解TCP协议及其源代码_第2张图片

 

 

 

 发现调用了tcp_init_sock,这里猜想tcpipv4init函数是采用的都是net/ipv4文件夹下的tcp.c文件中的内容进行调用的。

 深入理解TCP协议及其源代码_第3张图片

 

 

 深入理解TCP协议及其源代码_第4张图片

 

 

 查看socket.c中关于tcp_init_sock的源代码,发现大部分是对已创建的node以及tcp链进行了复制,仅有少部分调用了函数,可对tcp_init_xmit_timers,sk_sockets_allocated_inc函数分别进行分析。

 

void tcp_init_sock(struct sock *sk)
{
    struct inet_connection_sock *icsk = inet_csk(sk);
    struct tcp_sock *tp = tcp_sk(sk);

    tp->out_of_order_queue = RB_ROOT;
    sk->tcp_rtx_queue = RB_ROOT;
//对时间初始化 tcp_init_xmit_timers(sk); //初始化TCP链表头结点
INIT_LIST_HEAD(&tp->tsq_node); INIT_LIST_HEAD(&tp->tsorted_sent_queue); icsk->icsk_rto = TCP_TIMEOUT_INIT; tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT); minmax_reset(&tp->rtt_min, tcp_jiffies32, ~0U); /* So many TCP implementations out there (incorrectly) count the * initial SYN frame in their delayed-ACK and congestion control * algorithms that we must have the following bandaid to talk * efficiently to them. -DaveM */ tp->snd_cwnd = TCP_INIT_CWND; /* There's a bubble in the pipe until at least the first ACK. */ tp->app_limited = ~0U; /* See draft-stevens-tcpca-spec-01 for discussion of the * initialization of these values. */ //将变量值进行初始化 tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; tp->snd_cwnd_clamp = ~0; tp->mss_cache = TCP_MSS_DEFAULT; tp->reordering = sock_net(sk)->ipv4.sysctl_tcp_reordering; tcp_assign_congestion_control(sk); //偏移量置为0, tp->tsoffset = 0; tp->rack.reo_wnd_steps = 1; sk->sk_state = TCP_CLOSE; sk->sk_write_space = sk_stream_write_space; //set_flag将标志量初始化,将设置写权限,即能够在向需要啊发送的TCP数据中写入相应的数据。 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); icsk->icsk_sync_mss = tcp_sync_mss; //读写缓冲初始化 sk->sk_sndbuf = sock_net(sk)->ipv4.sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sock_net(sk)->ipv4.sysctl_tcp_rmem[1]; sk_sockets_allocated_inc(sk); sk->sk_route_forced_caps = NETIF_F_GSO; } EXPORT_SYMBOL(tcp_init_sock);

 

发现其中调用了两个方法类,以下对两个方法类分别进行分析。

首先对计时器进行了初始化,众所周知,TCP协议是一个可靠的协议,因此需要借助计时器进行监检测双方接收或者发送包是否有超时,进而判断是否存在丢包现象。

tcp_init_xmit_timers(sk)使用的是时钟的初始化。

 

1.2Socket计时器初始化

 

 

 

void tcp_init_xmit_timers(struct sock *sk)

{

inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer,

  &tcp_keepalive_timer);

hrtimer_init(&tcp_sk(sk)->pacing_timer, CLOCK_MONOTONIC,

     HRTIMER_MODE_ABS_PINNED_SOFT);

tcp_sk(sk)->pacing_timer.function = tcp_pace_kick;

 

hrtimer_init(&tcp_sk(sk)->compressed_ack_timer, CLOCK_MONOTONIC,

     HRTIMER_MODE_REL_PINNED_SOFT);

tcp_sk(sk)->compressed_ack_timer.function = tcp_compressed_ack_kick;

}

深入理解TCP协议及其源代码_第5张图片

 

 

 1、第一项
深入理解TCP协议及其源代码_第6张图片

 

 

 

调用的set_up是一个宏。

 #define timer_setup(timer, callback, flags) \

__init_timer((timer), (callback), (flags)

其目的是实现内核的定时机制的初始化。·  总结一下,看起来timer_setup(timer, callback, flags) 主要用是用callback和flags来给timer_list *timer 来赋值

因此inet_csk_xmit_timer调用内核计时器相关的初始化功能,将tcp写的时间进行了初始化,tcp延迟时间和tcp alive的时间

2、第二项

Hrtimer_init使用的是在内核的kernel/time/hrtimer

hrtimer_init初始化定时器工作模式。

hrtimer_init(&vibe_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
vibe_timer.function = timer_func;

初始化了定时器工作模式

 

 

 

1.3sk_sockets_allocated_inc(sk)

Clone a socket,and lock its clone

Caller must unlock socket even in error path

调用net中的core函数,其中涉及到了很多锁的知识。

深入理解TCP协议及其源代码_第7张图片

 

 

 该函数是用来克隆,是为了防止socket初始化失败。

深入理解TCP协议及其源代码_第8张图片

 

 

 

至此,对socket中init中较为重要的初始化函数进行了分析。

 

 

 

你可能感兴趣的:(深入理解TCP协议及其源代码)