现在的位置: 首页 > 综合 > 正文

Linux内核协议栈分析之tcp/ip初始化——tcp/ip通信并不神秘(2)

2013年05月19日 ⁄ 综合 ⁄ 共 3518字 ⁄ 字号 评论关闭

写在代码前:

        我:Jack,出来吧。今天晚上咱们分析Linux1.2.4内核的协议栈。

        Jack:上次不是分析Linux1.0的内核协议栈吗?怎么突然之间要分析1.2.4了?

        我:上次分析完Linux1.0的网卡初始化之后,又看了下sock初始化,发现1.0的代码协议栈这块儿层次还不是特别清晰,我甚至不知道它能不能通信。

        所以,我选择用1.2.4版本分析,这个版本层次更清晰些。

       Jack:好吧。你分析吧。

 

      asmlinkage void start_kernel(void)  //init/main.c            line 342
      sock_init();                        //init/main.c            line 383
      proto_init();                       //net/socket.c           line 1362
      while (pro->name != NULL)
      {
           (*pro->init_func)(pro);
           pro++;
      }                                       
      dev_init();                         //net/socket.c           line 1369

                                           问:在上一篇文章里不是已经做过网卡初始化了吗?为什么还会有dev_init()操作。

                                           答:在上一篇文章是生成dev这个结构体对象,这里的dev_init是执行dev对象你的函数指针.

这里的调用栈最核心的是proto_init()函数。//net/socket.c           line 1362

void proto_init(void)
{
	extern struct net_proto protocols[];	/* Network protocols */
	struct net_proto *pro;

	/* Kick all configured protocols. */
	pro = protocols;
	while (pro->name != NULL) 
	{
		(*pro->init_func)(pro);
		pro++;
	}
	/* We're all done... */
}

 这个函数没有参数传入——因为这个函数处理的数据是个全局变量——net_proto protocols[];。(全局变量这种龊B的东西在早期的Linux内核用得挺多的,Linux内核其实真的不神秘)

net_proto protocols[];定义在net/protocols.c

struct net_proto protocols[] = {
#ifdef	CONFIG_UNIX
  { "UNIX",	unix_proto_init	},
#endif
#if defined(CONFIG_IPX)||defined(CONFIG_ATALK)  
  { "UNIX",	p8022_proto_init },
  { "SNAP",	snap_proto_init },
#endif
#ifdef CONFIG_AX25  
  { "AX.25",	ax25_proto_init },
#endif  
#ifdef	CONFIG_INET
  { "INET",	inet_proto_init	},
#endif
#ifdef  CONFIG_IPX
  { "IPX",	ipx_proto_init },
#endif
#ifdef CONFIG_ATALK
  { "DDP",	atalk_proto_init },
#endif
  { NULL,	NULL		}
};

在我们一般的概念中,网络就是inet。其实inet只是net pro中的一种(用得最多,见得最多的那种)。在1.2.4的Linux内核版本里,支持"UNIX","UNIX","SNAP","AX.25","INET","IPX","DDP"这么多种net协议。而且,每种协议都有其对应的协议初始化函数——其实就是一个函数指针。例如我们知道的tcp/ip的协议初始化函数指针是inet_proto_init。

我们接着看一下inet_proto_init这个初始化函数做了些什么。

 

void inet_proto_init(struct net_proto *pro)
{
	struct inet_protocol *p;
	int i;


	printk("Swansea University Computer Society TCP/IP for NET3.019\n");

	/*
	 *	Tell SOCKET that we are alive... 
	 */
   
  	(void) sock_register(inet_proto_ops.family, &inet_proto_ops);

  	seq_offset = CURRENT_TIME*250;

	/*
	 *	Add all the protocols. 
	 */
	 
	for(i = 0; i < SOCK_ARRAY_SIZE; i++) 
	{
		tcp_prot.sock_array[i] = NULL;
		udp_prot.sock_array[i] = NULL;
		raw_prot.sock_array[i] = NULL;
  	}
	tcp_prot.inuse = 0;
	tcp_prot.highestinuse = 0;
	udp_prot.inuse = 0;
	udp_prot.highestinuse = 0;
	raw_prot.inuse = 0;
	raw_prot.highestinuse = 0;

	printk("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;
	}
	/*
	 *	Set the ARP module up
	 */
	arp_init();
  	/*
  	 *	Set the IP module up
  	 */
	ip_init();
}

这个函数做了3件事:

1、   (void) sock_register(inet_proto_ops.family, &inet_proto_ops);    //注册inet协议族,把inet协议的ops挂上去。

2、arp_init()。

3、ip_init()。

inet_proto_ops其实就是一个跳转表。定义在net/inet/af_inet.c    line 1482

static struct proto_ops inet_proto_ops = {
 AF_INET,

 inet_create,
 inet_dup,
 inet_release,
 inet_bind,
 inet_connect,
 inet_socketpair,
 inet_accept,
 inet_getname, 
 inet_read,
 inet_write,
 inet_select,
 inet_ioctl,
 inet_listen,
 inet_send,
 inet_recv,
 inet_sendto,
 inet_recvfrom,
 inet_shutdown,
 inet_setsockopt,
 inet_getsockopt,
 inet_fcntl,
};

如果你对Linux的文件系统比较熟悉,这些东西应该是一看就明白的。

arp_init();

ip_init();

这两个函数做的事情是完全类似的。

void arp_init (void)
{
	/* Register the packet type */
	arp_packet_type.type=htons(ETH_P_ARP);
	dev_add_pack(&arp_packet_type);
	/* Start with the regular checks for expired arp entries. */
	add_timer(&arp_timer);
	/* Register for device down reports */
	register_netdevice_notifier(&arp_dev_notifier);
}

 

void ip_init(void)
{
	ip_packet_type.type=htons(ETH_P_IP);
	dev_add_pack(&ip_packet_type);

	/* So we flush routes when a device is downed */	
	register_netdevice_notifier(&ip_rt_notifier);
/*	ip_raw_init();
	ip_packet_init();
	ip_tcp_init();
	ip_udp_init();*/
}

分别做了2件事:

1、定义包类型。

2、注册notifier。

notifier不是协议栈的主要主题,不作分析

至此,网络协议初始化就完成了。

 

抱歉!评论已关闭.