歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核--網絡棧實現分析

Linux內核--網絡棧實現分析

日期:2017/3/1 10:24:05   编辑: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. printk("Swansea University Computer Society NET3.019\n");
  5. /*
  6. * Initialize all address (protocol) families.
  7. */
  8. for (i = 0; i < NPROTO; ++i) pops[i] = NULL;
  9. /*
  10. * Initialize the protocols module.
  11. */
  12. proto_init();
  13. #ifdef CONFIG_NET
  14. /*
  15. * Initialize the DEV module.
  16. */
  17. dev_init();
  18. /*
  19. * And the bottom half handler
  20. */
  21. bh_base[NET_BH].routine= net_bh;
  22. enable_bh(NET_BH);
  23. #endif
  24. }
其中的地址族協議初始化語句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. int (*create) (struct socket *sock, int protocol);
  4. int (*dup) (struct socket *newsock, struct socket *oldsock);
  5. int (*release) (struct socket *sock, struct socket *peer);
  6. int (*bind) (struct socket *sock, struct sockaddr *umyaddr,
  7. int sockaddr_len);
  8. int (*connect) (struct socket *sock, struct sockaddr *uservaddr,
  9. int sockaddr_len, int flags);
  10. int (*socketpair) (struct socket *sock1, struct socket *sock2);
  11. int (*accept) (struct socket *sock, struct socket *newsock,
  12. int flags);
  13. int (*getname) (struct socket *sock, struct sockaddr *uaddr,
  14. int *usockaddr_len, int peer);
  15. int (*read) (struct socket *sock, char *ubuf, int size,
  16. int nonblock);
  17. int (*write) (struct socket *sock, char *ubuf, int size,
  18. int nonblock);
  19. int (*select) (struct socket *sock, int sel_type,
  20. select_table *wait);
  21. int (*ioctl) (struct socket *sock, unsigned int cmd,
  22. unsigned long arg);
  23. int (*listen) (struct socket *sock, int len);
  24. int (*send) (struct socket *sock, void *buff, int len, int nonblock,
  25. unsigned flags);
  26. int (*recv) (struct socket *sock, void *buff, int len, int nonblock,
  27. unsigned flags);
  28. int (*sendto) (struct socket *sock, void *buff, int len, int nonblock,
  29. unsigned flags, struct sockaddr *, int addr_len);
  30. int (*recvfrom) (struct socket *sock, void *buff, int len, int nonblock,
  31. unsigned flags, struct sockaddr *, int *addr_len);
  32. int (*shutdown) (struct socket *sock, int flags);
  33. int (*setsockopt) (struct socket *sock, int level, int optname,
  34. char *optval, int optlen);
  35. int (*getsockopt) (struct socket *sock, int level, int optname,
  36. char *optval, int *optlen);
  37. int (*fcntl) (struct socket *sock, unsigned int cmd,
  38. unsigned long arg);
  39. };
可以看到,這裡實際上就是一系列操作的函數,有點類似於文件系統中的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. /* Kick all configured protocols. */
  6. pro = protocols;
  7. while (pro->name != NULL)
  8. {
  9. (*pro->init_func)(pro);
  10. pro++;
  11. }
  12. /* We're all done... */
  13. }
全局的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. cli();//關中斷
  5. for(i = 0; i < NPROTO; i++) //查找一個可用的空閒表項
  6. {
  7. if (pops[i] != NULL)
  8. continue;//如果不空,則跳過
  9. pops[i] = ops;//進行賦值
  10. pops[i]->family = family;
  11. sti();//開中斷
  12. return(i);//返回用於剛剛注冊的協議向量號
  13. }
  14. sti();//出現異常,也要開中斷
  15. return(-ENOMEM);
  16. }

參數中的inet_proto_ops定義如下:

  1. static struct proto_ops inet_proto_ops = {
  2. AF_INET,
  3. inet_create,
  4. inet_dup,
  5. inet_release,
  6. inet_bind,
  7. inet_connect,
  8. inet_socketpair,
  9. inet_accept,
  10. inet_getname,
  11. inet_read,
  12. inet_write,
  13. inet_select,
  14. inet_ioctl,
  15. inet_listen,
  16. inet_send,
  17. inet_recv,
  18. inet_sendto,
  19. inet_recvfrom,
  20. inet_shutdown,
  21. inet_setsockopt,
  22. inet_getsockopt,
  23. inet_fcntl,
  24. };
其中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