Tracing Analysis of TCP in the kernel-9-tcp (IPv4) socket address binding-continued 2

Source: Internet
Author: User

Next, let's continue the analysis of yesterday. Next, let's start with the last part of the previous section:
I am an unknown pawn. If you reprint it, please indicate the source. Please do not copy it for use. Thank you!

In the kernel, The config_net_ns configuration option is to allow users to customize their own network space structure, that is, the above net structure. We can see the flexibility of the 2.6.26 kernel, however, this item is usually not configured in the kernel, so here we should get init_net. This structure is called from pure_initcall (net_ns_init) in the do_one_initcall () mechanism as analyzed in the previous section) registered net_ns_init,
# Define pure_initcall (FN) _ define_initcall ("0", FN, 0)
The net_ns_init function further calls setup_net () to set the init_net structure in detail. We will not analyze the initialization process of the socket in front of us, but there is a very important loop in setup_net initialization of init_net.

Net_ns_init () --> setup_net ()
List_for_each_entry (Ops, & pernet_list, list ){
If (OPS-> init ){
Error = OPS-> Init (net );
If (error0)
Goto out_undo;
}
}
In this loop, the pernet_operations of the hook structure will be used from the registered pernet_list queue in turn, and the hook function init in the structure will be called to set the initial structure of the Net network namespace. Here, pernet_list is a queue header, which is used in the/NET/CORE/net_namespace.c file to register the queue for the custom pernet_operations structure of person net, that is, the custom pernet_operations structure can be chained into the queue only when the config_net_ns situation we mentioned above is used.
Static list_head (pernet_list );
Here, the list_head macro is in include/Linux/list. h.
# Define list_head (name )/
Struct list_head name = list_head_init (name)
# Define list_head_init (name) {& (name), & (name )}
Struct list_head {
Struct list_head * Next, * Prev;
};
My friends may have noticed that I often put calls in front, indicating the structure of the data arranged in the back. This kind of habit is personally helpful for understanding and remembering. Learning with questions is far more efficient than learning with questions. So when is this structure initialized? The initcall mechanism mentioned in socket initialization in Section 1 of this class will show a sentence in/NET/CORE/dev. C.
Subsys_initcall (net_dev_init );
He references
# Define subsys_initcall (FN) _ define_initcall ("4", FN, 4)
Therefore, according to the initcall mechanism mentioned in section 1, the net_dev_init function will be executed at startup, and such code exists in this function:

Net_dev_init ()
If (register_pernet_subsys (& netdev_net_ops ))
Goto out;
If (register_pernet_device (& default_device_ops ))
Goto out;
The two functions called in the code above call the register_pernet_operations function.

Net_dev_init () --> register_pernet_subsys () and register_pernet_device ()
Int register_pernet_subsys (struct pernet_operations * OPS)
{
Int error;
Mutex_lock (& net_mutex );
Error = register_pernet_operations (first_device, OPS );
Mutex_unlock (& net_mutex );
Return Error;
}
Int register_pernet_device (struct pernet_operations * OPS)
{
Int error;
Mutex_lock (& net_mutex );
Error = register_pernet_operations (& pernet_list, OPS );
If (! Error & (first_device ==& pernet_list ))
First_device = & OPS-> list;
Mutex_unlock (& net_mutex );
Return Error;
}
We saw first_device In the first function register_pernet_subsys above, which is declared at 17 rows in net_namespace.c.

Net_dev_init () --> register_pernet_operations ()
Static struct list_head * first_device = & pernet_list;
Go to register_pernet_operations. Let's take a look.
Static int register_pernet_operations (struct list_head * List,
Struct pernet_operations * OPS)
{
If (OPS-> init = NULL)
Return 0;
Return OPS-> Init (& init_net );
}
In net_namespace.c, there is another function with the same name, but it must be enabled when the option to support the net_ns user-defined network is enabled. As mentioned above, so here we will go to the netdev_net_ops hook structure passed in the middle layer of the net_dev_init function, and execute the hook function init in this structure. Let's take a look at this structure.
Static struct pernet_operations _ net_initdata netdev_net_ops = {
. Init = netdev_init,
. Exit = netdev_exit,
};
Apparently, the netdev_init function is entered. before entering the function, we can see that it is an operation on the system's default network Space Structure Variable init_net.

Net_dev_init () --> register_pernet_operations () --> netdev_init ()
/* Initialize per network namespace state */
Static int _ net_init netdev_init (struct net * Net)
{
Init_list_head (& net-> dev_base_head );
Net-> dev_name_head = netdev_create_hash ();
If (net-> dev_name_head = NULL)
Goto err_name;
Net-> dev_index_head = netdev_create_hash ();
If (net-> dev_index_head = NULL)
Goto err_idx;
Return 0;
Err_idx:
Kfree (net-> dev_name_head );
Err_name:
Return-enomem;
}
I am an unknown pawn. This article was originally completed by me. Although I started to write articles in May March, it has been recognized by my friends and the article has also been reproduced.
Http://qinjiana07876.cublog.cn
In the above function, we can see several queue headers that initialize init_net, two of which are hash queues. For details about the concept of hash queue, refer to the introduction in the third version of Linux kernel. The following are two functions called by the kernel. The first function is to initialize the queue header, one function creates a hash queue header and initializes it. As shown above, net has these two dev_name_headers (the device name is the primary key hash Queue) and dev_index_head (hash queue with the device serial number as the primary key) hash queue header.

