Initialization and socket TCP protocol to create a TCP socket descriptor

We are still talking about the start_kernel, it will eventually run:

arch_call_rest_init() --> rest_init() --> Kernel_init() --> Kernei_init_freeable() --> do_basic_setup() --> do_initcalls() --> do_initcall_level(level) 

do_initcall_level (level) based on the start seq level from level 0 corresponding to successively perform initialization function level.

The first step: core_initcall: socket_init

In the document there socket.c following code:

core_initcall(sock_init); /* early initcall */

Use core_initcall initialization macros modified sock_init function, the macro function specified sock_init on level 1 of the code, which means that it is the most advanced part of the implementation of this function simply allocate some memory space, and creates a file sock_fs_type system. Call sock_init in do_basic_setup precedes internet protocol registration is called, so the basic socket initialization must be completed before each TCP / IP protocol members can register to socket layer. socket_init code is as follows:

static int __init sock_init(void)
{
    /*
     * Initialize sock SLAB cache.
     */
    sk_init();
    /*
     * Initialize skbuff SLAB cache
     */
    skb_init();
    /*
     * Initialize the protocols module.
     */
    init_inodecache();
    register_filesystem(&sock_fs_type);
    sock_mnt = kern_mount(&sock_fs_type);
    /* The real protocol initialization is performed in later initcalls.
     */
#ifdef CONFIG_NETFILTER
    netfilter_init();
#endif
#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
    skb_timestamping_init();
#endif
    return 0;
}

sock_init function looks relatively simple, in fact, which completed a very important job. The first sentence calls sk_init (), in fact, do not do anything substantive, but a number of variables assignment. The skb_init () function role is to create two caches, skbuff_head_cache and skbuff_fclone_cache. Agreement related data are created in both the cache. So this is the initialization data structure.

sk_buff structure  as follows:
a packet in the application layer becomes data, the TCP layer becomes a segment, the IP layer becomes packet, becomes the data link layer frame. linux kernel sk_buff {} structures to hold an array, for storing data to be transmitted or received by the network in the INET socket level and below it, so it needs to be designed to have sufficient extensibility.

In order to use the socket buffer, the kernel creates two backup cache lookaside cache, they are skbuff_head_cache and skbuff_fclone_cache, protocol stacks used to all sk_buff structures are dispensed from the two backup cache. The difference is the size specified when creating skbuff_head_cache unit memory area is sizeof (struct sk_buff), can accommodate any number of struct sk_buff, and skbuff_fclone_cache specified when creating unit memory area size is 2 * sizeof (struct sk_buff) + sizeof (atomic_t), its minimum unit region is a pair of struct sk_buff and a reference count, which is a clone of sk_buff, i.e. they point to the same data buffer, the reference count is 0, 1, or 2, which represents there are several sk_buff the pair has been called. 

Memory management functions
in sk_buff {} 4 pointer data, head, tail, end time of initialization, data, head, tail are directed to the head of the data area of the application, end points to the tail of the data area. In the later operations, are generally obtained in the beginning and end of the available data area by sk_buff data and tail. It means that the head and end of the data packet present in sk_buff maximum extended spatial extent.
The following is a network protocol stack memory management functions

SOCK_INIT () function call to the last netfilter_init (), which will be used to initialize the module according to the corresponding protocol configuration, the TCP / IP protocol stack function initializes inlet inet_init () function.

Step two: fs_initcall: inet_init ()

This function is defined in the linux / net / ipv4 / af_inet.c file source code is as follows:

static int __init inet_init(void)
{
    ...
    rc = proto_register(&tcp_prot, 1);
    if (rc)
        goto out;

    ...

    /*
     *    Tell SOCKET that we are alive...
     */

    (void)sock_register(&inet_family_ops);

    ...
    /*
     *    Add all the base protocols.
     */

    ...
    if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
        pr_crit("%s: Cannot add TCP protocol\n", __func__);
    ...
    /* Register the socket-side information for inet_create. */
    for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
        INIT_LIST_HEAD(r);

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

    ...

    /* Setup TCP slab cache for open requests. */
    tcp_init();

    ...

}

fs_initcall(inet_init);

tcp_init()函数将初始化tcp协议,其定义如下:

void __init tcp_init(void)
{
    ...
    tcp_v4_init();
    tcp_metrics_init();
    BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0);
    tcp_tasklet_init();
}

可以看到inet_init()中先inet_add_protocol()注册TCP协议再对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,
    .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,
    .keepalive        = tcp_set_keepalive,
    .recvmsg        = tcp_recvmsg,
    .sendmsg        = tcp_sendmsg,
    .sendpage        = tcp_sendpage,
    .backlog_rcv        = tcp_v4_do_rcv,
    .release_cb        = tcp_release_cb,
    ...
};
EXPORT_SYMBOL(tcp_prot);
/* 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,
};

创建TCP套接字描述符

一个套接字描述符在使用socket()后,就对应了一个特定的套接口结构,而在使用bind()之后,该套接口结构也就工作在特定的端口上了,等到connect()完成,对方的端点就也确定了。可是内核是如何为用户创建套接字的呢?可以参考如下:

https://www.cnblogs.com/codestack/p/10849706.html

关于DBG跟踪验证,思路如下:

按顺序对

arch_call_rest_init() --> rest_init() --> Kernel_init() --> Kernei_init_freeable() --> do_basic_setup() --> do_initcalls() --> do_initcall_level(level) 

do_initcall_level(level)

打上断点,然后对创建套接字描述符的内核函数打断点,启动内核,运行replyhi和hello程序,观察是否出现断点。

由于时间紧张,内容下次再补充。

Guess you like

Origin www.cnblogs.com/xhgblog/p/12103803.html