摘自:http://blog.chinaunix.net/uid-23629988-id-264304.html
本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
从今天开始的源码学习,就不再拘泥于一行语句的具体含义,而是将注意力主要集中在整体流程和框架上。
TCP/IP协议的初始化函数为inet_inet,由fs_initcall(inet_init); 在系统启动时,自动调用。
-
static int __init
inet_init(void)
-
{
-
struct sk_buff *dummy_skb;
-
struct inet_protosw *q;
-
struct list_head *r;
-
int rc = -EINVAL;
-
-
BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));
/* 申请reserved ports的bitmap
*/
-
sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);
-
if (!sysctl_local_reserved_ports)
-
goto out;
/*
注册TCP,UDP和RAW协议
*/
-
rc = proto_register(&tcp_prot, 1);
-
if (rc)
-
goto out_free_reserved_ports;
-
-
rc = proto_register(&udp_prot, 1);
-
if (rc)
-
goto out_unregister_tcp_proto;
-
-
rc = proto_register(&raw_prot, 1);
-
if (rc)
-
goto out_unregister_udp_proto;
-
-
/*
-
* Tell SOCKET that we are alive...
-
*/
/* 注册Inet familiy*/
-
(void)sock_register(&inet_family_ops);
-
-
#ifdef CONFIG_SYSCTL
-
ip_static_sysctl_init();
-
#endif
-
-
/*
-
* Add all the base protocols.
-
*/
/*
添加协议:ICMP,UDP,TCP和IGMP。
从这里就可以看出,内核中支持的TCP/IP协议种类
*/
-
if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
-
printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
-
if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
-
printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
-
if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
-
printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
-
#ifdef CONFIG_IP_MULTICAST
-
if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
-
printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");
-
#endif
-
-
/* Register the socket-side
information for inet_create. */
- /* 初始化inetsw */
-
for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
-
INIT_LIST_HEAD(r);
/*
将inetsw_array中的协议挂载到inetsw上
*/
-
for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
-
inet_register_protosw(q);
/*
下面是各个Inet模块的初始化。
*/
-
/*
-
* Set the ARP module up
-
*/
-
-
arp_init();
-
-
/*
-
* Set the IP module up
-
*/
-
-
ip_init();
-
-
tcp_v4_init();
-
-
/* Setup TCP slab cache for open
requests. */
-
tcp_init();
-
-
/* Setup UDP memory threshold */
-
udp_init();
-
-
/* Add UDP-Lite (RFC
3828) */
-
udplite4_register();
-
-
/*
-
* Set the ICMP layer up
-
*/
-
-
if (icmp_init() < 0)
-
panic("Failed to create the ICMP control socket.\n");
-
-
/*
-
* Initialise the multicast router
-
*/
-
#if defined(CONFIG_IP_MROUTE)
-
if (ip_mr_init())
-
printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
-
#endif
-
/*
-
* Initialise per-cpu ipv4 mibs
-
*/
-
-
if (init_ipv4_mibs())
-
printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");
-
-
ipv4_proc_init();
-
-
ipfrag_init();
/*
这个将IP协议注册L2层
*/
-
dev_add_pack(&ip_packet_type);
-
-
rc = 0;
-
out:
-
return rc;
-
out_unregister_udp_proto:
-
proto_unregister(&udp_prot);
-
out_unregister_tcp_proto:
-
proto_unregister(&tcp_prot);
-
out_free_reserved_ports:
-
kfree(sysctl_local_reserved_ports);
-
goto out;
- }
这个初始化函数比较简单,但是已经为我们揭开了TCP/IP架构的面纱的一角。
下面具体说说关键的地方。
- proto_register:这个操作主要是为了将注册协议,挂载到/proc文件系统上。通过/proc/net/protocols可以看到注册协议的统计信息;
- sock_register;这个操作是注册socket family。也就是socket(2)中的第一个参数所指的family;这样通过family就可以调用对应family的回调函数;
- inet_register_protosw:这个操作从名字上看是注册proto,其实我个人觉得实际上是根据socket type注册。这个type也是对应于socket(2)中第二个参数socket_type。这个注册支持重复type,但是如果以前已经存在permanet的type且新的proto与原有的proto协议相同,就会报告冲突。
- dev_add_pack(&ip_packet_type):这个操作是将IP协议注册到2层(ptype_base)当中。当2层协议与ip_packet_type.type(cpu_to_be16(ETH_P_IP))相等时,即收到的2层包的payload为IP协议,即调用ip_packet_type对应的回调函数。
当inet_init执行完时,基本的TCP/IP协议已经挂载完毕。
对于发送流程来说,通过socket(2)建立socket,先通过socket family找到family,也就是inet_family_ops,然后调用create,然后根据socket_type以及proto从inetsw的数组中,找到正确的inetsw,然后将其对应的operation,proto
信息,以及其它信息赋给了socket。那么以后的操作,就可以使用socket中的operation或者proto进行处理了。
对于接受流程来说,首先netif_receive_skb——2层的入口之一为例,当2层type等于ip_packet_type.type时,会调用ip_packet_type的回调函数func,也就是ip_rcv。接收再往后的流程需要再细看看,今天就到这里了。
下次将重点学习数据包的接收流程。