Net_dev_init () --> register_pernet_operations () --> netdev_init () --> init_list_head () and netdev_create_hash ()
Static inline void init_list_head (struct list_head * List)
{
List-> next = List;
List-> Prev = List;
}
Static struct hlist_head * netdev_create_hash (void)
{
Int I;
Struct hlist_head * hash;
Hash = kmalloc (sizeof (* hash) * netdev_hashentries, gfp_kernel );
If (hash! = NULL)
For (I = 0; inetdev_hashentries; I ++)
Init_hlist_head (& hash);
Return hash;
}
These two functions initialize the queue header. The first function is to initialize the common linked list header. The following function is to initialize the hash queue header. The function is simple. These two functions are in include/Linux/list. h and/NET/CORE/dev. C respectively. Next, let's look at the previously posted register_pernet_device function. When register_pernet_operations is called, The ult_device_ops hook structure is passed, and the init hook function in this structure will be executed.
Static struct pernet_operations _ net_initdata default_device_ops = {
. Exit = default_device_exit,
};

But we have not set the init hook function above. Let's take a look at the above register_pernet_operations function. It returns 0 directly, and then it will be executed in the register_pernet_device function.

Net_dev_init () --> register_pernet_device ()
If (! Error & (first_device ==& pernet_list ))
First_device = & OPS-> list;
However, we can see that first_device points to the queue header list in default_device_ops. Here we only see the initialization of several init_net queue headers, so there is no other important initialization, how to set the network structure of init_net. As the code goes deeper, we will see that this important data structure has been set and adjusted in multiple places. It can be said that init_net is the total entrance to the entire network structure, therefore, there is a network namespace, which is also the main role of struct net we mentioned earlier. I am an unknown pawn. Please repost it with a friend to indicate the source,
Http://qinjiana0786.cublog.cn
. For the time being, we cannot fully initialize init_net (some additional processes are prepared in the appendix at the end of this article). Here we will discuss and study the detailed initialization process step by step as we analyze the process, let's go back to the _ inet_dev_addr_type () function and continue to look at it. This is a very important function. To facilitate analysis, we can paste the code here again.

Sys_socketcall () --> sys_bind () --> inet_bind () --> inet_addr_type () -- >__ inet_dev_addr_type ()

Static inline unsigned _ inet_dev_addr_type (struct net * Net,
Const struct net_device * Dev,
_ Be32 ADDR)
{
Struct flowi FL = {. nl_u = {. ip4_u = {. daddr = ADDR }}};
Struct maid;
Unsigned ret = rtn_broadcast;
Struct fib_table * local_table;
If (%4_is_zeronet (ADDR) | %4_is_lbcast (ADDR ))
Return rtn_broadcast;
If (ipv4_is_multicast (ADDR ))
Return rtn_multicast;
# Ifdef config_ip_multiple_tables
Res. r = NULL;
# Endif
Local_table = maid (net, rt_table_local );
If (local_table ){
Ret = rtn_unicast;
If (! Local_table-> tb_lookup (local_table, & FL, & res )){
If (! Dev | Dev = res. fi-> fig)
Ret = res. type;
Maid (& res );
}
}
Return ret;
}
In the previous section, we analyzed that the route key value FL has set the "phone number" 192.168.1.1 initialization in the exercise at the beginning of the function. The function then judges the address. The first is ipv4_is_zeronet ()

Sys_socketcall () --> sys_bind () --> inet_bind () --> inet_addr_type () -- >__ inet_dev_addr_type () --> limit 4_is_zeronet ()
Static inline bool defaults 4_is_zeronet (_ be32 ADDR)
{
Return (ADDR & htonl (0xff000000) = htonl (0x00000000 );
}
Note that the macro htonl converts the numeric value to the CPU end or end to the required byte order. It actually calls _ cpu_to_be32 () for conversion, let's not look at this macro in detail. The ipv4_is_zeronet () function is used to check whether the 8-bit high IP address is 0 and the IP address is a zero-network address. Then

Sys_socketcall () --> sys_bind () --> inet_bind () --> inet_addr_type () -- >__ inet_dev_addr_type () --> listen 4_is_lbcast ()
Static inline bool listen 4_is_lbcast (_ be32 ADDR)
{
/* Limited broadcast */
Return ADDR = htonl (inaddr_broadcast );
}
# Define inaddr_broadcast (unsigned long INT) 0 xffffffff)
Check whether the address is a broadcast address type and

Sys_socketcall () --> sys_bind () --> inet_bind () --> inet_addr_type () -- >__ inet_dev_addr_type () --> limit 4_is_multicast ()
Static inline bool defaults 4_is_multicast (_ be32 ADDR)
{
Return (ADDR & htonl (0xf0000000) = htonl (0xe0000000 );
}
Check whether the address is of the multicast address type.
Distinguish broadcast, multicast, and unicast addresses.
The process of transmitting data from a computer to all computers in the network is broadcast;
The process of transmitting data from a computer to a specific group of computers on the network is multicast.
The process of transferring data from one computer to another is unicast.

If it is the preceding zero address and broadcast address type and multicast address type, this type of model is directly returned. However, if it is not these address types, you need to use fib_get_table () to find the specific route table, there are two functions in the Linux kernel, which are in/include/NET/ip_fib.h and/NET/IPv4/fib_frontend.c. This depends on whether the config_ip_multiple_tables option is configured in the kernel. For details, refer to "Policy Routing". There is a lot of information about this concept on the Internet. Its role is to execute your routing policies, here, we may need to reiterate the definition of a route. A route provides a better shortcut to reach the destination address, which is generally calculated in a series of ways, A route is located at the Layer 3, that is, the IP layer. Its location in Linux is extremely important. The route table structure provides a method function for calculating routes, we only need to give our first-time contacts a conceptual understanding to avoid too much theoretical entanglement. Let's take a look at this fib_get_table (). I believe our friends through this function really understand the role of the route table. We have enabled the IPv4 routing policy, so we will execute this function in/NET/IPv4/fib_frontend.c. Limited space, next article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.