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内核。原理相同。
- Linux0.11内核--启动引导代码分析bootsect.s
- Linux0.11内核--启动引导代码分析setup.s
- Linux0.11内核--idt(中断描述符表的初始化)head.s分析
进行前期的准备工作后,系统跳转到init/main.c下的start_kernel函数执行。
网络栈的层次结构如下图:(注:该图片摘自《Linux内核网络栈源代码情景分析》)
start_kernel函数经过平台初始化,内存初始化,陷阱初始化,中断初始化,进程调度初始化,缓冲区初始化等,然后执行socket_init(),最后开中断执行init()。
内核的网络战初始化函数socket_init()函数的实现在net/socket.c中
下面是该函数的实现
- void sock_init(void)//网络栈初始化
- {
- int i;
- printk("Swansea University Computer Society NET3.019\n");
- /*
- * Initialize all address (protocol) families.
- */
- for (i = 0; i < NPROTO; ++i) pops[i] = NULL;
- /*
- * 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
- }
这里文件中定义的NPROTO为16
#define NPROTO 16 /* should be enough for now.. */
而pop[i]是如何定义的呢?
static struct proto_ops *pops[NPROTO];
proto_ops结构体是什么呢?该结构体的定义在include/linux/net.h中,该结构体是具体的操作函数集合,是联系BSD套接字和INET套接字的接口,可以把BSD套接字看做是INET套接字的抽象,结构示意图如下:
具体定义在net.h中
- struct proto_ops {
- int family;
- int (*create) (struct socket *sock, int protocol);
- int (*dup) (struct socket *newsock, struct socket *oldsock);
- int (*release) (struct socket *sock, struct socket *peer);
- int (*bind) (struct socket *sock, struct sockaddr *umyaddr,
- int sockaddr_len);
- int (*connect) (struct socket *sock, struct sockaddr *uservaddr,
- int sockaddr_len, int flags);
- int (*socketpair) (struct socket *sock1, struct socket *sock2);
- int (*accept) (struct socket *sock, struct socket *newsock,
- int flags);
- int (*getname) (struct socket *sock, struct sockaddr *uaddr,
- int *usockaddr_len, int peer);
- int (*read) (struct socket *sock, char *ubuf, int size,
- int nonblock);
- int (*write) (struct socket *sock, char *ubuf, int size,
- int nonblock);
- int (*select) (struct socket *sock, int sel_type,
- select_table *wait);
- int (*ioctl) (struct socket *sock, unsigned int cmd,
- unsigned long arg);
- int (*listen) (struct socket *sock, int len);
- int (*send) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags);
- int (*recv) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags);
- int (*sendto) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags, struct sockaddr *, int addr_len);
- int (*recvfrom) (struct socket *sock, void *buff, int len, int nonblock,
- unsigned flags, struct sockaddr *, int *addr_len);
- int (*shutdown) (struct socket *sock, int flags);
- int (*setsockopt) (struct socket *sock, int level, int optname,
- char *optval, int optlen);
- int (*getsockopt) (struct socket *sock, int level, int optname,
- char *optval, int *optlen);
- int (*fcntl) (struct socket *sock, unsigned int cmd,
- unsigned long arg);
- };
接下来是proto_init()协议初始化。
- void proto_init(void)
- {
- extern struct net_proto protocols[]; /* Network protocols 全局变量,定义在protocols.c中 */
- struct net_proto *pro;
- /* Kick all configured protocols. */
- pro = protocols;
- while (pro->name != NULL)
- {
- (*pro->init_func)(pro);
- pro++;
- }
- /* We're all done... */
- }
- struct net_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 }
- };
- struct net_proto {
- char *name; /* Protocol name */
- void (*init_func)(struct net_proto *); /* Bootstrap */
- };
让我们回到proto_init()函数
接下来会执行inet_proto_init()函数,进行INET域协议的初始化。该函数的实现在net/inet/af_inet.c中
其中的
(void) sock_register(inet_proto_ops.family, &inet_proto_ops);
- int sock_register(int family, struct proto_ops *ops)
- {
- int i;
- cli();//关中断
- for(i = 0; i < NPROTO; i++) //查找一个可用的空闲表项
- {
- if (pops[i] != NULL)
- continue;//如果不空,则跳过
- pops[i] = ops;//进行赋值
- pops[i]->family = family;
- sti();//开中断
- return(i);//返回用于刚刚注册的协议向量号
- }
- sti();//出现异常,也要开中断
- return(-ENOMEM);
- }
参数中的inet_proto_ops定义如下:
- 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,
- };
然后
- printk("IP Protocols: ");
- for(p = inet_protocol_base; p != NULL;) //将inet_protocol_base指向的一个inet_protocol结构体加入数组inet_protos中
- {
- 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();//对IP层进行初始化
这是大体的一个初始化流程,讨论的不是很详细,后续会进行Linux内核网络栈源代码的详细分析。
|
【内容导航】 | |
第1页:网络栈初始化 | 第2页:数据包的传递过程 |
第3页:驱动程序层(上) | 第4页:网络层之IP协议(上) |
第5页:传输层之UDP协议(上) | 第6页:应用层获取数据包(上) |
第7页:数据包的传递过程(下) | 第8页:应用层发送数据(下) |
第9页:传输层之UDP协议(下) | 第10页:网络层之IP协议(下) |
第11页:驱动程序层(下) |
评论暂时关闭