TCP相关的sock数据结构及使用

TCPIP协议 专栏收录该内容
105 篇文章 6 订阅

TCP的三种sock数据结构

struct tcp_sock

struct tcp_timewait_sock

struct tcp_request_sock

初始化

inet_init函数中调用proto_register(&tcp_prot, 1),初始化tcp_prot:

static struct timewait_sock_ops   tcp_timewait_sock_ops = {
    .twsk_obj_size  = sizeof(struct tcp_timewait_sock),
}
struct request_sock_ops   tcp_request_sock_ops = {
    .family     =   PF_INET,
    .obj_size   =   sizeof(struct tcp_request_sock),
}

struct proto tcp_prot = {
    .name           = "TCP",
    .init           = tcp_v4_init_sock,
    .backlog_rcv    = tcp_v4_do_rcv,
    .obj_size       = sizeof(struct tcp_sock),
    .twsk_prot      = &tcp_timewait_sock_ops,
    .rsk_prot       = &tcp_request_sock_ops,
}

proto_register函数实现两个功能,1)分配3块tcp的mem cache:

tcp sock缓存,大小为sizeof(tcp_sock);
tcp timewait sock缓存,大小sizeof(struct tcp_timewait_sock);
tcp request sock缓存, 大小sizeof(struct tcp_request_sock);

2)将tcp_prot添加到全局proto_list链表,读取proc文件/proc/net/protocols时,遍历此链表。

TCP与IP层接口

注册回调函数,接收到TCP数据包时由IP层函数ip_local_deliver_finish调用。

static const struct net_protocol tcp_protocol = {
    .handler    =   tcp_v4_rcv,
};

inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)

TCP与INET层接口

注册函数inet_register_protosw将tcp_prot添加到全局链表inetsw,用户层socket API将调用其中的相应函数。

static struct inet_protosw inetsw_array[] =
{
    {
        .type =       SOCK_STREAM,
        .protocol =   IPPROTO_TCP,
        .prot =       &tcp_prot,     //tcp socket接口函数
        .ops =        &inet_stream_ops,  //inet流类型socket接口函数
    },
}

for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
	inet_register_protosw(q);

Socket调用流程

用户层创建tcp socket, 调用到inet_create(),遍历inetsw,找到注册的tcp的inet_protosw结构:

static int inet_create(struct net *net, struct socket *sock, int protocol,
               int kern)
{
    struct sock *sk;
	
	sock->ops = &inet_stream_ops;   //为清晰起见,使用伪代码
	
	//从之前初始化的mem cache中分配tcp_prot.obj_size大小的sock,即分配一个struct tcp_sock结构
	sk = sk_alloc(net, PF_INET, GFP_KERNEL, tcp_prot);
	
	sk->sk_prot = sk->sk_prot_creator = &tcp_prot;
	
	sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;   //这里是tcp_v4_do_rcv函数
	sk->sk_prot->init(sk);  //tcp_v4_init_sock函数
}

tcp_sock结构体本身,又包含了3种sock:

struct tcp_sock {
    struct inet_connection_sock inet_conn;
}
struct inet_connection_sock {
    struct inet_sock      icsk_inet;
}
struct inet_sock {
    struct sock     sk;   //上文sk_alloc返回的结果sk
}
inet_create函数最后调用tcp_v4_init_sock,
static int tcp_v4_init_sock(struct sock *sk)
	icsk->icsk_af_ops = &ipv4_specific;

const struct inet_connection_sock_af_ops   ipv4_specific = {
    .queue_xmit    = ip_queue_xmit,
    .send_check    = tcp_v4_send_check,
    .rebuild_header    = inet_sk_rebuild_header,
    .sk_rx_dst_set     = inet_sk_rx_dst_set,
    .conn_request      = tcp_v4_conn_request,
    .syn_recv_sock     = tcp_v4_syn_recv_sock,
}

TCP数据包接收

tcp连接状态处理函数tcp_rcv_state_process,

tcp_rcv_state_process()
{
    switch (sk->sk_state) {
    case TCP_LISTEN:
        if (th->syn) {
	    //调用ipv4_specific结构的tcp_v4_conn_request函数
            if (icsk->icsk_af_ops->conn_request(sk, skb) < 0)
                return 1;
		}
	switch (sk->sk_state) {
    case TCP_CLOSING:
        if (tp->snd_una == tp->write_seq) {
            tcp_time_wait(sk, TCP_TIME_WAIT, 0);
            goto discard;
        }
        break;
}

接收到SYN报文,运行TCP_LISTEN分支,最终调用tcp_conn_request函数处理SYN包,分配tcp_request_sock结构:

static const struct tcp_request_sock_ops   tcp_request_sock_ipv4_ops = {
    .mss_clamp  =   TCP_MSS_DEFAULT,
    .init_req   =   tcp_v4_init_req,
    .route_req  =   tcp_v4_route_req,
    .init_seq   =   tcp_v4_init_sequence,
    .send_synack    =   tcp_v4_send_synack,
    .queue_hash_add =   inet_csk_reqsk_queue_hash_add,
};
tcp_v4_conn_request()
{
    return tcp_conn_request(&tcp_request_sock_ops,
                &tcp_request_sock_ipv4_ops, sk, skb);
}

struct tcp_request_sock {
    struct inet_request_sock    req;
}
struct inet_request_sock {
    struct request_sock req;
}

int tcp_conn_request(struct request_sock_ops *rsk_ops,
             const struct tcp_request_sock_ops *af_ops,
             struct sock *sk, struct sk_buff *skb)
{
	struct request_sock *req;
	
	//从初始化的mem cache中分配tcp_request_sock_ops.obj_size大小的request_sock,
	//即分配一个struct tcp_request_sock结构
    req = inet_reqsk_alloc(rsk_ops);
    if (!req)
        goto drop;

	tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops;
}

TCP_CLOSING分支,分配tcp_timewait_sock结构:

void tcp_time_wait(struct sock *sk, int state, int timeo)
{
    struct inet_timewait_sock *tw = NULL;

	//从之前初始化的memcache中分配tcp_timewait_sock_ops.twsk_obj_size大小的inet_timewait_sock,
	//即分配一个struct tcp_timewait_sock结构
    tw = inet_twsk_alloc(sk, state);
		{
		 struct inet_timewait_sock *tw =
         kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab, GFP_ATOMIC);
		}
}

代码版本

Linux kernel 3.10

  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值