Kernel version: 2.6.34
This section is about how the socket was created and accessed by the kernel protocol stack, focusing only on two issues: sock when the kernel table was inserted, and how sock was accessed by the kernel. For the core of the sock insert, lookup functions are given a flowchart.
Sock How to insert a kernel table
Socket created can be used to communicate with the external network, the user can use the file descriptor FD to find the socket to operate, the kernel by look-up table to find the socket to operate. This means that when the socket is created, the item is generated in the file system and inserted into the table where the socket is stored, making it easier for the user and the kernel to access it in two ways.
To create the following UDP socket as an example, where the creation only specifies the socket of the protocol cluster is af_inet, the type is SOCK_DGRAM, the protocol is 0, the socket was created, the corresponding file descriptor, but still missing additional information, the socket is not inserted into the kernel table , or in a free State, in addition to the user through the FD operation, the kernel is not visible socket.
FD = socket (af_inet, SOCK_DGRAM, 0);
Depending on the role (server or client) being used, the next action is different. The two sentences when the server and the client and the external communication of the first sentence, after execution, with the external connection established, the socket inserted into the kernel table is also triggered by these two sentences.
Server-side UDP sockets
Bind (FD, &SERVERADDR, sizeof (SERVERADDR));
Client UDP sockets
Let's look at the specific action to create the socket, which only involves the code associated with the socket store, and the other aspects of these system calls are later analyzed in detail.
Sys_socket () Create socket, mapping file descriptor FD
retval = sock_create (family, type, protocol, &sock);
retval = SOCK_MAP_FD (sock, Flags & (O_cloexec | O_nonblock));
In the kernel, there are struct sockets, commonly referred to as sockets, which represent the interface of the network, and struct sock, which is the interface of the af_inet domain. General struct socket members called Sock,struct Sock member called SK, in the code do not confuse.
Sock_create ()--> __sock_create ()
Final execution __sock_create () to create, note __sock_create () the last parameter is 0, which is created by the user, and if 1, it is created by the kernel.
Assign the socket and set Sock->type to Sock_dgram.
Sock = Sock_alloc ();
Sock->type = type;
The parameters of the af_inet (or pf_inet) protocol family are obtained from the net_families, and the net_families array stores the parameters of the different protocol families, such as the Af_inet protocol family is registered when the IP module is loaded, Inet_init ()-> _register (&inet_family_ops), Sock_register () is the addition of parameters to the net_families array, inet_family_ops defined as follows:
PF = rcu_dereference (net_families[family]);
static const struct Net_proto_family inet_family_ops = {
. Family = pf_inet,
. Create = inet_create,
. Owner = TH Is_module,
};
Finally, the creation method of the corresponding protocol cluster is called, where the Pf->create () is inet_create (), which creates the structure sock of the inet domain.
Err = pf->create (NET, sock, Protocol, Kern);
From the __sock_create () code, you see that the creation consists of two steps: Sock_alloc () and Pf->create (). Sock_alloc () allocates the sock memory space and initializes the Inode; Pf->create () initializes SK.
Sock_alloc ()
Allocates space, allocates nodes (including sockets) through New_inode (), then obtains sock through Socket_i macros, in fact the inode and Sock are distributed together in New_inode (), and the structure is called Sock_alloc.
Inode = New_inode (SOCK_MNT->MNT_SB);
Sock = Socket_i (inode);
Sets the parameters of the Inode and returns sock.
inode-
>i_mode = S_ifsock | S_irwxugo;
Inode->i_uid = Current_fsuid ();
Inode->i_gid = Current_fsgid ();
Return sock;
Continue to look down on the specific creation process: New_inode (), after the allocation, will set the I_ino and I_state values.
struct Inode *new_inode (struct super_block *sb)
{
...
Inode = Alloc_inode (SB);
if (inode) {
spin_lock (&inode_lock);
__inode_add_to_lists (SB, NULL, inode);
Inode->i_ino = ++last_ino;
inode->i_state = 0;
Spin_unlock (&inode_lock);
}
return inode;
}
The Alloc_inode ()-> Sb->s_op->alloc_inode (), SB is SOCK_MNT->MNT_SB, so Alloc_inode () points to the SOCKFS action function Sock_ Alloc_inode.
static const
struct Super_operations sockfs_ops = {
. Alloc_inode = Sock_alloc_inode,
. Destroy_inode =sock_ Destroy_inode,
. Statfs = Simple_statfs,
};
Sock_alloc_inode () Allocates space for the size of the struct SOCKET_ALLOC structure by Kmem_cache_alloc (), while the struct SOCKET_ALLOC structure is defined as follows, but only the inode is returned. In fact, both the socket and the inode have been allocated space, after which you can access the socket via container_of.
static struct Inode *sock_alloc_inode (struct super_block *sb)
{struct Socket_alloc
;
ei = kmem_cache_alloc (Sock_inode_cachep, gfp_kernel);
.... Return &ei->vfs_inode;
}
struct Socket_alloc {
struct socket socket;
struct Inode vfs_inode;
Inet_create ()
Finds the appropriate socket interface from the INETSW according to the type, protocol.
List_for_each_entry_rcu (answer, &inetsw[sock->type], list) {
...
if (ipproto_ip = = Answer->protocol) break
;
...
}