歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> 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內核。原理相同。

  1. Linux0.11內核--啟動引導代碼分析bootsect.s  http://www.linuxidc.com/Linux/2012-04/59202.htm
  2. Linux0.11內核--啟動引導代碼分析setup.s  http://www.linuxidc.com/Linux/2012-04/59203.htm
  3. Linux0.11內核--idt(中斷描述符表的初始化)head.s分析 http://www.linuxidc.com/Linux/2012-04/59204.htm

進行前期的准備工作後,系統跳轉到init/main.c下的start_kernel函數執行。

網絡棧的層次結構如下圖:(注:該圖片摘自《Linux內核網絡棧源代碼情景分析》)


start_kernel函數經過平台初始化,內存初始化,陷阱初始化,中斷初始化,進程調度初始化,緩沖區初始化等,然後執行socket_init(),最後開中斷執行init()。

內核的網絡戰初始化函數socket_init()函數的實現在net/socket.c中

下面是該函數的實現

  1. void sock_init(void)//網絡棧初始化   
  2. {  
  3.     int i;  
  4.   
  5.     printk("Swansea University Computer Society NET3.019\n");  
  6.   
  7.     /* 
  8.      *  Initialize all address (protocol) families.  
  9.      */  
  10.        
  11.     for (i = 0; i < NPROTO; ++i) pops[i] = NULL;  
  12.   
  13.     /* 
  14.      *  Initialize the protocols module.  
  15.      */  
  16.   
  17.     proto_init();  
  18.   
  19. #ifdef CONFIG_NET   
  20.     /*  
  21.      *  Initialize the DEV module.  
  22.      */  
  23.   
  24.     dev_init();  
  25.     
  26.     /* 
  27.      *  And the bottom half handler  
  28.      */  
  29.   
  30.     bh_base[NET_BH].routine= net_bh;  
  31.     enable_bh(NET_BH);  
  32. #endif     
  33. }  
其中的地址族協議初始化語句for (i = 0; i < NPROTO; ++i) pops[i] = NULL;

這裡文件中定義的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中

  1. struct proto_ops {  
  2.   int   family;  
  3.   
  4.   int   (*create)   (struct socket *sock, int protocol);  
  5.   int   (*dup)      (struct socket *newsock, struct socket *oldsock);  
  6.   int   (*release)  (struct socket *sock, struct socket *peer);  
  7.   int   (*bind)     (struct socket *sock, struct sockaddr *umyaddr,  
  8.              int sockaddr_len);  
  9.   int   (*connect)  (struct socket *sock, struct sockaddr *uservaddr,  
  10.              int sockaddr_len, int flags);  
  11.   int   (*socketpair)   (struct socket *sock1, struct socket *sock2);  
  12.   int   (*accept)   (struct socket *sock, struct socket *newsock,  
  13.              int flags);  
  14.   int   (*getname)  (struct socket *sock, struct sockaddr *uaddr,  
  15.              int *usockaddr_len, int peer);  
  16.   int   (*read)     (struct socket *sock, char *ubuf, int size,  
  17.              int nonblock);  
  18.   int   (*write)    (struct socket *sock, char *ubuf, int size,  
  19.              int nonblock);  
  20.   int   (*select)   (struct socket *sock, int sel_type,  
  21.              select_table *wait);  
  22.   int   (*ioctl)    (struct socket *sock, unsigned int cmd,  
  23.              unsigned long arg);  
  24.   int   (*listen)   (struct socket *sock, int len);  
  25.   int   (*send)     (struct socket *sock, void *buff, int len, int nonblock,  
  26.              unsigned flags);  
  27.   int   (*recv)     (struct socket *sock, void *buff, int len, int nonblock,  
  28.              unsigned flags);  
  29.   int   (*sendto)   (struct socket *sock, void *buff, int len, int nonblock,  
  30.              unsigned flags, struct sockaddr *, int addr_len);  
  31.   int   (*recvfrom) (struct socket *sock, void *buff, int len, int nonblock,  
  32.              unsigned flags, struct sockaddr *, int *addr_len);  
  33.   int   (*shutdown) (struct socket *sock, int flags);  
  34.   int   (*setsockopt)   (struct socket *sock, int level, int optname,  
  35.              char *optval, int optlen);  
  36.   int   (*getsockopt)   (struct socket *sock, int level, int optname,  
  37.              char *optval, int *optlen);  
  38.   int   (*fcntl)    (struct socket *sock, unsigned int cmd,  
  39.              unsigned long arg);      
  40. };  
