inet_init代码如下:
static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
struct inet_protocol *p;
struct inet_protosw *q;
struct list_head *r;
printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0/n");
if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) {
printk(KERN_CRIT "inet_proto_init: panic/n");
return -EINVAL;
}
/*
* Tell SOCKET that we are alive... 注册socket,告诉socket inet类型的地址族已经准备好了
*/
(void) sock_register(&inet_family_ops);
/*
* Add all the protocols. 包括arp,ip、ICMP、UPD、tcp_v4、tcp、igmp的初始化,主要初始化各种协议对应的inode和socket变量。
其中arp_init完成系统中路由部分neighbour表的初始化
ip_init完成ip协议的初始化。在这两个函数中,都通过定义一个packet_type结构的变量将这种数据包对应的协议发送数据、允许发送设备都做初始化。
*/
printk(KERN_INFO "IP Protocols: ");
for (p = inet_protocol_base; p != NULL;) {
struct inet_protocol *tmp = (struct inet_protocol *) p->next;
inet_add_protocol(p);
printk("%s%s",p->name,tmp?", ":"/n");
p = tmp;
}
/* 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);
/*
* Set the ARP module up
*/
arp_init();
/*
* Set the IP module up
*/
ip_init();
tcp_v4_init(&inet_family_ops);
/* Setup TCP slab cache for open requests. */
tcp_init();
/*
* Set the ICMP layer up
*/
icmp_init(&inet_family_ops);
/* I wish inet_add_protocol had no constructor hook...
I had to move IPIP from net/ipv4/protocol.c :-( --ANK
*/
#ifdef CONFIG_NET_IPIP
ipip_init();
#endif
#ifdef CONFIG_NET_IPGRE
ipgre_init();
#endif
/*
* Initialise the multicast router
*/
#if defined(CONFIG_IP_MROUTE)
ip_mr_init();
#endif
/*
* Create all the /proc entries.
*/
#ifdef CONFIG_PROC_FS
proc_net_create ("raw", 0, raw_get_info);
proc_net_create ("netstat", 0, netstat_get_info);
proc_net_create ("snmp", 0, snmp_get_info);
proc_net_create ("sockstat", 0, afinet_get_info);
proc_net_create ("tcp", 0, tcp_get_info);
proc_net_create ("udp", 0, udp_get_info);
#endif /* CONFIG_PROC_FS */
ipfrag_init();
return 0;
}
module_init(inet_init);
调用inet_init的过程中,涉及到的函数如下:
1. start_kernel:
start_kernel
是Linux内核的启动函数,定义在init/main.c
文件中。start_kernel
,这个函数负责进行内核的初始化工作。2. rest_init:
start_kernel
中,会调用rest_init
函数,该函数的主要作用是创建一个内核线程,并让这个线程执行kernel_init
函数。3. kernel_init:
kernel_init
函数位于init/main.c
文件中,主要负责完成内核的初始化。kernel_init
中,会调用do_basic_setup
函数进行基本的系统设置。4. do_basic_setup:
do_basic_setup
函数中包含一系列基本的系统设置,最后调用kernel_init_freeable
函数。5. kernel_init_freeable:
kernel_init_freeable
函数中,会调用kernel_init_freeable
宏,其中包括了一系列的初始化函数,负责初始化各个子系统。init_post
函数,该函数位于kernel/init/main.c
文件中。6. init_post:
init_post
函数中,会调用initcall_init
函数,该函数位于init/main.c
文件中。initcall_init
函数负责执行所有的初始化回调函数,这些回调函数在编译阶段被链接到.initcall.init
节中。7. do_initcalls:
initcall_init
函数中,会调用do_initcalls
函数,该函数位于init/main.c
文件中。do_initcalls
函数会依次执行.initcall.init
节中的所有初始化回调函数。8. inet_init:
do_initcalls
函数中会调用do_basic_setup
函数,其中包括了对网络子系统的初始化。do_basic_setup
函数会调用inet_init
函数,该函数位于net/ipv4/af_inet.c
文件中。inet_init
函数负责初始化IPv4网络子系统。在Linux中,TCP/IP协议栈是在网络协议栈中的一部分,它负责处理网络通信的高层协议,如TCP和UDP。以下是对TCP/IP协议栈如何与上层套接口(Socket)和下层数据链路层关联的简要解释:
套接口(Socket):
协议族和套接口的创建:
socket
系统调用时,它指定了协议族(如AF_INET)和套接口类型(如SOCK_STREAM)。创建套接口数据结构:
协议栈初始化:
协议与套接口关联:
bind
系统调用将一个套接口绑定到一个特定的IP地址和端口上时,协议栈内部会将这个套接口与相应的协议(TCP或UDP)关联起来。监听和连接建立:
listen
系统调用,用于指示协议栈开始监听连接请求。当有新的连接请求到达时,协议栈会创建一个新的套接口数据结构来表示该连接。数据的上交和下发:
数据链路层关联:
协议栈通过数据结构的关联和相应的处理函数,将套接口与上层应用程序和下层数据链路层连接起来。这样的设计允许协议栈处理网络通信的细节,同时提供简单的套接口供应用程序使用。
在Linux内核中,TCP的三次握手过程的源代码涉及多个文件和函数。以下是对TCP三次握手过程的源代码分析,主要关注设置和发送SYN/ACK的位置以及状态转换的位置。
三次握手的过程包括以下步骤:
客户端发送SYN:
服务器回应SYN/ACK:
客户端发送ACK:
在Linux内核中,设置和发送SYN/ACK主要发生在服务器接收到客户端的SYN报文时。以下是相关源代码:
文件: net/ipv4/tcp_ipv4.c
函数: tcp_v4_syn_recv_sock
// net/ipv4/tcp_ipv4.c
static int tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
// ... 省略部分代码
/* Generate an ISN. The client will only send data when
* ACKing the ISN + 1.
*/
tcp_initialize_rcv_mss(sk);
/* Send out a synack here. */
tcp_send_synack(sk, req, req->rsk_rcv_wnd,
req->ts_recent,
req->ts_recent_stamp);
// ... 省略部分代码
/* Move to established and bump the window up. */
tcp_set_state(sk, TCP_ESTABLISHED);
tcp_initialize_rcv_mss(sk);
tcp_ecn_rcv_synack(sk, skb);
// ... 省略部分代码
return 0;
}
在 tcp_send_synack
函数中,会设置并发送SYN/ACK报文。
状态转换主要发生在服务器收到客户端的ACK报文后。以下是相关源代码:
文件: net/ipv4/tcp_input.c
函数: tcp_rcv_synsent_state_process
// net/ipv4/tcp_input.c
int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
struct tcphdr