linux内核网络初始化,Linux内核--网络栈实现分析

本文分析基于内核Linux Kernel 1.2.13

以后的系列博文将深入分析Linux内核的网络栈实现原理,这里看到曹桂平博士的分析后,也决定选择Linux内核1.2.13版本进行分析。

原因如下:

1.功能和网络栈层次已经非常清晰

2.该版本与其后续版本的衔接性较好

3.复杂度相对新的内核版本较小,复杂度低,更容易把握网络内核的实质

4.该内核版本比较系统资料可以查询

下面开始零基础分析Linux内核网络部分的初始化过程。

经过系统加电后执行的bootsect.S,setup.S,head.S,可以参考以前分析的0.11内核。原理相同。

进行前期的准备工作后,系统跳转到init/main.c下的start_kernel函数执行。

网络栈的层次结构如下图:(注:该图片摘自《Linux内核网络栈源代码情景分析》)

a615daf56631a59f554f71cc6468be21.png

start_kernel函数经过平台初始化,内存初始化,陷阱初始化,中断初始化,进程调度初始化,缓冲区初始化等,然后执行socket_init(),最后开中断执行init()。

内核的网络战初始化函数socket_init()函数的实现在net/socket.c中

下面是该函数的实现

voidsock_init(void)//网络栈初始化

{

inti;

printk("Swansea University Computer Society NET3.019\n");

/*

*  Initialize all address (protocol) families.

*/

for(i = 0; i 

/*

*  Initialize the protocols module.

*/

proto_init();

#ifdef CONFIG_NET

/*

*  Initialize the DEV module.

*/

dev_init();

/*

*  And the bottom half handler

*/

bh_base[NET_BH].routine= net_bh;

enable_bh(NET_BH);

#endif

}其中的地址族协议初始化语句for (i = 0; i < NPROTO; ++i) pops[i] = NULL;

这里文件中定义的NPROTO为16

#define NPROTO16/* should be enough for now..*/

而pop[i]是如何定义的呢?

static struct proto_ops *pops[NPROTO];

proto_ops结构体是什么呢?该结构体的定义在include/linux/net.h中,该结构体是具体的操作函数集合,是联系BSD套接字和INET套接字的接口,可以把BSD套接字看做是INET套接字的抽象,结构示意图如下:

25841a6778a92470b35d27b79344e8bb.gif

具体定义在net.h中

structproto_ops {

intfamily;

int(*create)   (structsocket *sock,intprotocol);

int(*dup)      (structsocket *newsock,structsocket *oldsock);

int(*release)  (structsocket *sock,structsocket *peer);

int(*bind)     (structsocket *sock,structsockaddr *umyaddr,

intsockaddr_len);

int(*connect)  (structsocket *sock,structsockaddr *uservaddr,

intsockaddr_len,intflags);

int(*socketpair)   (structsocket *sock1,structsocket *sock2);

int(*accept)   (structsocket *sock,structsocket *newsock,

intflags);

int(*getname)  (structsocket *sock,structsockaddr *uaddr,

int*usockaddr_len,intpeer);

int(*read)     (structsocket *sock,char*ubuf,intsize,

intnonblock);

int(*write)    (structsocket *sock,char*ubuf,intsize,

intnonblock);

int(*select)   (structsocket *sock,intsel_type,

select_table *wait);

int(*ioctl)    (structsocket *sock, unsignedintcmd,

unsignedlongarg);

int(*listen)   (structsocket *sock,intlen);

int(*send)     (structsocket *sock,void*buff,intlen,intnonblock,

unsigned flags);

int(*recv)     (structsocket *sock,void*buff,intlen,intnonblock,

unsigned flags);

int(*sendto)   (structsocket *sock,void*buff,intlen,intnonblock,

unsigned flags,structsockaddr *,intaddr_len);

int(*recvfrom) (structsocket *sock,void*buff,intlen,intnonblock,

unsigned flags,structsockaddr *,int*addr_len);

int(*shutdown) (structsocket *sock,intflags);

int(*setsockopt)   (structsocket *sock,intlevel,intoptname,

char*optval,intoptlen);

int(*getsockopt)   (structsocket *sock,intlevel,intoptname,

char*optval,int*optlen);

int(*fcntl)    (structsocket *sock, unsignedintcmd,

unsignedlongarg);

};可以看到,这里实际上就是一系列操作的函数,有点类似于文件系统中的file_operations。通过参数传递socket完成操作。

接下来是proto_init()协议初始化。

voidproto_init(void)

{

externstructnet_proto protocols[];/* Network protocols 全局变量,定义在protocols.c中 */

structnet_proto *pro;

/* Kick all configured protocols. */

pro = protocols;

while(pro->name != NULL)

{

(*pro->init_func)(pro);

pro++;

}

/* We're all done... */

}全局的protocols定义如下:

structnet_proto protocols[] = {

#ifdef  CONFIG_UNIX

{"UNIX", unix_proto_init },

#endif

#if defined(CONFIG_IPX)||defined(CONFIG_ATALK)

{"802.2",    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        }

};而结构体net_proto的定义net.h中为

structnet_proto {

char*name;/* Protocol name */

void(*init_func)(structnet_proto *);/* Bootstrap */

};以后注重讨论标准的INET域

让我们回到proto_init()函数

接下来会执行inet_proto_init()函数,进行INET域协议的初始化。该函数的实现在net/inet/af_inet.c中

其中的

(void) sock_register(inet_proto_ops.family, &inet_proto_ops);

intsock_register(intfamily,structproto_ops *ops)

{

inti;

cli();//关中断

for(i = 0; i 

{

if(pops[i] != NULL)

continue;//如果不空,则跳过

pops[i] = ops;//进行赋值

pops[i]->family = family;

sti();//开中断

return(i);//返回用于刚刚注册的协议向量号

}

sti();//出现异常,也要开中断

return(-ENOMEM);

}

参数中的inet_proto_ops定义如下:

staticstructproto_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,

};其中AF_INET宏定义为2,即INET协议族号为2,后面是函数指针,INET域的操作函数。

然后

printk("IP Protocols: ");

for(p = inet_protocol_base; p != NULL;)//将inet_protocol_base指向的一个inet_protocol结构体加入数组inet_protos中

{

structinet_protocol *tmp = (structinet_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();//对IP层进行初始化协议初始化完成后再执行dev_init()设备的初始化。

这是大体的一个初始化流程,讨论的不是很详细,后续会进行Linux内核网络栈源代码的详细分析。0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值