可以看到,這裡實際上就是一系列操作的函數,有點類似於文件系統中的file_operations。通過參數傳遞socket完成操作。

接下來是proto_init()協議初始化。

  1. void proto_init(void)  
  2. {  
  3.     extern struct net_proto protocols[];    /* Network protocols 全局變量,定義在protocols.c中 */  
  4.     struct net_proto *pro;  
  5.   
  6.     /* Kick all configured protocols. */  
  7.     pro = protocols;  
  8.     while (pro->name != NULL)   
  9.     {  
  10.         (*pro->init_func)(pro);  
  11.         pro++;  
  12.     }  
  13.     /* We're all done... */  
  14. }  
全局的protocols定義如下:
  1. struct net_proto protocols[] = {  
  2. #ifdef  CONFIG_UNIX   
  3.   { "UNIX", unix_proto_init },  
  4. #endif   
  5. #if defined(CONFIG_IPX)||defined(CONFIG_ATALK)     
  6.   { "802.2",    p8022_proto_init },  
  7.   { "SNAP", snap_proto_init },  
  8. #endif   
  9. #ifdef CONFIG_AX25     
  10.   { "AX.25",    ax25_proto_init },  
  11. #endif     
  12. #ifdef  CONFIG_INET   
  13.   { "INET", inet_proto_init },  
  14. #endif   
  15. #ifdef  CONFIG_IPX   
  16.   { "IPX",  ipx_proto_init },  
  17. #endif   
  18. #ifdef CONFIG_ATALK   
  19.   { "DDP",  atalk_proto_init },  
  20. #endif   
  21.   { NULL,   NULL        }  
  22. };  
而結構體net_proto的定義net.h中為
  1. struct net_proto {  
  2.     char *name;     /* Protocol name */  
  3.     void (*init_func)(struct net_proto *);  /* Bootstrap */  
  4. };  
以後注重討論標准的INET域

讓我們回到proto_init()函數

接下來會執行inet_proto_init()函數,進行INET域協議的初始化。該函數的實現在net/inet/af_inet.c中

其中的

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

  1. int sock_register(int family, struct proto_ops *ops)  
  2. {  
  3.     int i;  
  4.   
  5.     cli();//關中斷   
  6.     for(i = 0; i < NPROTO; i++) //查找一個可用的空閒表項   
  7.     {  
  8.         if (pops[i] != NULL)   
  9.             continue;//如果不空,則跳過   
  10.         pops[i] = ops;//進行賦值   
  11.         pops[i]->family = family;  
  12.         sti();//開中斷   
  13.         return(i);//返回用於剛剛注冊的協議向量號   
  14.     }  
  15.     sti();//出現異常,也要開中斷   
  16.     return(-ENOMEM);  
  17. }  

參數中的inet_proto_ops定義如下:

  1. static struct proto_ops inet_proto_ops = {  
  2.     AF_INET,  
  3.   
  4.     inet_create,  
  5.     inet_dup,  
  6.     inet_release,  
  7.     inet_bind,  
  8.     inet_connect,  
  9.     inet_socketpair,  
  10.     inet_accept,  
  11.     inet_getname,   
  12.     inet_read,  
  13.     inet_write,  
  14.     inet_select,  
  15.     inet_ioctl,  
  16.     inet_listen,  
  17.     inet_send,  
  18.     inet_recv,  
  19.     inet_sendto,  
  20.     inet_recvfrom,  
  21.     inet_shutdown,  
  22.     inet_setsockopt,  
  23.     inet_getsockopt,  
  24.     inet_fcntl,  
  25. };  
其中AF_INET宏定義為2,即INET協議族號為2,後面是函數指針,INET域的操作函數。

然後

  1. printk("IP Protocols: ");  
  2. for(p = inet_protocol_base; p != NULL;) //將inet_protocol_base指向的一個inet_protocol結構體加入數組inet_protos中   
  3. {  
  4.     struct inet_protocol *tmp = (struct inet_protocol *) p->next;  
  5.     inet_add_protocol(p);  
  6.     printk("%s%s",p->name,tmp?", ":"\n");  
  7.     p = tmp;  
  8. }  
  9. /* 
  10.  *  Set the ARP module up 
  11.  */  
  12. arp_init();//對地址解析層進行初始化   
  13.     /* 
  14.      *  Set the IP module up 
  15.      */  
  16. ip_init();//對IP層進行初始化  
協議初始化完成後再執行dev_init()設備的初始化。

這是大體的一個初始化流程,討論的不是很詳細,後續會進行Linux內核網絡棧源代碼的詳細分析。

Copyright © Linux教程網 All Rights Reserved