轉載地址?http://blog.csdn.net/yming0221/article/details/7488828
作者:閆明
?本文分析基于內核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.sLinux0.11內核--啟動引導代碼分析setup.sLinux0.11內核--idt(中斷描述符表的初始化)head.s分析?
進行前期的準備工作后,系統跳轉到init/main.c下的start_kernel函數執行。
網絡棧的層次結構如下圖:(注:該圖片摘自《Linux內核網絡棧源代碼情景分析》)
?
物理層主要提供各種連接的物理設備,如各種網卡,串口卡等;
鏈路層主要指的是提供對物理層進行訪問的各種接口卡的驅動程序,如網卡驅動等;
網路層的作用是負責將網絡數據包傳輸到正確的位置,最重要的網絡層協議當然就是IP協議了,其實網絡層還有其他的協議如ICMP,ARP,RARP等,只不過不像IP那樣被多數人所熟悉;
傳輸層的作用主要是提供端到端,說白一點就是提供應用程序之間的通信,傳輸層最著名的協議非TCP與UDP協議末屬了;
應用層,顧名思義,當然就是由應用程序提供的,用來對傳輸數據進行語義解釋的“人機界面”層了,比如HTTP,SMTP,FTP等等,其實應用層還不是人們最終所看到的那一層,最上面的一層應該是“解釋層”,負責將數據以各種不同的表項形式最終呈獻到人們眼前。
Linux網絡協議棧結構
1,系統調用接口層,實質是一個面向用戶空間應用程序的接口調用庫,向用戶空間應用程序提供使用網絡服務的接口。
2,協議無關的接口層,就是SOCKET層,這一層的目的是屏蔽底層的不同協議(更準確的來說主要是TCP與UDP,當然還包括RAW IP, SCTP等),以便與系統調用層之間的接口可以簡單,統一。簡單的說,不管我們應用層使用什么協議,都要通過系統調用接口來建立一個SOCKET,這個SOCKET其實是一個巨大的sock結構,它和下面一層的網絡協議層聯系起來,屏蔽了不同的網絡協議的不同,只吧數據部分呈獻給應用層(通過系統調用接口來呈獻)。
3,網絡協議實現層,毫無疑問,這是整個協議棧的核心。這一層主要實現各種網絡協議,最主要的當然是IP,ICMP,ARP,RARP,TCP,UDP等。這一層包含了很多設計的技巧與算法,相當的不錯。
4,與具體設備無關的驅動接口層,這一層的目的主要是為了統一不同的接口卡的驅動程序與網絡協議層的接口,它將各種不同的驅動程序的功能統一抽象為幾個特殊的動作,如open,close,init等,這一層可以屏蔽底層不同的驅動程序。
5,驅動程序層,這一層的目的就很簡單了,就是建立與硬件的接口層。
?
start_kernel函數經過平臺初始化,內存初始化,陷阱初始化,中斷初始化,進程調度初始化,緩沖區初始化等,然后執行socket_init(),最后開中斷執行init()。
內核的網絡戰初始化函數socket_init()函數的實現在net/socket.c中
下面是該函數的實現
?
[cpp]?view plaincopy
void?sock_init(void)??{??????int?i;????????printk("Swansea?University?Computer?Society?NET3.019\n");???????????????????????for?(i?=?0;?i?<?NPROTO;?++i)?pops[i]?=?NULL;??????????????????proto_init();????#ifdef?CONFIG_NET????????????????dev_init();????????????????????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套接字的抽象,結構示意圖如下:
具體定義在net.h中
?
[cpp]?view plaincopy
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);??????};??
可以看到,這里實際上就是一系列操作的函數,有點類似于文件系統中的file_operations。通過參數傳遞socket完成操作。
?
接下來是proto_init()協議初始化。
?
[cpp]?view plaincopy
void?proto_init(void)??{??????extern?struct?net_proto?protocols[];??????????struct?net_proto?*pro;??????????????pro?=?protocols;??????while?(pro->name?!=?NULL)???????{??????????(*pro->init_func)(pro);??????????pro++;??????}????????}?? 全局的protocols定義如下:
?
?
[cpp]?view plaincopy
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????????}??};??
而結構體net_proto的定義net.h中為
?
?
[cpp]?view plaincopy
struct?net_proto?{??????char?*name;???????????void?(*init_func)(struct?net_proto?*);????};?? 以后注重討論標準的INET域
讓我們回到proto_init()函數
?
接下來會執行inet_proto_init()函數,進行INET域協議的初始化。該函數的實現在net/inet/af_inet.c中
其中的
(void) sock_register(inet_proto_ops.family, &inet_proto_ops);
?
[cpp]?view plaincopy
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定義如下:
?
[cpp]?view plaincopy
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,??};??
其中AF_INET宏定義為2,即INET協議族號為2,后面是函數指針,INET域的操作函數。
?
然后
[cpp]?view plaincopy
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;??}??????arp_init();??????????ip_init();?? 協議初始化完成后再執行dev_init()設備的初始化。
?
這是大體的一個初始化流程,討論的不是很詳細,后續會進行Linux內核網絡棧源代碼的詳細分析。
轉載于:https://www.cnblogs.com/davidwang456/p/3604085.html
總結
以上是生活随笔為你收集整理的Linux内核--网络栈实现分析(一)--网络栈初始化--转的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。